From 1f87ccf0ae8f7ef422fc93415e507066ba5e2273 Mon Sep 17 00:00:00 2001 From: Katharine Hyatt Date: Sat, 19 Oct 2024 15:03:32 -0400 Subject: [PATCH 001/342] Test for showing AnnotatedIOBuffer --- test/strings/annotated.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/strings/annotated.jl b/test/strings/annotated.jl index 85acab74abf7b..9418ff26ef43a 100644 --- a/test/strings/annotated.jl +++ b/test/strings/annotated.jl @@ -244,4 +244,8 @@ end @test write(wrapio, Base.AnnotatedChar('a', [(:y, 2)])) == 1 @test read(seekstart(aio), Base.AnnotatedString) == Base.AnnotatedString("heya", [(1:3, :x, 1), (4:4, :y, 2)]) + # show-ing an AnnotatedIOBuffer + aio = Base.AnnotatedIOBuffer() + write(aio, Base.AnnotatedString("hello", [(1:5, :tag, 1)])) + @test sprint(show, aio) == "Base.AnnotatedIOBuffer(5 bytes, 1 annotation)" end From f6ebc4b2e87db68490a5c756dd4671c92ef8e789 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Wed, 27 Nov 2024 14:45:16 +0900 Subject: [PATCH 002/342] optimizer: handle `EnterNode` with `catch_dest == 0` (#56686) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In some parts of the optimizer code, such as `cfg_simplify!` and irinterp, it is assumed that `EnterNode` always has `catch_dest ≠ 0`, but this assumption is incorrect. This commit fixes those cases. --- Compiler/src/ssair/irinterp.jl | 6 ++++-- Compiler/src/ssair/passes.jl | 6 ++++-- Compiler/test/irpasses.jl | 29 ++++++++++++++++++++++++++++- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/Compiler/src/ssair/irinterp.jl b/Compiler/src/ssair/irinterp.jl index e96d27a85bc37..a4969e81828cc 100644 --- a/Compiler/src/ssair/irinterp.jl +++ b/Compiler/src/ssair/irinterp.jl @@ -249,8 +249,10 @@ function process_terminator!(@nospecialize(stmt), bb::Int, bb_ip::BitSetBoundedM return backedge elseif isa(stmt, EnterNode) dest = stmt.catch_dest - @assert dest > bb - push!(bb_ip, dest) + if dest ≠ 0 + @assert dest > bb + push!(bb_ip, dest) + end push!(bb_ip, bb+1) return false else diff --git a/Compiler/src/ssair/passes.jl b/Compiler/src/ssair/passes.jl index e61f3207fc07a..ff333b9b0a129 100644 --- a/Compiler/src/ssair/passes.jl +++ b/Compiler/src/ssair/passes.jl @@ -2393,8 +2393,10 @@ function cfg_simplify!(ir::IRCode) end elseif isa(terminator, EnterNode) catchbb = terminator.catch_dest - if bb_rename_succ[catchbb] == 0 - push!(worklist, catchbb) + if catchbb ≠ 0 + if bb_rename_succ[catchbb] == 0 + push!(worklist, catchbb) + end end elseif isa(terminator, GotoNode) || isa(terminator, ReturnNode) # No implicit fall through. Schedule from work list. diff --git a/Compiler/test/irpasses.jl b/Compiler/test/irpasses.jl index 412ff3b98cb19..e9d6f57337530 100644 --- a/Compiler/test/irpasses.jl +++ b/Compiler/test/irpasses.jl @@ -1816,7 +1816,34 @@ function f53521() end end end -@test code_typed(f53521)[1][2] === Nothing +let (ir,rt) = only(Base.code_ircode(f53521, ())) + @test rt == Nothing + Compiler.verify_ir(ir) + Compiler.cfg_simplify!(ir) + Compiler.verify_ir(ir) +end + +Base.@assume_effects :foldable Base.@constprop :aggressive function f53521(x::Int, ::Int) + VALUE = ScopedValue(x) + @with VALUE => 2 begin + for i = 1 + @with VALUE => 3 begin + local v + try + v = sin(VALUE[]) + catch + v = nothing + end + return v + end + end + end +end +let (ir,rt) = only(Base.code_ircode((Int,)) do y + f53521(1, y) + end) + @test rt == Union{Nothing,Float64} +end # Test that adce_pass! sets Refined on PhiNode values let code = Any[ From 42807311db112b0116c3e0923845808efec0fed4 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Wed, 27 Nov 2024 10:59:32 -0300 Subject: [PATCH 003/342] Pass `JULIA_NUM_THREADS=1` to the sysimage builder (#56695) Having multiple threads isn't suported during the build since the scheduler doesn't exist at this point. Fixes https://github.com/JuliaLang/julia/issues/56533 --- sysimage.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sysimage.mk b/sysimage.mk index 5371fbd975025..a74aace4dd11c 100644 --- a/sysimage.mk +++ b/sysimage.mk @@ -65,14 +65,14 @@ RELDATADIR := $(call rel_path,$(JULIAHOME)/base,$(build_datarootdir))/ # <-- mak $(build_private_libdir)/basecompiler.ji: $(COMPILER_SRCS) @$(call PRINT_JULIA, cd $(JULIAHOME)/base && \ - $(call spawn,$(JULIA_EXECUTABLE)) -C "$(JULIA_CPU_TARGET)" $(HEAPLIM) --output-ji $(call cygpath_w,$@).tmp \ + JULIA_NUM_THREADS=1 $(call spawn,$(JULIA_EXECUTABLE)) -C "$(JULIA_CPU_TARGET)" $(HEAPLIM) --output-ji $(call cygpath_w,$@).tmp \ --startup-file=no --warn-overwrite=yes -g$(BOOTSTRAP_DEBUG_LEVEL) -O1 Base_compiler.jl --buildroot $(RELBUILDROOT) --dataroot $(RELDATADIR)) @mv $@.tmp $@ $(build_private_libdir)/sys.ji: $(build_private_libdir)/basecompiler.ji $(JULIAHOME)/VERSION $(BASE_SRCS) $(STDLIB_SRCS) @$(call PRINT_JULIA, cd $(JULIAHOME)/base && \ if ! JULIA_BINDIR=$(call cygpath_w,$(build_bindir)) WINEPATH="$(call cygpath_w,$(build_bindir));$$WINEPATH" \ - $(call spawn, $(JULIA_EXECUTABLE)) -g1 -O1 -C "$(JULIA_CPU_TARGET)" $(HEAPLIM) --output-ji $(call cygpath_w,$@).tmp $(JULIA_SYSIMG_BUILD_FLAGS) \ + JULIA_NUM_THREADS=1 $(call spawn, $(JULIA_EXECUTABLE)) -g1 -O1 -C "$(JULIA_CPU_TARGET)" $(HEAPLIM) --output-ji $(call cygpath_w,$@).tmp $(JULIA_SYSIMG_BUILD_FLAGS) \ --startup-file=no --warn-overwrite=yes --sysimage $(call cygpath_w,$<) sysimg.jl --buildroot $(RELBUILDROOT) --dataroot $(RELDATADIR); then \ echo '*** This error might be fixed by running `make clean`. If the error persists$(COMMA) try `make cleanall`. ***'; \ false; \ From 68fa4a94421d4cb6ee406d31697f05b2def6aeef Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Wed, 27 Nov 2024 19:01:18 -0500 Subject: [PATCH 004/342] deps/cacert: Update to 2024-11-26 (#56697) --- deps/checksums/cacert-2024-03-11.pem/md5 | 1 - deps/checksums/cacert-2024-03-11.pem/sha512 | 1 - deps/checksums/cacert-2024-11-26.pem/md5 | 1 + deps/checksums/cacert-2024-11-26.pem/sha512 | 1 + deps/libgit2.version | 2 +- stdlib/MozillaCACerts_jll/Project.toml | 2 +- 6 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 deps/checksums/cacert-2024-03-11.pem/md5 delete mode 100644 deps/checksums/cacert-2024-03-11.pem/sha512 create mode 100644 deps/checksums/cacert-2024-11-26.pem/md5 create mode 100644 deps/checksums/cacert-2024-11-26.pem/sha512 diff --git a/deps/checksums/cacert-2024-03-11.pem/md5 b/deps/checksums/cacert-2024-03-11.pem/md5 deleted file mode 100644 index 618b6c74efdd4..0000000000000 --- a/deps/checksums/cacert-2024-03-11.pem/md5 +++ /dev/null @@ -1 +0,0 @@ -594084120d27f482b1dc48f558d12d48 diff --git a/deps/checksums/cacert-2024-03-11.pem/sha512 b/deps/checksums/cacert-2024-03-11.pem/sha512 deleted file mode 100644 index 441b8e84707b0..0000000000000 --- a/deps/checksums/cacert-2024-03-11.pem/sha512 +++ /dev/null @@ -1 +0,0 @@ -31f03cc19566d007c4cffdad2ada71d99b4734ad7b13bc4f30d73d321f40cbe13b87a801aa61d9788207a851cc1f95a8af8ac732a372d45edb932f204bce3744 diff --git a/deps/checksums/cacert-2024-11-26.pem/md5 b/deps/checksums/cacert-2024-11-26.pem/md5 new file mode 100644 index 0000000000000..865c6abf3e77a --- /dev/null +++ b/deps/checksums/cacert-2024-11-26.pem/md5 @@ -0,0 +1 @@ +92c13373d7dbe43bdc167479274a43e2 diff --git a/deps/checksums/cacert-2024-11-26.pem/sha512 b/deps/checksums/cacert-2024-11-26.pem/sha512 new file mode 100644 index 0000000000000..d51605348faf4 --- /dev/null +++ b/deps/checksums/cacert-2024-11-26.pem/sha512 @@ -0,0 +1 @@ +26c6fa1ac7bcfd523f9ab9e6c2d971103ccfc610ad0df504d4e9b064dad74576d77240c052b808f4c37c9240302a7e973a20f79ee39ac7bf3201a6fa9f0dfa96 diff --git a/deps/libgit2.version b/deps/libgit2.version index d51beb34c27f5..ae475f0b3644f 100644 --- a/deps/libgit2.version +++ b/deps/libgit2.version @@ -11,4 +11,4 @@ LIBGIT2_SHA1=d74d491481831ddcd23575d376e56d2197e95910 # 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 := 2024-03-11 +MOZILLA_CACERT_VERSION := 2024-11-26 diff --git a/stdlib/MozillaCACerts_jll/Project.toml b/stdlib/MozillaCACerts_jll/Project.toml index 181171a4c04c1..5df9bd5949972 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 = "2024.03.11" +version = "2024.11.26" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" From e50f1ce0f12ab4f6e6bbb719251ae678fb1f3665 Mon Sep 17 00:00:00 2001 From: Jakob Nybo Nissen Date: Thu, 28 Nov 2024 04:13:07 +0100 Subject: [PATCH 005/342] Make Threads.Condition public (#56503) Co-authored-by: Dilum Aluthge --- base/threadingconstructs.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/base/threadingconstructs.jl b/base/threadingconstructs.jl index a21d708b4a077..07ff814af1570 100644 --- a/base/threadingconstructs.jl +++ b/base/threadingconstructs.jl @@ -3,6 +3,8 @@ export threadid, nthreads, @threads, @spawn, threadpool, nthreadpools +public Condition + """ Threads.threadid([t::Task]) -> Int From 79d8d3f764e7fde6da323d1063293855612691fd Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 27 Nov 2024 22:13:34 -0500 Subject: [PATCH 006/342] support passing a specific Method to invoke (#56692) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Mosè Giordano <765740+giordano@users.noreply.github.com> --- Compiler/src/abstractinterpretation.jl | 57 +++++++++++++++----------- Compiler/src/abstractlattice.jl | 2 +- Compiler/src/utilities.jl | 4 +- NEWS.md | 1 + base/docs/basedocs.jl | 15 ++++++- src/builtins.c | 30 +++++++++----- test/core.jl | 7 ++++ 7 files changed, 77 insertions(+), 39 deletions(-) diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index a3abbf814165a..5946adf80ad52 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -856,8 +856,7 @@ end struct InvokeCall types # ::Type - lookupsig # ::Type - InvokeCall(@nospecialize(types), @nospecialize(lookupsig)) = new(types, lookupsig) + InvokeCall(@nospecialize(types)) = new(types) end struct ConstCallResult @@ -2218,26 +2217,38 @@ function abstract_invoke(interp::AbstractInterpreter, arginfo::ArgInfo, si::Stmt ft′ = argtype_by_index(argtypes, 2) ft = widenconst(ft′) ft === Bottom && return Future(CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo())) - (types, isexact, isconcrete, istype) = instanceof_tfunc(argtype_by_index(argtypes, 3), false) - isexact || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) - unwrapped = unwrap_unionall(types) - types === Bottom && return Future(CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo())) - if !(unwrapped isa DataType && unwrapped.name === Tuple.name) - return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo())) - end - argtype = argtypes_to_type(argtype_tail(argtypes, 4)) - nargtype = typeintersect(types, argtype) - nargtype === Bottom && return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo())) - nargtype isa DataType || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) # other cases are not implemented below - isdispatchelem(ft) || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below - ft = ft::DataType - lookupsig = rewrap_unionall(Tuple{ft, unwrapped.parameters...}, types)::Type - nargtype = Tuple{ft, nargtype.parameters...} - argtype = Tuple{ft, argtype.parameters...} - matched, valid_worlds = findsup(lookupsig, method_table(interp)) - matched === nothing && return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) - update_valid_age!(sv, valid_worlds) - method = matched.method + types = argtype_by_index(argtypes, 3) + if types isa Const && types.val isa Method + method = types.val::Method + types = method # argument value + lookupsig = method.sig # edge kind + argtype = argtypes_to_type(pushfirst!(argtype_tail(argtypes, 4), ft)) + nargtype = typeintersect(lookupsig, argtype) + nargtype === Bottom && return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo())) + nargtype isa DataType || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) # other cases are not implemented below + else + widenconst(types) >: Method && return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) + (types, isexact, isconcrete, istype) = instanceof_tfunc(argtype_by_index(argtypes, 3), false) + isexact || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) + unwrapped = unwrap_unionall(types) + types === Bottom && return Future(CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo())) + if !(unwrapped isa DataType && unwrapped.name === Tuple.name) + return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo())) + end + argtype = argtypes_to_type(argtype_tail(argtypes, 4)) + nargtype = typeintersect(types, argtype) + nargtype === Bottom && return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo())) + nargtype isa DataType || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) # other cases are not implemented below + isdispatchelem(ft) || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below + ft = ft::DataType + lookupsig = rewrap_unionall(Tuple{ft, unwrapped.parameters...}, types)::Type + nargtype = Tuple{ft, nargtype.parameters...} + argtype = Tuple{ft, argtype.parameters...} + matched, valid_worlds = findsup(lookupsig, method_table(interp)) + matched === nothing && return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) + update_valid_age!(sv, valid_worlds) + method = matched.method + end tienv = ccall(:jl_type_intersection_with_env, Any, (Any, Any), nargtype, method.sig)::SimpleVector ti = tienv[1] env = tienv[2]::SimpleVector @@ -2245,7 +2256,7 @@ function abstract_invoke(interp::AbstractInterpreter, arginfo::ArgInfo, si::Stmt match = MethodMatch(ti, env, method, argtype <: method.sig) ft′_box = Core.Box(ft′) lookupsig_box = Core.Box(lookupsig) - invokecall = InvokeCall(types, lookupsig) + invokecall = InvokeCall(types) return Future{CallMeta}(mresult, interp, sv) do result, interp, sv (; rt, exct, effects, edge, volatile_inf_result) = result local ft′ = ft′_box.contents diff --git a/Compiler/src/abstractlattice.jl b/Compiler/src/abstractlattice.jl index 645c865d085b3..c1f3050739170 100644 --- a/Compiler/src/abstractlattice.jl +++ b/Compiler/src/abstractlattice.jl @@ -229,7 +229,7 @@ end if isa(t, Const) # don't consider mutable values useful constants val = t.val - return isa(val, Symbol) || isa(val, Type) || !ismutable(val) + return isa(val, Symbol) || isa(val, Type) || isa(val, Method) || !ismutable(val) end isa(t, PartialTypeVar) && return false # this isn't forwardable return is_const_prop_profitable_arg(widenlattice(𝕃), t) diff --git a/Compiler/src/utilities.jl b/Compiler/src/utilities.jl index 11d926f0c9d4e..29f3dfa4afd4a 100644 --- a/Compiler/src/utilities.jl +++ b/Compiler/src/utilities.jl @@ -54,8 +54,8 @@ function count_const_size(@nospecialize(x), count_self::Bool = true) # No definite size (isa(x, GenericMemory) || isa(x, String) || isa(x, SimpleVector)) && return MAX_INLINE_CONST_SIZE + 1 - if isa(x, Module) - # We allow modules, because we already assume they are externally + if isa(x, Module) || isa(x, Method) + # We allow modules and methods, because we already assume they are externally # rooted, so we count their contents as 0 size. return sizeof(Ptr{Cvoid}) end diff --git a/NEWS.md b/NEWS.md index 535d14208f0b8..61bad831e261c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -119,6 +119,7 @@ New library features * `Base.require_one_based_indexing` and `Base.has_offset_axes` are now public ([#56196]) * New `ltruncate`, `rtruncate` and `ctruncate` functions for truncating strings to text width, accounting for char widths ([#55351]) * `isless` (and thus `cmp`, sorting, etc.) is now supported for zero-dimensional `AbstractArray`s ([#55772]) +* `invoke` now supports passing a Method instead of a type signature making this interface somewhat more flexible for certain uncommon use cases ([#56692]). Standard library changes ------------------------ diff --git a/base/docs/basedocs.jl b/base/docs/basedocs.jl index c872244964160..5119ceaf2164a 100644 --- a/base/docs/basedocs.jl +++ b/base/docs/basedocs.jl @@ -2030,21 +2030,32 @@ applicable """ invoke(f, argtypes::Type, args...; kwargs...) + invoke(f, argtypes::Method, args...; kwargs...) Invoke a method for the given generic function `f` matching the specified types `argtypes` on the specified arguments `args` and passing the keyword arguments `kwargs`. The arguments `args` must conform with the specified types in `argtypes`, i.e. conversion is not automatically performed. This method allows invoking a method other than the most specific matching method, which is useful when the behavior of a more general definition is explicitly needed (often as part of the -implementation of a more specific method of the same function). +implementation of a more specific method of the same function). However, because this means +the runtime must do more work, `invoke` is generally also slower--sometimes significantly +so--than doing normal dispatch with a regular call. -Be careful when using `invoke` for functions that you don't write. What definition is used +Be careful when using `invoke` for functions that you don't write. What definition is used for given `argtypes` is an implementation detail unless the function is explicitly states that calling with certain `argtypes` is a part of public API. For example, the change between `f1` and `f2` in the example below is usually considered compatible because the change is invisible by the caller with a normal (non-`invoke`) call. However, the change is visible if you use `invoke`. +# Passing a `Method` instead of a signature +The `argtypes` argument may be a `Method`, in which case the ordinary method table lookup is +bypassed entirely and the given method is invoked directly. Needing this feature is uncommon. +Note in particular that the specified `Method` may be entirely unreachable from ordinary dispatch +(or ordinary invoke), e.g. because it was replaced or fully covered by more specific methods. +If the method is part of the ordinary method table, this call behaves similar +to `invoke(f, method.sig, args...)`. + # Examples ```jldoctest julia> f(x::Real) = x^2; diff --git a/src/builtins.c b/src/builtins.c index b129cca0ee71d..c6b0bf130550b 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -931,22 +931,27 @@ JL_CALLABLE(jl_f__call_in_world_total) // tuples --------------------------------------------------------------------- -JL_CALLABLE(jl_f_tuple) +static jl_value_t *arg_tuple(jl_value_t *a1, jl_value_t **args, size_t nargs) { size_t i; - if (nargs == 0) - return (jl_value_t*)jl_emptytuple; - jl_datatype_t *tt = jl_inst_arg_tuple_type(args[0], &args[1], nargs, 0); + jl_datatype_t *tt = jl_inst_arg_tuple_type(a1, args, nargs, 0); JL_GC_PROMISE_ROOTED(tt); // it is a concrete type if (tt->instance != NULL) return tt->instance; jl_task_t *ct = jl_current_task; jl_value_t *jv = jl_gc_alloc(ct->ptls, jl_datatype_size(tt), tt); for (i = 0; i < nargs; i++) - set_nth_field(tt, jv, i, args[i], 0); + set_nth_field(tt, jv, i, i == 0 ? a1 : args[i - 1], 0); return jv; } +JL_CALLABLE(jl_f_tuple) +{ + if (nargs == 0) + return (jl_value_t*)jl_emptytuple; + return arg_tuple(args[0], &args[1], nargs); +} + JL_CALLABLE(jl_f_svec) { size_t i; @@ -1577,14 +1582,17 @@ JL_CALLABLE(jl_f_invoke) { JL_NARGSV(invoke, 2); jl_value_t *argtypes = args[1]; - JL_GC_PUSH1(&argtypes); - if (!jl_is_tuple_type(jl_unwrap_unionall(args[1]))) - jl_type_error("invoke", (jl_value_t*)jl_anytuple_type_type, args[1]); + if (jl_is_method(argtypes)) { + jl_method_t *m = (jl_method_t*)argtypes; + if (!jl_tuple1_isa(args[0], &args[2], nargs - 1, (jl_datatype_t*)m->sig)) + jl_type_error("invoke: argument type error", argtypes, arg_tuple(args[0], &args[2], nargs - 1)); + return jl_gf_invoke_by_method(m, args[0], &args[2], nargs - 1); + } + if (!jl_is_tuple_type(jl_unwrap_unionall(argtypes))) + jl_type_error("invoke", (jl_value_t*)jl_anytuple_type_type, argtypes); if (!jl_tuple_isa(&args[2], nargs - 2, (jl_datatype_t*)argtypes)) jl_type_error("invoke: argument type error", argtypes, jl_f_tuple(NULL, &args[2], nargs - 2)); - jl_value_t *res = jl_gf_invoke(argtypes, args[0], &args[2], nargs - 1); - JL_GC_POP(); - return res; + return jl_gf_invoke(argtypes, args[0], &args[2], nargs - 1); } // Expr constructor for internal use ------------------------------------------ diff --git a/test/core.jl b/test/core.jl index 836532d661638..39d02d5d567c9 100644 --- a/test/core.jl +++ b/test/core.jl @@ -8352,3 +8352,10 @@ macro define_call(sym) end @test eval(Expr(:toplevel, :(@define_call(f_macro_defined1)))) == 1 @test @define_call(f_macro_defined2) == 1 + +let m = which(+, (Int, Int)) + @eval f56692(i) = invoke(+, $m, i, 4) + global g56692() = f56692(5) == 9 ? "true" : false +end +@test @inferred(f56692(3)) == 7 +@test @inferred(g56692()) == "true" From 7e2e0aeca207e865c72c42282fb86db949854839 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 27 Nov 2024 22:15:24 -0500 Subject: [PATCH 007/342] Add mechanism to disable creating new worlds (#56639) --- base/experimental.jl | 9 +++ src/gf.c | 152 ++++++++++++++++++++++++++++------------- src/staticdata.c | 32 ++++++--- src/staticdata_utils.c | 142 +++++++++++++++++++++----------------- src/toplevel.c | 2 +- test/misc.jl | 36 +++++++--- 6 files changed, 243 insertions(+), 130 deletions(-) diff --git a/base/experimental.jl b/base/experimental.jl index 31238d4015b3b..411bb2407cdc5 100644 --- a/base/experimental.jl +++ b/base/experimental.jl @@ -494,4 +494,13 @@ function entrypoint(@nospecialize(argt::Type)) nothing end +""" + Base.Experimental.disable_new_worlds() + +Mark that no new worlds (methods additions, deletions, etc) are permitted to be created at +any future time, allowing for lower latencies for some operations and slightly lower memory +usage, by eliminating the tracking of those possible invalidation. +""" +disable_new_worlds() = ccall(:jl_disable_new_worlds, Cvoid, ()) + end diff --git a/src/gf.c b/src/gf.c index 90b874d614b0c..bbf065a4fac0d 100644 --- a/src/gf.c +++ b/src/gf.c @@ -24,6 +24,7 @@ extern "C" { #endif +_Atomic(int) allow_new_worlds = 1; JL_DLLEXPORT _Atomic(size_t) jl_world_counter = 1; // uses atomic acquire/release jl_mutex_t world_counter_lock; JL_DLLEXPORT size_t jl_get_world_counter(void) JL_NOTSAFEPOINT @@ -1819,38 +1820,42 @@ static void invalidate_backedges(jl_method_instance_t *replaced_mi, size_t max_w // add a backedge from callee to caller JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, jl_value_t *invokesig, jl_code_instance_t *caller) { + if (!jl_atomic_load_relaxed(&allow_new_worlds)) + return; if (invokesig == jl_nothing) invokesig = NULL; // julia uses `nothing` but C uses NULL (#undef) assert(jl_is_method_instance(callee)); assert(jl_is_code_instance(caller)); assert(invokesig == NULL || jl_is_type(invokesig)); JL_LOCK(&callee->def.method->writelock); - int found = 0; - // TODO: use jl_cache_type_(invokesig) like cache_method does to save memory - if (!callee->backedges) { - // lazy-init the backedges array - callee->backedges = jl_alloc_vec_any(0); - jl_gc_wb(callee, callee->backedges); - } - else { - size_t i = 0, l = jl_array_nrows(callee->backedges); - for (i = 0; i < l; i++) { - // optimized version of while (i < l) i = get_next_edge(callee->backedges, i, &invokeTypes, &mi); - jl_value_t *mi = jl_array_ptr_ref(callee->backedges, i); - if (mi != (jl_value_t*)caller) - continue; - jl_value_t *invokeTypes = i > 0 ? jl_array_ptr_ref(callee->backedges, i - 1) : NULL; - if (invokeTypes && jl_is_method_instance(invokeTypes)) - invokeTypes = NULL; - if ((invokesig == NULL && invokeTypes == NULL) || - (invokesig && invokeTypes && jl_types_equal(invokesig, invokeTypes))) { - found = 1; - break; + if (jl_atomic_load_relaxed(&allow_new_worlds)) { + int found = 0; + // TODO: use jl_cache_type_(invokesig) like cache_method does to save memory + if (!callee->backedges) { + // lazy-init the backedges array + callee->backedges = jl_alloc_vec_any(0); + jl_gc_wb(callee, callee->backedges); + } + else { + size_t i = 0, l = jl_array_nrows(callee->backedges); + for (i = 0; i < l; i++) { + // optimized version of while (i < l) i = get_next_edge(callee->backedges, i, &invokeTypes, &mi); + jl_value_t *mi = jl_array_ptr_ref(callee->backedges, i); + if (mi != (jl_value_t*)caller) + continue; + jl_value_t *invokeTypes = i > 0 ? jl_array_ptr_ref(callee->backedges, i - 1) : NULL; + if (invokeTypes && jl_is_method_instance(invokeTypes)) + invokeTypes = NULL; + if ((invokesig == NULL && invokeTypes == NULL) || + (invokesig && invokeTypes && jl_types_equal(invokesig, invokeTypes))) { + found = 1; + break; + } } } + if (!found) + push_edge(callee->backedges, invokesig, caller); } - if (!found) - push_edge(callee->backedges, invokesig, caller); JL_UNLOCK(&callee->def.method->writelock); } @@ -1858,37 +1863,41 @@ JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, JL_DLLEXPORT void jl_method_table_add_backedge(jl_methtable_t *mt, jl_value_t *typ, jl_code_instance_t *caller) { assert(jl_is_code_instance(caller)); + if (!jl_atomic_load_relaxed(&allow_new_worlds)) + return; JL_LOCK(&mt->writelock); - if (!mt->backedges) { - // lazy-init the backedges array - mt->backedges = jl_alloc_vec_any(2); - jl_gc_wb(mt, mt->backedges); - jl_array_ptr_set(mt->backedges, 0, typ); - jl_array_ptr_set(mt->backedges, 1, caller); - } - else { - // check if the edge is already present and avoid adding a duplicate - size_t i, l = jl_array_nrows(mt->backedges); - for (i = 1; i < l; i += 2) { - if (jl_array_ptr_ref(mt->backedges, i) == (jl_value_t*)caller) { - if (jl_types_equal(jl_array_ptr_ref(mt->backedges, i - 1), typ)) { - JL_UNLOCK(&mt->writelock); - return; + if (jl_atomic_load_relaxed(&allow_new_worlds)) { + if (!mt->backedges) { + // lazy-init the backedges array + mt->backedges = jl_alloc_vec_any(2); + jl_gc_wb(mt, mt->backedges); + jl_array_ptr_set(mt->backedges, 0, typ); + jl_array_ptr_set(mt->backedges, 1, caller); + } + else { + // check if the edge is already present and avoid adding a duplicate + size_t i, l = jl_array_nrows(mt->backedges); + for (i = 1; i < l; i += 2) { + if (jl_array_ptr_ref(mt->backedges, i) == (jl_value_t*)caller) { + if (jl_types_equal(jl_array_ptr_ref(mt->backedges, i - 1), typ)) { + JL_UNLOCK(&mt->writelock); + return; + } } } - } - // reuse an already cached instance of this type, if possible - // TODO: use jl_cache_type_(tt) like cache_method does, instead of this linear scan? - for (i = 1; i < l; i += 2) { - if (jl_array_ptr_ref(mt->backedges, i) != (jl_value_t*)caller) { - if (jl_types_equal(jl_array_ptr_ref(mt->backedges, i - 1), typ)) { - typ = jl_array_ptr_ref(mt->backedges, i - 1); - break; + // reuse an already cached instance of this type, if possible + // TODO: use jl_cache_type_(tt) like cache_method does, instead of this linear scan? + for (i = 1; i < l; i += 2) { + if (jl_array_ptr_ref(mt->backedges, i) != (jl_value_t*)caller) { + if (jl_types_equal(jl_array_ptr_ref(mt->backedges, i - 1), typ)) { + typ = jl_array_ptr_ref(mt->backedges, i - 1); + break; + } } } + jl_array_ptr_1d_push(mt->backedges, typ); + jl_array_ptr_1d_push(mt->backedges, (jl_value_t*)caller); } - jl_array_ptr_1d_push(mt->backedges, typ); - jl_array_ptr_1d_push(mt->backedges, (jl_value_t*)caller); } JL_UNLOCK(&mt->writelock); } @@ -2024,10 +2033,55 @@ static void jl_method_table_invalidate(jl_methtable_t *mt, jl_method_t *replaced } } +static int erase_method_backedges(jl_typemap_entry_t *def, void *closure) +{ + jl_method_t *method = def->func.method; + JL_LOCK(&method->writelock); + jl_value_t *specializations = jl_atomic_load_relaxed(&method->specializations); + if (jl_is_svec(specializations)) { + size_t i, l = jl_svec_len(specializations); + for (i = 0; i < l; i++) { + jl_method_instance_t *mi = (jl_method_instance_t*)jl_svecref(specializations, i); + if ((jl_value_t*)mi != jl_nothing) { + mi->backedges = NULL; + } + } + } + else { + jl_method_instance_t *mi = (jl_method_instance_t*)specializations; + mi->backedges = NULL; + } + JL_UNLOCK(&method->writelock); + return 1; +} + +static int erase_all_backedges(jl_methtable_t *mt, void *env) +{ + // removes all method caches + // this might not be entirely safe (GC or MT), thus we only do it very early in bootstrapping + JL_LOCK(&mt->writelock); + mt->backedges = NULL; + JL_UNLOCK(&mt->writelock); + jl_typemap_visitor(jl_atomic_load_relaxed(&mt->defs), erase_method_backedges, env); + return 1; +} + +JL_DLLEXPORT void jl_disable_new_worlds(void) +{ + if (jl_generating_output()) + jl_error("Disabling Method changes is not possible when generating output."); + JL_LOCK(&world_counter_lock); + jl_atomic_store_relaxed(&allow_new_worlds, 0); + JL_UNLOCK(&world_counter_lock); + jl_foreach_reachable_mtable(erase_all_backedges, (void*)NULL); +} + JL_DLLEXPORT void jl_method_table_disable(jl_methtable_t *mt, jl_method_t *method) { jl_typemap_entry_t *methodentry = do_typemap_search(mt, method); JL_LOCK(&world_counter_lock); + if (!jl_atomic_load_relaxed(&allow_new_worlds)) + jl_error("Method changes have been disabled via a call to disable_new_worlds."); JL_LOCK(&mt->writelock); // Narrow the world age on the method to make it uncallable size_t world = jl_atomic_load_relaxed(&jl_world_counter); @@ -2341,6 +2395,8 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method jl_typemap_entry_t *newentry = jl_method_table_add(mt, method, simpletype); JL_GC_PUSH1(&newentry); JL_LOCK(&world_counter_lock); + if (!jl_atomic_load_relaxed(&allow_new_worlds)) + jl_error("Method changes have been disabled via a call to disable_new_worlds."); size_t world = jl_atomic_load_relaxed(&jl_world_counter) + 1; jl_atomic_store_relaxed(&method->primary_world, world); jl_atomic_store_relaxed(&method->deleted_world, ~(size_t)0); diff --git a/src/staticdata.c b/src/staticdata.c index c2e8d7e3956ea..f5fe088ce1c98 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -89,6 +89,7 @@ External links: #include "julia_assert.h" static const size_t WORLD_AGE_REVALIDATION_SENTINEL = 0x1; +size_t jl_require_world = ~(size_t)0; #include "staticdata_utils.c" #include "precompile_utils.c" @@ -2678,7 +2679,6 @@ jl_genericmemory_t *jl_global_roots_list; jl_genericmemory_t *jl_global_roots_keyset; jl_mutex_t global_roots_lock; extern jl_mutex_t world_counter_lock; -extern size_t jl_require_world; jl_mutex_t precompile_field_replace_lock; jl_svec_t *precompile_field_replace JL_GLOBALLY_ROOTED; @@ -4044,16 +4044,30 @@ static jl_value_t *jl_restore_package_image_from_stream(void* pkgimage_handle, i // Add roots to methods jl_copy_roots(method_roots_list, jl_worklist_key((jl_array_t*)restored)); // Insert method extensions and handle edges + int new_methods = jl_array_nrows(extext_methods) > 0; + if (!new_methods) { + size_t i, l = jl_array_nrows(internal_methods); + for (i = 0; i < l; i++) { + jl_value_t *obj = jl_array_ptr_ref(internal_methods, i); + if (jl_is_method(obj)) { + new_methods = 1; + break; + } + } + } JL_LOCK(&world_counter_lock); - // allocate a world for the new methods, and insert them there, invalidating content as needed - size_t world = jl_atomic_load_relaxed(&jl_world_counter) + 1; - jl_activate_methods(extext_methods, internal_methods, world); - // TODO: inject new_ext_cis into caches here, so the system can see them immediately as potential candidates (before validation) - // allow users to start running in this updated world - jl_atomic_store_release(&jl_world_counter, world); - // now permit more methods to be added again + // allocate a world for the new methods, and insert them there, invalidating content as needed + size_t world = jl_atomic_load_relaxed(&jl_world_counter); + if (new_methods) + world += 1; + jl_activate_methods(extext_methods, internal_methods, world, pkgname); + // TODO: inject new_ext_cis into caches here, so the system can see them immediately as potential candidates (before validation) + // allow users to start running in this updated world + if (new_methods) + jl_atomic_store_release(&jl_world_counter, world); + // now permit more methods to be added again JL_UNLOCK(&world_counter_lock); - // but one of those immediate users is going to be our cache insertions + // but one of those immediate users is going to be our cache insertions jl_insert_backedges((jl_array_t*)edges, (jl_array_t*)new_ext_cis); // restore existing caches (needs to be last) // reinit ccallables jl_reinit_ccallable(&ccallable_list, base, pkgimage_handle); diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index 32e59d7d7c641..ea0b7216155bd 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -704,10 +704,12 @@ static void jl_add_methods(jl_array_t *external) } } -static void jl_activate_methods(jl_array_t *external, jl_array_t *internal, size_t world) +extern _Atomic(int) allow_new_worlds; +static void jl_activate_methods(jl_array_t *external, jl_array_t *internal, size_t world, const char *pkgname) { size_t i, l = jl_array_nrows(internal); for (i = 0; i < l; i++) { + // allow_new_worlds doesn't matter here, since we aren't actually changing anything external jl_value_t *obj = jl_array_ptr_ref(internal, i); if (jl_typetagis(obj, jl_typemap_entry_type)) { jl_typemap_entry_t *entry = (jl_typemap_entry_t*)obj; @@ -735,11 +737,17 @@ static void jl_activate_methods(jl_array_t *external, jl_array_t *internal, size } } l = jl_array_nrows(external); - for (i = 0; i < l; i++) { - jl_typemap_entry_t *entry = (jl_typemap_entry_t*)jl_array_ptr_ref(external, i); - jl_methtable_t *mt = jl_method_get_table(entry->func.method); - assert((jl_value_t*)mt != jl_nothing); - jl_method_table_activate(mt, entry); + if (l) { + if (!jl_atomic_load_relaxed(&allow_new_worlds)) { + jl_printf(JL_STDERR, "WARNING: Method changes for %s have been disabled via a call to disable_new_worlds.\n", pkgname); + return; + } + for (i = 0; i < l; i++) { + jl_typemap_entry_t *entry = (jl_typemap_entry_t*)jl_array_ptr_ref(external, i); + jl_methtable_t *mt = jl_method_get_table(entry->func.method); + assert((jl_value_t*)mt != jl_nothing); + jl_method_table_activate(mt, entry); + } } } @@ -864,71 +872,80 @@ static int jl_verify_method(jl_code_instance_t *codeinst, size_t *minworld, size size_t depth = stack->len; *bp = (char*)HT_NOTFOUND + depth; JL_TIMING(VERIFY_IMAGE, VERIFY_Methods); - jl_value_t *loctag = NULL; - jl_value_t *sig = NULL; - jl_value_t *matches = NULL; - JL_GC_PUSH3(&loctag, &matches, &sig); jl_svec_t *callees = jl_atomic_load_relaxed(&codeinst->edges); assert(jl_is_svec((jl_value_t*)callees)); // verify current edges - for (size_t j = 0; j < jl_svec_len(callees); ) { - jl_value_t *edge = jl_svecref(callees, j); - size_t min_valid2; - size_t max_valid2; - assert(!jl_is_method(edge)); // `Method`-edge isn't allowed for the optimized one-edge format - if (jl_is_code_instance(edge)) - edge = (jl_value_t*)((jl_code_instance_t*)edge)->def; - if (jl_is_method_instance(edge)) { - jl_method_instance_t *mi = (jl_method_instance_t*)edge; - sig = jl_type_intersection(mi->def.method->sig, (jl_value_t*)mi->specTypes); // TODO: ?? - verify_call(sig, callees, j, 1, world, &min_valid2, &max_valid2, &matches); - sig = NULL; - j += 1; - } - else if (jl_is_long(edge)) { - jl_value_t *sig = jl_svecref(callees, j + 1); - size_t nedges = jl_unbox_long(edge); - verify_call(sig, callees, j + 2, nedges, world, &min_valid2, &max_valid2, &matches); - j += 2 + nedges; - edge = sig; - } - else { - jl_method_instance_t *callee = (jl_method_instance_t*)jl_svecref(callees, j + 1); - jl_method_t *meth; - if (jl_is_mtable(callee)) { - // skip the legacy edge (missing backedge) - j += 2; - continue; + if (callees == jl_emptysvec) { + // quick return: no edges to verify (though we probably shouldn't have gotten here from WORLD_AGE_REVALIDATION_SENTINEL) + } + else if (*maxworld == jl_require_world) { + // if no new worlds were allocated since serializing the base module, then no new validation is worth doing right now either + *minworld = *maxworld; + } + else { + jl_value_t *loctag = NULL; + jl_value_t *sig = NULL; + jl_value_t *matches = NULL; + JL_GC_PUSH3(&loctag, &matches, &sig); + for (size_t j = 0; j < jl_svec_len(callees); ) { + jl_value_t *edge = jl_svecref(callees, j); + size_t min_valid2; + size_t max_valid2; + assert(!jl_is_method(edge)); // `Method`-edge isn't allowed for the optimized one-edge format + if (jl_is_code_instance(edge)) + edge = (jl_value_t*)((jl_code_instance_t*)edge)->def; + if (jl_is_method_instance(edge)) { + jl_method_instance_t *mi = (jl_method_instance_t*)edge; + sig = jl_type_intersection(mi->def.method->sig, (jl_value_t*)mi->specTypes); // TODO: ?? + verify_call(sig, callees, j, 1, world, &min_valid2, &max_valid2, &matches); + sig = NULL; + j += 1; } - if (jl_is_code_instance(callee)) - callee = ((jl_code_instance_t*)callee)->def; - if (jl_is_method_instance(callee)) { - meth = callee->def.method; + else if (jl_is_long(edge)) { + jl_value_t *sig = jl_svecref(callees, j + 1); + size_t nedges = jl_unbox_long(edge); + verify_call(sig, callees, j + 2, nedges, world, &min_valid2, &max_valid2, &matches); + j += 2 + nedges; + edge = sig; } else { - assert(jl_is_method(callee)); - meth = (jl_method_t*)callee; + jl_method_instance_t *callee = (jl_method_instance_t*)jl_svecref(callees, j + 1); + jl_method_t *meth; + if (jl_is_mtable(callee)) { + // skip the legacy edge (missing backedge) + j += 2; + continue; + } + if (jl_is_code_instance(callee)) + callee = ((jl_code_instance_t*)callee)->def; + if (jl_is_method_instance(callee)) { + meth = callee->def.method; + } + else { + assert(jl_is_method(callee)); + meth = (jl_method_t*)callee; + } + verify_invokesig(edge, meth, world, &min_valid2, &max_valid2); + j += 2; } - verify_invokesig(edge, meth, world, &min_valid2, &max_valid2); - j += 2; - } - if (*minworld < min_valid2) - *minworld = min_valid2; - if (*maxworld > max_valid2) - *maxworld = max_valid2; - if (max_valid2 != ~(size_t)0 && _jl_debug_method_invalidation) { - jl_array_ptr_1d_push(_jl_debug_method_invalidation, edge); - loctag = jl_cstr_to_string("insert_backedges_callee"); - jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag); - jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)codeinst); - jl_array_ptr_1d_push(_jl_debug_method_invalidation, matches); + if (*minworld < min_valid2) + *minworld = min_valid2; + if (*maxworld > max_valid2) + *maxworld = max_valid2; + if (max_valid2 != ~(size_t)0 && _jl_debug_method_invalidation) { + jl_array_ptr_1d_push(_jl_debug_method_invalidation, edge); + loctag = jl_cstr_to_string("insert_backedges_callee"); + jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag); + jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)codeinst); + jl_array_ptr_1d_push(_jl_debug_method_invalidation, matches); + } + //jl_static_show((JL_STREAM*)ios_stderr, (jl_value_t*)edge); + //ios_puts(max_valid2 == ~(size_t)0 ? "valid\n" : "INVALID\n", ios_stderr); + if (max_valid2 == 0 && !_jl_debug_method_invalidation) + break; } - //jl_static_show((JL_STREAM*)ios_stderr, (jl_value_t*)edge); - //ios_puts(max_valid2 == ~(size_t)0 ? "valid\n" : "INVALID\n", ios_stderr); - if (max_valid2 == 0 && !_jl_debug_method_invalidation) - break; + JL_GC_POP(); } - JL_GC_POP(); // verify recursive edges (if valid, or debugging) size_t cycle = depth; jl_code_instance_t *cause = codeinst; @@ -979,6 +996,7 @@ static int jl_verify_method(jl_code_instance_t *codeinst, size_t *minworld, size assert(*bp == (char*)HT_NOTFOUND + stack->len + 1); *bp = HT_NOTFOUND; if (_jl_debug_method_invalidation && *maxworld < current_world) { + jl_value_t *loctag; jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)child); loctag = jl_cstr_to_string("verify_methods"); JL_GC_PUSH1(&loctag); diff --git a/src/toplevel.c b/src/toplevel.c index 56a5f21f43661..e8286a584b119 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -496,7 +496,7 @@ static void body_attributes(jl_array_t *body, int *has_ccall, int *has_defs, int *forced_compile = jl_has_meta(body, jl_force_compile_sym); } -size_t jl_require_world = ~(size_t)0; +extern size_t jl_require_world; static jl_module_t *call_require(jl_module_t *mod, jl_sym_t *var) JL_GLOBALLY_ROOTED { JL_TIMING(LOAD_IMAGE, LOAD_Require); diff --git a/test/misc.jl b/test/misc.jl index 7f9992e22a3d7..5bbc2c3c65fa2 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -1211,10 +1211,7 @@ include("testenv.jl") let flags = Cmd(filter(a->!occursin("depwarn", a), collect(test_exeflags))) local cmd = `$test_exename $flags --depwarn=yes deprecation_exec.jl` - - if !success(pipeline(cmd; stdout=stdout, stderr=stderr)) - error("Deprecation test failed, cmd : $cmd") - end + run(cmd, devnull) end # PR #23664, make sure names don't get added to the default `Main` workspace @@ -1489,7 +1486,7 @@ end # Test that read fault on a prot-none region does not incorrectly give # ReadOnlyMemoryError, but rather crashes the program const MAP_ANONYMOUS_PRIVATE = Sys.isbsd() ? 0x1002 : 0x22 -let script = :( +let script = """ let ptr = Ptr{Cint}(ccall(:jl_mmap, Ptr{Cvoid}, (Ptr{Cvoid}, Csize_t, Cint, Cint, Cint, Int), C_NULL, 16*1024, 0, $MAP_ANONYMOUS_PRIVATE, -1, 0)) @@ -1499,19 +1496,24 @@ let script = :( println(e) end end - ) + """ cmd = if Sys.isunix() # Set the maximum core dump size to 0 to keep this expected crash from # producing a (and potentially overwriting an existing) core dump file - `sh -c "ulimit -c 0; $(Base.shell_escape(Base.julia_cmd())) -e '$script'"` + `sh -c "ulimit -c 0; $(Base.shell_escape(Base.julia_cmd())) -e $(Base.shell_escape(script))"` else - `$(Base.julia_cmd()) -e '$script'` + `$(Base.julia_cmd()) -e $script` + end + p = run(ignorestatus(cmd), devnull, stdout, devnull) + if p.termsignal == 0 + Sys.isunix() ? @test(p.exitcode ∈ (128+7, 128+10, 128+11)) : @test(p.exitcode != 0) # expect SIGBUS (7 on BSDs or 10 on Linux) or SIGSEGV (11) + else + @test(p.termsignal ∈ (7, 10, 11)) end - @test !success(cmd) end # issue #41656 -@test success(`$(Base.julia_cmd()) -e 'isempty(x) = true'`) +run(`$(Base.julia_cmd()) -e 'isempty(x) = true'`) @testset "Base/timing.jl" begin @test Base.jit_total_bytes() >= 0 @@ -1596,3 +1598,17 @@ end end @test !occursin("loop not unrolled", out_err) end + +let errs = IOBuffer() + run(`$(Base.julia_cmd()) -e ' + using Test + @test isdefined(DataType.name.mt, :backedges) + Base.Experimental.disable_new_worlds() + @test_throws "disable_new_worlds" @eval f() = 1 + @test !isdefined(DataType.name.mt, :backedges) + @test_throws "disable_new_worlds" Base.delete_method(which(+, (Int, Int))) + @test 1+1 == 2 + using Dates + '`, devnull, stdout, errs) + @test occursin("disable_new_worlds", String(take!(errs))) +end From 680803c33b45864c14b4f55a1cbda65a6a52b9e0 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Wed, 27 Nov 2024 22:15:52 -0500 Subject: [PATCH 008/342] get trimming test working again (#56689) --- contrib/juliac.jl | 19 ++++++++----------- src/staticdata.c | 1 + test/trimming/Makefile | 2 +- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/contrib/juliac.jl b/contrib/juliac.jl index 0f008976d2b4f..20d56615c6357 100644 --- a/contrib/juliac.jl +++ b/contrib/juliac.jl @@ -4,7 +4,6 @@ cmd = Base.julia_cmd() cmd = `$cmd --startup-file=no --history-file=no` output_type = nothing # exe, sharedlib, sysimage -trim = nothing outname = nothing file = nothing add_ccallables = false @@ -15,13 +14,16 @@ if help !== nothing println( """ Usage: julia juliac.jl [--output-exe | --output-lib | --output-sysimage] [options] - --trim= Only output code statically determined to be reachable + --experimental --trim= Only output code statically determined to be reachable --compile-ccallable Include all methods marked `@ccallable` in output --verbose Request verbose output """) exit(0) end +# arguments to forward to julia compilation process +julia_args = [] + let i = 1 while i <= length(ARGS) arg = ARGS[i] @@ -31,17 +33,13 @@ let i = 1 i == length(ARGS) && error("Output specifier requires an argument") global outname = ARGS[i+1] i += 1 - elseif startswith(arg, "--trim") - arg = split(arg, '=') - if length(arg) == 1 - global trim = "safe" - else - global trim = arg[2] - end elseif arg == "--compile-ccallable" global add_ccallables = true elseif arg == "--verbose" global verbose = true + elseif startswith(arg, "--trim") || arg == "--experimental" + # forwarded args + push!(julia_args, arg) else if arg[1] == '-' || !isnothing(file) println("Unexpected argument `$arg`") @@ -79,8 +77,7 @@ open(initsrc_path, "w") do io """) end -static_call_graph_arg() = isnothing(trim) ? `` : `--trim=$(trim)` -cmd = addenv(`$cmd --project=$(Base.active_project()) --output-o $img_path --output-incremental=no --strip-ir --strip-metadata $(static_call_graph_arg()) $(joinpath(@__DIR__,"juliac-buildscript.jl")) $absfile $output_type $add_ccallables`, "OPENBLAS_NUM_THREADS" => 1, "JULIA_NUM_THREADS" => 1) +cmd = addenv(`$cmd --project=$(Base.active_project()) --output-o $img_path --output-incremental=no --strip-ir --strip-metadata $julia_args $(joinpath(@__DIR__,"juliac-buildscript.jl")) $absfile $output_type $add_ccallables`, "OPENBLAS_NUM_THREADS" => 1, "JULIA_NUM_THREADS" => 1) verbose && println("Running: $cmd") if !success(pipeline(cmd; stdout, stderr)) println(stderr, "\nFailed to compile $file") diff --git a/src/staticdata.c b/src/staticdata.c index f5fe088ce1c98..78cfa85695076 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -2578,6 +2578,7 @@ static void strip_specializations_(jl_method_instance_t *mi) if (inferred && inferred != jl_nothing) { if (jl_options.strip_ir) { record_field_change((jl_value_t**)&codeinst->inferred, jl_nothing); + record_field_change((jl_value_t**)&codeinst->edges, (jl_value_t*)jl_emptysvec); } else if (jl_options.strip_metadata) { jl_value_t *stripped = strip_codeinfo_meta(mi->def.method, inferred, codeinst); diff --git a/test/trimming/Makefile b/test/trimming/Makefile index c6e105d637013..d2da21eb71a88 100644 --- a/test/trimming/Makefile +++ b/test/trimming/Makefile @@ -33,7 +33,7 @@ LDFLAGS_ADD = -lm $(shell $(JULIA_CONFIG) --ldflags --ldlibs) -ljulia-internal release: hello$(EXE) hello.o: $(SRCDIR)/hello.jl $(BUILDSCRIPT) - $(JULIA) -t 1 -J $(BIN)/../lib/julia/sys.so --startup-file=no --history-file=no --output-o $@ --output-incremental=no --strip-ir --strip-metadata --trim $(BUILDSCRIPT) $(SRCDIR)/hello.jl --output-exe true + $(JULIA) -t 1 -J $(BIN)/../lib/julia/sys.so --startup-file=no --history-file=no --output-o $@ --output-incremental=no --strip-ir --strip-metadata --experimental --trim $(BUILDSCRIPT) $(SRCDIR)/hello.jl --output-exe true init.o: $(SRCDIR)/init.c $(CC) -c -o $@ $< $(CPPFLAGS_ADD) $(CPPFLAGS) $(CFLAGS_ADD) $(CFLAGS) From 60f0057e03dbf5158c29c8fe6b4bc8e59fbde735 Mon Sep 17 00:00:00 2001 From: CY Han Date: Thu, 28 Nov 2024 11:19:15 +0800 Subject: [PATCH 009/342] doc: fix docstring for `Dates.format` (#56682) --- stdlib/Dates/src/io.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/Dates/src/io.jl b/stdlib/Dates/src/io.jl index 388edb693d76f..aa7019566093c 100644 --- a/stdlib/Dates/src/io.jl +++ b/stdlib/Dates/src/io.jl @@ -713,7 +713,7 @@ except that it does not truncate values longer than the width. When creating a `format` you can use any non-code characters as a separator. For example to generate the string "1996-01-15T00:00:00" you could use `format`: "yyyy-mm-ddTHH:MM:SS". Note that if you need to use a code character as a literal you can use the escape character -backslash. The string "1996y01m" can be produced with the format "yyyy\\ymm\\m". +backslash. The string "1996y01m" can be produced with the format raw"yyyy\\ymm\\m". """ function format(dt::TimeType, f::AbstractString; locale::Locale=ENGLISH) format(dt, DateFormat(f, locale)) From f5dc26b9d30ab4dcd52e0ff29e6b469f1f0c007c Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Wed, 27 Nov 2024 22:24:22 -0500 Subject: [PATCH 010/342] Make a failed extension load throw an error during pre-compilation (#56668) Co-authored-by: Ian Butterworth --- base/loading.jl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/base/loading.jl b/base/loading.jl index 0a70564077692..8ed43e4539c20 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -1587,9 +1587,14 @@ function run_extension_callbacks(extid::ExtensionId) true catch # Try to continue loading if loading an extension errors - errs = current_exceptions() - @error "Error during loading of extension $(extid.id.name) of $(extid.parentid.name), \ + if JLOptions().incremental != 0 + # during incremental precompilation, this should be fail-fast + rethrow() + else + errs = current_exceptions() + @error "Error during loading of extension $(extid.id.name) of $(extid.parentid.name), \ use `Base.retry_load_extensions()` to retry." exception=errs + end false finally global loading_extension = false From 9162b141b7638ffe6db577ae4a91761fc33eb0a5 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Thu, 28 Nov 2024 08:51:16 +0100 Subject: [PATCH 011/342] Remove arraylist_t from external native code APIs. (#56693) This makes them usable for external consumers like GPUCompiler.jl. --- src/aotcompile.cpp | 56 ++++++++++++++++++++++++++++++-------------- src/julia_internal.h | 8 ++++--- src/staticdata.c | 18 ++++++++++---- 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 6af5227aafd92..7b3c771f9dc12 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -95,33 +95,55 @@ void jl_get_function_id_impl(void *native_code, jl_code_instance_t *codeinst, } } -extern "C" JL_DLLEXPORT_CODEGEN -void jl_get_llvm_mis_impl(void *native_code, arraylist_t* MIs) +extern "C" JL_DLLEXPORT_CODEGEN void +jl_get_llvm_mis_impl(void *native_code, size_t *num_elements, jl_method_instance_t **data) { - jl_native_code_desc_t *data = (jl_native_code_desc_t*)native_code; - auto map = data->jl_fvar_map; + 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) { - jl_method_instance_t *mi = ci.first->def; - arraylist_push(MIs, mi); + data[i++] = ci.first->def; } } -extern "C" JL_DLLEXPORT_CODEGEN -void jl_get_llvm_gvs_impl(void *native_code, arraylist_t *gvs) +extern "C" JL_DLLEXPORT_CODEGEN void jl_get_llvm_gvs_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 *data = (jl_native_code_desc_t*)native_code; - arraylist_grow(gvs, data->jl_value_to_llvm.size()); - memcpy(gvs->items, data->jl_value_to_llvm.data(), gvs->len * sizeof(void*)); + jl_native_code_desc_t *desc = (jl_native_code_desc_t *)native_code; + auto &value_map = desc->jl_value_to_llvm; + + 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, arraylist_t *external_fns) +extern "C" JL_DLLEXPORT_CODEGEN void jl_get_llvm_external_fns_impl(void *native_code, + size_t *num_elements, + jl_code_instance_t *data) { - jl_native_code_desc_t *data = (jl_native_code_desc_t*)native_code; - arraylist_grow(external_fns, data->jl_external_to_llvm.size()); - memcpy(external_fns->items, data->jl_external_to_llvm.data(), - external_fns->len * sizeof(jl_code_instance_t*)); + jl_native_code_desc_t *desc = (jl_native_code_desc_t *)native_code; + auto &external_map = desc->jl_external_to_llvm; + + if (data == NULL) { + *num_elements = external_map.size(); + return; + } + + assert(*num_elements == external_map.size()); + memcpy((void *)data, (const void *)external_map.data(), + *num_elements * sizeof(jl_code_instance_t *)); } extern "C" JL_DLLEXPORT_CODEGEN diff --git a/src/julia_internal.h b/src/julia_internal.h index ca3f63b274968..e081c94329deb 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -1951,13 +1951,15 @@ JL_DLLIMPORT void *jl_create_native(jl_array_t *methods, LLVMOrcThreadSafeModule 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, arraylist_t *gvs); -JL_DLLIMPORT void jl_get_llvm_external_fns(void *native_code, arraylist_t *gvs); +JL_DLLIMPORT void jl_get_llvm_gvs(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, int32_t *func_idx, int32_t *specfunc_idx); 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, arraylist_t* MIs); +JL_DLLIMPORT void jl_get_llvm_mis(void *native_code, size_t *num_els, + jl_method_instance_t *MIs); 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 78cfa85695076..65584c015e228 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -2897,10 +2897,20 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array, int en = jl_gc_enable(0); if (native_functions) { - jl_get_llvm_gvs(native_functions, &gvars); - jl_get_llvm_external_fns(native_functions, &external_fns); - if (jl_options.trim) - jl_get_llvm_mis(native_functions, &MIs); + size_t num_gvars, num_external_fns; + jl_get_llvm_gvs(native_functions, &num_gvars, NULL); + arraylist_grow(&gvars, num_gvars); + jl_get_llvm_gvs(native_functions, &num_gvars, gvars.items); + jl_get_llvm_external_fns(native_functions, &num_external_fns, NULL); + arraylist_grow(&external_fns, num_external_fns); + jl_get_llvm_external_fns(native_functions, &num_external_fns, + (jl_code_instance_t *)external_fns.items); + if (jl_options.trim) { + 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); + } } if (jl_options.trim) { jl_rebuild_methtables(&MIs, &new_methtables); From 447dc2d8e9a71669c6a3f62ff8ac71054c811a94 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 28 Nov 2024 07:34:29 -0500 Subject: [PATCH 012/342] fix world_age_at_entry in codegen (#56700) --- src/ccall.cpp | 18 ++++-------- src/codegen.cpp | 73 ++++++++++++++++++++++++++----------------------- src/toplevel.c | 5 +--- 3 files changed, 46 insertions(+), 50 deletions(-) diff --git a/src/ccall.cpp b/src/ccall.cpp index 952625a71287b..707203bd13506 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -1712,18 +1712,12 @@ static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs) return ghostValue(ctx, jl_nothing_type); } else if (is_libjulia_func(jl_get_tls_world_age)) { - bool toplevel = !(ctx.linfo && jl_is_method(ctx.linfo->def.method)); - if (!toplevel) { // top level code does not see a stable world age during execution - ++CCALL_STAT(jl_get_tls_world_age); - assert(lrt == ctx.types().T_size); - assert(!isVa && !llvmcall && nccallargs == 0); - JL_GC_POP(); - Instruction *world_age = cast(ctx.world_age_at_entry); - setName(ctx.emission_context, world_age, "task_world_age"); - jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe); - ai.decorateInst(world_age); - return mark_or_box_ccall_result(ctx, world_age, retboxed, rt, unionall, static_rt); - } + ++CCALL_STAT(jl_get_tls_world_age); + assert(lrt == ctx.types().T_size); + assert(!isVa && !llvmcall && nccallargs == 0); + JL_GC_POP(); + Value *world_age = get_tls_world_age(ctx); + return mark_or_box_ccall_result(ctx, world_age, retboxed, rt, unionall, static_rt); } else if (is_libjulia_func(jl_get_world_counter)) { ++CCALL_STAT(jl_get_world_counter); diff --git a/src/codegen.cpp b/src/codegen.cpp index 3645a0b25827e..ebb96837f4db5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1985,7 +1985,7 @@ class jl_codectx_t { Value *pgcstack = NULL; Instruction *topalloca = NULL; - Value *world_age_at_entry = NULL; // Not valid to use in toplevel code + Value *world_age_at_entry = NULL; bool use_cache = false; bool external_linkage = false; @@ -2115,6 +2115,7 @@ static jl_cgval_t emit_sparam(jl_codectx_t &ctx, size_t i); static Value *emit_condition(jl_codectx_t &ctx, const jl_cgval_t &condV, const Twine &msg); static Value *get_current_task(jl_codectx_t &ctx); static Value *get_current_ptls(jl_codectx_t &ctx); +static Value *get_tls_world_age(jl_codectx_t &ctx); static Value *get_scope_field(jl_codectx_t &ctx); static Value *get_tls_world_age_field(jl_codectx_t &ctx); static void CreateTrap(IRBuilder<> &irbuilder, bool create_new_block = true); @@ -7044,11 +7045,7 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaidx_ std::tie(F, specF) = get_oc_function(ctx, (jl_method_t*)source.constant, (jl_tupletype_t*)env_t, argt_typ, ub.constant); if (F) { jl_cgval_t jlcall_ptr = mark_julia_type(ctx, F, false, jl_voidpointer_type); - jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe); - bool not_toplevel = (ctx.linfo && jl_is_method(ctx.linfo->def.method)); - Instruction *I = not_toplevel ? cast(ctx.world_age_at_entry) : - ctx.builder.CreateAlignedLoad(ctx.types().T_size, get_tls_world_age_field(ctx), ctx.types().alignof_ptr); - jl_cgval_t world_age = mark_julia_type(ctx, ai.decorateInst(I), false, jl_long_type); + jl_cgval_t world_age = mark_julia_type(ctx, get_tls_world_age(ctx), false, jl_long_type); jl_cgval_t fptr; if (specF) fptr = mark_julia_type(ctx, specF, false, jl_voidpointer_type); @@ -7207,6 +7204,25 @@ static Value *get_tls_world_age_field(jl_codectx_t &ctx) return emit_ptrgep(ctx, ct, offsetof(jl_task_t, world_age), "world_age"); } +// Get the value of the world age of the current task +static Value *get_tls_world_age(jl_codectx_t &ctx) +{ + if (ctx.world_age_at_entry) + return ctx.world_age_at_entry; + IRBuilderBase::InsertPointGuard IP(ctx.builder); + bool toplevel = !jl_is_method(ctx.linfo->def.method); + if (!toplevel) { + ctx.builder.SetInsertPoint(ctx.topalloca->getParent(), ++ctx.topalloca->getIterator()); + ctx.builder.SetCurrentDebugLocation(ctx.topalloca->getStableDebugLoc()); + } + jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe); + auto *world = ctx.builder.CreateAlignedLoad(ctx.types().T_size, get_tls_world_age_field(ctx), ctx.types().alignof_ptr); + ai.decorateInst(world); + if (!toplevel) + ctx.world_age_at_entry = world; + return world; +} + static Value *get_scope_field(jl_codectx_t &ctx) { Value *ct = get_current_task(ctx); @@ -7524,9 +7540,8 @@ static Function* gen_cfun_wrapper( auto world_age_field = get_tls_world_age_field(ctx); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe); - Value *last_age = ai.decorateInst( + ctx.world_age_at_entry = ai.decorateInst( ctx.builder.CreateAlignedLoad(ctx.types().T_size, world_age_field, ctx.types().alignof_ptr)); - ctx.world_age_at_entry = last_age; Value *world_v = ctx.builder.CreateAlignedLoad(ctx.types().T_size, prepare_global_in(jl_Module, jlgetworld_global), ctx.types().alignof_ptr); cast(world_v)->setOrdering(AtomicOrdering::Acquire); @@ -7808,7 +7823,7 @@ static Function* gen_cfun_wrapper( r = NULL; } - ctx.builder.CreateStore(last_age, world_age_field); + ctx.builder.CreateStore(ctx.world_age_at_entry, world_age_field); ctx.builder.CreateRet(r); ctx.builder.SetCurrentDebugLocation(noDbg); @@ -8418,7 +8433,6 @@ static jl_llvm_functions_t ctx.source = src; std::map labels; - bool toplevel = false; ctx.module = jl_is_method(lam->def.method) ? lam->def.method->module : lam->def.module; ctx.linfo = lam; ctx.name = TSM.getModuleUnlocked()->getModuleIdentifier().data(); @@ -8438,7 +8452,6 @@ static jl_llvm_functions_t if (vn != jl_unused_sym) ctx.vaSlot = ctx.nargs - 1; } - toplevel = !jl_is_method(lam->def.method); ctx.rettype = jlrettype; ctx.funcName = ctx.name; ctx.spvals_ptr = NULL; @@ -8776,12 +8789,12 @@ static jl_llvm_functions_t // step 6. set up GC frame allocate_gc_frame(ctx, b0); Value *last_age = NULL; - auto world_age_field = get_tls_world_age_field(ctx); - { // scope + Value *world_age_field = NULL; + if (ctx.is_opaque_closure) { + world_age_field = get_tls_world_age_field(ctx); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe); last_age = ai.decorateInst(ctx.builder.CreateAlignedLoad( ctx.types().T_size, world_age_field, ctx.types().alignof_ptr)); - ctx.world_age_at_entry = last_age; // Load world age for use in get_tls_world_age } // step 7. allocate local variables slots @@ -9005,6 +9018,7 @@ static jl_llvm_functions_t Value *worldaddr = emit_ptrgep(ctx, oc_this, offsetof(jl_opaque_closure_t, world)); jl_cgval_t closure_world = typed_load(ctx, worldaddr, NULL, (jl_value_t*)jl_long_type, nullptr, nullptr, false, AtomicOrdering::NotAtomic, false, ctx.types().alignof_ptr.value()); + assert(ctx.world_age_at_entry == nullptr); ctx.world_age_at_entry = closure_world.V; // The tls world in a OC is the world of the closure emit_unbox_store(ctx, closure_world, world_age_field, ctx.tbaa().tbaa_gcframe, ctx.types().alignof_ptr); @@ -9282,19 +9296,11 @@ static jl_llvm_functions_t Instruction &prologue_end = ctx.builder.GetInsertBlock()->back(); - // step 11a. For top-level code, load the world age - if (toplevel && !ctx.is_opaque_closure) { - LoadInst *world = ctx.builder.CreateAlignedLoad(ctx.types().T_size, - prepare_global_in(jl_Module, jlgetworld_global), ctx.types().alignof_ptr); - world->setOrdering(AtomicOrdering::Acquire); - ctx.builder.CreateAlignedStore(world, world_age_field, ctx.types().alignof_ptr); - } - - // step 11b. Emit the entry safepoint + // step 11a. Emit the entry safepoint if (JL_FEAT_TEST(ctx, safepoint_on_entry)) emit_gc_safepoint(ctx.builder, ctx.types().T_size, get_current_ptls(ctx), ctx.tbaa().tbaa_const); - // step 11c. Do codegen in control flow order + // step 11b. Do codegen in control flow order SmallVector workstack; std::map BB; std::map come_from_bb; @@ -9966,8 +9972,7 @@ static jl_llvm_functions_t Instruction *root = cast_or_null(ctx.slots[ctx.vaSlot].boxroot); if (root) { bool have_real_use = false; - for (Use &U : root->uses()) { - User *RU = U.getUser(); + for (User *RU : root->users()) { if (StoreInst *SRU = dyn_cast(RU)) { assert(isa(SRU->getValueOperand()) || SRU->getValueOperand() == restTuple); (void)SRU; @@ -9986,21 +9991,21 @@ static jl_llvm_functions_t } } if (!have_real_use) { - Instruction *use = NULL; - for (Use &U : root->uses()) { - if (use) // erase after the iterator moves on - use->eraseFromParent(); - User *RU = U.getUser(); - use = cast(RU); + for (User *RU : make_early_inc_range(root->users())) { + // This is safe because it checked above that each User is known and has at most one Use of root + cast(RU)->eraseFromParent(); } - if (use) - use->eraseFromParent(); root->eraseFromParent(); restTuple->eraseFromParent(); } } } + if (ctx.topalloca->use_empty()) { + ctx.topalloca->eraseFromParent(); + ctx.topalloca = nullptr; + } + // link the dependent llvmcall modules, but switch their function's linkage to internal // so that they don't conflict when they show up in the execution engine. Linker L(*jl_Module); diff --git a/src/toplevel.c b/src/toplevel.c index e8286a584b119..21737119af9a6 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -1050,10 +1050,7 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val // use codegen mfunc = jl_method_instance_for_thunk(thk, m); jl_resolve_globals_in_ir((jl_array_t*)thk->code, m, NULL, 0); - // Don't infer blocks containing e.g. method definitions, since it's probably not - // worthwhile and also unsound (see #24316). - // TODO: This is still not correct since an `eval` can happen elsewhere, but it - // helps in common cases. + // Don't infer blocks containing e.g. method definitions, since it's probably not worthwhile. size_t world = jl_atomic_load_acquire(&jl_world_counter); ct->world_age = world; if (!has_defs && jl_get_module_infer(m) != 0) { From 1ed2b98131cb7074cec5f556f222e8ad023285f9 Mon Sep 17 00:00:00 2001 From: Lilith Orion Hafner Date: Thu, 28 Nov 2024 07:43:03 -0600 Subject: [PATCH 013/342] Fix typo in `@cmd` docstring (#56664) I'm not sure what `` `cmd` `` could refer to, but it would make sense to refer to `` `str` `` in this case. I'm assuming it's a typo. --- base/cmd.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/cmd.jl b/base/cmd.jl index 84ec52f865e98..b46c8293cdf3c 100644 --- a/base/cmd.jl +++ b/base/cmd.jl @@ -491,7 +491,7 @@ end """ @cmd str -Similar to `cmd`, generate a `Cmd` from the `str` string which represents the shell command(s) to be executed. +Similar to ``` `str` ```, generate a `Cmd` from the `str` string which represents the shell command(s) to be executed. The [`Cmd`](@ref) object can be run as a process and can outlive the spawning julia process (see `Cmd` for more). # Examples From 5053a175274fc973e7d0479f4ee4452cb2865299 Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Thu, 28 Nov 2024 14:40:10 -0500 Subject: [PATCH 014/342] deps/pcre: Update to version 10.44 (#56704) --- deps/checksums/pcre | 72 +++++++++++++++---------------- deps/pcre.version | 2 +- stdlib/PCRE2_jll/Project.toml | 2 +- stdlib/PCRE2_jll/test/runtests.jl | 2 +- 4 files changed, 39 insertions(+), 39 deletions(-) diff --git a/deps/checksums/pcre b/deps/checksums/pcre index 018ffd5201653..0c2732f8cc2b5 100644 --- a/deps/checksums/pcre +++ b/deps/checksums/pcre @@ -1,36 +1,36 @@ -PCRE2.v10.43.0+1.aarch64-apple-darwin.tar.gz/md5/f1bee27b8d9465c14eaf9362701fb795 -PCRE2.v10.43.0+1.aarch64-apple-darwin.tar.gz/sha512/33b8f6e3703f0a52cd2d57897c28e35fb3c63af459296a2fef4e414dc99239617833b2ab176068d6aab690122a34a9ab9b6042dfff54b5a30ad60429a809818d -PCRE2.v10.43.0+1.aarch64-linux-gnu.tar.gz/md5/c55a569260e302f315f4a1bd185346ab -PCRE2.v10.43.0+1.aarch64-linux-gnu.tar.gz/sha512/be4d2883e69d562898a157424b2baa146fe79545a8c10935cf25b54e498ca2c14fae026fa0d958d175895fe2cb695d0f96ef7f09fecbf54e1cee4a55b81a382b -PCRE2.v10.43.0+1.aarch64-linux-musl.tar.gz/md5/fb041ccace415ccc26263968c6435a47 -PCRE2.v10.43.0+1.aarch64-linux-musl.tar.gz/sha512/06672ebe18e0f6bfa1dd2d5c02e10d9fd67236a73fd38ee2e8f4496d98f297f7866760f0be3b9cebeca348a5d748a3719e416b84cec96a90c71eac55afbbd905 -PCRE2.v10.43.0+1.aarch64-unknown-freebsd.tar.gz/md5/8c73fe6faa94102616cfafcc6cc1bf9d -PCRE2.v10.43.0+1.aarch64-unknown-freebsd.tar.gz/sha512/464a892e646fb5aa028d2e96e6f8beaa0c15f0ef56a6ba3388cba4ce85151448b0dfd51357a3e8dea4505957394ffbab14ceb29b9fc73a67e2b2f54dd28a7aed -PCRE2.v10.43.0+1.armv6l-linux-gnueabihf.tar.gz/md5/4f303a4cbf26abb7bf4ffb8bfe3d636d -PCRE2.v10.43.0+1.armv6l-linux-gnueabihf.tar.gz/sha512/dddb3b227ee48d8329f6c65c5d0fce9f460eccaec98594a05bf28d1d9af01397cf7ef86c96e88b0e96030a7f6d8406461f78dd5fa558db8fc8f7bfb3b522ed54 -PCRE2.v10.43.0+1.armv6l-linux-musleabihf.tar.gz/md5/eade1fff90404bf3584fd15b62be0cfa -PCRE2.v10.43.0+1.armv6l-linux-musleabihf.tar.gz/sha512/351f6fa11c39b90fcc4086bd00b1b1126ed92272595f0b745757ca4e7e360c84d244446a871029245c3bcf838b23f42d908f858e44fae7deb9002a36cb76753c -PCRE2.v10.43.0+1.armv7l-linux-gnueabihf.tar.gz/md5/daa0a34b2cf0b71a6f8e1f9456cd4b06 -PCRE2.v10.43.0+1.armv7l-linux-gnueabihf.tar.gz/sha512/ae72956ae7a9a5f315bfc816fdbb500937a170dfea306a28289ec9eac57d883cf2fa5a467ce9406eea80546b632a272c63bbb48b89ebe6d9f69d30366fd84180 -PCRE2.v10.43.0+1.armv7l-linux-musleabihf.tar.gz/md5/90bfb9e4efd7c92a2bb6a1a48fd88ecb -PCRE2.v10.43.0+1.armv7l-linux-musleabihf.tar.gz/sha512/147ac98d82fec4695de0c43c87d3d9242b9c024bc6df7ad7504d17ef6a12a029ed703c4deade0e2b24faf5283d66309f880d62f8c4834f27b2cc8889587d7abe -PCRE2.v10.43.0+1.i686-linux-gnu.tar.gz/md5/6fde649bf449c4122438fff32c0706ab -PCRE2.v10.43.0+1.i686-linux-gnu.tar.gz/sha512/edfaa15490497723c095eaa5df26194637b0606e9dce7b89b400024ef8ac42e21f010bb31c2cee5c735ce82fc8de0c42bf2b35b095a1e70a9a111d3bfba6da64 -PCRE2.v10.43.0+1.i686-linux-musl.tar.gz/md5/73aa8d13cc48338a5071e30b3a899109 -PCRE2.v10.43.0+1.i686-linux-musl.tar.gz/sha512/200e2d3ffd68f49b76c70a5be80cb0ae9703049214674485a2ab24abaaea7aefd6dec2042a14bd48cc52b04379f57322ec1e1788dc8c00896e1074921725d9cc -PCRE2.v10.43.0+1.i686-w64-mingw32.tar.gz/md5/4ddf0f31c97463e5216ed71afc4fb014 -PCRE2.v10.43.0+1.i686-w64-mingw32.tar.gz/sha512/75903d81668a66a5c4d830e31657391d507883943d86245998f224655406dcc6a95ba4f5fad20dcf608a98d6ccf49abe50107993448669b03c42a878d8466611 -PCRE2.v10.43.0+1.powerpc64le-linux-gnu.tar.gz/md5/64cb71080da1c97eba3a440ff53d298c -PCRE2.v10.43.0+1.powerpc64le-linux-gnu.tar.gz/sha512/16348b96a45c7a7d86775cb1d082b4d1c060e5a8acfb37554885d8da0db87430d8a40f834f008a90f4a7b1c07b8329df96836ba0430ecec506a143b7347bb101 -PCRE2.v10.43.0+1.x86_64-apple-darwin.tar.gz/md5/31bbb2485f5e06c3616fb061ffb2f022 -PCRE2.v10.43.0+1.x86_64-apple-darwin.tar.gz/sha512/3284ee63ed1e5631267efacb354a1d90bd1b7db0bc81d7233c9580eee4a9af06093c1c4f240786c34299df89a36a17ed92598fc302074f5a200c56cc96081bf1 -PCRE2.v10.43.0+1.x86_64-linux-gnu.tar.gz/md5/2fb7e0e9bbc32dddf543f4d395b50d3f -PCRE2.v10.43.0+1.x86_64-linux-gnu.tar.gz/sha512/5a533a3a01f817689077377835dc88edf914459ed0df7323f8f4dba602a47fd6af700075feb1f448221366b1cf7e2d717c615a5c506eb4ca2db9c600fd290fb0 -PCRE2.v10.43.0+1.x86_64-linux-musl.tar.gz/md5/b432063c93aa477dd0883428191041f8 -PCRE2.v10.43.0+1.x86_64-linux-musl.tar.gz/sha512/36475e90e29d7324046fe1da669fb37f667245a680df23f3978394964e14eb9bda3fd56703ad62cd56e27a5af77d8b6b9612516457ae803cef0627bd919e4628 -PCRE2.v10.43.0+1.x86_64-unknown-freebsd.tar.gz/md5/6124870a991e70c2ed8a64d8f3258760 -PCRE2.v10.43.0+1.x86_64-unknown-freebsd.tar.gz/sha512/4645a2d05af149467f2e4ce5e48853b57c585d6a5950c70726d04bc71a5d82f50809af141ad98e99671e764ac74965651ecad1c49a849caa8fd077c7f4911c7c -PCRE2.v10.43.0+1.x86_64-w64-mingw32.tar.gz/md5/cc4e9f45471f538c1fefa657ab99b878 -PCRE2.v10.43.0+1.x86_64-w64-mingw32.tar.gz/sha512/eed45e621263cb307b6e8ab42e2c12cf9e1d61ad523760fd721a85765c359b74d580752ca7c3d222e0cba26a74e872a6d43dbf2dbf08e4733a3e709417e48651 -pcre2-10.43.tar.bz2/md5/c8e2043cbc4abb80e76dba323f7c409f -pcre2-10.43.tar.bz2/sha512/8ac1520c32e9e5672404aaf6104e23c9ee5c3c28ad28ff101435599d813cbb20e0491a3fd34e012b4411b3e0366a4c6dfa3f02d093acaa6ff0ab25478bb7ade9 +PCRE2.v10.44.0+0.aarch64-apple-darwin.tar.gz/md5/14de26cfc0f6ff7635fac39e81e81a27 +PCRE2.v10.44.0+0.aarch64-apple-darwin.tar.gz/sha512/45079ecca5f4966a32895fcc63585f1dd60f306dc1cb5c098d42452fcff67f7f6b405c200a15747af4680151bb6a6374832a0119b8ddd743d2ed13d0beaef7c9 +PCRE2.v10.44.0+0.aarch64-linux-gnu.tar.gz/md5/3cf179ed36d37bff698ab81cf3d5797b +PCRE2.v10.44.0+0.aarch64-linux-gnu.tar.gz/sha512/db93e5a5c0c46b5536ed49515682d9bfe1d23f6ba8ae2468289ec8f2160140f39f5606a3c7095f45251f3663d8ccf2d6d7e5e8b1efb21c39bbf9a13b6ec60ef9 +PCRE2.v10.44.0+0.aarch64-linux-musl.tar.gz/md5/02baa415218f581a5ceeb7bf7fc0a090 +PCRE2.v10.44.0+0.aarch64-linux-musl.tar.gz/sha512/1685f37ed8f465ecc2f738fdf65d20bb1806934ff2c50194882282fb6c3900121c61c39210e4c0b89847493bfc3e15bb7b9136b0d968103b47c8662a78b412fe +PCRE2.v10.44.0+0.aarch64-unknown-freebsd.tar.gz/md5/4de065ea59ab4f622b46079df1d9d941 +PCRE2.v10.44.0+0.aarch64-unknown-freebsd.tar.gz/sha512/aa6df9edfb690d155a8b5a9390db7ca11622ac0020174cf070a33a075801bfe43bd4c80b8e28017989a8b7374d39897cdcf72ab0e1962e3e234239975f7ac0b4 +PCRE2.v10.44.0+0.armv6l-linux-gnueabihf.tar.gz/md5/f8a0907fbb20a06507fce849db098c4f +PCRE2.v10.44.0+0.armv6l-linux-gnueabihf.tar.gz/sha512/3f5bcc1742380a31683a81740d55e198d7ec8d8ea5a13d6d0556d6603e4fadbf0dc648093c44e36dd6d3793c52a5e3dae6f2f459c73e3d3b5a005f3395d26772 +PCRE2.v10.44.0+0.armv6l-linux-musleabihf.tar.gz/md5/8854c24183441aa6fd21989c00888904 +PCRE2.v10.44.0+0.armv6l-linux-musleabihf.tar.gz/sha512/a74d9378f071dc4cb021e5171d66cd4ac5de3b348e993fc90d824ce5d2f554f7c8af7af55ec31d874d302aaba7d542b6505cc5963e53656c28026a06a53ed48b +PCRE2.v10.44.0+0.armv7l-linux-gnueabihf.tar.gz/md5/04960309ee7cf69a53e280878d5880ef +PCRE2.v10.44.0+0.armv7l-linux-gnueabihf.tar.gz/sha512/a1644daf036daa3799368598427c87c23bcfdddac55a0d06adca08a2e9d617c893285855af562101b05129d0ed0d84d22f5a8a1703316ecd09aa1752b8330eef +PCRE2.v10.44.0+0.armv7l-linux-musleabihf.tar.gz/md5/1335defc6090be76c509840633f7cdfb +PCRE2.v10.44.0+0.armv7l-linux-musleabihf.tar.gz/sha512/9595052eeae4da413b930b14d7e89359a29220cd9e908325e0b7788c8f4a2feb2134e78a0d8f56007787f0fefadc9de31750db6104bbdd048fa50e1d785c2a8c +PCRE2.v10.44.0+0.i686-linux-gnu.tar.gz/md5/e2d6be1d19566c965c2afeb995aba52f +PCRE2.v10.44.0+0.i686-linux-gnu.tar.gz/sha512/4a9d981bb6aa9150b670db7c5d4d188c8391fcb2a16bc710ede7a84bf7ec546fc5fd9096a339720579d25b6dcb5674b2b5b28e9664e5ef589b1a5044ce38b6a7 +PCRE2.v10.44.0+0.i686-linux-musl.tar.gz/md5/23cf857bd3daea4f094fcec48a7712dc +PCRE2.v10.44.0+0.i686-linux-musl.tar.gz/sha512/534f0cfab0cd60db9498eff387f7280a8baaf893a98dd2e7a737e68ba6473ed8236e9da85116eefb9812ec5323c705a00fcaff010b1900f752de8bdff65ef3ad +PCRE2.v10.44.0+0.i686-w64-mingw32.tar.gz/md5/3d05764df2305f16e4ffab60031ad40c +PCRE2.v10.44.0+0.i686-w64-mingw32.tar.gz/sha512/3e21cc6b71849c1a361373de30567990dba13dfd8812e7a7b5e2734b572bf1d45aeb730289d329975e76932c4c40e476824be2ab8e80a40fb7a7e2f46159235a +PCRE2.v10.44.0+0.powerpc64le-linux-gnu.tar.gz/md5/596d7c29d1417ed8959ea3ae3b4df453 +PCRE2.v10.44.0+0.powerpc64le-linux-gnu.tar.gz/sha512/89e03bfd6890150e2c8dddc4e7d024f2e09421c25a3d0fef3b5cd7f6bab7d6402ec1e82b02ecb5d26d01dfa2fb6068d050513894c374b7f2244c8fcbf00d69e2 +PCRE2.v10.44.0+0.x86_64-apple-darwin.tar.gz/md5/18f13c78ff6388c601bd36788e526b31 +PCRE2.v10.44.0+0.x86_64-apple-darwin.tar.gz/sha512/7b43a289f54064fc3c292de98173ec91cde2e49402c99c7848cbdc0e6d90a23a86d41f521e3986fcc8d941ee070d09e29ddc89a4e23009b8e9333e577ae4a09c +PCRE2.v10.44.0+0.x86_64-linux-gnu.tar.gz/md5/9f45feca0955f81ceb898208b9c74e15 +PCRE2.v10.44.0+0.x86_64-linux-gnu.tar.gz/sha512/eac215838306f7b5adb2166c3f620a69ed52fbd752ef3673a887507963a826c305d9b078dbb5236dc9a45eaca0d34f77325aab41703745701a077c84822ec0d0 +PCRE2.v10.44.0+0.x86_64-linux-musl.tar.gz/md5/79f092c6e8e971027ac6c1f0987376fb +PCRE2.v10.44.0+0.x86_64-linux-musl.tar.gz/sha512/2c5655b0f719a7d442c89f1040f2973b03f8becd855a0cfd6c0a985a07b25de351a84e3b9daaebd952b62628db0d937de08a8d05ee4bcace7e72d6b5ce6b8435 +PCRE2.v10.44.0+0.x86_64-unknown-freebsd.tar.gz/md5/a0bc32a099a584d453458a76c892fe47 +PCRE2.v10.44.0+0.x86_64-unknown-freebsd.tar.gz/sha512/6649c1b9e9569a9decccf6ebaa61d44acdb9069208ec796777d8e70a908210f775be2142053f6a5762ebaa321e297f6d8b51db99629766bc702c498b5f772492 +PCRE2.v10.44.0+0.x86_64-w64-mingw32.tar.gz/md5/eeffb6164fba08b0d5c7f50afa081475 +PCRE2.v10.44.0+0.x86_64-w64-mingw32.tar.gz/sha512/f06db992a2070a88559c15224972aeb098d4291a4325970fc0fbbb7cdd539f4a2fd4f90c0de90a34fe454da6c38290f9e0c7fdf2fe8c441f687fe4491d652adc +pcre2-10.44.tar.bz2/md5/9d1fe11e2e919c7b395e3e8f0a5c3eec +pcre2-10.44.tar.bz2/sha512/ee91cc10a2962bc7818b03d368df3dd31f42ea9a7260ae51483ea8cd331b7431e36e63256b0adc213cc6d6741e7c90414fd420622308c0ae3fcb5dd878591be2 diff --git a/deps/pcre.version b/deps/pcre.version index e3ea507376105..681e97e197f51 100644 --- a/deps/pcre.version +++ b/deps/pcre.version @@ -2,4 +2,4 @@ PCRE_JLL_NAME := PCRE2 ## source build -PCRE_VER := 10.43 +PCRE_VER := 10.44 diff --git a/stdlib/PCRE2_jll/Project.toml b/stdlib/PCRE2_jll/Project.toml index ae1fb74922d79..fee83c7ce552c 100644 --- a/stdlib/PCRE2_jll/Project.toml +++ b/stdlib/PCRE2_jll/Project.toml @@ -1,6 +1,6 @@ name = "PCRE2_jll" uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15" -version = "10.43.0+1" +version = "10.44.0+0" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" diff --git a/stdlib/PCRE2_jll/test/runtests.jl b/stdlib/PCRE2_jll/test/runtests.jl index af0ed9434d2b6..21df2ec430e0e 100644 --- a/stdlib/PCRE2_jll/test/runtests.jl +++ b/stdlib/PCRE2_jll/test/runtests.jl @@ -6,5 +6,5 @@ using Test, Libdl, PCRE2_jll vstr = zeros(UInt8, 32) @test ccall((:pcre2_config_8, libpcre2_8), Cint, (UInt32, Ref{UInt8}), 11, vstr) > 0 vn = VersionNumber(split(unsafe_string(pointer(vstr)), " ")[1]) - @test vn == v"10.43.0" + @test vn == v"10.44.0" end From c1f806dfc168fa2a3dd426f0c003a843bd01aaad Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 28 Nov 2024 22:20:40 -0500 Subject: [PATCH 015/342] compile: make more efficient by discarding internal names (#56702) These are not user-visible, so this makes the compiler faster and more efficient with no effort on our part, and avoids duplicating the debug_level parameter. --- src/aotcompile.cpp | 7 +++++-- src/ccall.cpp | 10 ++++++++-- src/codegen.cpp | 27 ++++++++++++--------------- src/jitlayers.cpp | 7 ++++--- src/jitlayers.h | 1 - src/llvm-late-gc-lowering.cpp | 21 ++++++--------------- src/llvm-pass-helpers.cpp | 7 ------- 7 files changed, 35 insertions(+), 45 deletions(-) diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 7b3c771f9dc12..1d1e48efc8c6c 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -593,9 +593,10 @@ void *jl_create_native_impl(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvm }); egal_set method_roots; jl_codegen_params_t params(ctxt, std::move(target_info.first), std::move(target_info.second)); + if (!llvmmod) + params.getContext().setDiscardValueNames(true); params.params = cgparams; params.imaging_mode = imaging; - params.debug_level = cgparams->debug_info_level; params.external_linkage = _external_linkage; params.temporary_roots = jl_alloc_array_1d(jl_array_any_type, 0); JL_GC_PUSH3(¶ms.temporary_roots, &method_roots.list, &method_roots.keyset); @@ -1719,6 +1720,7 @@ static SmallVector add_output(Module &M, TargetMachine &TM, Stri for (unsigned i = 0; i < threads; i++) { std::function func = [&, i]() { LLVMContext ctx; + ctx.setDiscardValueNames(true); #if JL_LLVM_VERSION < 170000 SetOpaquePointer(ctx); #endif @@ -1930,6 +1932,7 @@ void jl_dump_native_impl(void *native_code, if (z) { JL_TIMING(NATIVE_AOT, NATIVE_Sysimg); LLVMContext Context; + Context.setDiscardValueNames(true); #if JL_LLVM_VERSION < 170000 SetOpaquePointer(Context); #endif @@ -2077,6 +2080,7 @@ void jl_dump_native_impl(void *native_code, { JL_TIMING(NATIVE_AOT, NATIVE_Metadata); LLVMContext Context; + Context.setDiscardValueNames(true); #if JL_LLVM_VERSION < 170000 SetOpaquePointer(Context); #endif @@ -2278,7 +2282,6 @@ void jl_get_llvmf_defn_impl(jl_llvmf_dump_t* dump, jl_method_instance_t *mi, jl_ // output.imaging = true; // This would also be nice, but it seems to cause OOMs on the windows32 builder // To get correct names in the IR this needs to be at least 2 - output.debug_level = params.debug_info_level; output.temporary_roots = jl_alloc_array_1d(jl_array_any_type, 0); JL_GC_PUSH1(&output.temporary_roots); auto decls = jl_emit_code(m, mi, src, output); diff --git a/src/ccall.cpp b/src/ccall.cpp index 707203bd13506..52f8f807132e5 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -851,6 +851,7 @@ static jl_cgval_t emit_llvmcall(jl_codectx_t &ctx, jl_value_t **args, size_t nar // generate a temporary module that contains our IR std::unique_ptr Mod; + bool shouldDiscardValueNames = ctx.builder.getContext().shouldDiscardValueNames(); Function *f; if (entry == NULL) { // we only have function IR, which we should put in a function @@ -878,7 +879,9 @@ static jl_cgval_t emit_llvmcall(jl_codectx_t &ctx, jl_value_t **args, size_t nar << jl_string_data(ir) << "\n}"; SMDiagnostic Err = SMDiagnostic(); + ctx.builder.getContext().setDiscardValueNames(false); Mod = parseAssemblyString(ir_stream.str(), Err, ctx.builder.getContext()); + ctx.builder.getContext().setDiscardValueNames(shouldDiscardValueNames); // backwards compatibility: support for IR with integer pointers if (!Mod) { @@ -911,8 +914,9 @@ static jl_cgval_t emit_llvmcall(jl_codectx_t &ctx, jl_value_t **args, size_t nar << jl_string_data(ir) << "\n}"; SMDiagnostic Err = SMDiagnostic(); - Mod = - parseAssemblyString(compat_ir_stream.str(), Err, ctx.builder.getContext()); + ctx.builder.getContext().setDiscardValueNames(false); + Mod = parseAssemblyString(compat_ir_stream.str(), Err, ctx.builder.getContext()); + ctx.builder.getContext().setDiscardValueNames(shouldDiscardValueNames); } if (!Mod) { @@ -932,7 +936,9 @@ static jl_cgval_t emit_llvmcall(jl_codectx_t &ctx, jl_value_t **args, size_t nar if (jl_is_string(ir)) { SMDiagnostic Err = SMDiagnostic(); + ctx.builder.getContext().setDiscardValueNames(false); Mod = parseAssemblyString(jl_string_data(ir), Err, ctx.builder.getContext()); + ctx.builder.getContext().setDiscardValueNames(shouldDiscardValueNames); if (!Mod) { std::string message = "Failed to parse LLVM assembly: \n"; raw_string_ostream stream(message); diff --git a/src/codegen.cpp b/src/codegen.cpp index ebb96837f4db5..0b483696567ad 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -167,7 +167,7 @@ void setName(jl_codegen_params_t ¶ms, Value *V, const Twine &Name) // is not checking that setName is only called for non-folded instructions (e.g. folded bitcasts // and 0-byte geps), which can result in information loss on the renamed instruction. assert((isa(V) || isa(V)) && "Should only set names on instructions!"); - if (params.debug_level >= 2 && !isa(V)) { + if (!isa(V)) { V->setName(Name); } } @@ -175,23 +175,21 @@ void setName(jl_codegen_params_t ¶ms, Value *V, const Twine &Name) void maybeSetName(jl_codegen_params_t ¶ms, Value *V, const Twine &Name) { // To be used when we may get an Instruction or something that is not an instruction i.e Constants/Arguments - if (params.debug_level >= 2 && isa(V)) { + if (isa(V)) V->setName(Name); - } } void setName(jl_codegen_params_t ¶ms, Value *V, std::function GetName) { assert((isa(V) || isa(V)) && "Should only set names on instructions!"); - if (params.debug_level >= 2 && !isa(V)) { + if (!params.getContext().shouldDiscardValueNames() && !isa(V)) V->setName(Twine(GetName())); - } } void setNameWithField(jl_codegen_params_t ¶ms, Value *V, std::function GetObjName, jl_datatype_t *jt, unsigned idx, const Twine &suffix) { assert((isa(V) || isa(V)) && "Should only set names on instructions!"); - if (params.debug_level >= 2 && !isa(V)) { + if (!params.getContext().shouldDiscardValueNames() && !isa(V)) { if (jl_is_tuple_type(jt)){ V->setName(Twine(GetObjName()) + "[" + Twine(idx + 1) + "]"+ suffix); return; @@ -8327,7 +8325,7 @@ static jl_returninfo_t get_specsig_function(jl_codectx_t &ctx, Module *M, Value if (f == NULL) { f = Function::Create(ftype, GlobalVariable::ExternalLinkage, name, M); jl_init_function(f, ctx.emission_context.TargetTriple); - if (ctx.emission_context.debug_level >= 2) { + if (ctx.emission_context.params->debug_info_level >= 2) { ios_t sigbuf; ios_mem(&sigbuf, 0); jl_static_show_func_sig((JL_STREAM*) &sigbuf, sig); @@ -8435,7 +8433,7 @@ static jl_llvm_functions_t std::map labels; ctx.module = jl_is_method(lam->def.method) ? lam->def.method->module : lam->def.module; ctx.linfo = lam; - ctx.name = TSM.getModuleUnlocked()->getModuleIdentifier().data(); + ctx.name = name_from_method_instance(lam); size_t nreq = src->nargs; int va = src->isva; ctx.nargs = nreq; @@ -8488,7 +8486,7 @@ static jl_llvm_functions_t // jl_printf(JL_STDERR, "\n*** compiling %s at %s:%d\n\n", // jl_symbol_name(ctx.name), ctx.file.str().c_str(), toplineno); - bool debug_enabled = ctx.emission_context.debug_level != 0; + bool debug_enabled = ctx.emission_context.params->debug_info_level != 0; if (dbgFuncName.empty()) // Should never happen anymore? debug_enabled = false; @@ -8564,7 +8562,6 @@ static jl_llvm_functions_t // allocate Function declarations and wrapper objects //Safe because params holds ctx lock Module *M = TSM.getModuleUnlocked(); - M->addModuleFlag(Module::Warning, "julia.debug_level", ctx.emission_context.debug_level); jl_debugcache_t debugcache; debugcache.initialize(M); jl_returninfo_t returninfo = {}; @@ -8572,7 +8569,7 @@ static jl_llvm_functions_t bool has_sret = false; if (specsig) { // assumes !va and !needsparams SmallVector ArgNames(0); - if (ctx.emission_context.debug_level >= 2) { + if (!M->getContext().shouldDiscardValueNames()) { ArgNames.resize(ctx.nargs, ""); for (int i = 0; i < ctx.nargs; i++) { jl_sym_t *argname = slot_symbol(ctx, i); @@ -8639,7 +8636,7 @@ static jl_llvm_functions_t declarations.functionObject = needsparams ? "jl_fptr_sparam" : "jl_fptr_args"; } - if (ctx.emission_context.debug_level >= 2 && lam->def.method && jl_is_method(lam->def.method) && lam->specTypes != (jl_value_t*)jl_emptytuple_type) { + if (!params.getContext().shouldDiscardValueNames() && ctx.emission_context.params->debug_info_level >= 2 && lam->def.method && jl_is_method(lam->def.method) && lam->specTypes != (jl_value_t*)jl_emptytuple_type) { ios_t sigbuf; ios_mem(&sigbuf, 0); jl_static_show_func_sig((JL_STREAM*) &sigbuf, (jl_value_t*)lam->specTypes); @@ -8694,7 +8691,7 @@ static jl_llvm_functions_t if (debug_enabled) { topfile = dbuilder.createFile(ctx.file, "."); DISubroutineType *subrty; - if (ctx.emission_context.debug_level <= 1) + if (ctx.emission_context.params->debug_info_level <= 1) subrty = debugcache.jl_di_func_null_sig; else if (!specsig) subrty = debugcache.jl_di_func_sig; @@ -8715,7 +8712,7 @@ static jl_llvm_functions_t ); topdebugloc = DILocation::get(ctx.builder.getContext(), toplineno, 0, SP, NULL); f->setSubprogram(SP); - if (ctx.emission_context.debug_level >= 2) { + if (ctx.emission_context.params->debug_info_level >= 2) { const bool AlwaysPreserve = true; // Go over all arguments and local variables and initialize their debug information for (i = 0; i < nreq; i++) { @@ -10161,7 +10158,7 @@ jl_llvm_functions_t jl_emit_codeinst( if (// keep code when keeping everything !(JL_DELETE_NON_INLINEABLE) || // aggressively keep code when debugging level >= 2 - // note that this uses the global jl_options.debug_level, not the local emission_ctx.debug_level + // note that this uses the global jl_options.debug_level, not the local emission_ctx.debug_info_level jl_options.debug_level > 1) { // update the stored code if (inferred != (jl_value_t*)src) { diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index d7e8ca4a4850a..42ddfb688af39 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -690,9 +690,9 @@ static void jl_emit_codeinst_to_jit( JL_TIMING(CODEINST_COMPILE, CODEINST_COMPILE); // emit the code in LLVM IR form to the new context jl_codegen_params_t params(std::make_unique(), jl_ExecutionEngine->getDataLayout(), jl_ExecutionEngine->getTargetTriple()); // Locks the context + params.getContext().setDiscardValueNames(true); params.cache = true; params.imaging_mode = imaging_default(); - params.debug_level = jl_options.debug_level; orc::ThreadSafeModule result_m = jl_create_ts_module(name_from_method_instance(codeinst->def), params.tsctx, params.DL, params.TargetTriple); params.temporary_roots = jl_alloc_array_1d(jl_array_any_type, 0); @@ -795,9 +795,10 @@ int jl_compile_extern_c_impl(LLVMOrcThreadSafeModuleRef llvmmod, void *p, void * Module *M = into->getModuleUnlocked(); jl_codegen_params_t params(into->getContext(), M->getDataLayout(), Triple(M->getTargetTriple())); params.imaging_mode = imaging_default(); - params.debug_level = jl_options.debug_level; - if (pparams == NULL) + if (pparams == NULL) { + M->getContext().setDiscardValueNames(true); pparams = ¶ms; + } assert(pparams->tsctx.getContext() == into->getContext().getContext()); const char *name = jl_generate_ccallable(wrap(into), sysimg, declrt, sigt, *pparams); if (!sysimg) { diff --git a/src/jitlayers.h b/src/jitlayers.h index d5fa878211200..baba5412226e3 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -259,7 +259,6 @@ struct jl_codegen_params_t { bool cache = false; bool external_linkage = false; bool imaging_mode; - int debug_level; bool use_swiftcc = true; jl_codegen_params_t(orc::ThreadSafeContext ctx, DataLayout DL, Triple triple) : tsctx(std::move(ctx)), diff --git a/src/llvm-late-gc-lowering.cpp b/src/llvm-late-gc-lowering.cpp index 3e372ec9884e7..d95cc9c49b698 100644 --- a/src/llvm-late-gc-lowering.cpp +++ b/src/llvm-late-gc-lowering.cpp @@ -1944,28 +1944,19 @@ void LateLowerGCFrame::CleanupWriteBarriers(Function &F, State *S, const SmallVe if (CFGModified) { *CFGModified = true; } - auto DebugInfoMeta = F.getParent()->getModuleFlag("julia.debug_level"); - int debug_info = 1; - if (DebugInfoMeta != nullptr) { - debug_info = cast(cast(DebugInfoMeta)->getValue())->getZExtValue(); - } IRBuilder<> builder(CI); builder.SetCurrentDebugLocation(CI->getDebugLoc()); - auto parBits = builder.CreateAnd(EmitLoadTag(builder, T_size, parent), GC_OLD_MARKED); - setName(parBits, "parent_bits", debug_info); - auto parOldMarked = builder.CreateICmpEQ(parBits, ConstantInt::get(T_size, GC_OLD_MARKED)); - setName(parOldMarked, "parent_old_marked", debug_info); + auto parBits = builder.CreateAnd(EmitLoadTag(builder, T_size, parent), GC_OLD_MARKED, "parent_bits"); + auto parOldMarked = builder.CreateICmpEQ(parBits, ConstantInt::get(T_size, GC_OLD_MARKED), "parent_old_marked"); auto mayTrigTerm = SplitBlockAndInsertIfThen(parOldMarked, CI, false); builder.SetInsertPoint(mayTrigTerm); - setName(mayTrigTerm->getParent(), "may_trigger_wb", debug_info); + mayTrigTerm->getParent()->setName("may_trigger_wb"); Value *anyChldNotMarked = NULL; for (unsigned i = 1; i < CI->arg_size(); i++) { Value *child = CI->getArgOperand(i); - Value *chldBit = builder.CreateAnd(EmitLoadTag(builder, T_size, child), GC_MARKED); - setName(chldBit, "child_bit", debug_info); - Value *chldNotMarked = builder.CreateICmpEQ(chldBit, ConstantInt::get(T_size, 0),"child_not_marked"); - setName(chldNotMarked, "child_not_marked", debug_info); + Value *chldBit = builder.CreateAnd(EmitLoadTag(builder, T_size, child), GC_MARKED, "child_bit"); + Value *chldNotMarked = builder.CreateICmpEQ(chldBit, ConstantInt::get(T_size, 0), "child_not_marked"); anyChldNotMarked = anyChldNotMarked ? builder.CreateOr(anyChldNotMarked, chldNotMarked) : chldNotMarked; } assert(anyChldNotMarked); // handled by all_of test above @@ -1973,7 +1964,7 @@ void LateLowerGCFrame::CleanupWriteBarriers(Function &F, State *S, const SmallVe SmallVector Weights{1, 9}; auto trigTerm = SplitBlockAndInsertIfThen(anyChldNotMarked, mayTrigTerm, false, MDB.createBranchWeights(Weights)); - setName(trigTerm->getParent(), "trigger_wb", debug_info); + trigTerm->getParent()->setName("trigger_wb"); builder.SetInsertPoint(trigTerm); if (CI->getCalledOperand() == write_barrier_func) { builder.CreateCall(getOrDeclare(jl_intrinsics::queueGCRoot), parent); diff --git a/src/llvm-pass-helpers.cpp b/src/llvm-pass-helpers.cpp index cc6c73161968d..4e9e4826b4f75 100644 --- a/src/llvm-pass-helpers.cpp +++ b/src/llvm-pass-helpers.cpp @@ -335,10 +335,3 @@ namespace jl_well_known { return addGCAllocAttributes(allocTypedFunc); }); } - -void setName(llvm::Value *V, const llvm::Twine &Name, int debug_info) -{ - if (debug_info >= 2 && !llvm::isa(V)) { - V->setName(Name); - } -} From d32843b606bdb59957662d267f258d3dc7bf27b5 Mon Sep 17 00:00:00 2001 From: Valentin Churavy Date: Sat, 30 Nov 2024 16:34:42 +0100 Subject: [PATCH 016/342] Automatically enable JITPROFILING with ITTAPI (#55598) This helps when profiling remotely since VTunes doesn't support setting environment variables on remote systems. Will still respect `ENABLE_JITPROFILING=0`. --- src/codegen.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 0b483696567ad..b8bed0793730b 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -81,6 +81,10 @@ #include #include +#ifdef USE_ITTAPI +#include "ittapi/ittnotify.h" +#endif + using namespace llvm; static bool jl_fpo_disabled(const Triple &TT) { @@ -10427,8 +10431,16 @@ extern "C" void jl_init_llvm(void) const char *jit_profiling = getenv("ENABLE_JITPROFILING"); #if defined(JL_USE_INTEL_JITEVENTS) - if (jit_profiling && atoi(jit_profiling)) { - jl_using_intel_jitevents = 1; + if (jit_profiling) { + if (atoi(jit_profiling)) { + jl_using_intel_jitevents = 1; + } + } else { +#ifdef USE_ITTAPI + __itt_collection_state state = __itt_get_collection_state(); + jl_using_intel_jitevents = state == __itt_collection_init_successful || + state == __itt_collection_collector_exists; +#endif } #endif From ef328064a96fb143c28e2765f5a84b3ab8c43c87 Mon Sep 17 00:00:00 2001 From: Zentrik Date: Sun, 1 Dec 2024 04:35:39 +0000 Subject: [PATCH 017/342] Fix string handling in jlchecksum (#56720) A `TAGGED_RELEASE_BANNER` with spaces such as `Official https://julialang.org release` produces the error `/cache/build/builder-amdci4-5/julialang/julia-master/deps/tools/jlchecksum: 66: [: Official: unexpected operator`. --- deps/tools/jlchecksum | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/tools/jlchecksum b/deps/tools/jlchecksum index 329d3a2a845d4..9945ec89e6bda 100755 --- a/deps/tools/jlchecksum +++ b/deps/tools/jlchecksum @@ -63,7 +63,7 @@ find_checksum() fi done if [ ! -f "$DEPSDIR/checksums/$BASENAME/$CHECKSUM_TYPE" ]; then - if [ ${TAGGED_RELEASE_BANNER:-} ]; then + if [ "${TAGGED_RELEASE_BANNER:-}" ]; then echo "WARNING: $CHECKSUM_TYPE checksum for $BASENAME not found in deps/checksums/, failing release build." >&2 exit 3 fi From ea421126d831b18fa00408794247317b544b18d8 Mon Sep 17 00:00:00 2001 From: Priynsh <119518987+Priynsh@users.noreply.github.com> Date: Mon, 2 Dec 2024 00:29:52 +0530 Subject: [PATCH 018/342] Clarifying ispunct behavior difference between Julia and C in documentation (#56727) Fixes #56680. This PR updates the documentation for the ispunct function in Julia to explicitly note its differing behavior from the similarly named function in C. --------- Co-authored-by: Lilith Orion Hafner --- base/strings/unicode.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/base/strings/unicode.jl b/base/strings/unicode.jl index ad047514c85a6..fcb4a371e9898 100644 --- a/base/strings/unicode.jl +++ b/base/strings/unicode.jl @@ -534,11 +534,17 @@ iscntrl(c::AbstractChar) = c <= '\x1f' || '\x7f' <= c <= '\u9f' Tests whether a character belongs to the Unicode general category Punctuation, i.e. a character whose category code begins with 'P'. +!!! note + This behavior is different from the `ispunct` function in C. + # Examples ```jldoctest julia> ispunct('α') false +julia> ispunct('=') +false + julia> ispunct('/') true From 8ce7d0fce419746e36556d561fe7d1c89704e291 Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Mon, 2 Dec 2024 11:13:51 -0400 Subject: [PATCH 019/342] [NEWS.md] Add PR numbers and remove some 1.11 changes that accidentally came back. (#56722) --- NEWS.md | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/NEWS.md b/NEWS.md index 61bad831e261c..c1d5f38f337b0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -55,11 +55,11 @@ Command-line option changes --------------------------- * The `-m/--module` flag can be passed to run the `main` function inside a package with a set of arguments. - This `main` function should be declared using `@main` to indicate that it is an entry point. + This `main` function should be declared using `@main` to indicate that it is an entry point. ([#52103]) * Enabling or disabling color text in Julia can now be controlled with the [`NO_COLOR`](https://no-color.org/) or [`FORCE_COLOR`](https://force-color.org/) environment variables. These variables are also honored by Julia's build system ([#53742], [#56346]). -* `--project=@temp` starts Julia with a temporary environment. +* `--project=@temp` starts Julia with a temporary environment. ([#51149]) * New `--trace-compile-timing` option to report how long each method reported by `--trace-compile` took to compile, in ms. ([#54662]) * `--trace-compile` now prints recompiled methods in yellow or with a trailing comment if color is not supported ([#55763]) @@ -72,7 +72,7 @@ Multi-threading changes a `OncePerProcess{T}` type, which allows defining a function that should be run exactly once the first time it is called, and then always return the same result value of type `T` every subsequent time afterwards. There are also `OncePerThread{T}` and `OncePerTask{T}` types for - similar usage with threads or tasks. ([#TBD]) + similar usage with threads or tasks. ([#55793]) Build system changes -------------------- @@ -86,32 +86,15 @@ New library functions * The new `isfull(c::Channel)` function can be used to check if `put!(c, some_value)` will block. ([#53159]) * `waitany(tasks; throw=false)` and `waitall(tasks; failfast=false, throw=false)` which wait multiple tasks at once ([#53341]). * `uuid7()` creates an RFC 9652 compliant UUID with version 7 ([#54834]). -* `insertdims(array; dims)` allows to insert singleton dimensions into an array which is the inverse operation to `dropdims` +* `insertdims(array; dims)` allows to insert singleton dimensions into an array which is the inverse operation to `dropdims`. ([#45793]) * The new `Fix` type is a generalization of `Fix1/Fix2` for fixing a single argument ([#54653]). New library features -------------------- -* `invmod(n, T)` where `T` is a native integer type now computes the modular inverse of `n` in the modular integer ring that `T` defines ([#52180]). -* `invmod(n)` is an abbreviation for `invmod(n, typeof(n))` for native integer types ([#52180]). -* `replace(string, pattern...)` now supports an optional `IO` argument to - write the output to a stream rather than returning a string ([#48625]). -* `sizehint!(s, n)` now supports an optional `shrink` argument to disable shrinking ([#51929]). -* New function `Docs.hasdoc(module, symbol)` tells whether a name has a docstring ([#52139]). -* New function `Docs.undocumented_names(module)` returns a module's undocumented public names ([#52413]). -* Passing an `IOBuffer` as a stdout argument for `Process` spawn now works as - expected, synchronized with `wait` or `success`, so a `Base.BufferStream` is - no longer required there for correctness to avoid data races ([#52461]). -* After a process exits, `closewrite` will no longer be automatically called on - the stream passed to it. Call `wait` on the process instead to ensure the - content is fully written, then call `closewrite` manually to avoid - data-races. Or use the callback form of `open` to have all that handled - automatically. -* `@timed` now additionally returns the elapsed compilation and recompilation time ([#52889]) * `escape_string` takes additional keyword arguments `ascii=true` (to escape all non-ASCII characters) and `fullhex=true` (to require full 4/8-digit hex numbers - for u/U escapes, e.g. for C compatibility) [#55099]). -* `filter` can now act on a `NamedTuple` ([#50795]). + for u/U escapes, e.g. for C compatibility) ([#55099]). * `tempname` can now take a suffix string to allow the file name to include a suffix and include that suffix in the uniquing checking ([#53474]) * `RegexMatch` objects can now be used to construct `NamedTuple`s and `Dict`s ([#50988]) @@ -133,7 +116,7 @@ Standard library changes * A new standard library for applying syntax highlighting to Julia code, this uses `JuliaSyntax` and `StyledStrings` to implement a `highlight` function - that creates an `AnnotatedString` with syntax highlighting applied. + that creates an `AnnotatedString` with syntax highlighting applied. ([#51810]) #### Package Manager From 6a0de347469abe38c970b9efbf0244f2d60806ca Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sat, 30 Nov 2024 18:06:26 -0500 Subject: [PATCH 020/342] ircode: cleanup code crud - support gc running - don't duplicate field 4 - remove some unused code only previously needed for handling cycles (which are not valid in IR) --- src/clangsa/GCChecker.cpp | 3 +- src/ircode.c | 399 +++++++++++++++++++++++++------------- src/serialize.h | 69 ------- 3 files changed, 263 insertions(+), 208 deletions(-) diff --git a/src/clangsa/GCChecker.cpp b/src/clangsa/GCChecker.cpp index cac89a6761d01..40093ca15859b 100644 --- a/src/clangsa/GCChecker.cpp +++ b/src/clangsa/GCChecker.cpp @@ -847,7 +847,8 @@ bool GCChecker::isGCTrackedType(QualType QT) { Name.ends_with_insensitive("jl_vararg_t") || Name.ends_with_insensitive("jl_opaque_closure_t") || Name.ends_with_insensitive("jl_globalref_t") || - // Probably not technically true for these, but let's allow it + // Probably not technically true for these, but let's allow it as a root + Name.ends_with_insensitive("jl_ircode_state") || Name.ends_with_insensitive("typemap_intersection_env") || Name.ends_with_insensitive("interpreter_state") || Name.ends_with_insensitive("jl_typeenv_t") || diff --git a/src/ircode.c b/src/ircode.c index bec8d46513eef..d3137ce26edef 100644 --- a/src/ircode.c +++ b/src/ircode.c @@ -10,17 +10,76 @@ #include "julia_internal.h" #include "serialize.h" -#ifndef _OS_WINDOWS_ -#include -#endif - -#include "valgrind.h" #include "julia_assert.h" #ifdef __cplusplus extern "C" { #endif +#define TAG_SYMBOL 2 +#define TAG_SSAVALUE 3 +#define TAG_DATATYPE 4 +#define TAG_SLOTNUMBER 5 +#define TAG_SVEC 6 +// #define TAG_UNUSED 7 +#define TAG_NULL 8 +#define TAG_EXPR 9 +#define TAG_PHINODE 10 +#define TAG_PHICNODE 11 +#define TAG_LONG_SYMBOL 12 +#define TAG_LONG_SVEC 13 +#define TAG_LONG_EXPR 14 +#define TAG_LONG_PHINODE 15 +#define TAG_LONG_PHICNODE 16 +#define TAG_METHODROOT 17 +#define TAG_EDGE 18 +#define TAG_STRING 19 +#define TAG_SHORT_INT64 20 +//#define TAG_UNUSED 21 +#define TAG_CNULL 22 +#define TAG_ARRAY1D 23 +#define TAG_SINGLETON 24 +#define TAG_MODULE 25 +#define TAG_TVAR 26 +#define TAG_METHOD_INSTANCE 27 +#define TAG_METHOD 28 +#define TAG_CODE_INSTANCE 29 +#define TAG_COMMONSYM 30 +#define TAG_NEARBYGLOBAL 31 +#define TAG_GLOBALREF 32 +#define TAG_CORE 33 +#define TAG_BASE 34 +#define TAG_BITYPENAME 35 +#define TAG_NEARBYMODULE 36 +#define TAG_INT32 37 +#define TAG_INT64 38 +#define TAG_UINT8 39 +#define TAG_VECTORTY 40 +#define TAG_PTRTY 41 +#define TAG_LONG_SSAVALUE 42 +#define TAG_LONG_METHODROOT 43 +#define TAG_LONG_EDGE 44 +#define TAG_SHORTER_INT64 45 +#define TAG_SHORT_INT32 46 +#define TAG_CALL1 47 +#define TAG_CALL2 48 +#define TAG_SHORT_BACKREF 49 +#define TAG_BACKREF 50 +#define TAG_UNIONALL 51 +#define TAG_GOTONODE 52 +#define TAG_QUOTENODE 53 +#define TAG_GENERAL 54 +#define TAG_GOTOIFNOT 55 +#define TAG_RETURNNODE 56 +#define TAG_ARGUMENT 57 +#define TAG_RELOC_METHODROOT 58 +#define TAG_BINDING 59 +#define TAG_MEMORYT 60 +#define TAG_ENTERNODE 61 + +#define LAST_TAG 61 + + typedef struct { ios_t *s; // method we're compressing for @@ -38,29 +97,29 @@ static jl_value_t *deser_tag[256]; static htable_t common_symbol_tag; static jl_value_t *deser_symbols[256]; -void *jl_lookup_ser_tag(jl_value_t *v) +static void *jl_lookup_ser_tag(jl_value_t *v) { return ptrhash_get(&ser_tag, v); } -void *jl_lookup_common_symbol(jl_value_t *v) +static void *jl_lookup_common_symbol(jl_value_t *v) { return ptrhash_get(&common_symbol_tag, v); } -jl_value_t *jl_deser_tag(uint8_t tag) +static jl_value_t *jl_deser_tag(uint8_t tag) { return deser_tag[tag]; } -jl_value_t *jl_deser_symbol(uint8_t tag) +static jl_value_t *jl_deser_symbol(uint8_t tag) { return deser_symbols[tag]; } // --- encoding --- -static void jl_encode_value_(jl_ircode_state *s, jl_value_t *v, int as_literal) JL_GC_DISABLED; +static void jl_encode_value_(jl_ircode_state *s, jl_value_t *v, int as_literal); #define jl_encode_value(s, v) jl_encode_value_((s), (jl_value_t*)(v), 0) static void tagged_root(rle_reference *rr, jl_ircode_state *s, int i) @@ -69,7 +128,7 @@ static void tagged_root(rle_reference *rr, jl_ircode_state *s, int i) s->relocatability = 0; } -static void literal_val_id(rle_reference *rr, jl_ircode_state *s, jl_value_t *v) JL_GC_DISABLED +static void literal_val_id(rle_reference *rr, jl_ircode_state *s, jl_value_t *v) { jl_array_t *rs = s->method->roots; int i, l = jl_array_nrows(rs); @@ -142,7 +201,7 @@ static void jl_encode_as_indexed_root(jl_ircode_state *s, jl_value_t *v) } } -static void jl_encode_memory_slice(jl_ircode_state *s, jl_genericmemory_t *mem, size_t offset, size_t len) JL_GC_DISABLED +static void jl_encode_memory_slice(jl_ircode_state *s, jl_genericmemory_t *mem, size_t offset, size_t len) { jl_datatype_t *t = (jl_datatype_t*)jl_typetagof(mem); size_t i; @@ -180,7 +239,7 @@ static void jl_encode_memory_slice(jl_ircode_state *s, jl_genericmemory_t *mem, } } -static void jl_encode_value_(jl_ircode_state *s, jl_value_t *v, int as_literal) JL_GC_DISABLED +static void jl_encode_value_(jl_ircode_state *s, jl_value_t *v, int as_literal) { size_t i; @@ -306,8 +365,11 @@ static void jl_encode_value_(jl_ircode_state *s, jl_value_t *v, int as_literal) } for (i = 0; i < l; i++) { int32_t e = jl_array_data(edges, int32_t)[i]; - if (e <= 20) - jl_encode_value(s, jl_box_int32(e)); + if (e <= 0 && e <= 20) { // 1-byte encodings + jl_value_t *ebox = jl_box_int32(e); + JL_GC_PROMISE_ROOTED(ebox); + jl_encode_value(s, ebox); + } else jl_encode_int32(s, e); } @@ -333,25 +395,39 @@ static void jl_encode_value_(jl_ircode_state *s, jl_value_t *v, int as_literal) } else if (jl_is_gotonode(v)) { write_uint8(s->s, TAG_GOTONODE); - jl_encode_value(s, jl_get_nth_field(v, 0)); + jl_value_t *f = jl_get_nth_field(v, 0); + JL_GC_PUSH1(&f); + jl_encode_value(s, f); + JL_GC_POP(); } else if (jl_is_gotoifnot(v)) { write_uint8(s->s, TAG_GOTOIFNOT); - jl_encode_value(s, jl_get_nth_field(v, 0)); - jl_encode_value(s, jl_get_nth_field(v, 1)); + jl_value_t *f = jl_get_nth_field_noalloc(v, 0); + JL_GC_PUSH1(&f); + jl_encode_value(s, f); + f = jl_get_nth_field(v, 1); + jl_encode_value(s, f); + JL_GC_POP(); } else if (jl_is_enternode(v)) { write_uint8(s->s, TAG_ENTERNODE); - jl_encode_value(s, jl_get_nth_field(v, 0)); - jl_encode_value(s, jl_get_nth_field(v, 1)); + jl_value_t *f = jl_get_nth_field(v, 0); + JL_GC_PUSH1(&f); + jl_encode_value(s, f); + f = jl_get_nth_field_noalloc(v, 1); + jl_encode_value(s, f); + JL_GC_POP(); } else if (jl_is_argument(v)) { write_uint8(s->s, TAG_ARGUMENT); - jl_encode_value(s, jl_get_nth_field(v, 0)); + jl_value_t *f = jl_get_nth_field(v, 0); + JL_GC_PUSH1(&f); + jl_encode_value(s, f); + JL_GC_POP(); } else if (jl_is_returnnode(v)) { write_uint8(s->s, TAG_RETURNNODE); - jl_encode_value(s, jl_get_nth_field(v, 0)); + jl_encode_value(s, jl_returnnode_value(v)); } else if (jl_is_quotenode(v)) { write_uint8(s->s, TAG_QUOTENODE); @@ -394,19 +470,15 @@ static void jl_encode_value_(jl_ircode_state *s, jl_value_t *v, int as_literal) write_int32(s->s, jl_string_len(v)); ios_write(s->s, jl_string_data(v), jl_string_len(v)); } - else if (as_literal && jl_is_array(v)) { + else if (as_literal && jl_is_array(v) && jl_array_ndims(v)) { jl_array_t *ar = (jl_array_t*)v; - if (jl_array_ndims(ar) == 1) { - write_uint8(s->s, TAG_ARRAY1D); - } - else { - write_uint8(s->s, TAG_ARRAY); - write_uint16(s->s, jl_array_ndims(ar)); - } - for (i = 0; i < jl_array_ndims(ar); i++) - jl_encode_value(s, jl_box_long(jl_array_dim(ar, i))); + write_uint8(s->s, TAG_ARRAY1D); + size_t l = jl_array_dim0(ar); + jl_value_t *lbox = jl_box_long(l); + JL_GC_PUSH1(&lbox); + jl_encode_value(s, lbox); + JL_GC_POP(); jl_encode_value(s, jl_typeof(ar)); - size_t l = jl_array_len(ar); const jl_datatype_layout_t *layout = ((jl_datatype_t*)jl_typetagof(ar->ref.mem))->layout; size_t offset; if (layout->flags.arrayelem_isunion || layout->size == 0) @@ -419,7 +491,10 @@ static void jl_encode_value_(jl_ircode_state *s, jl_value_t *v, int as_literal) jl_genericmemory_t* m = (jl_genericmemory_t*)v; write_uint8(s->s, TAG_MEMORYT); jl_encode_value(s, (jl_datatype_t*)jl_typetagof(v)); - jl_encode_value(s, jl_box_long(m->length)); + jl_value_t *lbox = jl_box_long(m->length); + JL_GC_PUSH1(&lbox); + jl_encode_value(s, lbox); + JL_GC_POP(); jl_encode_memory_slice(s, m, 0, m->length); } else if (as_literal && jl_is_layout_opaque(((jl_datatype_t*)jl_typeof(v))->layout)) { @@ -428,16 +503,8 @@ static void jl_encode_value_(jl_ircode_state *s, jl_value_t *v, int as_literal) else if (as_literal || jl_is_uniontype(v) || jl_is_newvarnode(v) || jl_is_linenode(v) || jl_is_upsilonnode(v) || jl_is_pinode(v) || jl_is_slotnumber(v) || jl_is_ssavalue(v) || (jl_isbits(jl_typeof(v)) && jl_datatype_size(jl_typeof(v)) <= 64)) { + write_uint8(s->s, TAG_GENERAL); jl_datatype_t *t = (jl_datatype_t*)jl_typeof(v); - size_t tsz = jl_datatype_size(t); - if (tsz <= 255) { - write_uint8(s->s, TAG_SHORT_GENERAL); - write_uint8(s->s, tsz); - } - else { - write_uint8(s->s, TAG_GENERAL); - write_int32(s->s, tsz); - } jl_encode_value(s, t); char *data = (char*)jl_data_ptr(v); @@ -492,34 +559,35 @@ static jl_code_info_flags_t code_info_flags(uint8_t propagate_inbounds, uint8_t // --- decoding --- -static jl_value_t *jl_decode_value(jl_ircode_state *s) JL_GC_DISABLED; +static jl_value_t *jl_decode_value(jl_ircode_state *s); -static jl_value_t *jl_decode_value_svec(jl_ircode_state *s, uint8_t tag) JL_GC_DISABLED +static jl_value_t *jl_decode_value_svec(jl_ircode_state *s, uint8_t tag) { size_t i, len; if (tag == TAG_SVEC) len = read_uint8(s->s); else len = read_int32(s->s); - jl_svec_t *sv = jl_alloc_svec_uninit(len); - jl_value_t **data = jl_svec_data(sv); - for (i = 0; i < len; i++) { - data[i] = jl_decode_value(s); - } + jl_svec_t *sv = jl_alloc_svec(len); + JL_GC_PUSH1(&sv); + for (i = 0; i < len; i++) + jl_svecset(sv, i, jl_decode_value(s)); + JL_GC_POP(); return (jl_value_t*)sv; } -static jl_value_t *jl_decode_value_memory(jl_ircode_state *s, jl_value_t *mty, size_t nel) JL_GC_DISABLED +static jl_genericmemory_t *jl_decode_value_memory(jl_ircode_state *s, jl_value_t *mty, size_t nel) { jl_genericmemory_t *m = jl_alloc_genericmemory(mty, nel); + JL_GC_PUSH1(&m); const jl_datatype_layout_t *layout = ((jl_datatype_t*)mty)->layout; if (layout->flags.arrayelem_isboxed) { jl_value_t **data = (jl_value_t**)m->ptr; size_t i, numel = m->length; for (i = 0; i < numel; i++) { data[i] = jl_decode_value(s); + jl_gc_wb(m, data[i]); } - assert(jl_astaggedvalue(m)->bits.gc == GC_CLEAN); // gc is disabled } else if (layout->first_ptr >= 0) { size_t i, numel = m->length; @@ -534,49 +602,48 @@ static jl_value_t *jl_decode_value_memory(jl_ircode_state *s, jl_value_t *mty, s if ((char*)fld != start) ios_readall(s->s, start, (const char*)fld - start); *fld = jl_decode_value(s); + jl_gc_wb(m, fld); start = (char*)&fld[1]; } data += elsz; if (data != start) ios_readall(s->s, start, data - start); } - assert(jl_astaggedvalue(m)->bits.gc == GC_CLEAN); // gc is disabled } else { size_t extra = jl_genericmemory_isbitsunion(m) ? m->length : 0; size_t tot = m->length * layout->size + extra; ios_readall(s->s, (char*)m->ptr, tot); } - return (jl_value_t*)m; + JL_GC_POP(); + return m; } JL_DLLEXPORT jl_array_t *jl_alloc_array_nd(jl_value_t *atype, size_t *dims, size_t ndims); -static jl_value_t *jl_decode_value_array(jl_ircode_state *s, uint8_t tag) JL_GC_DISABLED +static jl_value_t *jl_decode_value_array1d(jl_ircode_state *s, uint8_t tag) { - int16_t i, ndims; - if (tag == TAG_ARRAY1D) - ndims = 1; - else - ndims = read_uint16(s->s); - size_t *dims = (size_t*)alloca(ndims * sizeof(size_t)); - size_t len = 1; - for (i = 0; i < ndims; i++) { - dims[i] = jl_unbox_long(jl_decode_value(s)); - len *= dims[i]; - } + int16_t ndims = 1; + size_t dim0 = jl_unbox_long(jl_decode_value(s)); + size_t len = dim0; jl_value_t *aty = jl_decode_value(s); - jl_array_t *a = jl_alloc_array_nd(aty, dims, ndims); - a->ref.mem = (jl_genericmemory_t*)jl_decode_value_memory(s, jl_field_type_concrete((jl_datatype_t*)jl_field_type_concrete((jl_datatype_t*)aty, 0), 1), len); + JL_GC_PROMISE_ROOTED(aty); // (JL_ALWAYS_LEAFTYPE) + jl_genericmemory_t *mem = jl_decode_value_memory(s, jl_field_type_concrete((jl_datatype_t*)jl_field_type_concrete((jl_datatype_t*)aty, 0), 1), len); + JL_GC_PUSH1(&mem); + int tsz = sizeof(jl_array_t) + ndims*sizeof(size_t); + jl_array_t *a = (jl_array_t*)jl_gc_alloc(s->ptls, tsz, aty); + a->ref.mem = mem; const jl_datatype_layout_t *layout = ((jl_datatype_t*)jl_typetagof(a->ref.mem))->layout; if (layout->flags.arrayelem_isunion || layout->size == 0) a->ref.ptr_or_offset = (void*)0; else a->ref.ptr_or_offset = a->ref.mem->ptr; + a->dimsize[0] = dim0; + JL_GC_POP(); return (jl_value_t*)a; } -static jl_value_t *jl_decode_value_expr(jl_ircode_state *s, uint8_t tag) JL_GC_DISABLED +static jl_value_t *jl_decode_value_expr(jl_ircode_state *s, uint8_t tag) { size_t i, len; jl_sym_t *head = NULL; @@ -597,14 +664,18 @@ static jl_value_t *jl_decode_value_expr(jl_ircode_state *s, uint8_t tag) JL_GC_D if (head == NULL) head = (jl_sym_t*)jl_decode_value(s); jl_expr_t *e = jl_exprn(head, len); + JL_GC_PUSH1(&e); jl_value_t **data = jl_array_ptr_data(e->args); + jl_value_t *owner = jl_array_owner(e->args); for (i = 0; i < len; i++) { data[i] = jl_decode_value(s); + jl_gc_wb(owner, data[i]); } + JL_GC_POP(); return (jl_value_t*)e; } -static jl_value_t *jl_decode_value_phi(jl_ircode_state *s, uint8_t tag) JL_GC_DISABLED +static jl_value_t *jl_decode_value_phi(jl_ircode_state *s, uint8_t tag) { size_t i, len_e, len_v; if (tag == TAG_PHINODE) { @@ -614,9 +685,13 @@ static jl_value_t *jl_decode_value_phi(jl_ircode_state *s, uint8_t tag) JL_GC_DI len_e = read_int32(s->s); len_v = read_int32(s->s); } - jl_array_t *e = jl_alloc_array_1d(jl_array_int32_type, len_e); - jl_array_t *v = jl_alloc_vec_any(len_v); - jl_value_t *phi = jl_new_struct(jl_phinode_type, e, v); + jl_array_t *e = NULL; + jl_array_t *v = NULL; + jl_value_t *phi = NULL; + JL_GC_PUSH3(&e, &v, &phi); + e = jl_alloc_array_1d(jl_array_int32_type, len_e); + v = jl_alloc_vec_any(len_v); + phi = jl_new_struct(jl_phinode_type, e, v); int32_t *data_e = jl_array_data(e, int32_t); for (i = 0; i < len_e; i++) { data_e[i] = jl_unbox_int32(jl_decode_value(s)); @@ -624,11 +699,13 @@ static jl_value_t *jl_decode_value_phi(jl_ircode_state *s, uint8_t tag) JL_GC_DI jl_value_t **data_v = jl_array_ptr_data(v); for (i = 0; i < len_v; i++) { data_v[i] = jl_decode_value(s); + jl_gc_wb(jl_array_owner(v), data_v[i]); } + JL_GC_POP(); return phi; } -static jl_value_t *jl_decode_value_phic(jl_ircode_state *s, uint8_t tag) JL_GC_DISABLED +static jl_value_t *jl_decode_value_phic(jl_ircode_state *s, uint8_t tag) { size_t i, len; if (tag == TAG_PHICNODE) @@ -636,41 +713,53 @@ static jl_value_t *jl_decode_value_phic(jl_ircode_state *s, uint8_t tag) JL_GC_D else len = read_int32(s->s); jl_array_t *v = jl_alloc_vec_any(len); - jl_value_t *phic = jl_new_struct(jl_phicnode_type, v); + jl_value_t *phic = (jl_value_t*)v; + JL_GC_PUSH1(&phic); + phic = jl_new_struct(jl_phicnode_type, v); jl_value_t **data = jl_array_ptr_data(v); for (i = 0; i < len; i++) { data[i] = jl_decode_value(s); + jl_gc_wb(jl_array_owner(v), data[i]); } + JL_GC_POP(); return phic; } -static jl_value_t *jl_decode_value_globalref(jl_ircode_state *s) JL_GC_DISABLED +static jl_value_t *jl_decode_value_globalref(jl_ircode_state *s) { - jl_value_t *mod = jl_decode_value(s); - jl_value_t *var = jl_decode_value(s); - return jl_module_globalref((jl_module_t*)mod, (jl_sym_t*)var); + jl_module_t *mod = (jl_module_t*)jl_decode_value(s); + JL_GC_PROMISE_ROOTED(mod); + jl_sym_t *var = (jl_sym_t*)jl_decode_value(s); + JL_GC_PROMISE_ROOTED(var); + return jl_module_globalref(mod, var); } -static jl_value_t *jl_decode_value_any(jl_ircode_state *s, uint8_t tag) JL_GC_DISABLED +static jl_value_t *jl_decode_value_any(jl_ircode_state *s) { - int32_t sz = (tag == TAG_SHORT_GENERAL ? read_uint8(s->s) : read_int32(s->s)); - jl_value_t *v = jl_gc_alloc(s->ptls, sz, NULL); - jl_set_typeof(v, (void*)(intptr_t)0xf50); jl_datatype_t *dt = (jl_datatype_t*)jl_decode_value(s); - if (dt->smalltag) + JL_GC_PROMISE_ROOTED(dt); // (JL_ALWAYS_LEAFTYPE) + // jl_new_struct_uninit + size_t sz = jl_datatype_size(dt); + jl_value_t *v = jl_gc_alloc(s->ptls, sz, dt); + if (dt->smalltag) // TODO: do we need this? jl_set_typetagof(v, dt->smalltag, 0); - else - jl_set_typeof(v, dt); char *data = (char*)jl_data_ptr(v); size_t i, np = dt->layout->npointers; char *start = data; - for (i = 0; i < np; i++) { - uint32_t ptr = jl_ptr_offset(dt, i); - jl_value_t **fld = &((jl_value_t**)data)[ptr]; - if ((char*)fld != start) - ios_readall(s->s, start, (const char*)fld - start); - *fld = jl_decode_value(s); - start = (char*)&fld[1]; + if (np) { + if (sz > 0) + memset(v, 0, sz); + JL_GC_PUSH1(&v); + for (i = 0; i < np; i++) { + uint32_t ptr = jl_ptr_offset(dt, i); + jl_value_t **fld = &((jl_value_t**)data)[ptr]; + if ((char*)fld != start) + ios_readall(s->s, start, (const char*)fld - start); + *fld = jl_decode_value(s); + jl_gc_wb(v, *fld); + start = (char*)&fld[1]; + } + JL_GC_POP(); } data += jl_datatype_size(dt); if (data != start) @@ -678,7 +767,7 @@ static jl_value_t *jl_decode_value_any(jl_ircode_state *s, uint8_t tag) JL_GC_DI return v; } -static jl_value_t *jl_decode_value(jl_ircode_state *s) JL_GC_DISABLED +static jl_value_t *jl_decode_value(jl_ircode_state *s) { assert(!ios_eof(s->s)); jl_value_t *v; @@ -724,10 +813,12 @@ static jl_value_t *jl_decode_value(jl_ircode_state *s) JL_GC_DISABLED case TAG_SLOTNUMBER: v = jl_box_slotnumber(read_uint16(s->s)); return v; - case TAG_ARRAY: JL_FALLTHROUGH; case TAG_ARRAY1D: - return jl_decode_value_array(s, tag); + case TAG_ARRAY1D: + return jl_decode_value_array1d(s, tag); case TAG_MEMORYT: - return jl_decode_value_memory(s, jl_decode_value(s), jl_unbox_long(jl_decode_value(s))); + v = jl_decode_value(s); + JL_GC_PROMISE_ROOTED(v); // (JL_ALWAYS_LEAFTYPE) + return (jl_value_t*)jl_decode_value_memory(s, v, jl_unbox_long(jl_decode_value(s))); case TAG_EXPR: JL_FALLTHROUGH; case TAG_LONG_EXPR: JL_FALLTHROUGH; case TAG_CALL1: JL_FALLTHROUGH; @@ -738,27 +829,47 @@ static jl_value_t *jl_decode_value(jl_ircode_state *s) JL_GC_DISABLED case TAG_PHICNODE: JL_FALLTHROUGH; case TAG_LONG_PHICNODE: return jl_decode_value_phic(s, tag); case TAG_GOTONODE: JL_FALLTHROUGH; case TAG_QUOTENODE: + { v = jl_new_struct_uninit(tag == TAG_GOTONODE ? jl_gotonode_type : jl_quotenode_type); + JL_GC_PUSH1(&v); set_nth_field(tag == TAG_GOTONODE ? jl_gotonode_type : jl_quotenode_type, v, 0, jl_decode_value(s), 0); + JL_GC_POP(); return v; + } case TAG_GOTOIFNOT: + { v = jl_new_struct_uninit(jl_gotoifnot_type); + JL_GC_PUSH1(&v); set_nth_field(jl_gotoifnot_type, v, 0, jl_decode_value(s), 0); set_nth_field(jl_gotoifnot_type, v, 1, jl_decode_value(s), 0); + JL_GC_POP(); return v; + } case TAG_ENTERNODE: + { v = jl_new_struct_uninit(jl_enternode_type); + JL_GC_PUSH1(&v); set_nth_field(jl_enternode_type, v, 0, jl_decode_value(s), 0); set_nth_field(jl_enternode_type, v, 1, jl_decode_value(s), 0); + JL_GC_POP(); return v; + } case TAG_ARGUMENT: + { v = jl_new_struct_uninit(jl_argument_type); + JL_GC_PUSH1(&v); set_nth_field(jl_argument_type, v, 0, jl_decode_value(s), 0); + JL_GC_POP(); return v; + } case TAG_RETURNNODE: + { v = jl_new_struct_uninit(jl_returnnode_type); + JL_GC_PUSH1(&v); set_nth_field(jl_returnnode_type, v, 0, jl_decode_value(s), 0); + JL_GC_POP(); return v; + } case TAG_SHORTER_INT64: v = jl_box_int64((int16_t)read_uint16(s->s)); return v; @@ -777,9 +888,14 @@ static jl_value_t *jl_decode_value(jl_ircode_state *s) JL_GC_DISABLED case TAG_UINT8: return jl_box_uint8(read_uint8(s->s)); case TAG_NEARBYGLOBAL: - assert(s->method != NULL); + { + jl_method_t *m = s->method; + assert(m != NULL); + JL_GC_PROMISE_ROOTED(m); v = jl_decode_value(s); - return jl_module_globalref(s->method->module, (jl_sym_t*)v); + JL_GC_PROMISE_ROOTED(v); // symbol + return jl_module_globalref(m->module, (jl_sym_t*)v); + } case TAG_NEARBYMODULE: assert(s->method != NULL); return (jl_value_t*)s->method->module; @@ -792,19 +908,29 @@ static jl_value_t *jl_decode_value(jl_ircode_state *s) JL_GC_DISABLED case TAG_BASE: return (jl_value_t*)jl_base_module; case TAG_VECTORTY: + { v = jl_decode_value(s); - return jl_apply_type2((jl_value_t*)jl_array_type, v, jl_box_long(1)); + JL_GC_PUSH1(&v); + v = jl_apply_type2((jl_value_t*)jl_array_type, v, jl_box_long(1)); + JL_GC_POP(); + return v; + } case TAG_PTRTY: + { v = jl_decode_value(s); - return jl_apply_type1((jl_value_t*)jl_pointer_type, v); + JL_GC_PUSH1(&v); + v = jl_apply_type1((jl_value_t*)jl_pointer_type, v); + JL_GC_POP(); + return v; + } case TAG_STRING: n = read_int32(s->s); v = jl_alloc_string(n); ios_readall(s->s, jl_string_data(v), n); return v; default: - assert(tag == TAG_GENERAL || tag == TAG_SHORT_GENERAL); - return jl_decode_value_any(s, tag); + assert(tag == TAG_GENERAL); + return jl_decode_value_any(s); } } @@ -880,8 +1006,6 @@ JL_DLLEXPORT jl_string_t *jl_compress_ir(jl_method_t *m, jl_code_info_t *code) assert(jl_array_nrows(code->code) == codelocs_nstmts(code->debuginfo->codelocs) || jl_string_len(code->debuginfo->codelocs) == 0); ios_t dest; ios_mem(&dest, 0); - int en = jl_gc_enable(0); // Might GC - size_t i; if (m->roots == NULL) { m->roots = jl_alloc_vec_any(0); @@ -919,38 +1043,35 @@ JL_DLLEXPORT jl_string_t *jl_compress_ir(jl_method_t *m, jl_code_info_t *code) write_int32(s.s, (int32_t)nargs); } - for (i = 0; i < 5; i++) { - int copy = 1; - if (i == 1) { // skip debuginfo - assert(jl_field_offset(jl_code_info_type, i) == offsetof(jl_code_info_t, debuginfo)); - continue; - } - jl_encode_value_(&s, jl_get_nth_field((jl_value_t*)code, i), copy); - } + jl_encode_value_(&s, (jl_value_t*)code->code, 1); + jl_encode_value_(&s, (jl_value_t*)code->ssavaluetypes, 1); + jl_encode_value_(&s, (jl_value_t*)code->ssaflags, 1); // For opaque closure, also save the slottypes. We technically only need the first slot type, // but this is simpler for now. We may want to refactor where this gets stored in the future. if (m->is_for_opaque_closure) jl_encode_value_(&s, code->slottypes, 1); + jl_string_t *v = NULL; + JL_GC_PUSH1(&v); // Slotnames. For regular methods, we require that m->slot_syms matches the // CodeInfo's slotnames, so we do not need to save it here. - if (m->generator) + if (m->generator) { // can't optimize generated functions - jl_encode_value_(&s, (jl_value_t*)jl_compress_argnames(code->slotnames), 1); - else + v = jl_compress_argnames(code->slotnames); + jl_encode_value_(&s, (jl_value_t*)v, 1); + } + else { jl_encode_value(&s, jl_nothing); + } write_uint8(s.s, s.relocatability); ios_flush(s.s); - jl_string_t *v = jl_pchar_to_string(s.s->buf, s.s->size); + v = jl_pchar_to_string(s.s->buf, s.s->size); ios_close(s.s); - if (jl_array_nrows(m->roots) == 0) { + if (jl_array_nrows(m->roots) == 0) m->roots = NULL; - } - JL_GC_PUSH1(&v); - jl_gc_enable(en); JL_UNLOCK(&m->writelock); // Might GC JL_GC_POP(); @@ -965,12 +1086,10 @@ JL_DLLEXPORT jl_code_info_t *jl_uncompress_ir(jl_method_t *m, jl_code_instance_t JL_LOCK(&m->writelock); // protect the roots array (Might GC) assert(jl_is_method(m)); assert(jl_is_string(data)); - size_t i; ios_t src; ios_mem(&src, 0); ios_setbuf(&src, (char*)jl_string_data(data), jl_string_len(data), 0); src.size = jl_string_len(data); - int en = jl_gc_enable(0); // Might GC jl_ircode_state s = { &src, m, @@ -978,8 +1097,10 @@ JL_DLLEXPORT jl_code_info_t *jl_uncompress_ir(jl_method_t *m, jl_code_instance_t jl_current_task->ptls, 1 }; - jl_code_info_t *code = jl_new_code_info_uninit(); + jl_value_t *slotnames = NULL; + JL_GC_PUSH2(&code, &slotnames); + jl_code_info_flags_t flags; flags.packed = read_uint16(s.s); code->inlining = flags.bits.inlining; @@ -991,9 +1112,9 @@ JL_DLLEXPORT jl_code_info_t *jl_uncompress_ir(jl_method_t *m, jl_code_instance_t code->purity.bits = read_uint16(s.s); code->inlining_cost = read_uint16(s.s); - size_t nslots = read_int32(s.s); code->slotflags = jl_alloc_array_1d(jl_array_uint8_type, nslots); + jl_gc_wb(code, code->slotflags); ios_readall(s.s, jl_array_data(code->slotflags, char), nslots); if (flags.bits.nargsmatchesmethod) { @@ -1002,25 +1123,29 @@ JL_DLLEXPORT jl_code_info_t *jl_uncompress_ir(jl_method_t *m, jl_code_instance_t code->nargs = read_int32(s.s); } - for (i = 0; i < 5; i++) { - if (i == 1) // skip debuginfo - continue; - assert(jl_field_isptr(jl_code_info_type, i)); - jl_value_t **fld = (jl_value_t**)((char*)jl_data_ptr(code) + jl_field_offset(jl_code_info_type, i)); - *fld = jl_decode_value(&s); - } - if (m->is_for_opaque_closure) + code->code = (jl_array_t*)jl_decode_value(&s); + jl_gc_wb(code, code->code); + code->ssavaluetypes = jl_decode_value(&s); + jl_gc_wb(code, code->ssavaluetypes); + code->ssaflags = (jl_array_t*)jl_decode_value(&s); + jl_gc_wb(code, code->ssaflags); + + if (m->is_for_opaque_closure) { code->slottypes = jl_decode_value(&s); + jl_gc_wb(code, code->slottypes); + } - jl_value_t *slotnames = jl_decode_value(&s); + slotnames = jl_decode_value(&s); if (!jl_is_string(slotnames)) slotnames = m->slot_syms; code->slotnames = jl_uncompress_argnames(slotnames); + jl_gc_wb(code, code->slotnames); if (metadata) code->debuginfo = jl_atomic_load_relaxed(&metadata->debuginfo); else code->debuginfo = m->debuginfo; + jl_gc_wb(code, code->debuginfo); assert(code->debuginfo); assert(jl_array_nrows(code->code) == codelocs_nstmts(code->debuginfo->codelocs) || jl_string_len(code->debuginfo->codelocs) == 0); @@ -1029,10 +1154,7 @@ JL_DLLEXPORT jl_code_info_t *jl_uncompress_ir(jl_method_t *m, jl_code_instance_t assert(ios_getc(s.s) == -1); ios_close(s.s); - JL_GC_PUSH1(&code); - jl_gc_enable(en); JL_UNLOCK(&m->writelock); // Might GC - JL_GC_POP(); if (metadata) { code->parent = metadata->def; jl_gc_wb(code, code->parent); @@ -1043,6 +1165,7 @@ JL_DLLEXPORT jl_code_info_t *jl_uncompress_ir(jl_method_t *m, jl_code_instance_t code->edges = (jl_value_t*)s.edges; jl_gc_wb(code, s.edges); } + JL_GC_POP(); return code; } @@ -1470,7 +1593,7 @@ void jl_init_serializer(void) deser_tag[TAG_DATATYPE] = (jl_value_t*)jl_datatype_type; deser_tag[TAG_SLOTNUMBER] = (jl_value_t*)jl_slotnumber_type; deser_tag[TAG_SVEC] = (jl_value_t*)jl_simplevector_type; - deser_tag[TAG_ARRAY] = (jl_value_t*)jl_array_type; + deser_tag[TAG_ARRAY1D] = (jl_value_t*)jl_array_type; deser_tag[TAG_MEMORYT] = (jl_value_t*)jl_genericmemory_type; deser_tag[TAG_EXPR] = (jl_value_t*)jl_expr_type; deser_tag[TAG_PHINODE] = (jl_value_t*)jl_phinode_type; diff --git a/src/serialize.h b/src/serialize.h index 3aa82a1d09a9b..549c1588073ff 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -7,69 +7,6 @@ extern "C" { #endif -#define TAG_SYMBOL 2 -#define TAG_SSAVALUE 3 -#define TAG_DATATYPE 4 -#define TAG_SLOTNUMBER 5 -#define TAG_SVEC 6 -#define TAG_ARRAY 7 -#define TAG_NULL 8 -#define TAG_EXPR 9 -#define TAG_PHINODE 10 -#define TAG_PHICNODE 11 -#define TAG_LONG_SYMBOL 12 -#define TAG_LONG_SVEC 13 -#define TAG_LONG_EXPR 14 -#define TAG_LONG_PHINODE 15 -#define TAG_LONG_PHICNODE 16 -#define TAG_METHODROOT 17 -#define TAG_EDGE 18 -#define TAG_STRING 19 -#define TAG_SHORT_INT64 20 -#define TAG_SHORT_GENERAL 21 -#define TAG_CNULL 22 -#define TAG_ARRAY1D 23 -#define TAG_SINGLETON 24 -#define TAG_MODULE 25 -#define TAG_TVAR 26 -#define TAG_METHOD_INSTANCE 27 -#define TAG_METHOD 28 -#define TAG_CODE_INSTANCE 29 -#define TAG_COMMONSYM 30 -#define TAG_NEARBYGLOBAL 31 -#define TAG_GLOBALREF 32 -#define TAG_CORE 33 -#define TAG_BASE 34 -#define TAG_BITYPENAME 35 -#define TAG_NEARBYMODULE 36 -#define TAG_INT32 37 -#define TAG_INT64 38 -#define TAG_UINT8 39 -#define TAG_VECTORTY 40 -#define TAG_PTRTY 41 -#define TAG_LONG_SSAVALUE 42 -#define TAG_LONG_METHODROOT 43 -#define TAG_LONG_EDGE 44 -#define TAG_SHORTER_INT64 45 -#define TAG_SHORT_INT32 46 -#define TAG_CALL1 47 -#define TAG_CALL2 48 -#define TAG_SHORT_BACKREF 49 -#define TAG_BACKREF 50 -#define TAG_UNIONALL 51 -#define TAG_GOTONODE 52 -#define TAG_QUOTENODE 53 -#define TAG_GENERAL 54 -#define TAG_GOTOIFNOT 55 -#define TAG_RETURNNODE 56 -#define TAG_ARGUMENT 57 -#define TAG_RELOC_METHODROOT 58 -#define TAG_BINDING 59 -#define TAG_MEMORYT 60 -#define TAG_ENTERNODE 61 - -#define LAST_TAG 61 - #define write_uint8(s, n) ios_putc((n), (s)) #define read_uint8(s) ((uint8_t)ios_getc((s))) #define write_int8(s, n) write_uint8((s), (n)) @@ -137,12 +74,6 @@ static inline uint32_t read_uint32(ios_t *s) JL_NOTSAFEPOINT #define read_uint(s) read_uint32(s) #endif - -void *jl_lookup_ser_tag(jl_value_t *v); -void *jl_lookup_common_symbol(jl_value_t *v); -jl_value_t *jl_deser_tag(uint8_t tag); -jl_value_t *jl_deser_symbol(uint8_t tag); - #ifdef __cplusplus } #endif From 42e14d6983ac855726b31b753adba05aaefcf884 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 2 Dec 2024 12:32:16 -0500 Subject: [PATCH 021/342] ircode: small optimization for nearby ssavalue Since most ssavalue are used just after their def, this gives a small memory savings on compressed IR (a fraction of a percent). --- src/ircode.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/ircode.c b/src/ircode.c index d3137ce26edef..de27f8dbeefca 100644 --- a/src/ircode.c +++ b/src/ircode.c @@ -21,7 +21,7 @@ extern "C" { #define TAG_DATATYPE 4 #define TAG_SLOTNUMBER 5 #define TAG_SVEC 6 -// #define TAG_UNUSED 7 +#define TAG_NEARBYSSAVALUE 7 #define TAG_NULL 8 #define TAG_EXPR 9 #define TAG_PHINODE 10 @@ -82,6 +82,7 @@ extern "C" { typedef struct { ios_t *s; + size_t ssaid; // method we're compressing for jl_method_t *method; jl_svec_t *edges; @@ -307,6 +308,10 @@ static void jl_encode_value_(jl_ircode_state *s, jl_value_t *v, int as_literal) jl_encode_value(s, jl_globalref_name(v)); } } + else if (jl_is_ssavalue(v) && s->ssaid - ((jl_ssavalue_t*)v)->id < 256) { + write_uint8(s->s, TAG_NEARBYSSAVALUE); + write_uint8(s->s, s->ssaid - ((jl_ssavalue_t*)v)->id); + } else if (jl_is_ssavalue(v) && ((jl_ssavalue_t*)v)->id < 256 && ((jl_ssavalue_t*)v)->id >= 0) { write_uint8(s->s, TAG_SSAVALUE); write_uint8(s->s, ((jl_ssavalue_t*)v)->id); @@ -807,6 +812,9 @@ static jl_value_t *jl_decode_value(jl_ircode_state *s) case TAG_SSAVALUE: v = jl_box_ssavalue(read_uint8(s->s)); return v; + case TAG_NEARBYSSAVALUE: + v = jl_box_ssavalue(s->ssaid - read_uint8(s->s)); + return v; case TAG_LONG_SSAVALUE: v = jl_box_ssavalue(read_uint16(s->s)); return v; @@ -1014,6 +1022,7 @@ JL_DLLEXPORT jl_string_t *jl_compress_ir(jl_method_t *m, jl_code_info_t *code) jl_value_t *edges = code->edges; jl_ircode_state s = { &dest, + 0, m, (!isdef && jl_is_svec(edges)) ? (jl_svec_t*)edges : jl_emptysvec, jl_current_task->ptls, @@ -1043,7 +1052,13 @@ JL_DLLEXPORT jl_string_t *jl_compress_ir(jl_method_t *m, jl_code_info_t *code) write_int32(s.s, (int32_t)nargs); } - jl_encode_value_(&s, (jl_value_t*)code->code, 1); + size_t i, l = jl_array_dim0(code->code); + write_uint64(s.s, l); + for (i = 0; i < l; i++) { + s.ssaid = i; + jl_encode_value(&s, jl_array_ptr_ref(code->code, i)); + } + s.ssaid = 0; jl_encode_value_(&s, (jl_value_t*)code->ssavaluetypes, 1); jl_encode_value_(&s, (jl_value_t*)code->ssaflags, 1); @@ -1092,6 +1107,7 @@ JL_DLLEXPORT jl_code_info_t *jl_uncompress_ir(jl_method_t *m, jl_code_instance_t src.size = jl_string_len(data); jl_ircode_state s = { &src, + 0, m, metadata == NULL ? NULL : jl_atomic_load_relaxed(&metadata->edges), jl_current_task->ptls, @@ -1123,8 +1139,14 @@ JL_DLLEXPORT jl_code_info_t *jl_uncompress_ir(jl_method_t *m, jl_code_instance_t code->nargs = read_int32(s.s); } - code->code = (jl_array_t*)jl_decode_value(&s); + size_t i, n = read_uint64(s.s); + code->code = jl_alloc_array_1d(jl_array_any_type, n); jl_gc_wb(code, code->code); + for (i = 0; i < n; i++) { + s.ssaid = i; + jl_array_ptr_set(code->code, i, jl_decode_value(&s)); + } + s.ssaid = 0; code->ssavaluetypes = jl_decode_value(&s); jl_gc_wb(code, code->ssavaluetypes); code->ssaflags = (jl_array_t*)jl_decode_value(&s); From f1b0b010dd20591a013c71d8f3f7a09503e55baf Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Mon, 2 Dec 2024 18:02:41 -0500 Subject: [PATCH 022/342] Fix scope of hoisted signature-local variables (#56712) When we declare inner methods, e.g. the `f` in ``` function fs() f(lhs::Integer) = 1 f(lhs::Integer, rhs::(local x=Integer; x)) = 2 return f end ``` we must hoist the definition of the (appropriately mangled) generic function `f` to top-level, including all variables that were used in the signature definition of `f`. This situation is a bit unique in the language because it uses inner function scope, but gets executed in toplevel scope. For example, you're not allowed to use a local of the inner function in the signature definition: ``` julia> function fs() local x=Integer f(lhs::Integer, rhs::x) = 2 return f end ERROR: syntax: local variable x cannot be used in closure declaration Stacktrace: [1] top-level scope @ REPL[3]:1 ``` In particular, the restriction is signature-local: ``` julia> function fs() f(rhs::(local x=Integer; x)) = 1 f(lhs::Integer, rhs::x) = 2 return f end ERROR: syntax: local variable x cannot be used in closure declaration Stacktrace: [1] top-level scope @ REPL[4]:1 ``` There's a special intermediate form `moved-local` that gets generated for this definition. In c6c3d72d1cbddb3d27e0df0e739bb27dd709a413, this form stopped getting generated for certain inner methods. I suspect this happened because of the incorrect assumption that the set of moved locals is being computed over all signatures, rather than being a per-signature property. The result of all of this was that this is one of the few places where lowering still generated a symbol as the lhs of an assignment for a global (instead of globalref), because the code that generates the assignment assumes it's a local, but the later pass doesn't know this. Because we still retain the code for this from before we started using globalref consistently, this wasn't generally causing a problems, except possibly leaking a global (or potentially assigning to a global when this wasn't intended). However, in follow on work, I want to make use of knowing whether the LHS is a global or local in lowering, so this was causing me trouble. Fix all of this by putting back the `moved-local` where it was dropped. Fixes #56711 --- src/julia-syntax.scm | 1 + test/syntax.jl | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 72e97da3c2daa..852d5eb4d6f86 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -4279,6 +4279,7 @@ f(x) = yt(x) (if (or exists (and short (pair? alldefs))) `(toplevel-butfirst (null) + ,@(map (lambda (v) `(moved-local ,v)) moved-vars) ,@sp-inits ,@mk-method (latestworld)) diff --git a/test/syntax.jl b/test/syntax.jl index d9d311ac6615d..0fb752bae480f 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -4033,3 +4033,11 @@ end @test isa(create_inner_f_no_methods(), Function) @test length(methods(create_inner_f_no_methods())) == 0 @test Base.invoke_in_world(first(methods(create_inner_f_one_method)).primary_world, create_inner_f_one_method()) == 1 + +# Issue 56711 - Scope of signature hoisting +function fs56711() + f(lhs::Integer) = 1 + f(lhs::Integer, rhs::(local x_should_not_be_defined=Integer; x_should_not_be_defined)) = 2 + return f +end +@test !@isdefined(x_should_not_be_defined) From 1b37a2f9e0afc5f684e0b2a0af17cd9526aae529 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 2 Dec 2024 20:09:26 -0500 Subject: [PATCH 023/342] ircode: avoid serializing ssaflags in the common case when they are all zero When not all-zero, run-length encoding would also probably be great here for lowered code (before inference). --- Compiler/test/interpreter_exec.jl | 6 +++--- src/ircode.c | 30 +++++++++++++++++++++++------- src/julia_internal.h | 1 + 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/Compiler/test/interpreter_exec.jl b/Compiler/test/interpreter_exec.jl index 4972df1a27202..b1d450f8f4286 100644 --- a/Compiler/test/interpreter_exec.jl +++ b/Compiler/test/interpreter_exec.jl @@ -23,7 +23,7 @@ let m = Meta.@lower 1 + 1 ] nstmts = length(src.code) src.ssavaluetypes = nstmts - src.ssaflags = fill(UInt8(0x00), nstmts) + src.ssaflags = fill(zero(UInt32), nstmts) src.debuginfo = Core.DebugInfo(:none) Compiler.verify_ir(Compiler.inflate_ir(src)) global test29262 = true @@ -63,7 +63,7 @@ let m = Meta.@lower 1 + 1 ] nstmts = length(src.code) src.ssavaluetypes = nstmts - src.ssaflags = fill(UInt8(0x00), nstmts) + src.ssaflags = fill(zero(UInt32), nstmts) src.debuginfo = Core.DebugInfo(:none) m.args[1] = copy(src) Compiler.verify_ir(Compiler.inflate_ir(src)) @@ -103,7 +103,7 @@ let m = Meta.@lower 1 + 1 ] nstmts = length(src.code) src.ssavaluetypes = nstmts - src.ssaflags = fill(UInt8(0x00), nstmts) + src.ssaflags = fill(zero(UInt32), nstmts) src.debuginfo = Core.DebugInfo(:none) Compiler.verify_ir(Compiler.inflate_ir(src)) global test29262 = true diff --git a/src/ircode.c b/src/ircode.c index de27f8dbeefca..9e64e3fe2b574 100644 --- a/src/ircode.c +++ b/src/ircode.c @@ -549,7 +549,8 @@ static void jl_encode_value_(jl_ircode_state *s, jl_value_t *v, int as_literal) static jl_code_info_flags_t code_info_flags(uint8_t propagate_inbounds, uint8_t has_fcall, uint8_t nospecializeinfer, uint8_t isva, - uint8_t inlining, uint8_t constprop, uint8_t nargsmatchesmethod) + uint8_t inlining, uint8_t constprop, uint8_t nargsmatchesmethod, + jl_array_t *ssaflags) { jl_code_info_flags_t flags; flags.bits.propagate_inbounds = propagate_inbounds; @@ -559,6 +560,11 @@ static jl_code_info_flags_t code_info_flags(uint8_t propagate_inbounds, uint8_t flags.bits.inlining = inlining; flags.bits.constprop = constprop; flags.bits.nargsmatchesmethod = nargsmatchesmethod; + flags.bits.has_ssaflags = 0; + const uint32_t *ssaflag_data = jl_array_data(ssaflags, uint32_t); + for (size_t i = 0, l = jl_array_dim0(ssaflags); i < l; i++) + if (ssaflag_data[i]) + flags.bits.has_ssaflags = 1; return flags; } @@ -1033,7 +1039,8 @@ JL_DLLEXPORT jl_string_t *jl_compress_ir(jl_method_t *m, jl_code_info_t *code) jl_code_info_flags_t flags = code_info_flags(code->propagate_inbounds, code->has_fcall, code->nospecializeinfer, code->isva, code->inlining, code->constprop, - nargsmatchesmethod); + nargsmatchesmethod, + code->ssaflags); write_uint16(s.s, checked_size(flags.packed, IR_DATASIZE_FLAGS)); write_uint16(s.s, checked_size(code->purity.bits, IR_DATASIZE_PURITY)); write_uint16(s.s, checked_size(code->inlining_cost, IR_DATASIZE_INLINING_COST)); @@ -1060,7 +1067,11 @@ JL_DLLEXPORT jl_string_t *jl_compress_ir(jl_method_t *m, jl_code_info_t *code) } s.ssaid = 0; jl_encode_value_(&s, (jl_value_t*)code->ssavaluetypes, 1); - jl_encode_value_(&s, (jl_value_t*)code->ssaflags, 1); + assert(jl_typetagis(code->ssaflags, jl_array_uint32_type)); + assert(jl_array_dim0(code->ssaflags) == l); + const uint32_t *ssaflags_data = jl_array_data(code->ssaflags, uint32_t); + if (flags.bits.has_ssaflags) + ios_write(s.s, (const char*)ssaflags_data, l * sizeof(*ssaflags_data)); // For opaque closure, also save the slottypes. We technically only need the first slot type, // but this is simpler for now. We may want to refactor where this gets stored in the future. @@ -1139,18 +1150,23 @@ JL_DLLEXPORT jl_code_info_t *jl_uncompress_ir(jl_method_t *m, jl_code_instance_t code->nargs = read_int32(s.s); } - size_t i, n = read_uint64(s.s); - code->code = jl_alloc_array_1d(jl_array_any_type, n); + size_t i, l = read_uint64(s.s); + code->code = jl_alloc_array_1d(jl_array_any_type, l); jl_gc_wb(code, code->code); - for (i = 0; i < n; i++) { + for (i = 0; i < l; i++) { s.ssaid = i; jl_array_ptr_set(code->code, i, jl_decode_value(&s)); } s.ssaid = 0; code->ssavaluetypes = jl_decode_value(&s); jl_gc_wb(code, code->ssavaluetypes); - code->ssaflags = (jl_array_t*)jl_decode_value(&s); + code->ssaflags = jl_alloc_array_1d(jl_array_uint32_type, l); jl_gc_wb(code, code->ssaflags); + uint32_t *ssaflags_data = jl_array_data(code->ssaflags, uint32_t); + if (flags.bits.has_ssaflags) + ios_readall(s.s, (char*)ssaflags_data, l * sizeof(*ssaflags_data)); + else + memset(ssaflags_data, 0, l * sizeof(*ssaflags_data)); if (m->is_for_opaque_closure) { code->slottypes = jl_decode_value(&s); diff --git a/src/julia_internal.h b/src/julia_internal.h index e081c94329deb..2178f603441e0 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -651,6 +651,7 @@ typedef struct { uint16_t nargsmatchesmethod:1; uint16_t inlining:2; // 0 = use heuristic; 1 = aggressive; 2 = none uint16_t constprop:2; // 0 = use heuristic; 1 = aggressive; 2 = none + uint16_t has_ssaflags:1; } jl_code_info_flags_bitfield_t; typedef union { From efa917e8775cd40fdd74b657d1e5d2db2342cd07 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Mon, 2 Dec 2024 20:28:05 -0500 Subject: [PATCH 024/342] Extend `invoke` to accept CodeInstance (#56660) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is an alternative mechanism to #56650 that largely achieves the same result, but by hooking into `invoke` rather than a generated function. They are orthogonal mechanisms, and its possible we want both. However, in #56650, both Jameson and Valentin were skeptical of the generated function signature bottleneck. This PR is sort of a hybrid of mechanism in #52964 and what I proposed in https://github.com/JuliaLang/julia/pull/56650#issuecomment-2493800877. In particular, this PR: 1. Extends `invoke` to support a CodeInstance in place of its usual `types` argument. 2. Adds a new `typeinf` optimized generic. The semantics of this optimized generic allow the compiler to instead call a companion `typeinf_edge` function, allowing a mid-inference interpreter switch (like #52964), without being forced through a concrete signature bottleneck. However, if calling `typeinf_edge` does not work (e.g. because the compiler version is mismatched), this still has well defined semantics, you just don't get inference support. The additional benefit of the `typeinf` optimized generic is that it lets custom cache owners tell the runtime how to "cure" code instances that have lost their native code. Currently the runtime only knows how to do that for `owner == nothing` CodeInstances (by re-running inference). This extension is not implemented, but the idea is that the runtime would be permitted to call the `typeinf` optimized generic on the dead CodeInstance's `owner` and `def` fields to obtain a cured CodeInstance (or a user-actionable error from the plugin). This PR includes an implementation of `with_new_compiler` from #56650. This PR includes just enough compiler support to make the compiler optimize this to the same code that #56650 produced: ``` julia> @code_typed with_new_compiler(sin, 1.0) CodeInfo( 1 ─ $(Expr(:foreigncall, :(:jl_get_tls_world_age), UInt64, svec(), 0, :(:ccall)))::UInt64 │ %2 = builtin Core.getfield(args, 1)::Float64 │ %3 = invoke sin(%2::Float64)::Float64 └── return %3 ) => Float64 ``` However, the implementation here is extremely incomplete. I'm putting it up only as a directional sketch to see if people prefer it over #56650. If so, I would prepare a cleaned up version of this PR that has the optimized generics as well as the curing support, but not the full inference integration (which needs a fair bit more work). --- .../extras/CompilerDevTools/Manifest.toml | 15 +++++ Compiler/extras/CompilerDevTools/Project.toml | 5 ++ .../CompilerDevTools/src/CompilerDevTools.jl | 56 +++++++++++++++++++ Compiler/src/abstractinterpretation.jl | 48 +++++++++++++--- Compiler/src/abstractlattice.jl | 2 +- Compiler/src/bootstrap.jl | 10 +++- Compiler/src/stmtinfo.jl | 11 ++++ Compiler/src/utilities.jl | 4 +- NEWS.md | 2 + base/docs/basedocs.jl | 17 ++++++ base/optimized_generics.jl | 27 +++++++++ src/builtins.c | 22 ++++++++ src/interpreter.c | 24 +++++++- test/core.jl | 14 +++++ 14 files changed, 242 insertions(+), 15 deletions(-) create mode 100644 Compiler/extras/CompilerDevTools/Manifest.toml create mode 100644 Compiler/extras/CompilerDevTools/Project.toml create mode 100644 Compiler/extras/CompilerDevTools/src/CompilerDevTools.jl diff --git a/Compiler/extras/CompilerDevTools/Manifest.toml b/Compiler/extras/CompilerDevTools/Manifest.toml new file mode 100644 index 0000000000000..bcc78f1ded34a --- /dev/null +++ b/Compiler/extras/CompilerDevTools/Manifest.toml @@ -0,0 +1,15 @@ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.12.0-DEV" +manifest_format = "2.0" +project_hash = "84f495a1bf065c95f732a48af36dd0cd2cefb9d5" + +[[deps.Compiler]] +path = "../.." +uuid = "807dbc54-b67e-4c79-8afb-eafe4df6f2e1" +version = "0.0.2" + +[[deps.CompilerDevTools]] +path = "." +uuid = "92b2d91f-d2bd-4c05-9214-4609ac33433f" +version = "0.0.0" diff --git a/Compiler/extras/CompilerDevTools/Project.toml b/Compiler/extras/CompilerDevTools/Project.toml new file mode 100644 index 0000000000000..a2749a9a56a84 --- /dev/null +++ b/Compiler/extras/CompilerDevTools/Project.toml @@ -0,0 +1,5 @@ +name = "CompilerDevTools" +uuid = "92b2d91f-d2bd-4c05-9214-4609ac33433f" + +[deps] +Compiler = "807dbc54-b67e-4c79-8afb-eafe4df6f2e1" diff --git a/Compiler/extras/CompilerDevTools/src/CompilerDevTools.jl b/Compiler/extras/CompilerDevTools/src/CompilerDevTools.jl new file mode 100644 index 0000000000000..cd3f7b7b4bdac --- /dev/null +++ b/Compiler/extras/CompilerDevTools/src/CompilerDevTools.jl @@ -0,0 +1,56 @@ +module CompilerDevTools + +using Compiler +using Core.IR + +struct SplitCacheOwner; end +struct SplitCacheInterp <: Compiler.AbstractInterpreter + world::UInt + inf_params::Compiler.InferenceParams + opt_params::Compiler.OptimizationParams + inf_cache::Vector{Compiler.InferenceResult} + function SplitCacheInterp(; + world::UInt = Base.get_world_counter(), + inf_params::Compiler.InferenceParams = Compiler.InferenceParams(), + opt_params::Compiler.OptimizationParams = Compiler.OptimizationParams(), + inf_cache::Vector{Compiler.InferenceResult} = Compiler.InferenceResult[]) + new(world, inf_params, opt_params, inf_cache) + end +end + +Compiler.InferenceParams(interp::SplitCacheInterp) = interp.inf_params +Compiler.OptimizationParams(interp::SplitCacheInterp) = interp.opt_params +Compiler.get_inference_world(interp::SplitCacheInterp) = interp.world +Compiler.get_inference_cache(interp::SplitCacheInterp) = interp.inf_cache +Compiler.cache_owner(::SplitCacheInterp) = SplitCacheOwner() + +import Core.OptimizedGenerics.CompilerPlugins: typeinf, typeinf_edge +@eval @noinline typeinf(::SplitCacheOwner, mi::MethodInstance, source_mode::UInt8) = + Base.invoke_in_world(which(typeinf, Tuple{SplitCacheOwner, MethodInstance, UInt8}).primary_world, Compiler.typeinf_ext, SplitCacheInterp(; world=Base.tls_world_age()), mi, source_mode) + +@eval @noinline function typeinf_edge(::SplitCacheOwner, mi::MethodInstance, parent_frame::Compiler.InferenceState, world::UInt, source_mode::UInt8) + # TODO: This isn't quite right, we're just sketching things for now + interp = SplitCacheInterp(; world) + Compiler.typeinf_edge(interp, mi.def, mi.specTypes, Core.svec(), parent_frame, false, false) +end + +# TODO: This needs special compiler support to properly case split for multiple +# method matches, etc. +@noinline function mi_for_tt(tt, world=Base.tls_world_age()) + interp = SplitCacheInterp(; world) + match, _ = Compiler.findsup(tt, Compiler.method_table(interp)) + Base.specialize_method(match) +end + +function with_new_compiler(f, args...) + tt = Base.signature_type(f, typeof(args)) + world = Base.tls_world_age() + new_compiler_ci = Core.OptimizedGenerics.CompilerPlugins.typeinf( + SplitCacheOwner(), mi_for_tt(tt), Compiler.SOURCE_MODE_ABI + ) + invoke(f, new_compiler_ci, args...) +end + +export with_new_compiler + +end diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index 5946adf80ad52..ffb4f4312cdcf 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -2218,16 +2218,46 @@ function abstract_invoke(interp::AbstractInterpreter, arginfo::ArgInfo, si::Stmt ft = widenconst(ft′) ft === Bottom && return Future(CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo())) types = argtype_by_index(argtypes, 3) - if types isa Const && types.val isa Method - method = types.val::Method - types = method # argument value - lookupsig = method.sig # edge kind - argtype = argtypes_to_type(pushfirst!(argtype_tail(argtypes, 4), ft)) - nargtype = typeintersect(lookupsig, argtype) - nargtype === Bottom && return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo())) - nargtype isa DataType || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) # other cases are not implemented below + if types isa Const && types.val isa Union{Method, CodeInstance} + method_or_ci = types.val + if isa(method_or_ci, CodeInstance) + our_world = sv.world.this + argtype = argtypes_to_type(pushfirst!(argtype_tail(argtypes, 4), ft)) + sig = method_or_ci.def.specTypes + exct = method_or_ci.exctype + if !hasintersect(argtype, sig) + return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo())) + elseif !(argtype <: sig) + exct = Union{exct, TypeError} + end + callee_valid_range = WorldRange(method_or_ci.min_world, method_or_ci.max_world) + if !(our_world in callee_valid_range) + if our_world < first(callee_valid_range) + update_valid_age!(sv, WorldRange(first(sv.world.valid_worlds), first(callee_valid_range)-1)) + else + update_valid_age!(sv, WorldRange(last(callee_valid_range)+1, last(sv.world.valid_worlds))) + end + 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) + exct = Union{exct, ErrorException} + end + update_valid_age!(sv, callee_valid_range) + return Future(CallMeta(method_or_ci.rettype, exct, Effects(decode_effects(method_or_ci.ipo_purity_bits), nothrow=(exct===Bottom)), + InvokeCICallInfo(method_or_ci))) + else + method = method_or_ci::Method + types = method # argument value + lookupsig = method.sig # edge kind + argtype = argtypes_to_type(pushfirst!(argtype_tail(argtypes, 4), ft)) + nargtype = typeintersect(lookupsig, argtype) + nargtype === Bottom && return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo())) + nargtype isa DataType || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) # other cases are not implemented below + # Fall through to generic invoke handling + end else - widenconst(types) >: Method && return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) + widenconst(types) >: Union{Method, CodeInstance} && return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) (types, isexact, isconcrete, istype) = instanceof_tfunc(argtype_by_index(argtypes, 3), false) isexact || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) unwrapped = unwrap_unionall(types) diff --git a/Compiler/src/abstractlattice.jl b/Compiler/src/abstractlattice.jl index c1f3050739170..7a9cff8918175 100644 --- a/Compiler/src/abstractlattice.jl +++ b/Compiler/src/abstractlattice.jl @@ -229,7 +229,7 @@ end if isa(t, Const) # don't consider mutable values useful constants val = t.val - return isa(val, Symbol) || isa(val, Type) || isa(val, Method) || !ismutable(val) + return isa(val, Symbol) || isa(val, Type) || isa(val, Method) || isa(val, CodeInstance) || !ismutable(val) end isa(t, PartialTypeVar) && return false # this isn't forwardable return is_const_prop_profitable_arg(widenlattice(𝕃), t) diff --git a/Compiler/src/bootstrap.jl b/Compiler/src/bootstrap.jl index 7ee439cc7ac67..475c53e317152 100644 --- a/Compiler/src/bootstrap.jl +++ b/Compiler/src/bootstrap.jl @@ -5,7 +5,15 @@ # especially try to make sure any recursive and leaf functions have concrete signatures, # since we won't be able to specialize & infer them at runtime -activate_codegen!() = ccall(:jl_set_typeinf_func, Cvoid, (Any,), typeinf_ext_toplevel) +function activate_codegen!() + ccall(:jl_set_typeinf_func, Cvoid, (Any,), typeinf_ext_toplevel) + Core.eval(Compiler, quote + let typeinf_world_age = Base.tls_world_age() + @eval Core.OptimizedGenerics.CompilerPlugins.typeinf(::Nothing, mi::MethodInstance, source_mode::UInt8) = + Base.invoke_in_world($(Expr(:$, :typeinf_world_age)), typeinf_ext_toplevel, mi, Base.tls_world_age(), source_mode) + end + end) +end function bootstrap!() let time() = ccall(:jl_clock_now, Float64, ()) diff --git a/Compiler/src/stmtinfo.jl b/Compiler/src/stmtinfo.jl index 830bfa02d2d99..9f0f1f38d4c8a 100644 --- a/Compiler/src/stmtinfo.jl +++ b/Compiler/src/stmtinfo.jl @@ -268,6 +268,17 @@ end add_edges_impl(edges::Vector{Any}, info::UnionSplitApplyCallInfo) = for split in info.infos; add_edges!(edges, split); end +""" + info::InvokeCICallInfo + +Represents a resolved call to `Core.invoke` targeting a `Core.CodeInstance` +""" +struct InvokeCICallInfo <: CallInfo + edge::CodeInstance +end +add_edges_impl(edges::Vector{Any}, info::InvokeCICallInfo) = + add_one_edge!(edges, info.edge) + """ info::InvokeCallInfo diff --git a/Compiler/src/utilities.jl b/Compiler/src/utilities.jl index 29f3dfa4afd4a..da20f9aafbfb2 100644 --- a/Compiler/src/utilities.jl +++ b/Compiler/src/utilities.jl @@ -54,8 +54,8 @@ function count_const_size(@nospecialize(x), count_self::Bool = true) # No definite size (isa(x, GenericMemory) || isa(x, String) || isa(x, SimpleVector)) && return MAX_INLINE_CONST_SIZE + 1 - if isa(x, Module) || isa(x, Method) - # We allow modules and methods, because we already assume they are externally + if isa(x, Module) || isa(x, Method) || isa(x, CodeInstance) + # We allow modules, methods and CodeInstance, because we already assume they are externally # rooted, so we count their contents as 0 size. return sizeof(Ptr{Cvoid}) end diff --git a/NEWS.md b/NEWS.md index c1d5f38f337b0..b77a786c24823 100644 --- a/NEWS.md +++ b/NEWS.md @@ -103,6 +103,8 @@ New library features * New `ltruncate`, `rtruncate` and `ctruncate` functions for truncating strings to text width, accounting for char widths ([#55351]) * `isless` (and thus `cmp`, sorting, etc.) is now supported for zero-dimensional `AbstractArray`s ([#55772]) * `invoke` now supports passing a Method instead of a type signature making this interface somewhat more flexible for certain uncommon use cases ([#56692]). +* `invoke` now supports passing a CodeInstance instead of a type, which can enable +certain compiler plugin workflows ([#56660]). Standard library changes ------------------------ diff --git a/base/docs/basedocs.jl b/base/docs/basedocs.jl index 5119ceaf2164a..141950f5e92ff 100644 --- a/base/docs/basedocs.jl +++ b/base/docs/basedocs.jl @@ -2031,6 +2031,7 @@ applicable """ invoke(f, argtypes::Type, args...; kwargs...) invoke(f, argtypes::Method, args...; kwargs...) + invoke(f, argtypes::CodeInstance, args...; kwargs...) Invoke a method for the given generic function `f` matching the specified types `argtypes` on the specified arguments `args` and passing the keyword arguments `kwargs`. The arguments `args` must @@ -2056,6 +2057,22 @@ Note in particular that the specified `Method` may be entirely unreachable from If the method is part of the ordinary method table, this call behaves similar to `invoke(f, method.sig, args...)`. +!!! compat "Julia 1.12" + Passing a `Method` requires Julia 1.12. + +# Passing a `CodeInstance` instead of a signature +The `argtypes` argument may be a `CodeInstance`, bypassing both method lookup and specialization. +The semantics of this invocation are similar to a function pointer call of the `CodeInstance`'s +`invoke` pointer. It is an error to invoke a `CodeInstance` with arguments that do not match its +parent MethodInstance or from a world age not included in the `min_world`/`max_world` range. +It is undefined behavior to invoke a CodeInstance whose behavior does not match the constraints +specified in its fields. For some code instances with `owner !== nothing` (i.e. those generated +by external compilers), it may be an error to invoke them after passing through precompilation. +This is an advanced interface intended for use with external compiler plugins. + +!!! compat "Julia 1.12" + Passing a `CodeInstance` requires Julia 1.12. + # Examples ```jldoctest julia> f(x::Real) = x^2; diff --git a/base/optimized_generics.jl b/base/optimized_generics.jl index 86b54a294564d..c0b953777ca94 100644 --- a/base/optimized_generics.jl +++ b/base/optimized_generics.jl @@ -54,4 +54,31 @@ module KeyValue function get end end +# Compiler-recognized intrinsics for compiler plugins +""" + module CompilerPlugins + +Implements a pair of functions `typeinf`/`typeinf_edge`. When the optimizer sees +a call to `typeinf`, it has license to instead call `typeinf_edge`, supplying the +current inference stack in `parent_frame` (but otherwise supplying the arguments +to `typeinf`). typeinf_edge will return the `CodeInstance` that `typeinf` would +have returned at runtime. The optimizer may perform a non-IPO replacement of +the call to `typeinf` by the result of `typeinf_edge`. In addition, the IPO-safe +fields of the `CodeInstance` may be propagated in IPO mode. +""" +module CompilerPlugins + """ + typeinf(owner, mi, source_mode)::CodeInstance + + Return a `CodeInstance` for the given `mi` whose valid results include at + the least current tls world and satisfies the requirements of `source_mode`. + """ + function typeinf end + + """ + typeinf_edge(owner, mi, parent_frame, world, abi_mode)::CodeInstance + """ + function typeinf_edge end +end + end diff --git a/src/builtins.c b/src/builtins.c index c6b0bf130550b..3f555da9d2a83 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1587,6 +1587,28 @@ JL_CALLABLE(jl_f_invoke) if (!jl_tuple1_isa(args[0], &args[2], nargs - 1, (jl_datatype_t*)m->sig)) jl_type_error("invoke: argument type error", argtypes, arg_tuple(args[0], &args[2], nargs - 1)); return jl_gf_invoke_by_method(m, args[0], &args[2], nargs - 1); + } else if (jl_is_code_instance(argtypes)) { + jl_code_instance_t *codeinst = (jl_code_instance_t*)args[1]; + jl_callptr_t invoke = jl_atomic_load_acquire(&codeinst->invoke); + if (jl_tuple1_isa(args[0], &args[2], nargs - 2, (jl_datatype_t*)codeinst->def->specTypes)) { + jl_type_error("invoke: argument type error", codeinst->def->specTypes, arg_tuple(args[0], &args[2], nargs - 2)); + } + if (jl_atomic_load_relaxed(&codeinst->min_world) > jl_current_task->world_age || + jl_current_task->world_age > jl_atomic_load_relaxed(&codeinst->max_world)) { + jl_error("invoke: CodeInstance not valid for this world"); + } + if (!invoke) { + jl_compile_codeinst(codeinst); + invoke = jl_atomic_load_acquire(&codeinst->invoke); + } + if (invoke) { + return invoke(args[0], &args[2], nargs - 2, codeinst); + } else { + if (codeinst->owner != jl_nothing || !jl_is_method(codeinst->def->def.value)) { + jl_error("Failed to invoke or compile external codeinst"); + } + return jl_gf_invoke_by_method(codeinst->def->def.method, args[0], &args[2], nargs - 1); + } } if (!jl_is_tuple_type(jl_unwrap_unionall(argtypes))) jl_type_error("invoke", (jl_value_t*)jl_anytuple_type_type, argtypes); diff --git a/src/interpreter.c b/src/interpreter.c index 49a3afed14f0c..2dc1c9ed5a0c4 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -137,8 +137,28 @@ static jl_value_t *do_invoke(jl_value_t **args, size_t nargs, interpreter_state argv[i-1] = eval_value(args[i], s); jl_value_t *c = args[0]; assert(jl_is_code_instance(c) || jl_is_method_instance(c)); - jl_method_instance_t *meth = jl_is_method_instance(c) ? (jl_method_instance_t*)c : ((jl_code_instance_t*)c)->def; - jl_value_t *result = jl_invoke(argv[0], nargs == 2 ? NULL : &argv[1], nargs - 2, meth); + jl_value_t *result = NULL; + if (jl_is_code_instance(c)) { + jl_code_instance_t *codeinst = (jl_code_instance_t*)c; + assert(jl_atomic_load_relaxed(&codeinst->min_world) <= jl_current_task->world_age && + jl_current_task->world_age <= jl_atomic_load_relaxed(&codeinst->max_world)); + jl_callptr_t invoke = jl_atomic_load_acquire(&codeinst->invoke); + if (!invoke) { + jl_compile_codeinst(codeinst); + invoke = jl_atomic_load_acquire(&codeinst->invoke); + } + if (invoke) { + result = invoke(argv[0], nargs == 2 ? NULL : &argv[1], nargs - 2, codeinst); + + } else { + if (codeinst->owner != jl_nothing) { + jl_error("Failed to invoke or compile external codeinst"); + } + result = jl_invoke(argv[0], nargs == 2 ? NULL : &argv[1], nargs - 2, codeinst->def); + } + } else { + result = jl_invoke(argv[0], nargs == 2 ? NULL : &argv[1], nargs - 2, (jl_method_instance_t*)c); + } JL_GC_POP(); return result; } diff --git a/test/core.jl b/test/core.jl index 39d02d5d567c9..63952e8728e1e 100644 --- a/test/core.jl +++ b/test/core.jl @@ -8353,9 +8353,23 @@ end @test eval(Expr(:toplevel, :(@define_call(f_macro_defined1)))) == 1 @test @define_call(f_macro_defined2) == 1 +# `invoke` of `Method` let m = which(+, (Int, Int)) @eval f56692(i) = invoke(+, $m, i, 4) global g56692() = f56692(5) == 9 ? "true" : false end @test @inferred(f56692(3)) == 7 @test @inferred(g56692()) == "true" + +# `invoke` of `CodeInstance` +f_invalidate_me() = return 1 +f_invoke_me() = return f_invalidate_me() +@test f_invoke_me() == 1 +const f_invoke_me_ci = Base.specialize_method(Base._which(Tuple{typeof(f_invoke_me)})).cache +f_call_me() = invoke(f_invoke_me, f_invoke_me_ci) +@test invoke(f_invoke_me, f_invoke_me_ci) == 1 +@test f_call_me() == 1 +@test_throws TypeError invoke(f_invoke_me, f_invoke_me_ci, 1) +f_invalidate_me() = 2 +@test_throws ErrorException invoke(f_invoke_me, f_invoke_me_ci) +@test_throws ErrorException f_call_me() From ba8290ea4cf47abd69ff45d2e011259dca161ed1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A1ll=20Haraldsson?= Date: Tue, 3 Dec 2024 01:46:24 +0000 Subject: [PATCH 025/342] Update references to LTS from v1.6 to v1.10 (#56729) --- CONTRIBUTING.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fd7f1c89420d6..9a3fe2cd441b3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -278,8 +278,8 @@ Be sure to change the UUID value back before making the pull request. The process of [creating a patch release](https://docs.julialang.org/en/v1/devdocs/build/distributing/#Point-releasing-101) is roughly as follows: -1. Create a new branch (e.g. `backports-release-1.6`) against the relevant minor release - branch (e.g. `release-1.6`). Usually a corresponding pull request is created as well. +1. Create a new branch (e.g. `backports-release-1.10`) against the relevant minor release + branch (e.g. `release-1.10`). Usually a corresponding pull request is created as well. 2. Add commits, nominally from `master` (hence "backports"), to that branch. See below for more information on this process. @@ -291,8 +291,8 @@ The process of [creating a patch release](https://docs.julialang.org/en/v1/devdo the pull request associated with the backports branch. Fix any issues. 4. Once all test and benchmark reports look good, merge the backports branch into - the corresponding release branch (e.g. merge `backports-release-1.6` into - `release-1.6`). + the corresponding release branch (e.g. merge `backports-release-1.10` into + `release-1.10`). 5. Open a pull request that bumps the version of the relevant minor release to the next patch version, e.g. as in [this pull request](https://github.com/JuliaLang/julia/pull/37718). From 2c87290f2e7d5c057d1f4bdce9c5568c01f31d69 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Tue, 3 Dec 2024 01:19:03 -0500 Subject: [PATCH 026/342] lowering: Canonicalize to builtins for global assignment (#56713) This adjusts lowering to emit `setglobal!` for assignment to globals, thus making the `=` expr head used only for slots in `CodeInfo` and entirely absent in `IRCode`. The primary reason for this is just to reduce the number of special cases that compiler passes have to reason about. In IRCode, `=` was already essentially equivalent to `setglobal!`, so there's no good reason not to canonicalize. Finally, the `=` syntax form for globals already gets recognized specially to insert `convert` calls to their declared binding type, so this doesn't impose any additional requirements on lowering to distinguish local from global assignments. In general, I'd also like to separate syntax and intermediate forms as much as possible where their semantics differ, which this accomplises by just using the builtin. This change is mostly semantically invisible, except that spliced-in GlobalRefs now declare their binding because they are indistinguishable from ordinary assignments at the stage where I inserted the lowering. If we want to, we can preserve the difference, but it'd be a bit more annoying for not much benefit, because: 1. The spliced in version was only recently made to work anyway, and 2. The semantics of when exactly bindings are declared is still messy on master anyway and will get tweaked shortly in further binding partitions work. --- Compiler/src/abstractinterpretation.jl | 8 +------- Compiler/src/optimize.jl | 11 +---------- Compiler/src/ssair/EscapeAnalysis.jl | 12 ------------ Compiler/src/ssair/verify.jl | 10 ++-------- Compiler/test/inline.jl | 2 +- src/interpreter.c | 24 +++++------------------- src/julia-syntax.scm | 14 ++++++++++---- test/syntax.jl | 5 +++-- 8 files changed, 23 insertions(+), 63 deletions(-) diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index ffb4f4312cdcf..24daaf1e6f626 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -4050,13 +4050,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState, nextr end effects === nothing || merge_override_effects!(interp, effects, frame) if lhs !== nothing && rt !== Bottom - if isa(lhs, SlotNumber) - changes = StateUpdate(lhs, VarState(rt, false)) - elseif isa(lhs, GlobalRef) - handle_global_assignment!(interp, frame, currsaw_latestworld, lhs, rt) - else - merge_effects!(interp, frame, EFFECTS_UNKNOWN) - end + changes = StateUpdate(lhs::SlotNumber, VarState(rt, false)) end end if !has_curr_ssaflag(frame, IR_FLAG_NOTHROW) diff --git a/Compiler/src/optimize.jl b/Compiler/src/optimize.jl index d2dfd26bfa00d..856e64e404388 100644 --- a/Compiler/src/optimize.jl +++ b/Compiler/src/optimize.jl @@ -1408,16 +1408,7 @@ function statement_cost(ex::Expr, line::Int, src::Union{CodeInfo, IRCode}, sptyp extyp = line == -1 ? Any : argextype(SSAValue(line), src, sptypes) return extyp === Union{} ? 0 : UNKNOWN_CALL_COST elseif head === :(=) - if ex.args[1] isa GlobalRef - cost = UNKNOWN_CALL_COST - else - cost = 0 - end - a = ex.args[2] - if a isa Expr - cost = plus_saturate(cost, statement_cost(a, -1, src, sptypes, params)) - end - return cost + return statement_cost(ex.args[2], -1, src, sptypes, params) elseif head === :copyast return 100 end diff --git a/Compiler/src/ssair/EscapeAnalysis.jl b/Compiler/src/ssair/EscapeAnalysis.jl index 47a7840628bb5..4f32550d056b2 100644 --- a/Compiler/src/ssair/EscapeAnalysis.jl +++ b/Compiler/src/ssair/EscapeAnalysis.jl @@ -642,13 +642,6 @@ function analyze_escapes(ir::IRCode, nargs::Int, 𝕃ₒ::AbstractLattice, get_e escape_invoke!(astate, pc, stmt.args) elseif head === :new || head === :splatnew escape_new!(astate, pc, stmt.args) - elseif head === :(=) - lhs, rhs = stmt.args - if isa(lhs, GlobalRef) # global store - add_escape_change!(astate, rhs, ⊤) - else - unexpected_assignment!(ir, pc) - end elseif head === :foreigncall escape_foreigncall!(astate, pc, stmt.args) elseif head === :throw_undef_if_not # XXX when is this expression inserted ? @@ -981,11 +974,6 @@ function escape_unanalyzable_obj!(astate::AnalysisState, @nospecialize(obj), obj return objinfo end -@noinline function unexpected_assignment!(ir::IRCode, pc::Int) - @eval Main (ir = $ir; pc = $pc) - error("unexpected assignment found: inspect `Main.pc` and `Main.pc`") -end - is_nothrow(ir::IRCode, pc::Int) = has_flag(ir[SSAValue(pc)], IR_FLAG_NOTHROW) # NOTE if we don't maintain the alias set that is separated from the lattice state, we can do diff --git a/Compiler/src/ssair/verify.jl b/Compiler/src/ssair/verify.jl index 59051058e1750..072a564a31f78 100644 --- a/Compiler/src/ssair/verify.jl +++ b/Compiler/src/ssair/verify.jl @@ -363,14 +363,8 @@ function verify_ir(ir::IRCode, print::Bool=true, isforeigncall = false if isa(stmt, Expr) if stmt.head === :(=) - if stmt.args[1] isa SSAValue - @verify_error "SSAValue as assignment LHS" - raise_error() - end - if stmt.args[2] isa GlobalRef - # undefined GlobalRef as assignment RHS is OK - continue - end + @verify_error "Assignment should have been removed during SSA conversion" + raise_error() elseif stmt.head === :isdefined if length(stmt.args) > 2 || (length(stmt.args) == 2 && !isa(stmt.args[2], Bool)) @verify_error "malformed isdefined" diff --git a/Compiler/test/inline.jl b/Compiler/test/inline.jl index 46b78db3b781c..5f95fb761859e 100644 --- a/Compiler/test/inline.jl +++ b/Compiler/test/inline.jl @@ -2111,7 +2111,7 @@ for run_finalizer_escape_test in (run_finalizer_escape_test1, run_finalizer_esca global finalizer_escape::Int = 0 let src = code_typed1(run_finalizer_escape_test, Tuple{Bool, Bool}) - @test any(x->isexpr(x, :(=)), src.code) + @test any(iscall((src, Core.setglobal!)), src.code) end let diff --git a/src/interpreter.c b/src/interpreter.c index 2dc1c9ed5a0c4..fa4fba94a60a5 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -589,25 +589,11 @@ static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, size_t ip, s->locals[n - 1] = rhs; } else { - jl_module_t *modu; - jl_sym_t *sym; - // Plain assignment is allowed to create bindings at - // toplevel and only for the current module - int alloc = toplevel; - if (jl_is_globalref(lhs)) { - modu = jl_globalref_mod(lhs); - sym = jl_globalref_name(lhs); - alloc &= modu == s->module; - } - else { - assert(jl_is_symbol(lhs)); - modu = s->module; - sym = (jl_sym_t*)lhs; - } - JL_GC_PUSH1(&rhs); - jl_binding_t *b = jl_get_binding_wr(modu, sym, alloc); - jl_checked_assignment(b, modu, sym, rhs); - JL_GC_POP(); + // This is an unmodeled error. Our frontend only generates + // legal `=` expressions, but since GlobalRef used to be legal + // here, give a loud error in case any package is modifying + // internals. + jl_error("Invalid IR: Assignment LHS not a Slot"); } } else if (head == jl_leave_sym) { diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 852d5eb4d6f86..c7ca5d553bb31 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -4607,14 +4607,20 @@ f(x) = yt(x) (cdr cnd) (list cnd)))))) tests)) + (define (emit-assignment-or-setglobal lhs rhs) + (if (globalref? lhs) + (begin + (emit `(global ,lhs)) + (emit `(call (top setglobal!) ,(cadr lhs) (inert ,(caddr lhs)) ,rhs))) + (emit `(= ,lhs ,rhs)))) (define (emit-assignment lhs rhs) (if rhs (if (valid-ir-rvalue? lhs rhs) - (emit `(= ,lhs ,rhs)) + (emit-assignment-or-setglobal lhs rhs) (let ((rr (make-ssavalue))) (emit `(= ,rr ,rhs)) - (emit `(= ,lhs ,rr)))) - (emit `(= ,lhs (null)))) ; in unreachable code (such as after return), still emit the assignment so that the structure of those uses is preserved + (emit-assignment-or-setglobal lhs rr))) + (emit-assignment-or-setglobal lhs `(null))) ; in unreachable code (such as after return), still emit the assignment so that the structure of those uses is preserved #f) ;; the interpreter loop. `break-labels` keeps track of the labels to jump to ;; for all currently closing break-blocks. @@ -4693,7 +4699,7 @@ f(x) = yt(x) rhs (make-ssavalue)))) (if (not (eq? rr rhs)) (emit `(= ,rr ,rhs))) - (emit `(= ,lhs ,rr)) + (emit-assignment-or-setglobal lhs rr) (if tail (emit-return tail rr)) rr) (emit-assignment lhs rhs)))))) diff --git a/test/syntax.jl b/test/syntax.jl index 0fb752bae480f..315f2d8b0f38b 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -3713,7 +3713,7 @@ end module Foreign54607 # Syntactic, not dynamic try_to_create_binding1() = (Foreign54607.foo = 2) - # GlobalRef is allowed for same-module assignment + # GlobalRef is allowed for same-module assignment and declares the binding @eval try_to_create_binding2() = ($(GlobalRef(Foreign54607, :foo2)) = 2) function global_create_binding() global bar @@ -3728,7 +3728,7 @@ module Foreign54607 end @test_throws ErrorException (Foreign54607.foo = 1) @test_throws ErrorException Foreign54607.try_to_create_binding1() -@test_throws ErrorException Foreign54607.try_to_create_binding2() +Foreign54607.try_to_create_binding2() function assign_in_foreign_module() (Foreign54607.foo = 1) nothing @@ -3744,6 +3744,7 @@ Foreign54607.global_create_binding() @test isdefined(Foreign54607, :baz) @test isdefined(Foreign54607, :compiled_assign) @test isdefined(Foreign54607, :gr_assign) +@test isdefined(Foreign54607, :foo2) Foreign54607.bar = 8 @test Foreign54607.bar == 8 begin From 9acf1129c91cddd9194f529ad9cc82afd2694190 Mon Sep 17 00:00:00 2001 From: Julius Krumbiegel <22495855+jkrumbiegel@users.noreply.github.com> Date: Tue, 3 Dec 2024 08:45:28 +0100 Subject: [PATCH 027/342] Actually show glyphs for latex or emoji shortcodes being suggested in the REPL (#54800) When a user requests a completion for a backslash shortcode, this PR adds the glyphs for all the suggestions to the output. This makes it much easier to find the result one is looking for, especially if the user doesn't know all latex and emoji specifiers by heart. Before: image After: image --------- Co-authored-by: Dilum Aluthge --- stdlib/REPL/src/LineEdit.jl | 38 +++++++++++++++++++++++++---- stdlib/REPL/src/REPL.jl | 6 ++--- stdlib/REPL/src/REPLCompletions.jl | 34 +++++++++++++++++--------- stdlib/REPL/test/replcompletions.jl | 33 +++++++++++++++++-------- 4 files changed, 81 insertions(+), 30 deletions(-) diff --git a/stdlib/REPL/src/LineEdit.jl b/stdlib/REPL/src/LineEdit.jl index e881a65ca6b1c..e15807f645119 100644 --- a/stdlib/REPL/src/LineEdit.jl +++ b/stdlib/REPL/src/LineEdit.jl @@ -181,7 +181,18 @@ struct EmptyHistoryProvider <: HistoryProvider end reset_state(::EmptyHistoryProvider) = nothing -complete_line(c::EmptyCompletionProvider, s; hint::Bool=false) = String[], "", true +# Before, completions were always given as strings. But at least for backslash +# completions, it's nice to see what glyphs are available in the completion preview. +# To separate between what's shown in the preview list of possible matches, and what's +# actually completed, we introduce this struct. +struct NamedCompletion + completion::String # what is actually completed, for example "\trianglecdot" + name::String # what is displayed in lists of possible completions, for example "◬ \trianglecdot" +end + +NamedCompletion(completion::String) = NamedCompletion(completion, completion) + +complete_line(c::EmptyCompletionProvider, s; hint::Bool=false) = NamedCompletion[], "", true # complete_line can be specialized for only two arguments, when the active module # doesn't matter (e.g. Pkg does this) @@ -308,6 +319,7 @@ end set_action!(s, command::Symbol) = nothing +common_prefix(completions::Vector{NamedCompletion}) = common_prefix(map(x -> x.completion, completions)) function common_prefix(completions::Vector{String}) ret = "" c1 = completions[1] @@ -330,6 +342,8 @@ end # does not restrict column length when multiple columns are used. const MULTICOLUMN_THRESHOLD = 5 +show_completions(s::PromptState, completions::Vector{NamedCompletion}) = show_completions(s, map(x -> x.name, completions)) + # Show available completions function show_completions(s::PromptState, completions::Vector{String}) # skip any lines of input after the cursor @@ -374,6 +388,18 @@ function complete_line(s::MIState) end end +# due to close coupling of the Pkg ReplExt `complete_line` can still return a vector of strings, +# so we convert those in this helper +function complete_line_named(args...; kwargs...)::Tuple{Vector{NamedCompletion},String,Bool} + result = complete_line(args...; kwargs...)::Union{Tuple{Vector{NamedCompletion},String,Bool},Tuple{Vector{String},String,Bool}} + if result isa Tuple{Vector{NamedCompletion},String,Bool} + return result + else + completions, partial, should_complete = result + return map(NamedCompletion, completions), partial, should_complete + end +end + function check_for_hint(s::MIState) st = state(s) if !options(st).hint_tab_completes || !eof(buffer(st)) @@ -383,12 +409,14 @@ function check_for_hint(s::MIState) return clear_hint(st) end - completions, partial, should_complete = try - complete_line(st.p.complete, st, s.active_module; hint = true)::Tuple{Vector{String},String,Bool} + named_completions, partial, should_complete = try + complete_line_named(st.p.complete, st, s.active_module; hint = true) catch @debug "error completing line for hint" exception=current_exceptions() return clear_hint(st) end + completions = map(x -> x.completion, named_completions) + isempty(completions) && return clear_hint(st) # Don't complete for single chars, given e.g. `x` completes to `xor` if length(partial) > 1 && should_complete @@ -425,7 +453,7 @@ function clear_hint(s::ModeState) end function complete_line(s::PromptState, repeats::Int, mod::Module; hint::Bool=false) - completions, partial, should_complete = complete_line(s.p.complete, s, mod; hint)::Tuple{Vector{String},String,Bool} + completions, partial, should_complete = complete_line_named(s.p.complete, s, mod; hint) isempty(completions) && return false if !should_complete # should_complete is false for cases where we only want to show @@ -435,7 +463,7 @@ function complete_line(s::PromptState, repeats::Int, mod::Module; hint::Bool=fal # Replace word by completion prev_pos = position(s) push_undo(s) - edit_splice!(s, (prev_pos - sizeof(partial)) => prev_pos, completions[1]) + edit_splice!(s, (prev_pos - sizeof(partial)) => prev_pos, completions[1].completion) else p = common_prefix(completions) if !isempty(p) && p != partial diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index 50f610ff3b3e8..6c3f4bd4ba73a 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -843,7 +843,7 @@ function complete_line(c::REPLCompletionProvider, s::PromptState, mod::Module; h full = LineEdit.input_string(s) ret, range, should_complete = completions(full, lastindex(partial), mod, c.modifiers.shift, hint) c.modifiers = LineEdit.Modifiers() - return unique!(String[completion_text(x) for x in ret]), partial[range], should_complete + return unique!(LineEdit.NamedCompletion[named_completion(x) for x in ret]), partial[range], should_complete end function complete_line(c::ShellCompletionProvider, s::PromptState; hint::Bool=false) @@ -851,14 +851,14 @@ function complete_line(c::ShellCompletionProvider, s::PromptState; hint::Bool=fa partial = beforecursor(s.input_buffer) full = LineEdit.input_string(s) ret, range, should_complete = shell_completions(full, lastindex(partial), hint) - return unique!(String[completion_text(x) for x in ret]), partial[range], should_complete + return unique!(LineEdit.NamedCompletion[named_completion(x) for x in ret]), partial[range], should_complete end function complete_line(c::LatexCompletions, s; hint::Bool=false) partial = beforecursor(LineEdit.buffer(s)) full = LineEdit.input_string(s)::String ret, range, should_complete = bslash_completions(full, lastindex(partial), hint)[2] - return unique!(String[completion_text(x) for x in ret]), partial[range], should_complete + return unique!(LineEdit.NamedCompletion[named_completion(x) for x in ret]), partial[range], should_complete end with_repl_linfo(f, repl) = f(outstream(repl)) diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index 1f2c0cabbdb38..0bffb1a1015cd 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -2,7 +2,7 @@ module REPLCompletions -export completions, shell_completions, bslash_completions, completion_text +export completions, shell_completions, bslash_completions, completion_text, named_completion using Core: Const # We want to insulate the REPLCompletion module from any changes the user may @@ -13,6 +13,8 @@ using Base.Meta using Base: propertynames, something, IdSet using Base.Filesystem: _readdirx +using ..REPL.LineEdit: NamedCompletion + abstract type Completion end struct TextCompletion <: Completion @@ -57,8 +59,10 @@ struct MethodCompletion <: Completion end struct BslashCompletion <: Completion - bslash::String + completion::String # what is actually completed, for example "\trianglecdot" + name::String # what is displayed, for example "◬ \trianglecdot" end +BslashCompletion(completion::String) = BslashCompletion(completion, completion) struct ShellCompletion <: Completion text::String @@ -114,13 +118,21 @@ _completion_text(c::PackageCompletion) = c.package _completion_text(c::PropertyCompletion) = sprint(Base.show_sym, c.property) _completion_text(c::FieldCompletion) = sprint(Base.show_sym, c.field) _completion_text(c::MethodCompletion) = repr(c.method) -_completion_text(c::BslashCompletion) = c.bslash _completion_text(c::ShellCompletion) = c.text _completion_text(c::DictCompletion) = c.key _completion_text(c::KeywordArgumentCompletion) = c.kwarg*'=' completion_text(c) = _completion_text(c)::String +named_completion(c::BslashCompletion) = NamedCompletion(c.completion, c.name) + +function named_completion(c) + text = completion_text(c)::String + return NamedCompletion(text, text) +end + +named_completion_completion(c) = named_completion(c).completion::String + const Completions = Tuple{Vector{Completion}, UnitRange{Int}, Bool} function completes_global(x, name) @@ -984,12 +996,10 @@ function bslash_completions(string::String, pos::Int, hint::Bool=false) end # return possible matches; these cannot be mixed with regular # Julian completions as only latex / emoji symbols contain the leading \ - if startswith(s, "\\:") # emoji - namelist = Iterators.filter(k -> startswith(k, s), keys(emoji_symbols)) - else # latex - namelist = Iterators.filter(k -> startswith(k, s), keys(latex_symbols)) - end - return (true, (Completion[BslashCompletion(name) for name in sort!(collect(namelist))], slashpos:pos, true)) + symbol_dict = startswith(s, "\\:") ? emoji_symbols : latex_symbols + namelist = Iterators.filter(k -> startswith(k, s), keys(symbol_dict)) + completions = Completion[BslashCompletion(name, "$(symbol_dict[name]) $name") for name in sort!(collect(namelist))] + return (true, (completions, slashpos:pos, true)) end return (false, (Completion[], 0:-1, false)) end @@ -1099,7 +1109,7 @@ function complete_keyword_argument(partial::String, last_idx::Int, context_modul complete_keyval!(suggestions, last_word) end - return sort!(suggestions, by=completion_text), wordrange + return sort!(suggestions, by=named_completion_completion), wordrange end function get_loading_candidates(pkgstarts::String, project_file::String) @@ -1298,7 +1308,7 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif complete_identifiers!(suggestions, context_module, string, name, pos, separatorpos, startpos; shift) - return sort!(unique!(completion_text, suggestions), by=completion_text), (separatorpos+1):pos, true + return sort!(unique!(named_completion, suggestions), by=named_completion_completion), (separatorpos+1):pos, true elseif inc_tag === :cmd # TODO: should this call shell_completions instead of partially reimplementing it? let m = match(r"[\t\n\r\"`><=*?|]| (?!\\)", reverse(partial)) # fuzzy shell_parse in reverse @@ -1496,7 +1506,7 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif complete_identifiers!(suggestions, context_module, string, name, pos, separatorpos, startpos; comp_keywords, complete_modules_only, shift) - return sort!(unique!(completion_text, suggestions), by=completion_text), namepos:pos, true + return sort!(unique!(named_completion, suggestions), by=named_completion_completion), namepos:pos, true end function shell_completions(string, pos, hint::Bool=false) diff --git a/stdlib/REPL/test/replcompletions.jl b/stdlib/REPL/test/replcompletions.jl index b259567884486..2c8d48cc232cf 100644 --- a/stdlib/REPL/test/replcompletions.jl +++ b/stdlib/REPL/test/replcompletions.jl @@ -170,17 +170,23 @@ end function map_completion_text(completions) c, r, res = completions - return map(completion_text, c), r, res + return map(x -> named_completion(x).completion, c), r, res +end + +function map_named_completion(completions) + c, r, res = completions + return map(named_completion, c), r, res end test_complete(s) = map_completion_text(@inferred(completions(s, lastindex(s)))) test_scomplete(s) = map_completion_text(@inferred(shell_completions(s, lastindex(s)))) -test_bslashcomplete(s) = map_completion_text(@inferred(bslash_completions(s, lastindex(s)))[2]) test_complete_context(s, m=@__MODULE__; shift::Bool=true) = map_completion_text(@inferred(completions(s,lastindex(s), m, shift))) test_complete_foo(s) = test_complete_context(s, Main.CompletionFoo) test_complete_noshift(s) = map_completion_text(@inferred(completions(s, lastindex(s), Main, false))) +test_bslashcomplete(s) = map_named_completion(@inferred(bslash_completions(s, lastindex(s)))[2]) + test_methods_list(@nospecialize(f), tt) = map(x -> string(x.method), Base._methods_by_ftype(Base.signature_type(f, tt), 10, Base.get_world_counter())) @@ -350,7 +356,8 @@ end # test latex symbol completions let s = "\\alpha" c, r = test_bslashcomplete(s) - @test c[1] == "α" + @test c[1].completion == "α" + @test c[1].name == "α" @test r == 1:lastindex(s) @test length(c) == 1 end @@ -358,7 +365,8 @@ end # test latex symbol completions after unicode #9209 let s = "α\\alpha" c, r = test_bslashcomplete(s) - @test c[1] == "α" + @test c[1].completion == "α" + @test c[1].name == "α" @test r == 3:sizeof(s) @test length(c) == 1 end @@ -366,20 +374,25 @@ end # test emoji symbol completions let s = "\\:koala:" c, r = test_bslashcomplete(s) - @test c[1] == "🐨" + @test c[1].completion == "🐨" + @test c[1].name == "🐨" @test r == 1:sizeof(s) @test length(c) == 1 end let s = "\\:ko" c, r = test_bslashcomplete(s) - @test "\\:koala:" in c + ko = only(filter(c) do namedcompletion + namedcompletion.completion == "\\:koala:" + end) + @test ko.name == "🐨 \\:koala:" end # test emoji symbol completions after unicode #9209 let s = "α\\:koala:" c, r = test_bslashcomplete(s) - @test c[1] == "🐨" + @test c[1].name == "🐨" + @test c[1].completion == "🐨" @test r == 3:sizeof(s) @test length(c) == 1 end @@ -1069,8 +1082,8 @@ let s, c, r # Issue #8047 s = "@show \"/dev/nul\"" c,r = completions(s, 15) - c = map(completion_text, c) - @test "null\"" in c + c = map(named_completion, c) + @test "null\"" in [_c.completion for _c in c] @test r == 13:15 @test s[r] == "nul" @@ -1476,7 +1489,7 @@ function test_dict_completion(dict_name) @test c == Any["\"abcd\"]"] s = "$dict_name[\"abcd]" # trailing close bracket c, r = completions(s, lastindex(s) - 1) - c = map(completion_text, c) + c = map(x -> named_completion(x).completion, c) @test c == Any["\"abcd\""] s = "$dict_name[:b" c, r = test_complete(s) From 2590e675885b97579a7531c343a546f6f5bbcbe5 Mon Sep 17 00:00:00 2001 From: Daniel Wennberg Date: Tue, 3 Dec 2024 05:36:39 -0800 Subject: [PATCH 028/342] Update annotated.jl docstrings according to #55741 (#56736) Annotations now use a NamedTuple --- base/strings/annotated.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/base/strings/annotated.jl b/base/strings/annotated.jl index c5c330fe0dfcd..814ee2afa9d55 100644 --- a/base/strings/annotated.jl +++ b/base/strings/annotated.jl @@ -55,9 +55,9 @@ like [`string`](@ref) but preserves any annotations present in the arguments. # Examples -```julia-repl +```jldoctest; setup=:(using Base: AnnotatedString) julia> AnnotatedString("this is an example annotated string", - [(1:18, :A => 1), (12:28, :B => 2), (18:35, :C => 3)]) + [(1:18, :A, 1), (12:28, :B, 2), (18:35, :C, 3)]) "this is an example annotated string" ``` """ @@ -87,8 +87,8 @@ AnnotatedChar(s::S, annotations::Vector{$Annotation}) # Examples -```julia-repl -julia> AnnotatedChar('j', :label => 1) +```jldoctest; setup=:(using Base: AnnotatedChar) +julia> AnnotatedChar('j', [(:label, 1)]) 'j': ASCII/Unicode U+006A (category Ll: Letter, lowercase) ``` """ @@ -232,11 +232,11 @@ See also [`AnnotatedString`](@ref) and [`AnnotatedChar`](@ref). ## Examples -```julia-repl +```jldoctest; setup=:(using Base: AnnotatedString, annotatedstring) julia> annotatedstring("now a AnnotatedString") "now a AnnotatedString" -julia> annotatedstring(AnnotatedString("annotated", [(1:9, :label => 1)]), ", and unannotated") +julia> annotatedstring(AnnotatedString("annotated", [(1:9, :label, 1)]), ", and unannotated") "annotated, and unannotated" ``` """ @@ -344,7 +344,7 @@ end annotate!(str::AnnotatedString, [range::UnitRange{Int}], label::Symbol, value) annotate!(str::SubString{AnnotatedString}, [range::UnitRange{Int}], label::Symbol, value) -Annotate a `range` of `str` (or the entire string) with a labeled value (`label` => `value`). +Annotate a `range` of `str` (or the entire string) with a labeled value `(label, value)`. To remove existing `label` annotations, use a value of `nothing`. The order in which annotations are applied to `str` is semantically meaningful, @@ -365,7 +365,7 @@ annotate!(s::SubString{<:AnnotatedString}, label::Symbol, @nospecialize(val::Any """ annotate!(char::AnnotatedChar, label::Symbol, value::Any) -Annotate `char` with the pair `label => value`. +Annotate `char` with the labeled value `(label, value)`. """ annotate!(c::AnnotatedChar, label::Symbol, @nospecialize(val::Any)) = (push!(c.annotations, Annotation((; label, val))); c) From 5ae26276c1a1834f7b2ebdaf03696278df59b11b Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 3 Dec 2024 19:50:25 -0500 Subject: [PATCH 029/342] effects: pack bits better (#56737) There is no reason to preserve duplicates of the bits for the value before and after inference, and many of the numbers in the comments had gotten incorrect. Now we are able to pack all 16 bits of currently defined bitflags into 20 bits, instead of 25 bits (although either case still rounds up to 32). There was also no reason for InferenceState to be mutating of CodeInfo during execution, so remove that mutation. --- Compiler/src/inferencestate.jl | 25 +++++++++---------- Compiler/src/optimize.jl | 45 +++++++++++++++++++--------------- Compiler/src/typeinfer.jl | 3 ++- src/julia.h | 13 +++------- 4 files changed, 42 insertions(+), 44 deletions(-) diff --git a/Compiler/src/inferencestate.jl b/Compiler/src/inferencestate.jl index 9eb929b725fbf..6988e74310fc5 100644 --- a/Compiler/src/inferencestate.jl +++ b/Compiler/src/inferencestate.jl @@ -267,6 +267,7 @@ mutable struct InferenceState bb_vartables::Vector{Union{Nothing,VarTable}} # nothing if not analyzed yet bb_saw_latestworld::Vector{Bool} ssavaluetypes::Vector{Any} + ssaflags::Vector{UInt32} edges::Vector{Any} stmt_info::Vector{CallInfo} @@ -343,6 +344,7 @@ mutable struct InferenceState bb_vartable1[i] = VarState(argtyp, i > nargtypes) end src.ssavaluetypes = ssavaluetypes = Any[ NOT_FOUND for i = 1:nssavalues ] + ssaflags = copy(src.ssaflags) unreachable = BitSet() pclimitations = IdSet{InferenceState}() @@ -374,7 +376,7 @@ mutable struct InferenceState this = new( mi, WorldWithRange(world, valid_worlds), mod, sptypes, slottypes, src, cfg, spec_info, - currbb, currpc, ip, handler_info, ssavalue_uses, bb_vartables, bb_saw_latestworld, ssavaluetypes, edges, stmt_info, + currbb, currpc, ip, handler_info, ssavalue_uses, bb_vartables, bb_saw_latestworld, ssavaluetypes, ssaflags, edges, stmt_info, tasks, pclimitations, limitations, cycle_backedges, callstack, parentid, frameid, cycleid, result, unreachable, bestguess, exc_bestguess, ipo_effects, restrict_abstract_call_sites, cache_mode, insert_coverage, @@ -1004,25 +1006,22 @@ function callers_in_cycle(sv::InferenceState) end callers_in_cycle(sv::IRInterpretationState) = AbsIntCycle(sv.callstack::Vector{AbsIntState}, 0, 0) -get_curr_ssaflag(sv::InferenceState) = sv.src.ssaflags[sv.currpc] +get_curr_ssaflag(sv::InferenceState) = sv.ssaflags[sv.currpc] get_curr_ssaflag(sv::IRInterpretationState) = sv.ir.stmts[sv.curridx][:flag] -has_curr_ssaflag(sv::InferenceState, flag::UInt32) = has_flag(sv.src.ssaflags[sv.currpc], flag) +has_curr_ssaflag(sv::InferenceState, flag::UInt32) = has_flag(sv.ssaflags[sv.currpc], flag) has_curr_ssaflag(sv::IRInterpretationState, flag::UInt32) = has_flag(sv.ir.stmts[sv.curridx][:flag], flag) function set_curr_ssaflag!(sv::InferenceState, flag::UInt32, mask::UInt32=typemax(UInt32)) - curr_flag = sv.src.ssaflags[sv.currpc] - sv.src.ssaflags[sv.currpc] = (curr_flag & ~mask) | flag -end -function set_curr_ssaflag!(sv::IRInterpretationState, flag::UInt32, mask::UInt32=typemax(UInt32)) - curr_flag = sv.ir.stmts[sv.curridx][:flag] - sv.ir.stmts[sv.curridx][:flag] = (curr_flag & ~mask) | flag + curr_flag = sv.ssaflags[sv.currpc] + sv.ssaflags[sv.currpc] = (curr_flag & ~mask) | flag + nothing end -add_curr_ssaflag!(sv::InferenceState, flag::UInt32) = sv.src.ssaflags[sv.currpc] |= flag +add_curr_ssaflag!(sv::InferenceState, flag::UInt32) = sv.ssaflags[sv.currpc] |= flag add_curr_ssaflag!(sv::IRInterpretationState, flag::UInt32) = add_flag!(sv.ir.stmts[sv.curridx], flag) -sub_curr_ssaflag!(sv::InferenceState, flag::UInt32) = sv.src.ssaflags[sv.currpc] &= ~flag +sub_curr_ssaflag!(sv::InferenceState, flag::UInt32) = sv.ssaflags[sv.currpc] &= ~flag sub_curr_ssaflag!(sv::IRInterpretationState, flag::UInt32) = sub_flag!(sv.ir.stmts[sv.curridx], flag) function merge_effects!(::AbstractInterpreter, caller::InferenceState, effects::Effects) @@ -1035,8 +1034,8 @@ function merge_effects!(::AbstractInterpreter, caller::InferenceState, effects:: end merge_effects!(::AbstractInterpreter, ::IRInterpretationState, ::Effects) = return -decode_statement_effects_override(sv::AbsIntState) = - decode_statement_effects_override(get_curr_ssaflag(sv)) +decode_statement_effects_override(sv::InferenceState) = decode_statement_effects_override(sv.src.ssaflags[sv.currpc]) +decode_statement_effects_override(sv::IRInterpretationState) = decode_statement_effects_override(UInt32(0)) struct InferenceLoopState rt diff --git a/Compiler/src/optimize.jl b/Compiler/src/optimize.jl index 856e64e404388..1c02bd67b5bd4 100644 --- a/Compiler/src/optimize.jl +++ b/Compiler/src/optimize.jl @@ -17,37 +17,41 @@ const SLOT_USEDUNDEF = 32 # slot has uses that might raise UndefVarError const IR_FLAG_NULL = zero(UInt32) # This statement is marked as @inbounds by user. -# Ff replaced by inlining, any contained boundschecks may be removed. +# If replaced by inlining, any contained boundschecks may be removed. const IR_FLAG_INBOUNDS = one(UInt32) << 0 # This statement is marked as @inline by user const IR_FLAG_INLINE = one(UInt32) << 1 # This statement is marked as @noinline by user const IR_FLAG_NOINLINE = one(UInt32) << 2 -# An optimization pass has updated this statement in a way that may -# have exposed information that inference did not see. Re-running -# inference on this statement may be profitable. -const IR_FLAG_REFINED = one(UInt32) << 3 # This statement is proven :consistent -const IR_FLAG_CONSISTENT = one(UInt32) << 4 +const IR_FLAG_CONSISTENT = one(UInt32) << 3 # This statement is proven :effect_free -const IR_FLAG_EFFECT_FREE = one(UInt32) << 5 +const IR_FLAG_EFFECT_FREE = one(UInt32) << 4 # This statement is proven :nothrow -const IR_FLAG_NOTHROW = one(UInt32) << 6 -# This statement is proven :terminates -const IR_FLAG_TERMINATES = one(UInt32) << 7 -# This statement is proven :noub -const IR_FLAG_NOUB = one(UInt32) << 8 -# TODO: Both of these should eventually go away once -# This statement is :effect_free == EFFECT_FREE_IF_INACCESSIBLEMEMONLY -const IR_FLAG_EFIIMO = one(UInt32) << 9 -# This statement is :inaccessiblememonly == INACCESSIBLEMEM_OR_ARGMEMONLY -const IR_FLAG_INACCESSIBLEMEM_OR_ARGMEM = one(UInt32) << 10 +const IR_FLAG_NOTHROW = one(UInt32) << 5 +# This statement is proven :terminates_globally +const IR_FLAG_TERMINATES = one(UInt32) << 6 +#const IR_FLAG_TERMINATES_LOCALLY = one(UInt32) << 7 +#const IR_FLAG_NOTASKSTATE = one(UInt32) << 8 +#const IR_FLAG_INACCESSIBLEMEM = one(UInt32) << 9 +const IR_FLAG_NOUB = one(UInt32) << 10 +#const IR_FLAG_NOUBINIB = one(UInt32) << 11 +#const IR_FLAG_CONSISTENTOVERLAY = one(UInt32) << 12 # This statement is :nortcall -const IR_FLAG_NORTCALL = one(UInt32) << 11 +const IR_FLAG_NORTCALL = one(UInt32) << 13 +# An optimization pass has updated this statement in a way that may +# have exposed information that inference did not see. Re-running +# inference on this statement may be profitable. +const IR_FLAG_REFINED = one(UInt32) << 16 # This statement has no users and may be deleted if flags get refined to IR_FLAGS_REMOVABLE -const IR_FLAG_UNUSED = one(UInt32) << 12 +const IR_FLAG_UNUSED = one(UInt32) << 17 +# TODO: Both of these next two should eventually go away once +# This statement is :effect_free == EFFECT_FREE_IF_INACCESSIBLEMEMONLY +const IR_FLAG_EFIIMO = one(UInt32) << 18 +# This statement is :inaccessiblememonly == INACCESSIBLEMEM_OR_ARGMEMONLY +const IR_FLAG_INACCESSIBLEMEM_OR_ARGMEM = one(UInt32) << 19 -const NUM_IR_FLAGS = 13 # sync with julia.h +const NUM_IR_FLAGS = 3 # sync with julia.h const IR_FLAGS_EFFECTS = IR_FLAG_CONSISTENT | IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW | @@ -815,6 +819,7 @@ function scan_non_dataflow_flags!(inst::Instruction, sv::PostOptAnalysisState) sv.nortcall = false end end + nothing end function scan_inconsistency!(inst::Instruction, sv::PostOptAnalysisState) diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index 83ec0271ea474..20c0a5000bd39 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -413,6 +413,7 @@ function finishinfer!(me::InferenceState, interp::AbstractInterpreter) ipo_effects = result.ipo_effects = me.ipo_effects = adjust_effects(me) result.exc_result = me.exc_bestguess = refine_exception_type(me.exc_bestguess, ipo_effects) me.src.rettype = widenconst(ignorelimited(bestguess)) + me.src.ssaflags = me.ssaflags me.src.min_world = first(me.world.valid_worlds) me.src.max_world = last(me.world.valid_worlds) istoplevel = !(me.linfo.def isa Method) @@ -936,7 +937,7 @@ function codeinfo_for_const(interp::AbstractInterpreter, mi::MethodInstance, @no tree.slotflags = fill(0x00, nargs) tree.ssavaluetypes = 1 tree.debuginfo = DebugInfo(mi) - tree.ssaflags = UInt32[0] + tree.ssaflags = [IR_FLAG_NULL] tree.rettype = Core.Typeof(val) tree.edges = Core.svec() set_inlineable!(tree, true) diff --git a/src/julia.h b/src/julia.h index 944fd3c43a297..6c0dd700f9472 100644 --- a/src/julia.h +++ b/src/julia.h @@ -279,7 +279,7 @@ typedef union __jl_purity_overrides_t { } _jl_purity_overrides_t; #define NUM_EFFECTS_OVERRIDES 11 -#define NUM_IR_FLAGS 13 +#define NUM_IR_FLAGS 3 // This type describes a single function body typedef struct _jl_code_info_t { @@ -292,15 +292,8 @@ typedef struct _jl_code_info_t { // 1 << 0 = inbounds region // 1 << 1 = callsite inline region // 1 << 2 = callsite noinline region - // 1 << 3 = refined statement - // 1 << 4 = :consistent - // 1 << 5 = :effect_free - // 1 << 6 = :nothrow - // 1 << 7 = :terminates - // 1 << 8 = :noub - // 1 << 9 = :effect_free_if_inaccessiblememonly - // 1 << 10 = :inaccessiblemem_or_argmemonly - // 1 << 11-19 = callsite effects overrides + // 1 << 3-14 = purity + // 1 << 16+ = reserved for inference // miscellaneous data: jl_array_t *slotnames; // names of local variables jl_array_t *slotflags; // local var bit flags From e48bf8cba9a9305050704e3f21b53431ae123e93 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Wed, 4 Dec 2024 07:04:39 -0500 Subject: [PATCH 030/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?Pkg=20stdlib=20from=207b759d7f0=20to=20d84a1a38b=20(#56743)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: Pkg URL: https://github.com/JuliaLang/Pkg.jl.git Stdlib branch: master Julia branch: master Old commit: 7b759d7f0 New commit: d84a1a38b Julia version: 1.12.0-DEV Pkg version: 1.12.0 Bump invoked by: @KristofferC Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaLang/Pkg.jl/compare/7b759d7f0af56c5ad01f2289bbad71284a556970...d84a1a38b6466fa7400e9ad2874a0ef963a10456 ``` $ git log --oneline 7b759d7f0..d84a1a38b d84a1a38b Allow use of a url and subdir in [sources] (#4039) cd75456a8 Fix heading (#4102) b61066120 rename FORMER_STDLIBS -> UPGRADABLE_STDLIBS (#4070) 814949ed2 Increase version of `StaticArrays` in `why` tests (#4077) 83e13631e Run CI on backport branch too (#4094) ``` Co-authored-by: Dilum Aluthge --- .../Pkg-7b759d7f0af56c5ad01f2289bbad71284a556970.tar.gz/md5 | 1 - .../Pkg-7b759d7f0af56c5ad01f2289bbad71284a556970.tar.gz/sha512 | 1 - .../Pkg-d84a1a38b6466fa7400e9ad2874a0ef963a10456.tar.gz/md5 | 1 + .../Pkg-d84a1a38b6466fa7400e9ad2874a0ef963a10456.tar.gz/sha512 | 1 + stdlib/Pkg.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/Pkg-7b759d7f0af56c5ad01f2289bbad71284a556970.tar.gz/md5 delete mode 100644 deps/checksums/Pkg-7b759d7f0af56c5ad01f2289bbad71284a556970.tar.gz/sha512 create mode 100644 deps/checksums/Pkg-d84a1a38b6466fa7400e9ad2874a0ef963a10456.tar.gz/md5 create mode 100644 deps/checksums/Pkg-d84a1a38b6466fa7400e9ad2874a0ef963a10456.tar.gz/sha512 diff --git a/deps/checksums/Pkg-7b759d7f0af56c5ad01f2289bbad71284a556970.tar.gz/md5 b/deps/checksums/Pkg-7b759d7f0af56c5ad01f2289bbad71284a556970.tar.gz/md5 deleted file mode 100644 index e55e74562d717..0000000000000 --- a/deps/checksums/Pkg-7b759d7f0af56c5ad01f2289bbad71284a556970.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -20d63322fc5b547d4c2464c27e9a6a0e diff --git a/deps/checksums/Pkg-7b759d7f0af56c5ad01f2289bbad71284a556970.tar.gz/sha512 b/deps/checksums/Pkg-7b759d7f0af56c5ad01f2289bbad71284a556970.tar.gz/sha512 deleted file mode 100644 index 5094dddb8142a..0000000000000 --- a/deps/checksums/Pkg-7b759d7f0af56c5ad01f2289bbad71284a556970.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -93dd178af474c76cce9368416d34570b66cc44c7c311e4dc14569d3f9deed70afcae8a2b1976535ed0732ed305c6d8d1b0ef04cbeeaa3af2891e97650d51467d diff --git a/deps/checksums/Pkg-d84a1a38b6466fa7400e9ad2874a0ef963a10456.tar.gz/md5 b/deps/checksums/Pkg-d84a1a38b6466fa7400e9ad2874a0ef963a10456.tar.gz/md5 new file mode 100644 index 0000000000000..f5f87b3f2fa9e --- /dev/null +++ b/deps/checksums/Pkg-d84a1a38b6466fa7400e9ad2874a0ef963a10456.tar.gz/md5 @@ -0,0 +1 @@ +1a5c995237815e0d7d5ee1ec50006c1c diff --git a/deps/checksums/Pkg-d84a1a38b6466fa7400e9ad2874a0ef963a10456.tar.gz/sha512 b/deps/checksums/Pkg-d84a1a38b6466fa7400e9ad2874a0ef963a10456.tar.gz/sha512 new file mode 100644 index 0000000000000..839cd4704a135 --- /dev/null +++ b/deps/checksums/Pkg-d84a1a38b6466fa7400e9ad2874a0ef963a10456.tar.gz/sha512 @@ -0,0 +1 @@ +2e0b984c8272fe4468e0b527698a58d5010ef3f18d38d862665902e5a0e0b7ba65d3085b3d9de367a7b48a216e71d1611687804254503b3905b7b4d217a00f2f diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 8b40c45c4366f..9ef9ca4b04376 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = master -PKG_SHA1 = 7b759d7f0af56c5ad01f2289bbad71284a556970 +PKG_SHA1 = d84a1a38b6466fa7400e9ad2874a0ef963a10456 PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 From 8aac4cc282004e5f4c7fc70810207956fde98164 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Thu, 5 Dec 2024 00:33:33 -0700 Subject: [PATCH 031/342] Hide IRShow include from Revise (#56756) Revise in theory wants to re-evaluate this include, but it fails at doing so, because the include call no longer works after bootstrap. It happens to work right now on master, because the lowering of `Compiler.include` happens to hide the include call from Revise, but that's a Revise bug I'm about to fix. Address this by moving the include call into the package and using an absolute include if necessary. --- Compiler/src/Compiler.jl | 16 +++++++++++++++- base/show.jl | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Compiler/src/Compiler.jl b/Compiler/src/Compiler.jl index 2cf7e5508196c..ddcea8a6c5cbb 100644 --- a/Compiler/src/Compiler.jl +++ b/Compiler/src/Compiler.jl @@ -181,12 +181,26 @@ include("bootstrap.jl") include("reflection_interface.jl") include("opaque_closure.jl") +macro __SOURCE_FILE__() + __source__.file === nothing && return nothing + return __source__.file::Symbol +end + module IRShow end +function load_irshow!() + if isdefined(Base, :end_base_include) + # This code path is exclusively for Revise, which may want to re-run this + # after bootstrap. + include(IRShow, Base.joinpath(Base.dirname(Base.String(@__SOURCE_FILE__)), "ssair/show.jl")) + else + include(IRShow, "ssair/show.jl") + end +end if !isdefined(Base, :end_base_include) # During bootstrap, skip including this file and defer it to base/show.jl to include later else # When this module is loaded as the standard library, include this file as usual - include(IRShow, "ssair/show.jl") + load_irshow!() end end # baremodule Compiler diff --git a/base/show.jl b/base/show.jl index 23957d6e29b2d..cb36488b92bc1 100644 --- a/base/show.jl +++ b/base/show.jl @@ -2821,7 +2821,7 @@ function show(io::IO, vm::Core.TypeofVararg) end end -Compiler.include(Compiler.IRShow, "ssair/show.jl") # define `show` for the compiler types +Compiler.load_irshow!() const IRShow = Compiler.IRShow # an alias for compatibility function show(io::IO, src::CodeInfo; debuginfo::Symbol=:source) From e572d2316fb5bd6cb5e57c0d4300edddb4eb2062 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Thu, 5 Dec 2024 18:12:23 +0900 Subject: [PATCH 032/342] fixup!: JuliaLang/julia#56756 (#56758) We need to quote it, otherwise it would result in `UnderVarError`. --- Compiler/src/Compiler.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Compiler/src/Compiler.jl b/Compiler/src/Compiler.jl index ddcea8a6c5cbb..8dd15462ed998 100644 --- a/Compiler/src/Compiler.jl +++ b/Compiler/src/Compiler.jl @@ -183,7 +183,7 @@ include("opaque_closure.jl") macro __SOURCE_FILE__() __source__.file === nothing && return nothing - return __source__.file::Symbol + return QuoteNode(__source__.file::Symbol) end module IRShow end From 5835c3b69e4e0f47eeb9a512d91622b50ad3423c Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Thu, 5 Dec 2024 17:38:12 +0530 Subject: [PATCH 033/342] Accept more general Integer sizes in reshape (#55521) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR generalizes the `reshape` methods to accept `Integer`s instead of `Int`s, and adds a `_reshape_uncolon` method for `Integer` arguments. The current `_reshape_uncolon` method that accepts `Int`s is left unchanged to ensure that the inferred types are not impacted. I've also tried to ensure that most `Integer` subtypes in `Base` that may be safely converted to `Int`s pass through that method. The call sequence would now go like this: ```julia reshape(A, ::Tuple{Vararg{Union{Integer, Colon}}}) -> reshape(A, ::Tuple{Vararg{Integer}}) -> reshape(A, ::Tuple{Vararg{Int}}) (fallback) ``` This lets packages define `reshape(A::CustomArray, ::Tuple{Integer, Vararg{Integer}})` without having to implement `_reshape_uncolon` by themselves (or having to call internal `Base` functions, as in https://github.com/JuliaArrays/FillArrays.jl/issues/373). `reshape` calls involving a `Colon` would convert this to an `Integer` in `Base`, and then pass the `Integer` sizes to the custom method defined in the package. This PR does not resolve issues like https://github.com/JuliaLang/julia/issues/40076 because this still converts `Integer`s to `Int`s in the actual reshaping step. However, `BigInt` sizes that may be converted to `Int`s will work now: ```julia julia> reshape(1:4, big(2), big(2)) 2×2 reshape(::UnitRange{Int64}, 2, 2) with eltype Int64: 1 3 2 4 julia> reshape(1:4, big(1), :) 1×4 reshape(::UnitRange{Int64}, 1, 4) with eltype Int64: 1 2 3 4 ``` Note that the reshape method with `Integer` sizes explicitly converts these to `Int`s to avoid self-recursion (as opposed to calling `to_shape` to carry out the conversion implicitly). In the future, we may want to decide what to do with types or values that can't be converted to an `Int`. --------- Co-authored-by: Neven Sajko --- base/reshapedarray.jl | 57 +++++++++++++++++++++----------- test/abstractarray.jl | 20 +++++++++++ test/offsetarray.jl | 11 ++++++ test/testhelpers/OffsetArrays.jl | 4 ++- 4 files changed, 72 insertions(+), 20 deletions(-) diff --git a/base/reshapedarray.jl b/base/reshapedarray.jl index 07f608588837b..f65a7d8c9561a 100644 --- a/base/reshapedarray.jl +++ b/base/reshapedarray.jl @@ -121,37 +121,56 @@ reshape reshape(parent::AbstractArray, dims::IntOrInd...) = reshape(parent, dims) reshape(parent::AbstractArray, shp::Tuple{Union{Integer,OneTo}, Vararg{Union{Integer,OneTo}}}) = reshape(parent, to_shape(shp)) +reshape(parent::AbstractArray, dims::Tuple{Integer, Vararg{Integer}}) = reshape(parent, map(Int, dims)) reshape(parent::AbstractArray, dims::Dims) = _reshape(parent, dims) # Allow missing dimensions with Colon(): reshape(parent::AbstractVector, ::Colon) = parent reshape(parent::AbstractVector, ::Tuple{Colon}) = parent reshape(parent::AbstractArray, dims::Int...) = reshape(parent, dims) -reshape(parent::AbstractArray, dims::Union{Int,Colon}...) = reshape(parent, dims) -reshape(parent::AbstractArray, dims::Tuple{Vararg{Union{Int,Colon}}}) = reshape(parent, _reshape_uncolon(parent, dims)) -@inline function _reshape_uncolon(A, dims) - @noinline throw1(dims) = throw(DimensionMismatch(string("new dimensions $(dims) ", - "may have at most one omitted dimension specified by `Colon()`"))) - @noinline throw2(A, dims) = throw(DimensionMismatch(string("array size $(length(A)) ", - "must be divisible by the product of the new dimensions $dims"))) - pre = _before_colon(dims...)::Tuple{Vararg{Int}} +reshape(parent::AbstractArray, dims::Integer...) = reshape(parent, dims) +reshape(parent::AbstractArray, dims::Union{Integer,Colon}...) = reshape(parent, dims) +reshape(parent::AbstractArray, dims::Tuple{Vararg{Union{Integer,Colon}}}) = reshape(parent, _reshape_uncolon(parent, dims)) + +@noinline throw1(dims) = throw(DimensionMismatch(LazyString("new dimensions ", dims, + " may have at most one omitted dimension specified by `Colon()`"))) +@noinline throw2(lenA, dims) = throw(DimensionMismatch(string("array size ", lenA, + " must be divisible by the product of the new dimensions ", dims))) + +@inline function _reshape_uncolon(A, _dims::Tuple{Vararg{Union{Integer, Colon}}}) + # promote the dims to `Int` at least + dims = map(x -> x isa Colon ? x : promote_type(typeof(x), Int)(x), _dims) + pre = _before_colon(dims...) post = _after_colon(dims...) _any_colon(post...) && throw1(dims) - post::Tuple{Vararg{Int}} len = length(A) - sz, is_exact = if iszero(len) - (0, true) + _reshape_uncolon_computesize(len, dims, pre, post) +end +@inline function _reshape_uncolon_computesize(len::Int, dims, pre::Tuple{Vararg{Int}}, post::Tuple{Vararg{Int}}) + sz = if iszero(len) + 0 else let pr = Core.checked_dims(pre..., post...) # safe product - if iszero(pr) - throw2(A, dims) - end - (quo, rem) = divrem(len, pr) - (Int(quo), iszero(rem)) + quo = _reshape_uncolon_computesize_nonempty(len, dims, pr) + convert(Int, quo) end - end::Tuple{Int,Bool} - is_exact || throw2(A, dims) - (pre..., sz, post...)::Tuple{Int,Vararg{Int}} + end + (pre..., sz, post...) +end +@inline function _reshape_uncolon_computesize(len, dims, pre, post) + pr = prod((pre..., post...)) + sz = if iszero(len) + promote(len, pr)[1] # zero of the correct type + else + _reshape_uncolon_computesize_nonempty(len, dims, pr) + end + (pre..., sz, post...) +end +@inline function _reshape_uncolon_computesize_nonempty(len, dims, pr) + iszero(pr) && throw2(len, dims) + (quo, rem) = divrem(len, pr) + iszero(rem) || throw2(len, dims) + quo end @inline _any_colon() = false @inline _any_colon(dim::Colon, tail...) = true diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 2a2ec8e8e432c..4af4099eced45 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -2186,3 +2186,23 @@ end copyto!(A, 1, x, 1) @test A == axes(A,1) end + +@testset "reshape with Integer sizes" begin + @test reshape(1:4, big(2), big(2)) == reshape(1:4, 2, 2) + a = [1 2 3; 4 5 6] + reshaped_arrays = ( + reshape(a, 3, 2), + reshape(a, (3, 2)), + reshape(a, big(3), big(2)), + reshape(a, (big(3), big(2))), + reshape(a, :, big(2)), + reshape(a, (:, big(2))), + reshape(a, big(3), :), + reshape(a, (big(3), :)), + ) + @test allequal(reshaped_arrays) + for b ∈ reshaped_arrays + @test b isa Matrix{Int} + @test b.ref === a.ref + end +end diff --git a/test/offsetarray.jl b/test/offsetarray.jl index fb5855dfbaa0d..8e2ee33c49ed6 100644 --- a/test/offsetarray.jl +++ b/test/offsetarray.jl @@ -914,3 +914,14 @@ end b = sum(a, dims=1) @test b[begin] == sum(r) end + +@testset "reshape" begin + A0 = [1 3; 2 4] + A = reshape(A0, 2:3, 4:5) + @test axes(A) == Base.IdentityUnitRange.((2:3, 4:5)) + + B = reshape(A0, -10:-9, 9:10) + @test isa(B, OffsetArray{Int,2}) + @test parent(B) == A0 + @test axes(B) == Base.IdentityUnitRange.((-10:-9, 9:10)) +end diff --git a/test/testhelpers/OffsetArrays.jl b/test/testhelpers/OffsetArrays.jl index 17b2d8c28680a..e895372a34974 100644 --- a/test/testhelpers/OffsetArrays.jl +++ b/test/testhelpers/OffsetArrays.jl @@ -529,7 +529,7 @@ _similar_axes_or_length(AT, ax::I, ::I) where {I} = similar(AT, map(_indexlength # reshape accepts a single colon Base.reshape(A::AbstractArray, inds::OffsetAxis...) = reshape(A, inds) -function Base.reshape(A::AbstractArray, inds::Tuple{OffsetAxis,Vararg{OffsetAxis}}) +function Base.reshape(A::AbstractArray, inds::Tuple{Vararg{OffsetAxis}}) AR = reshape(no_offset_view(A), map(_indexlength, inds)) O = OffsetArray(AR, map(_offset, axes(AR), inds)) return _popreshape(O, axes(AR), _filterreshapeinds(inds)) @@ -557,6 +557,8 @@ Base.reshape(A::OffsetArray, inds::Tuple{OffsetAxis,Vararg{OffsetAxis}}) = OffsetArray(_reshape(parent(A), inds), map(_toaxis, inds)) # And for non-offset axes, we can just return a reshape of the parent directly Base.reshape(A::OffsetArray, inds::Tuple{Union{Integer,Base.OneTo},Vararg{Union{Integer,Base.OneTo}}}) = _reshape_nov(A, inds) +Base.reshape(A::OffsetArray, inds::Tuple{Integer,Vararg{Integer}}) = _reshape_nov(A, inds) +Base.reshape(A::OffsetArray, inds::Tuple{Union{Colon, Integer}, Vararg{Union{Colon, Integer}}}) = _reshape_nov(A, inds) Base.reshape(A::OffsetArray, inds::Dims) = _reshape_nov(A, inds) Base.reshape(A::OffsetVector, ::Colon) = A Base.reshape(A::OffsetVector, ::Tuple{Colon}) = A From b8230c02c6e015cc5fd8e33811474ff1b82299bc Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 6 Dec 2024 06:17:24 -0500 Subject: [PATCH 034/342] drop llvm 16 support (#56751) Co-authored-by: Valentin Churavy --- doc/src/devdocs/build/build.md | 2 +- src/APInt-C.cpp | 54 -------- src/APInt-C.h | 15 --- src/Makefile | 6 +- src/aotcompile.cpp | 30 +---- src/ccall.cpp | 3 - src/cgutils.cpp | 66 +--------- src/codegen.cpp | 81 +----------- src/disasm.cpp | 10 +- src/jitlayers.cpp | 156 +---------------------- src/jitlayers.h | 20 +-- src/llvm-codegen-shared.h | 22 +--- src/llvm-cpufeatures.cpp | 2 +- src/llvm-julia-licm.cpp | 4 - src/llvm-late-gc-lowering.cpp | 21 --- src/llvm-lower-handlers.cpp | 4 - src/llvm-multiversioning.cpp | 8 +- src/llvm-pass-helpers.cpp | 14 -- src/llvm-propagate-addrspaces.cpp | 18 --- src/llvm-ptls.cpp | 8 -- src/llvm-remove-addrspaces.cpp | 28 ---- src/llvm-simdloop.cpp | 4 - src/llvm-version.h | 8 +- src/pipeline.cpp | 36 +----- src/processor.cpp | 8 -- src/runtime_ccall.cpp | 4 - src/runtime_intrinsics.c | 11 -- src/support/win32-clang-ABI-bug/optional | 10 -- 28 files changed, 19 insertions(+), 634 deletions(-) diff --git a/doc/src/devdocs/build/build.md b/doc/src/devdocs/build/build.md index 553f7c2e815cf..966ef3d102d1c 100644 --- a/doc/src/devdocs/build/build.md +++ b/doc/src/devdocs/build/build.md @@ -249,7 +249,7 @@ The most complicated dependency is LLVM, for which we require additional patches For packaging Julia with LLVM, we recommend either: - bundling a Julia-only LLVM library inside the Julia package, or - adding the patches to the LLVM package of the distribution. - * A complete list of patches is available in on [Github](https://github.com/JuliaLang/llvm-project) see the `julia-release/15.x` branch. + * A complete list of patches is available in on [Github](https://github.com/JuliaLang/llvm-project) see the `julia-release/18.x` branch. * The only Julia-specific patch is the lib renaming (`llvm7-symver-jlprefix.patch`), which should _not_ be applied to a system LLVM. * The remaining patches are all upstream bug fixes, and have been contributed into upstream LLVM. diff --git a/src/APInt-C.cpp b/src/APInt-C.cpp index e73399c2ecde4..86b0bdb27638b 100644 --- a/src/APInt-C.cpp +++ b/src/APInt-C.cpp @@ -475,7 +475,6 @@ void LLVMTrunc(jl_datatype_t *ty, integerPart *pa, jl_datatype_t *otys, integerP memcpy(pr, pa, onumbytes); } -#if JL_LLVM_VERSION >= 170000 extern "C" JL_DLLEXPORT unsigned countr_zero_8(uint8_t Val) { return countr_zero(Val); @@ -495,27 +494,6 @@ extern "C" JL_DLLEXPORT unsigned countr_zero_64(uint64_t Val) { return countr_zero(Val); } -#else -extern "C" JL_DLLEXPORT -unsigned countTrailingZeros_8(uint8_t Val) { - return countTrailingZeros(Val); -} - -extern "C" JL_DLLEXPORT -unsigned countTrailingZeros_16(uint16_t Val) { - return countTrailingZeros(Val); -} - -extern "C" JL_DLLEXPORT -unsigned countTrailingZeros_32(uint32_t Val) { - return countTrailingZeros(Val); -} - -extern "C" JL_DLLEXPORT -unsigned countTrailingZeros_64(uint64_t Val) { - return countTrailingZeros(Val); -} -#endif extern "C" JL_DLLEXPORT void jl_LLVMSMod(unsigned numbits, integerPart *pa, integerPart *pb, integerPart *pr) { @@ -545,7 +523,6 @@ void jl_LLVMFlipSign(unsigned numbits, integerPart *pa, integerPart *pb, integer memcpy(pr, pa, numbytes); } -#if JL_LLVM_VERSION >= 170000 extern "C" JL_DLLEXPORT unsigned LLVMPopcount(unsigned numbits, integerPart *pa) { CREATE(a) @@ -575,34 +552,3 @@ unsigned LLVMCountl_zero(unsigned numbits, integerPart *pa) { CREATE(a) return a.countl_zero(); } -#else -extern "C" JL_DLLEXPORT -unsigned LLVMCountPopulation(unsigned numbits, integerPart *pa) { - CREATE(a) - return a.countPopulation(); -} - -extern "C" JL_DLLEXPORT -unsigned LLVMCountTrailingOnes(unsigned numbits, integerPart *pa) { - CREATE(a) - return a.countTrailingOnes(); -} - -extern "C" JL_DLLEXPORT -unsigned LLVMCountTrailingZeros(unsigned numbits, integerPart *pa) { - CREATE(a) - return a.countTrailingZeros(); -} - -extern "C" JL_DLLEXPORT -unsigned LLVMCountLeadingOnes(unsigned numbits, integerPart *pa) { - CREATE(a) - return a.countLeadingOnes(); -} - -extern "C" JL_DLLEXPORT -unsigned LLVMCountLeadingZeros(unsigned numbits, integerPart *pa) { - CREATE(a) - return a.countLeadingZeros(); -} -#endif diff --git a/src/APInt-C.h b/src/APInt-C.h index a44d922a40d24..59ce3c765eeec 100644 --- a/src/APInt-C.h +++ b/src/APInt-C.h @@ -54,19 +54,11 @@ JL_DLLEXPORT int LLVMDiv_uov(unsigned numbits, integerPart *pa, integerPart *pb, JL_DLLEXPORT int LLVMRem_sov(unsigned numbits, integerPart *pa, integerPart *pb, integerPart *pr); JL_DLLEXPORT int LLVMRem_uov(unsigned numbits, integerPart *pa, integerPart *pb, integerPart *pr); -#if JL_LLVM_VERSION >= 170000 JL_DLLEXPORT unsigned LLVMPopcount(unsigned numbits, integerPart *pa); JL_DLLEXPORT unsigned LLVMCountr_one(unsigned numbits, integerPart *pa); JL_DLLEXPORT unsigned LLVMCountr_zero(unsigned numbits, integerPart *pa); JL_DLLEXPORT unsigned LLVMCountl_one(unsigned numbits, integerPart *pa); JL_DLLEXPORT unsigned LLVMCountl_zero(unsigned numbits, integerPart *pa); -#else -JL_DLLEXPORT unsigned LLVMCountPopulation(unsigned numbits, integerPart *pa); -JL_DLLEXPORT unsigned LLVMCountTrailingOnes(unsigned numbits, integerPart *pa); -JL_DLLEXPORT unsigned LLVMCountTrailingZeros(unsigned numbits, integerPart *pa); -JL_DLLEXPORT unsigned LLVMCountLeadingOnes(unsigned numbits, integerPart *pa); -JL_DLLEXPORT unsigned LLVMCountLeadingZeros(unsigned numbits, integerPart *pa); -#endif JL_DLLEXPORT void LLVMFPtoSI(jl_datatype_t *ty, integerPart *pa, jl_datatype_t *oty, integerPart *pr); JL_DLLEXPORT void LLVMFPtoUI(jl_datatype_t *ty, integerPart *pa, jl_datatype_t *oty, integerPart *pr); @@ -82,17 +74,10 @@ JL_DLLEXPORT int LLVMFPtoUI_exact(jl_datatype_t *ty, integerPart *pa, jl_datatyp JL_DLLEXPORT void jl_LLVMSMod(unsigned numbits, integerPart *pa, integerPart *pb, integerPart *pr); JL_DLLEXPORT void jl_LLVMFlipSign(unsigned numbits, integerPart *pa, integerPart *pb, integerPart *pr); -#if JL_LLVM_VERSION >= 170000 JL_DLLEXPORT unsigned countr_zero_8(uint8_t Val); JL_DLLEXPORT unsigned countr_zero_16(uint16_t Val); JL_DLLEXPORT unsigned countr_zero_32(uint32_t Val); JL_DLLEXPORT unsigned countr_zero_64(uint64_t Val); -#else -JL_DLLEXPORT unsigned countTrailingZeros_8(uint8_t Val); -JL_DLLEXPORT unsigned countTrailingZeros_16(uint16_t Val); -JL_DLLEXPORT unsigned countTrailingZeros_32(uint32_t Val); -JL_DLLEXPORT unsigned countTrailingZeros_64(uint64_t Val); -#endif //uint8_t getSwappedBytes_8(uint8_t Value); // no-op //uint16_t getSwappedBytes_16(uint16_t Value); diff --git a/src/Makefile b/src/Makefile index 3458f51fa5548..9355ca2c4c675 100644 --- a/src/Makefile +++ b/src/Makefile @@ -77,11 +77,7 @@ else # JULIACODEGEN != LLVM endif -RT_LLVM_LIBS := support - -ifeq ($(shell test $(LLVM_VER_MAJ) -ge 16 && echo true),true) -RT_LLVM_LIBS += targetparser -endif +RT_LLVM_LIBS := support targetparser ifeq ($(OS),WINNT) SRCS += win32_ucontext diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 1d1e48efc8c6c..ba9a3c05e41ff 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -4,11 +4,7 @@ #include "platform.h" // target support -#if JL_LLVM_VERSION >= 170000 #include -#else -#include -#endif #include "llvm/Support/CodeGen.h" #include #include @@ -963,11 +959,7 @@ static FunctionInfo getFunctionWeight(const Function &F) auto val = F.getFnAttribute("julia.mv.clones").getValueAsString(); // base16, so must be at most 4 * length bits long // popcount gives number of clones - #if JL_LLVM_VERSION >= 170000 info.clones = APInt(val.size() * 4, val, 16).popcount() + 1; - #else - info.clones = APInt(val.size() * 4, val, 16).countPopulation() + 1; - #endif } info.weight += info.insts; // more basic blocks = more complex than just sum of insts, @@ -1372,7 +1364,7 @@ static AOTOutputs add_output_impl(Module &M, TargetMachine &SourceTM, ShardTimer // So for now we inject a definition of these functions that calls our runtime // functions. We do so after optimization to avoid cloning these functions. // Float16 conversion routines -#if defined(_CPU_X86_64_) && defined(_OS_DARWIN_) && JL_LLVM_VERSION >= 160000 +#if defined(_CPU_X86_64_) && defined(_OS_DARWIN_) // LLVM 16 reverted to soft-float ABI for passing half on x86_64 Darwin // https://github.com/llvm/llvm-project/commit/2bcf51c7f82ca7752d1bba390a2e0cb5fdd05ca9 injectCRTAlias(M, "__gnu_h2f_ieee", "julia_half_to_float", @@ -1721,9 +1713,6 @@ static SmallVector add_output(Module &M, TargetMachine &TM, Stri std::function func = [&, i]() { LLVMContext ctx; ctx.setDiscardValueNames(true); - #if JL_LLVM_VERSION < 170000 - SetOpaquePointer(ctx); - #endif // Lazily deserialize the entire module timers[i].deserialize.startTimer(); auto EM = getLazyBitcodeModule(MemoryBufferRef(StringRef(serialized.data(), serialized.size()), "Optimized"), ctx); @@ -1888,7 +1877,7 @@ void jl_dump_native_impl(void *native_code, Str += "10.14.0"; TheTriple.setOSName(Str); } - Optional RelocModel; + std::optional RelocModel; if (TheTriple.isOSLinux() || TheTriple.isOSFreeBSD() || TheTriple.isOSOpenBSD()) { RelocModel = Reloc::PIC_; } @@ -1933,9 +1922,6 @@ void jl_dump_native_impl(void *native_code, JL_TIMING(NATIVE_AOT, NATIVE_Sysimg); LLVMContext Context; Context.setDiscardValueNames(true); - #if JL_LLVM_VERSION < 170000 - SetOpaquePointer(Context); - #endif Module sysimgM("sysimg", Context); sysimgM.setTargetTriple(TheTriple.str()); sysimgM.setDataLayout(DL); @@ -2081,9 +2067,6 @@ void jl_dump_native_impl(void *native_code, JL_TIMING(NATIVE_AOT, NATIVE_Metadata); LLVMContext Context; Context.setDiscardValueNames(true); - #if JL_LLVM_VERSION < 170000 - SetOpaquePointer(Context); - #endif Module metadataM("metadata", Context); metadataM.setTargetTriple(TheTriple.str()); metadataM.setDataLayout(DL); @@ -2299,16 +2282,7 @@ void jl_get_llvmf_defn_impl(jl_llvmf_dump_t* dump, jl_method_instance_t *mi, jl_ } else { auto p = literal_static_pointer_val(global.first, global.second->getValueType()); - #if JL_LLVM_VERSION >= 170000 Type *elty = PointerType::get(output.getContext(), 0); - #else - Type *elty; - if (p->getType()->isOpaquePointerTy()) { - elty = PointerType::get(output.getContext(), 0); - } else { - elty = p->getType()->getNonOpaquePointerElementType(); - } - #endif // For pretty printing, when LLVM inlines the global initializer into its loads auto alias = GlobalAlias::create(elty, 0, GlobalValue::PrivateLinkage, global.second->getName() + ".jit", p, global.second->getParent()); global.second->setInitializer(ConstantExpr::getBitCast(alias, global.second->getValueType())); diff --git a/src/ccall.cpp b/src/ccall.cpp index 52f8f807132e5..9aa1c56e2e78f 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -264,9 +264,6 @@ static GlobalVariable *emit_plt_thunk( SmallVector args; for (auto &arg : plt->args()) args.push_back(&arg); - #if JL_LLVM_VERSION < 170000 - assert(cast(ptr->getType())->isOpaqueOrPointeeTypeMatches(functype)); - #endif CallInst *ret = irbuilder.CreateCall( functype, ptr, ArrayRef(args)); diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 7d4bd917eff30..9e170555e6149 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -60,11 +60,7 @@ static Value *decay_derived(jl_codectx_t &ctx, Value *V) if (T->getPointerAddressSpace() == AddressSpace::Derived) return V; // Once llvm deletes pointer element types, we won't need it here any more either. - #if JL_LLVM_VERSION >= 170000 Type *NewT = PointerType::get(T, AddressSpace::Derived); - #else - Type *NewT = PointerType::getWithSamePointeeType(cast(T), AddressSpace::Derived); - #endif return ctx.builder.CreateAddrSpaceCast(V, NewT); } @@ -74,11 +70,7 @@ static Value *maybe_decay_tracked(jl_codectx_t &ctx, Value *V) Type *T = V->getType(); if (T->getPointerAddressSpace() != AddressSpace::Tracked) return V; - #if JL_LLVM_VERSION >= 170000 Type *NewT = PointerType::get(T, AddressSpace::Derived); - #else - Type *NewT = PointerType::getWithSamePointeeType(cast(T), AddressSpace::Derived); - #endif return ctx.builder.CreateAddrSpaceCast(V, NewT); } @@ -1010,54 +1002,6 @@ static void emit_memcpy_llvm(jl_codectx_t &ctx, Value *dst, jl_aliasinfo_t const { if (sz == 0) return; - #if JL_LLVM_VERSION < 170000 - // If the types are small and simple, use load and store directly. - // Going through memcpy can cause LLVM (e.g. SROA) to create bitcasts between float and int - // that interferes with other optimizations. - // TODO: Restore this for opaque pointers? Needs extra type information from the caller. - if (ctx.builder.getContext().supportsTypedPointers() && sz <= 64) { - // The size limit is arbitrary but since we mainly care about floating points and - // machine size vectors this should be enough. - const DataLayout &DL = jl_Module->getDataLayout(); - auto srcty = cast(src->getType()); - //TODO unsafe nonopaque pointer - auto srcel = srcty->getNonOpaquePointerElementType(); - auto dstty = cast(dst->getType()); - //TODO unsafe nonopaque pointer - auto dstel = dstty->getNonOpaquePointerElementType(); - while (srcel->isArrayTy() && srcel->getArrayNumElements() == 1) { - src = ctx.builder.CreateConstInBoundsGEP2_32(srcel, src, 0, 0); - srcel = srcel->getArrayElementType(); - srcty = srcel->getPointerTo(); - } - while (dstel->isArrayTy() && dstel->getArrayNumElements() == 1) { - dst = ctx.builder.CreateConstInBoundsGEP2_32(dstel, dst, 0, 0); - dstel = dstel->getArrayElementType(); - dstty = dstel->getPointerTo(); - } - - llvm::Type *directel = nullptr; - if (srcel->isSized() && srcel->isSingleValueType() && DL.getTypeStoreSize(srcel) == sz) { - directel = srcel; - dst = emit_bitcast(ctx, dst, srcty); - } - else if (dstel->isSized() && dstel->isSingleValueType() && - DL.getTypeStoreSize(dstel) == sz) { - directel = dstel; - src = emit_bitcast(ctx, src, dstty); - } - if (directel) { - if (isa(src) && !src->hasName()) - setName(ctx.emission_context, src, "memcpy_refined_src"); - if (isa(dst) && !dst->hasName()) - setName(ctx.emission_context, dst, "memcpy_refined_dst"); - auto val = src_ai.decorateInst(ctx.builder.CreateAlignedLoad(directel, src, MaybeAlign(align_src), is_volatile)); - dst_ai.decorateInst(ctx.builder.CreateAlignedStore(val, dst, align_dst, is_volatile)); - ++SkippedMemcpys; - return; - } - } - #endif ++EmittedMemcpys; // the memcpy intrinsic does not allow to specify different alias tags @@ -1940,7 +1884,7 @@ static std::pair emit_isa(jl_codectx_t &ctx, const jl_cgval_t &x, // actual `isa` calls, this optimization should already have been performed upstream // anyway, but having this optimization in codegen might still be beneficial for // `typeassert`s if we can make it correct. - Optional known_isa; + std::optional known_isa; jl_value_t *intersected_type = type; if (x.constant) known_isa = jl_isa(x.constant, type); @@ -3786,11 +3730,7 @@ static void recursively_adjust_ptr_type(llvm::Value *Val, unsigned FromAS, unsig for (auto *User : Val->users()) { if (isa(User)) { GetElementPtrInst *Inst = cast(User); - #if JL_LLVM_VERSION >= 170000 Inst->mutateType(PointerType::get(Inst->getType(), ToAS)); - #else - Inst->mutateType(PointerType::getWithSamePointeeType(cast(Inst->getType()), ToAS)); - #endif recursively_adjust_ptr_type(Inst, FromAS, ToAS); } else if (isa(User)) { @@ -3799,11 +3739,7 @@ static void recursively_adjust_ptr_type(llvm::Value *Val, unsigned FromAS, unsig } else if (isa(User)) { BitCastInst *Inst = cast(User); - #if JL_LLVM_VERSION >= 170000 Inst->mutateType(PointerType::get(Inst->getType(), ToAS)); - #else - Inst->mutateType(PointerType::getWithSamePointeeType(cast(Inst->getType()), ToAS)); - #endif recursively_adjust_ptr_type(Inst, FromAS, ToAS); } } diff --git a/src/codegen.cpp b/src/codegen.cpp index b8bed0793730b..b9d42b9b5af16 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -23,11 +23,7 @@ #include #include #include -#if JL_LLVM_VERSION >= 170000 #include -#else -#include -#endif #include #include @@ -637,11 +633,7 @@ static AttributeList get_func_attrs(LLVMContext &C) static AttributeList get_donotdelete_func_attrs(LLVMContext &C) { AttrBuilder FnAttrs(C); -#if JL_LLVM_VERSION >= 160000 FnAttrs.addMemoryAttr(MemoryEffects::inaccessibleMemOnly()); -#else - FnAttrs.addAttribute(Attribute::InaccessibleMemOnly); -#endif FnAttrs.addAttribute(Attribute::WillReturn); FnAttrs.addAttribute(Attribute::NoUnwind); return AttributeList::get(C, @@ -671,11 +663,7 @@ static AttributeList get_attrs_box_float(LLVMContext &C, unsigned nbytes) auto FnAttrs = AttrBuilder(C); FnAttrs.addAttribute(Attribute::WillReturn); FnAttrs.addAttribute(Attribute::NoUnwind); -#if JL_LLVM_VERSION >= 160000 FnAttrs.addMemoryAttr(MemoryEffects::inaccessibleMemOnly()); -#else - FnAttrs.addAttribute(Attribute::InaccessibleMemOnly); -#endif auto RetAttrs = AttrBuilder(C); RetAttrs.addAttribute(Attribute::NonNull); RetAttrs.addDereferenceableAttr(nbytes); @@ -691,11 +679,7 @@ static AttributeList get_attrs_box_sext(LLVMContext &C, unsigned nbytes) auto FnAttrs = AttrBuilder(C); FnAttrs.addAttribute(Attribute::WillReturn); FnAttrs.addAttribute(Attribute::NoUnwind); -#if JL_LLVM_VERSION >= 160000 FnAttrs.addMemoryAttr(MemoryEffects::inaccessibleMemOnly()); -#else - FnAttrs.addAttribute(Attribute::InaccessibleMemOnly); -#endif auto RetAttrs = AttrBuilder(C); RetAttrs.addAttribute(Attribute::NonNull); RetAttrs.addAttribute(Attribute::getWithDereferenceableBytes(C, nbytes)); @@ -712,11 +696,7 @@ static AttributeList get_attrs_box_zext(LLVMContext &C, unsigned nbytes) auto FnAttrs = AttrBuilder(C); FnAttrs.addAttribute(Attribute::WillReturn); FnAttrs.addAttribute(Attribute::NoUnwind); -#if JL_LLVM_VERSION >= 160000 FnAttrs.addMemoryAttr(MemoryEffects::inaccessibleMemOnly()); -#else - FnAttrs.addAttribute(Attribute::InaccessibleMemOnly); -#endif auto RetAttrs = AttrBuilder(C); RetAttrs.addAttribute(Attribute::NonNull); RetAttrs.addDereferenceableAttr(nbytes); @@ -1141,12 +1121,7 @@ static const auto jlegalx_func = new JuliaFunction{ return FunctionType::get(getInt32Ty(C), {T, T, T_size}, false); }, [](LLVMContext &C) { AttrBuilder FnAttrs(C); -#if JL_LLVM_VERSION >= 160000 FnAttrs.addMemoryAttr(MemoryEffects::inaccessibleOrArgMemOnly()); -#else - FnAttrs.addAttribute(Attribute::ReadOnly); - FnAttrs.addAttribute(Attribute::ArgMemOnly); -#endif FnAttrs.addAttribute(Attribute::NoUnwind); return AttributeList::get(C, AttributeSet::get(C, FnAttrs), @@ -1166,9 +1141,7 @@ static const auto jl_alloc_obj_func = new JuliaFunction{ auto FnAttrs = AttrBuilder(C); FnAttrs.addAllocSizeAttr(1, None); // returns %1 bytes FnAttrs.addAllocKindAttr(AllocFnKind::Alloc); -#if JL_LLVM_VERSION >= 160000 FnAttrs.addMemoryAttr(MemoryEffects::argMemOnly(ModRefInfo::Ref) | MemoryEffects::inaccessibleMemOnly(ModRefInfo::ModRef)); -#endif FnAttrs.addAttribute(Attribute::WillReturn); FnAttrs.addAttribute(Attribute::NoUnwind); auto RetAttrs = AttrBuilder(C); @@ -1204,11 +1177,7 @@ static const auto jl_typeof_func = new JuliaFunction<>{ }, [](LLVMContext &C) { AttrBuilder FnAttrs(C); -#if JL_LLVM_VERSION >= 160000 FnAttrs.addMemoryAttr(MemoryEffects::none()); -#else - FnAttrs.addAttribute(Attribute::ReadNone); -#endif FnAttrs.addAttribute(Attribute::NoUnwind); FnAttrs.addAttribute(Attribute::NoRecurse); return AttributeList::get(C, @@ -1223,11 +1192,7 @@ static const auto jl_write_barrier_func = new JuliaFunction<>{ {JuliaType::get_prjlvalue_ty(C)}, true); }, [](LLVMContext &C) { AttrBuilder FnAttrs(C); -#if JL_LLVM_VERSION >= 160000 FnAttrs.addMemoryAttr(MemoryEffects::inaccessibleMemOnly()); -#else - FnAttrs.addAttribute(Attribute::InaccessibleMemOnly); -#endif FnAttrs.addAttribute(Attribute::NoUnwind); FnAttrs.addAttribute(Attribute::NoRecurse); return AttributeList::get(C, @@ -1300,12 +1265,7 @@ static const auto memcmp_func = new JuliaFunction{ {getPointerTy(C), getPointerTy(C), T_size}, false); }, [](LLVMContext &C) { AttrBuilder FnAttrs(C); -#if JL_LLVM_VERSION >= 160000 FnAttrs.addMemoryAttr(MemoryEffects::argMemOnly(ModRefInfo::Ref)); -#else - FnAttrs.addAttribute(Attribute::ArgMemOnly); - FnAttrs.addAttribute(Attribute::ReadOnly); -#endif FnAttrs.addAttribute(Attribute::NoUnwind); return AttributeList::get(C, AttributeSet::get(C, FnAttrs), @@ -1355,11 +1315,7 @@ static const auto jlfieldindex_func = new JuliaFunction<>{ }, [](LLVMContext &C) { AttrBuilder FnAttrs(C); -#if JL_LLVM_VERSION >= 160000 FnAttrs.addMemoryAttr(MemoryEffects::readOnly()); -#else - FnAttrs.addAttribute(Attribute::ReadOnly); -#endif FnAttrs.addAttribute(Attribute::NoUnwind); FnAttrs.addAttribute(Attribute::WillReturn); return AttributeList::get(C, @@ -1425,9 +1381,7 @@ static const auto jl_allocgenericmemory = new JuliaFunction= 160000 FnAttrs.addMemoryAttr(MemoryEffects::inaccessibleMemOnly(ModRefInfo::ModRef) | MemoryEffects::argMemOnly(ModRefInfo::Ref)); -#endif FnAttrs.addAttribute(Attribute::WillReturn); RetAttrs.addAlignmentAttr(Align(16)); RetAttrs.addAttribute(Attribute::NonNull); @@ -1505,11 +1459,7 @@ static const auto pointer_from_objref_func = new JuliaFunction<>{ {PointerType::get(JuliaType::get_jlvalue_ty(C), AddressSpace::Derived)}, false); }, [](LLVMContext &C) { AttrBuilder FnAttrs(C); -#if JL_LLVM_VERSION >= 160000 FnAttrs.addMemoryAttr(MemoryEffects::none()); -#else - FnAttrs.addAttribute(Attribute::ReadNone); -#endif FnAttrs.addAttribute(Attribute::NoUnwind); return AttributeList::get(C, AttributeSet::get(C, FnAttrs), @@ -1532,11 +1482,7 @@ static const auto gc_loaded_func = new JuliaFunction<>{ FnAttrs.addAttribute(Attribute::Speculatable); FnAttrs.addAttribute(Attribute::WillReturn); FnAttrs.addAttribute(Attribute::NoRecurse); -#if JL_LLVM_VERSION >= 160000 FnAttrs.addMemoryAttr(MemoryEffects::none()); -#else - FnAttrs.addAttribute(Attribute::ReadNone); -#endif AttrBuilder RetAttrs(C); RetAttrs.addAttribute(Attribute::NonNull); RetAttrs.addAttribute(Attribute::NoUndef); @@ -2440,11 +2386,7 @@ static Value *emit_inttoptr(jl_codectx_t &ctx, Value *v, Type *ty) auto ptr = I->getOperand(0); if (ty->getPointerAddressSpace() == ptr->getType()->getPointerAddressSpace()) return ptr; - #if JL_LLVM_VERSION >= 170000 else - #else - else if (cast(ty)->hasSameElementTypeAs(cast(ptr->getType()))) - #endif return ctx.builder.CreateAddrSpaceCast(ptr, ty); } ++EmittedIntToPtrs; @@ -10343,10 +10285,6 @@ char jl_using_perf_jitevents = 0; int jl_is_timing_passes = 0; -#if JL_LLVM_VERSION < 170000 -int jl_opaque_ptrs_set = 0; -#endif - extern "C" void jl_init_llvm(void) { jl_page_size = jl_getpagesize(); @@ -10365,12 +10303,8 @@ extern "C" void jl_init_llvm(void) initializeAnalysis(Registry); initializeTransformUtils(Registry); initializeInstCombine(Registry); -#if JL_LLVM_VERSION >= 160000 - // TODO -#else - initializeAggressiveInstCombine(Registry); - initializeInstrumentation(Registry); -#endif + // TODO: initializeAggressiveInstCombine(Registry); + // TODO: initializeInstrumentation(Registry); initializeTarget(Registry); #ifdef USE_POLLY polly::initializePollyPasses(Registry); @@ -10396,17 +10330,6 @@ extern "C" void jl_init_llvm(void) if (clopt && clopt->getNumOccurrences() == 0) cl::ProvidePositionalOption(clopt, "4", 1); - #if JL_LLVM_VERSION < 170000 - // we want the opaque-pointers to be opt-in, per LLVMContext, for this release - // so change the default value back to pre-14.x, without changing the NumOccurrences flag for it - clopt = llvmopts.lookup("opaque-pointers"); - if (clopt && clopt->getNumOccurrences() == 0) { - clopt->addOccurrence(1, clopt->ArgStr, "false", true); - } else { - jl_opaque_ptrs_set = 1; - } - #endif - clopt = llvmopts.lookup("time-passes"); if (clopt && clopt->getNumOccurrences() > 0) jl_is_timing_passes = 1; diff --git a/src/disasm.cpp b/src/disasm.cpp index b944e48430c29..6a7985bd7ec1b 100644 --- a/src/disasm.cpp +++ b/src/disasm.cpp @@ -58,11 +58,7 @@ #include "llvm-version.h" // for outputting disassembly -#if JL_LLVM_VERSION >= 170000 #include -#else -#include -#endif #include #include #include @@ -505,7 +501,7 @@ jl_value_t *jl_dump_function_ir_impl(jl_llvmf_dump_t *dump, char strip_ir_metada auto TSM = std::unique_ptr(unwrap(dump->TSM)); //If TSM is not passed in, then the context MUST be locked externally. //RAII will release the lock - Optional lock; + std::optional lock; if (TSM) { lock.emplace(TSM->getContext().getLock()); } @@ -1107,11 +1103,7 @@ static void jl_dump_asm_internal( const MCOperand &OpI = Inst.getOperand(Op); if (OpI.isImm()) { int64_t imm = OpI.getImm(); - #if JL_LLVM_VERSION >= 170000 if (opinfo.operands()[Op].OperandType == MCOI::OPERAND_PCREL) - #else - if (opinfo.OpInfo[Op].OperandType == MCOI::OPERAND_PCREL) - #endif imm += Fptr + Index; const char *name = DisInfo.lookupSymbolName(imm); if (name) diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 42ddfb688af39..80867daade267 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -37,11 +37,7 @@ #include #include #include -#if JL_LLVM_VERSION >= 170000 #include -#else -#include -#endif #include #include @@ -1103,22 +1099,13 @@ class JLDebuginfoPlugin : public ObjectLinkingLayer::Plugin { return Error::success(); } -#if JL_LLVM_VERSION >= 160000 Error notifyRemovingResources(JITDylib &JD, orc::ResourceKey K) override -#else - Error notifyRemovingResources(orc::ResourceKey K) override -#endif { return Error::success(); } -#if JL_LLVM_VERSION >= 160000 void notifyTransferringResources(JITDylib &JD, orc::ResourceKey DstKey, orc::ResourceKey SrcKey) override {} -#else - void notifyTransferringResources(orc::ResourceKey DstKey, - orc::ResourceKey SrcKey) override {} -#endif void modifyPassConfig(MaterializationResponsibility &MR, jitlink::LinkGraph &, jitlink::PassConfiguration &PassConfig) override @@ -1168,21 +1155,12 @@ class JLMemoryUsagePlugin : public ObjectLinkingLayer::Plugin { Error notifyFailed(orc::MaterializationResponsibility &MR) override { return Error::success(); } -#if JL_LLVM_VERSION >= 160000 Error notifyRemovingResources(JITDylib &JD, orc::ResourceKey K) override -#else - Error notifyRemovingResources(orc::ResourceKey K) override -#endif { return Error::success(); } -#if JL_LLVM_VERSION >= 160000 void notifyTransferringResources(JITDylib &JD, orc::ResourceKey DstKey, orc::ResourceKey SrcKey) override {} -#else - void notifyTransferringResources(orc::ResourceKey DstKey, - orc::ResourceKey SrcKey) override {} -#endif void modifyPassConfig(orc::MaterializationResponsibility &, jitlink::LinkGraph &, @@ -1199,11 +1177,7 @@ class JLMemoryUsagePlugin : public ObjectLinkingLayer::Plugin { for (auto block : section.blocks()) { secsize += block->getSize(); } -#if JL_LLVM_VERSION >= 160000 if ((section.getMemProt() & orc::MemProt::Exec) == orc::MemProt::None) { -#else - if ((section.getMemProt() & jitlink::MemProt::Exec) == jitlink::MemProt::None) { -#endif data_size += secsize; } else { code_size += secsize; @@ -1235,11 +1209,7 @@ class JLMemoryUsagePlugin : public ObjectLinkingLayer::Plugin { // TODO: Port our memory management optimisations to JITLink instead of using the // default InProcessMemoryManager. std::unique_ptr createJITLinkMemoryManager() JL_NOTSAFEPOINT { -#if JL_LLVM_VERSION < 160000 - return cantFail(orc::MapperJITLinkMemoryManager::CreateWithMapper()); -#else return cantFail(orc::MapperJITLinkMemoryManager::CreateWithMapper(/*Reservation Granularity*/ 16 * 1024 * 1024)); -#endif } #ifdef _COMPILER_CLANG_ @@ -1288,21 +1258,11 @@ class ForwardingMemoryManager : public RuntimeDyld::MemoryManager { bool IsReadOnly) override { return MemMgr->allocateDataSection(Size, Alignment, SectionID, SectionName, IsReadOnly); } -#if JL_LLVM_VERSION >= 160000 virtual void reserveAllocationSpace(uintptr_t CodeSize, Align CodeAlign, uintptr_t RODataSize, Align RODataAlign, uintptr_t RWDataSize, Align RWDataAlign) override { return MemMgr->reserveAllocationSpace(CodeSize, CodeAlign, RODataSize, RODataAlign, RWDataSize, RWDataAlign); } -#else - virtual void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign, - uintptr_t RODataSize, - uint32_t RODataAlign, - uintptr_t RWDataSize, - uint32_t RWDataAlign) override { - return MemMgr->reserveAllocationSpace(CodeSize, CodeAlign, RODataSize, RODataAlign, RWDataSize, RWDataAlign); - } -#endif virtual bool needsToReserveAllocationSpace() override { return MemMgr->needsToReserveAllocationSpace(); } @@ -1415,7 +1375,7 @@ namespace { FeaturesStr = Features.getString(); } // Allocate a target... - Optional codemodel = + std::optional codemodel = #ifdef _P64 // Make sure we are using the large code model on 64bit // Let LLVM pick a default suitable for jitting on 32bit @@ -1830,11 +1790,6 @@ struct JuliaOJIT::DLSymOptimizer { if (named) { auto T = GV.getValueType(); assert(T->isPointerTy()); - #if JL_LLVM_VERSION < 170000 - if (!T->isOpaquePointerTy()) { - T = T->getNonOpaquePointerElementType(); - } - #endif init = GlobalAlias::create(T, 0, GlobalValue::PrivateLinkage, GV.getName() + ".jit", init, &M); } GV.setInitializer(init); @@ -1885,11 +1840,6 @@ struct JuliaOJIT::DLSymOptimizer { if (named) { auto T = CI->getType(); assert(T->isPointerTy()); - #if JL_LLVM_VERSION < 170000 - if (!T->isOpaquePointerTy()) { - T = T->getNonOpaquePointerElementType(); - } - #endif init = GlobalAlias::create(T, 0, GlobalValue::PrivateLinkage, CI->getName() + ".jit", init, &M); } // DCE and SimplifyCFG will kill the branching structure around @@ -1933,19 +1883,6 @@ void fixupTM(TargetMachine &TM) { } } -#if JL_LLVM_VERSION < 170000 -extern int jl_opaque_ptrs_set; -void SetOpaquePointer(LLVMContext &ctx) { - if (jl_opaque_ptrs_set) - return; -#ifndef JL_LLVM_OPAQUE_POINTERS - ctx.setOpaquePointers(false); -#else - ctx.setOpaquePointers(true); -#endif -} -#endif - llvm::DataLayout jl_create_datalayout(TargetMachine &TM) { // Mark our address spaces as non-integral auto jl_data_layout = TM.createDataLayout(); @@ -2053,7 +1990,7 @@ JuliaOJIT::JuliaOJIT() orc::SymbolAliasMap jl_crt = { // Float16 conversion routines -#if defined(_CPU_X86_64_) && defined(_OS_DARWIN_) && JL_LLVM_VERSION >= 160000 +#if defined(_CPU_X86_64_) && defined(_OS_DARWIN_) // LLVM 16 reverted to soft-float ABI for passing half on x86_64 Darwin // https://github.com/llvm/llvm-project/commit/2bcf51c7f82ca7752d1bba390a2e0cb5fdd05ca9 { mangle("__gnu_h2f_ieee"), { mangle("julia_half_to_float"), JITSymbolFlags::Exported } }, @@ -2087,7 +2024,6 @@ JuliaOJIT::JuliaOJIT() #ifdef MSAN_EMUTLS_WORKAROUND orc::SymbolMap msan_crt; - #if JL_LLVM_VERSION >= 170000 msan_crt[mangle("__emutls_get_address")] = {ExecutorAddr::fromPtr(msan_workaround::getTLSAddress), JITSymbolFlags::Exported}; msan_crt[mangle("__emutls_v.__msan_param_tls")] = {ExecutorAddr::fromPtr( reinterpret_cast(static_cast(msan_workaround::MSanTLS::param))), JITSymbolFlags::Exported}; @@ -2105,25 +2041,6 @@ JuliaOJIT::JuliaOJIT() reinterpret_cast(static_cast(msan_workaround::MSanTLS::va_arg_overflow_size))), JITSymbolFlags::Exported}; msan_crt[mangle("__emutls_v.__msan_origin_tls")] = {ExecutorAddr::fromPtr( reinterpret_cast(static_cast(msan_workaround::MSanTLS::origin))), JITSymbolFlags::Exported}; - #else - msan_crt[mangle("__emutls_get_address")] = JITEvaluatedSymbol::fromPointer(msan_workaround::getTLSAddress, JITSymbolFlags::Exported); - msan_crt[mangle("__emutls_v.__msan_param_tls")] = JITEvaluatedSymbol::fromPointer( - reinterpret_cast(static_cast(msan_workaround::MSanTLS::param)), JITSymbolFlags::Exported); - msan_crt[mangle("__emutls_v.__msan_param_origin_tls")] = JITEvaluatedSymbol::fromPointer( - reinterpret_cast(static_cast(msan_workaround::MSanTLS::param_origin)), JITSymbolFlags::Exported); - msan_crt[mangle("__emutls_v.__msan_retval_tls")] = JITEvaluatedSymbol::fromPointer( - reinterpret_cast(static_cast(msan_workaround::MSanTLS::retval)), JITSymbolFlags::Exported); - msan_crt[mangle("__emutls_v.__msan_retval_origin_tls")] = JITEvaluatedSymbol::fromPointer( - reinterpret_cast(static_cast(msan_workaround::MSanTLS::retval_origin)), JITSymbolFlags::Exported); - msan_crt[mangle("__emutls_v.__msan_va_arg_tls")] = JITEvaluatedSymbol::fromPointer( - reinterpret_cast(static_cast(msan_workaround::MSanTLS::va_arg)), JITSymbolFlags::Exported); - msan_crt[mangle("__emutls_v.__msan_va_arg_origin_tls")] = JITEvaluatedSymbol::fromPointer( - reinterpret_cast(static_cast(msan_workaround::MSanTLS::va_arg_origin)), JITSymbolFlags::Exported); - msan_crt[mangle("__emutls_v.__msan_va_arg_overflow_size_tls")] = JITEvaluatedSymbol::fromPointer( - reinterpret_cast(static_cast(msan_workaround::MSanTLS::va_arg_overflow_size)), JITSymbolFlags::Exported); - msan_crt[mangle("__emutls_v.__msan_origin_tls")] = JITEvaluatedSymbol::fromPointer( - reinterpret_cast(static_cast(msan_workaround::MSanTLS::origin)), JITSymbolFlags::Exported); - #endif cantFail(GlobalJD.define(orc::absoluteSymbols(msan_crt))); #endif #if JL_LLVM_VERSION < 190000 @@ -2133,11 +2050,7 @@ JuliaOJIT::JuliaOJIT() // hopefully fixed upstream by e7698a13e319a9919af04d3d693a6f6ea7168a44 static int64_t jl___asan_globals_registered; orc::SymbolMap asan_crt; - #if JL_LLVM_VERSION >= 170000 asan_crt[mangle("___asan_globals_registered")] = {ExecutorAddr::fromPtr(&jl___asan_globals_registered), JITSymbolFlags::Common | JITSymbolFlags::Exported}; - #else - asan_crt[mangle("___asan_globals_registered")] = JITEvaluatedSymbol::fromPointer(&jl___asan_globals_registered, JITSymbolFlags::Common | JITSymbolFlags::Exported); - #endif cantFail(JD.define(orc::absoluteSymbols(asan_crt))); #endif #endif @@ -2148,9 +2061,6 @@ JuliaOJIT::~JuliaOJIT() = default; ThreadSafeContext JuliaOJIT::makeContext() { auto ctx = std::make_unique(); - #if JL_LLVM_VERSION < 170000 - SetOpaquePointer(*ctx); - #endif return orc::ThreadSafeContext(std::move(ctx)); } @@ -2162,11 +2072,7 @@ orc::SymbolStringPtr JuliaOJIT::mangle(StringRef Name) void JuliaOJIT::addGlobalMapping(StringRef Name, uint64_t Addr) { - #if JL_LLVM_VERSION >= 170000 cantFail(JD.define(orc::absoluteSymbols({{mangle(Name), {ExecutorAddr::fromPtr((void*)Addr), JITSymbolFlags::Exported}}}))); - #else - cantFail(JD.define(orc::absoluteSymbols({{mangle(Name), JITEvaluatedSymbol::fromPointer((void*)Addr)}}))); - #endif } void JuliaOJIT::addModule(orc::ThreadSafeModule TSM) @@ -2245,7 +2151,6 @@ SmallVector JuliaOJIT::findSymbols(ArrayRef Names) return Addrs; } -#if JL_LLVM_VERSION >= 170000 Expected JuliaOJIT::findSymbol(StringRef Name, bool ExportedSymbolsOnly) { orc::JITDylib* SearchOrders[3] = {&JD, &GlobalJD, &ExternalJD}; @@ -2286,50 +2191,6 @@ uint64_t JuliaOJIT::getFunctionAddress(StringRef Name) } return addr->getAddress().getValue(); } -#else -JL_JITSymbol JuliaOJIT::findSymbol(StringRef Name, bool ExportedSymbolsOnly) -{ - orc::JITDylib* SearchOrders[3] = {&JD, &GlobalJD, &ExternalJD}; - ArrayRef SearchOrder = ArrayRef(&SearchOrders[0], ExportedSymbolsOnly ? 3 : 1); - auto Sym = ES.lookup(SearchOrder, Name); - if (Sym) - return *Sym; - return Sym.takeError(); -} - -JL_JITSymbol JuliaOJIT::findUnmangledSymbol(StringRef Name) -{ - return findSymbol(getMangledName(Name), true); -} - -Expected JuliaOJIT::findExternalJDSymbol(StringRef Name, bool ExternalJDOnly) -{ - orc::JITDylib* SearchOrders[3] = {&ExternalJD, &GlobalJD, &JD}; - ArrayRef SearchOrder = ArrayRef(&SearchOrders[0], ExternalJDOnly ? 1 : 3); - auto Sym = ES.lookup(SearchOrder, getMangledName(Name)); - return Sym; -} - -uint64_t JuliaOJIT::getGlobalValueAddress(StringRef Name) -{ - auto addr = findSymbol(getMangledName(Name), false); - if (!addr) { - consumeError(addr.takeError()); - return 0; - } - return cantFail(addr).getAddress(); -} - -uint64_t JuliaOJIT::getFunctionAddress(StringRef Name) -{ - auto addr = findSymbol(getMangledName(Name), false); - if (!addr) { - consumeError(addr.takeError()); - return 0; - } - return cantFail(addr).getAddress(); -} -#endif StringRef JuliaOJIT::getFunctionAtAddress(uint64_t Addr, jl_callptr_t invoke, jl_code_instance_t *codeinst) { @@ -2361,13 +2222,8 @@ StringRef JuliaOJIT::getFunctionAtAddress(uint64_t Addr, jl_callptr_t invoke, jl } #ifdef JL_USE_JITLINK -#if JL_LLVM_VERSION >= 170000 #define addAbsoluteToMap(map,name) \ (map[mangle(#name)] = {ExecutorAddr::fromPtr(&name), JITSymbolFlags::Exported | JITSymbolFlags::Callable}, orc::ExecutorAddr::fromPtr(&name)) -#else -#define addAbsoluteToMap(map,name) \ - (map[mangle(#name)] = JITEvaluatedSymbol::fromPointer(&name, JITSymbolFlags::Exported | JITSymbolFlags::Callable), orc::ExecutorAddr::fromPtr(&name)) -#endif void JuliaOJIT::enableJITDebuggingSupport() { @@ -2552,11 +2408,7 @@ void jl_merge_module(orc::ThreadSafeModule &destTSM, orc::ThreadSafeModule srcTS } // Reparent the global variable: SG.removeFromParent(); - #if JL_LLVM_VERSION >= 170000 dest.insertGlobalVariable(&SG); - #else - dest.getGlobalList().push_back(&SG); - #endif // Comdat is owned by the Module SG.setComdat(nullptr); } @@ -2603,11 +2455,7 @@ void jl_merge_module(orc::ThreadSafeModule &destTSM, orc::ThreadSafeModule srcTS } } SG.removeFromParent(); - #if JL_LLVM_VERSION >= 170000 dest.insertAlias(&SG); - #else - dest.getAliasList().push_back(&SG); - #endif } // metadata nodes need to be explicitly merged not just copied diff --git a/src/jitlayers.h b/src/jitlayers.h index baba5412226e3..6665be6a33faa 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -363,14 +363,6 @@ class MaxAlignedAllocImpl }; using MaxAlignedAlloc = MaxAlignedAllocImpl<>; -#if JL_LLVM_VERSION < 170000 -typedef JITSymbol JL_JITSymbol; -// The type that is similar to SymbolInfo on LLVM 4.0 is actually -// `JITEvaluatedSymbol`. However, we only use this type when a JITSymbol -// is expected. -typedef JITSymbol JL_SymbolInfo; -#endif - using CompilerResultT = Expected>; using OptimizerResultT = Expected; using SharedBytesT = StringSet::MapEntryTy)>>; @@ -472,7 +464,7 @@ class JuliaOJIT { } private: ResourcePool &pool; - Optional resource; + std::optional resource; }; OwningResource operator*() JL_NOTSAFEPOINT { @@ -558,16 +550,10 @@ class JuliaOJIT { orc::ExecutionSession &getExecutionSession() JL_NOTSAFEPOINT { return ES; } orc::JITDylib &getExternalJITDylib() JL_NOTSAFEPOINT { return ExternalJD; } - #if JL_LLVM_VERSION >= 170000 Expected findSymbol(StringRef Name, bool ExportedSymbolsOnly) JL_NOTSAFEPOINT; Expected findUnmangledSymbol(StringRef Name) JL_NOTSAFEPOINT; Expected findExternalJDSymbol(StringRef Name, bool ExternalJDOnly) JL_NOTSAFEPOINT; SmallVector findSymbols(ArrayRef Names) JL_NOTSAFEPOINT; - #else - JITEvaluatedSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) JL_NOTSAFEPOINT; - JITEvaluatedSymbol findUnmangledSymbol(StringRef Name) JL_NOTSAFEPOINT; - Expected findExternalJDSymbol(StringRef Name, bool ExternalJDOnly) JL_NOTSAFEPOINT; - #endif uint64_t getGlobalValueAddress(StringRef Name) JL_NOTSAFEPOINT; uint64_t getFunctionAddress(StringRef Name) JL_NOTSAFEPOINT; StringRef getFunctionAtAddress(uint64_t Addr, jl_callptr_t invoke, jl_code_instance_t *codeinst) JL_NOTSAFEPOINT; @@ -660,10 +646,6 @@ Module &jl_codegen_params_t::shared_module() JL_NOTSAFEPOINT { } void fixupTM(TargetMachine &TM) JL_NOTSAFEPOINT; -#if JL_LLVM_VERSION < 170000 -void SetOpaquePointer(LLVMContext &ctx) JL_NOTSAFEPOINT; -#endif - void optimizeDLSyms(Module &M); // NewPM diff --git a/src/llvm-codegen-shared.h b/src/llvm-codegen-shared.h index a99e18f3e3762..d9551e0552f9c 100644 --- a/src/llvm-codegen-shared.h +++ b/src/llvm-codegen-shared.h @@ -1,5 +1,6 @@ // This file is a part of Julia. License is MIT: https://julialang.org/license +#include #include #include #include @@ -8,30 +9,15 @@ #include #include #include - -#if JL_LLVM_VERSION >= 160000 #include -#endif #include "julia.h" #define STR(csym) #csym #define XSTR(csym) STR(csym) -#if JL_LLVM_VERSION >= 160000 - -#include - -template -using Optional = std::optional; static constexpr std::nullopt_t None = std::nullopt; -#else - -#include - -#endif - enum AddressSpace { Generic = 0, Tracked = 10, @@ -180,7 +166,7 @@ static inline llvm::Instruction *tbaa_decorate(llvm::MDNode *md, llvm::Instructi using namespace llvm; inst->setMetadata(llvm::LLVMContext::MD_tbaa, md); if (llvm::isa(inst) && md && md == get_tbaa_const(md->getContext())) { - inst->setMetadata(llvm::LLVMContext::MD_invariant_load, llvm::MDNode::get(md->getContext(), None)); + inst->setMetadata(llvm::LLVMContext::MD_invariant_load, llvm::MDNode::get(md->getContext(), std::nullopt)); } return inst; } @@ -245,11 +231,7 @@ static inline void emit_gc_safepoint(llvm::IRBuilder<> &builder, llvm::Type *T_s if (!F) { FunctionType *FT = FunctionType::get(Type::getVoidTy(C), {T_size->getPointerTo()}, false); F = Function::Create(FT, Function::ExternalLinkage, "julia.safepoint", M); -#if JL_LLVM_VERSION >= 160000 F->setMemoryEffects(MemoryEffects::inaccessibleOrArgMemOnly()); -#else - F->addFnAttr(Attribute::InaccessibleMemOrArgMemOnly); -#endif } builder.CreateCall(F, {signal_page}); } diff --git a/src/llvm-cpufeatures.cpp b/src/llvm-cpufeatures.cpp index 05d62adc57926..a6e963664b0f3 100644 --- a/src/llvm-cpufeatures.cpp +++ b/src/llvm-cpufeatures.cpp @@ -37,7 +37,7 @@ STATISTIC(LoweredWithoutFMA, "Number of have_fma's that were lowered to false"); extern JuliaOJIT *jl_ExecutionEngine; // whether this platform unconditionally (i.e. without needing multiversioning) supports FMA -Optional always_have_fma(Function &intr, const Triple &TT) JL_NOTSAFEPOINT { +std::optional always_have_fma(Function &intr, const Triple &TT) JL_NOTSAFEPOINT { if (TT.isAArch64()) { auto intr_name = intr.getName(); auto typ = intr_name.substr(strlen("julia.cpu.have_fma.")); diff --git a/src/llvm-julia-licm.cpp b/src/llvm-julia-licm.cpp index 8d80f7fd54877..baf844dffa89c 100644 --- a/src/llvm-julia-licm.cpp +++ b/src/llvm-julia-licm.cpp @@ -342,11 +342,7 @@ struct JuliaLICM : public JuliaPassContext { } } if (changed && SE) { -#if JL_LLVM_VERSION >= 160000 SE->forgetLoopDispositions(); -#else - SE->forgetLoopDispositions(L); -#endif } #ifdef JL_VERIFY_PASSES assert(!verifyLLVMIR(*L)); diff --git a/src/llvm-late-gc-lowering.cpp b/src/llvm-late-gc-lowering.cpp index d95cc9c49b698..ff2cac6e49406 100644 --- a/src/llvm-late-gc-lowering.cpp +++ b/src/llvm-late-gc-lowering.cpp @@ -1163,9 +1163,6 @@ State LateLowerGCFrame::LocalScan(Function &F) { } if (CI->hasStructRetAttr()) { Type *ElT = getAttributeAtIndex(CI->getAttributes(), 1, Attribute::StructRet).getValueAsType(); - #if JL_LLVM_VERSION < 170000 - assert(cast(CI->getArgOperand(0)->getType())->isOpaqueOrPointeeTypeMatches(getAttributeAtIndex(CI->getAttributes(), 1, Attribute::StructRet).getValueAsType())); - #endif auto tracked = CountTrackedPointers(ElT, true); if (tracked.count) { AllocaInst *SRet = dyn_cast((CI->arg_begin()[0])->stripInBoundsOffsets()); @@ -1252,38 +1249,20 @@ State LateLowerGCFrame::LocalScan(Function &F) { callee->getName() == "memcmp") { continue; } -#if JL_LLVM_VERSION >= 160000 if (callee->getMemoryEffects().onlyReadsMemory() || callee->getMemoryEffects().onlyAccessesArgPointees()) { continue; } -#else - if (callee->hasFnAttribute(Attribute::ReadNone) || - callee->hasFnAttribute(Attribute::ReadOnly) || - callee->hasFnAttribute(Attribute::ArgMemOnly)) { - continue; - } -#endif if (MemTransferInst *MI = dyn_cast(CI)) { MaybeTrackDst(S, MI); } } -#if JL_LLVM_VERSION >= 160000 if (isa(CI) || CI->getMemoryEffects().onlyAccessesArgPointees() || CI->getMemoryEffects().onlyReadsMemory()) { // Intrinsics are never safepoints. continue; } -#else - if (isa(CI) || - CI->hasFnAttr(Attribute::ArgMemOnly) || - CI->hasFnAttr(Attribute::ReadNone) || - CI->hasFnAttr(Attribute::ReadOnly)) { - // Intrinsics are never safepoints. - continue; - } -#endif SmallVector CalleeRoots; for (Use &U : CI->args()) { // Find all callee rooted arguments. diff --git a/src/llvm-lower-handlers.cpp b/src/llvm-lower-handlers.cpp index e09ea892ee488..c359bf6c117ce 100644 --- a/src/llvm-lower-handlers.cpp +++ b/src/llvm-lower-handlers.cpp @@ -8,11 +8,7 @@ #include #include -#if JL_LLVM_VERSION >= 170000 #include -#else -#include -#endif #include #include #include diff --git a/src/llvm-multiversioning.cpp b/src/llvm-multiversioning.cpp index 22ef973decfe9..a76d076ebd6f3 100644 --- a/src/llvm-multiversioning.cpp +++ b/src/llvm-multiversioning.cpp @@ -15,11 +15,7 @@ #include #include #include -#if JL_LLVM_VERSION >= 170000 #include -#else -#include -#endif #include #include #include @@ -51,7 +47,7 @@ using namespace llvm; -extern Optional always_have_fma(Function&, const Triple &TT); +extern std::optional always_have_fma(Function&, const Triple &TT); namespace { constexpr uint32_t clone_mask = @@ -185,7 +181,7 @@ struct TargetSpec { } }; -static Optional> get_target_specs(Module &M) { +static std::optional> get_target_specs(Module &M) { auto md = M.getModuleFlag("julia.mv.specs"); if (!md) return None; diff --git a/src/llvm-pass-helpers.cpp b/src/llvm-pass-helpers.cpp index 4e9e4826b4f75..ca25251040fb2 100644 --- a/src/llvm-pass-helpers.cpp +++ b/src/llvm-pass-helpers.cpp @@ -129,9 +129,7 @@ namespace jl_intrinsics { static Function *addGCAllocAttributes(Function *target) { auto FnAttrs = AttrBuilder(target->getContext()); -#if JL_LLVM_VERSION >= 160000 FnAttrs.addMemoryAttr(MemoryEffects::argMemOnly(ModRefInfo::Ref) | MemoryEffects::inaccessibleMemOnly(ModRefInfo::ModRef)); -#endif FnAttrs.addAllocKindAttr(AllocFnKind::Alloc); FnAttrs.addAttribute(Attribute::WillReturn); FnAttrs.addAttribute(Attribute::NoUnwind); @@ -228,11 +226,7 @@ namespace jl_intrinsics { false), Function::ExternalLinkage, QUEUE_GC_ROOT_NAME); -#if JL_LLVM_VERSION >= 160000 intrinsic->setMemoryEffects(MemoryEffects::inaccessibleOrArgMemOnly()); -#else - intrinsic->addFnAttr(Attribute::InaccessibleMemOrArgMemOnly); -#endif return intrinsic; }); @@ -248,11 +242,7 @@ namespace jl_intrinsics { false), Function::ExternalLinkage, SAFEPOINT_NAME); -#if JL_LLVM_VERSION >= 160000 intrinsic->setMemoryEffects(MemoryEffects::inaccessibleOrArgMemOnly()); -#else - intrinsic->addFnAttr(Attribute::InaccessibleMemOrArgMemOnly); -#endif return intrinsic; }); } @@ -309,11 +299,7 @@ namespace jl_well_known { false), Function::ExternalLinkage, GC_QUEUE_ROOT_NAME); -#if JL_LLVM_VERSION >= 160000 func->setMemoryEffects(MemoryEffects::inaccessibleOrArgMemOnly()); -#else - func->addFnAttr(Attribute::InaccessibleMemOrArgMemOnly); -#endif return func; }); diff --git a/src/llvm-propagate-addrspaces.cpp b/src/llvm-propagate-addrspaces.cpp index 4e5a2ee5e0d54..06a52ad3dcb43 100644 --- a/src/llvm-propagate-addrspaces.cpp +++ b/src/llvm-propagate-addrspaces.cpp @@ -163,22 +163,14 @@ Value *PropagateJuliaAddrspacesVisitor::LiftPointer(Module *M, Value *V, Instruc Instruction *InstV = cast(V); Instruction *NewV = InstV->clone(); ToInsert.push_back(std::make_pair(NewV, InstV)); - #if JL_LLVM_VERSION >= 170000 Type *NewRetTy = PointerType::get(InstV->getType(), allocaAddressSpace); - #else - Type *NewRetTy = PointerType::getWithSamePointeeType(cast(InstV->getType()), allocaAddressSpace); - #endif NewV->mutateType(NewRetTy); LiftingMap[InstV] = NewV; ToRevisit.push_back(NewV); } } auto CollapseCastsAndLift = [&](Value *CurrentV, Instruction *InsertPt) -> Value * { - #if JL_LLVM_VERSION >= 170000 PointerType *TargetType = PointerType::get(CurrentV->getType(), allocaAddressSpace); - #else - PointerType *TargetType = PointerType::getWithSamePointeeType(cast(CurrentV->getType()), allocaAddressSpace); - #endif while (!LiftingMap.count(CurrentV)) { if (isa(CurrentV)) CurrentV = cast(CurrentV)->getOperand(0); @@ -192,17 +184,7 @@ Value *PropagateJuliaAddrspacesVisitor::LiftPointer(Module *M, Value *V, Instruc } if (LiftingMap.count(CurrentV)) CurrentV = LiftingMap[CurrentV]; - #if JL_LLVM_VERSION >= 170000 assert(CurrentV->getType() == TargetType); - #else - if (CurrentV->getType() != TargetType) { - // Shouldn't get here when using opaque pointers, so the new BitCastInst is fine - assert(CurrentV->getContext().supportsTypedPointers()); - auto *BCI = new BitCastInst(CurrentV, TargetType); - ToInsert.push_back(std::make_pair(BCI, InsertPt)); - CurrentV = BCI; - } - #endif return CurrentV; }; diff --git a/src/llvm-ptls.cpp b/src/llvm-ptls.cpp index 614ed15f840e6..e36136859517a 100644 --- a/src/llvm-ptls.cpp +++ b/src/llvm-ptls.cpp @@ -9,11 +9,7 @@ #include #include -#if JL_LLVM_VERSION >= 170000 #include -#else -#include -#endif #include #include #include @@ -67,11 +63,7 @@ struct LowerPTLS { void LowerPTLS::set_pgcstack_attrs(CallInst *pgcstack) const { -#if JL_LLVM_VERSION >= 160000 pgcstack->addFnAttr(Attribute::getWithMemoryEffects(pgcstack->getContext(), MemoryEffects::none())); -#else - addFnAttr(pgcstack, Attribute::ReadNone); -#endif addFnAttr(pgcstack, Attribute::NoUnwind); } diff --git a/src/llvm-remove-addrspaces.cpp b/src/llvm-remove-addrspaces.cpp index 89ae1d292d108..bb492f467e74c 100644 --- a/src/llvm-remove-addrspaces.cpp +++ b/src/llvm-remove-addrspaces.cpp @@ -44,19 +44,7 @@ class AddrspaceRemoveTypeRemapper : public ValueMapTypeRemapper { DstTy = SrcTy; if (auto Ty = dyn_cast(SrcTy)) { - #if JL_LLVM_VERSION >= 170000 DstTy = PointerType::get(Ty->getContext(), ASRemapper(Ty->getAddressSpace())); - #else - if (Ty->isOpaque()) { - DstTy = PointerType::get(Ty->getContext(), ASRemapper(Ty->getAddressSpace())); - } - else { - //Remove once opaque pointer transition is complete - DstTy = PointerType::get( - remapType(Ty->getNonOpaquePointerElementType()), - ASRemapper(Ty->getAddressSpace())); - } - #endif } else if (auto Ty = dyn_cast(SrcTy)) { SmallVector Params; @@ -157,24 +145,8 @@ class AddrspaceRemoveValueMaterializer : public ValueMaterializer { Ops.push_back(NewOp ? cast(NewOp) : Op); } - #if JL_LLVM_VERSION >= 170000 if (CE->getOpcode() != Instruction::GetElementPtr) DstV = CE->getWithOperands(Ops, Ty); - #else - if (CE->getOpcode() == Instruction::GetElementPtr) { - // GEP const exprs need to know the type of the source. - // asserts remapType(typeof arg0) == typeof mapValue(arg0). - Constant *Src = CE->getOperand(0); - auto ptrty = cast(Src->getType()->getScalarType()); - //Remove once opaque pointer transition is complete - if (!ptrty->isOpaque()) { - Type *SrcTy = remapType(ptrty->getNonOpaquePointerElementType()); - DstV = CE->getWithOperands(Ops, Ty, false, SrcTy); - } - } - else - DstV = CE->getWithOperands(Ops, Ty); - #endif } } diff --git a/src/llvm-simdloop.cpp b/src/llvm-simdloop.cpp index e12b30e3db466..3faa9d9728e67 100644 --- a/src/llvm-simdloop.cpp +++ b/src/llvm-simdloop.cpp @@ -297,11 +297,7 @@ static bool processLoop(Loop &L, OptimizationRemarkEmitter &ORE, ScalarEvolution } if (SE) -#if JL_LLVM_VERSION >= 160000 SE->forgetLoopDispositions(); -#else - SE->forgetLoopDispositions(&L); -#endif } #ifdef JL_VERIFY_PASSES diff --git a/src/llvm-version.h b/src/llvm-version.h index 984e918d480cc..061d80deb02f9 100644 --- a/src/llvm-version.h +++ b/src/llvm-version.h @@ -10,12 +10,8 @@ #define JL_LLVM_VERSION (LLVM_VERSION_MAJOR * 10000 + LLVM_VERSION_MINOR * 100 \ + LLVM_VERSION_PATCH) -#if JL_LLVM_VERSION < 150000 - #error Only LLVM versions >= 15.0.0 are supported by Julia -#endif - -#if JL_LLVM_VERSION >= 160000 - #define JL_LLVM_OPAQUE_POINTERS 1 +#if JL_LLVM_VERSION < 170000 + #error Only LLVM versions >= 17.0.0 are supported by Julia #endif #if JL_LLVM_VERSION < 19000 && defined(_CPU_RISCV64_) diff --git a/src/pipeline.cpp b/src/pipeline.cpp index f8976099ee53c..8c9054c0d65ff 100644 --- a/src/pipeline.cpp +++ b/src/pipeline.cpp @@ -150,15 +150,9 @@ namespace { // Opts.UseAfterReturn = CodeGenOpts.getSanitizeAddressUseAfterReturn(); // MPM.addPass(RequireAnalysisPass()); //Let's assume the defaults are actually fine for our purposes - #if JL_LLVM_VERSION < 160000 - // MPM.addPass(ModuleAddressSanitizerPass( - // Opts, UseGlobalGC, UseOdrIndicator, DestructorKind)); - MPM.addPass(ModuleAddressSanitizerPass(AddressSanitizerOptions())); - #else // LLVM 16+ // MPM.addPass(AddressSanitizerPass( // Opts, UseGlobalGC, UseOdrIndicator, DestructorKind)); MPM.addPass(AddressSanitizerPass(AddressSanitizerOptions(), true, false)); - #endif // } }; ASanPass(/*SanitizerKind::Address, */false); @@ -347,12 +341,8 @@ static void buildEarlySimplificationPipeline(ModulePassManager &MPM, PassBuilder FPM.addPass(DCEPass()); FPM.addPass(SimplifyCFGPass(basicSimplifyCFGOptions())); if (O.getSpeedupLevel() >= 1) { -#if JL_LLVM_VERSION >= 160000 // TODO check the LLVM 15 default. FPM.addPass(SROAPass(SROAOptions::PreserveCFG)); -#else - FPM.addPass(SROAPass()); -#endif } MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } @@ -389,12 +379,8 @@ static void buildEarlyOptimizerPipeline(ModulePassManager &MPM, PassBuilder *PB, if (O.getSpeedupLevel() >= 1) { FunctionPassManager FPM; if (O.getSpeedupLevel() >= 2) { -#if JL_LLVM_VERSION >= 160000 // TODO check the LLVM 15 default. FPM.addPass(SROAPass(SROAOptions::PreserveCFG)); -#else - FPM.addPass(SROAPass()); -#endif // SROA can duplicate PHI nodes which can block LowerSIMD FPM.addPass(InstCombinePass()); FPM.addPass(JumpThreadingPass()); @@ -468,12 +454,8 @@ static void buildScalarOptimizerPipeline(FunctionPassManager &FPM, PassBuilder * if (options.enable_scalar_optimizations) { if (O.getSpeedupLevel() >= 2) { JULIA_PASS(FPM.addPass(AllocOptPass())); - #if JL_LLVM_VERSION >= 160000 // TODO check the LLVM 15 default. FPM.addPass(SROAPass(SROAOptions::PreserveCFG)); - #else - FPM.addPass(SROAPass()); - #endif FPM.addPass(InstSimplifyPass()); FPM.addPass(GVNPass()); FPM.addPass(MemCpyOptPass()); @@ -737,12 +719,7 @@ void NewPM::run(Module &M) { //We must recreate the analysis managers every time //so that analyses from previous runs of the pass manager //do not hang around for the next run -#if JL_LLVM_VERSION >= 160000 StandardInstrumentations SI(M.getContext(),false); -#else - StandardInstrumentations SI(false); -#endif -#if JL_LLVM_VERSION >= 170000 PassInstrumentationCallbacks PIC; adjustPIC(PIC); TimePasses.registerCallbacks(PIC); @@ -752,17 +729,6 @@ void NewPM::run(Module &M) { ModuleAnalysisManager MAM; SI.registerCallbacks(PIC, &MAM); SI.getTimePasses().setOutStream(nulls()); //TODO: figure out a better way of doing this -#else - FunctionAnalysisManager FAM(createFAM(O, *TM.get())); - PassInstrumentationCallbacks PIC; - adjustPIC(PIC); - TimePasses.registerCallbacks(PIC); - SI.registerCallbacks(PIC, &FAM); - SI.getTimePasses().setOutStream(nulls()); //TODO: figure out a better way of doing this - LoopAnalysisManager LAM; - CGSCCAnalysisManager CGAM; - ModuleAnalysisManager MAM; -#endif PassBuilder PB(TM.get(), PipelineTuningOptions(), None, &PIC); PB.registerLoopAnalyses(LAM); PB.registerFunctionAnalyses(FAM); @@ -794,7 +760,7 @@ OptimizationLevel getOptLevel(int optlevel) { } //This part is also basically stolen from LLVM's PassBuilder.cpp file -static Optional> parseJuliaPipelineOptions(StringRef name) { +static std::optional> parseJuliaPipelineOptions(StringRef name) { if (name.consume_front("julia")) { auto O = OptimizationLevel::O2; auto options = OptimizationOptions::defaults(); diff --git a/src/processor.cpp b/src/processor.cpp index bc12f5b54be19..3edebcc2f3ae6 100644 --- a/src/processor.cpp +++ b/src/processor.cpp @@ -7,11 +7,7 @@ #include #include #include -#if JL_LLVM_VERSION >= 170000 #include -#else -#include -#endif #include #include @@ -162,11 +158,7 @@ struct FeatureList { { int cnt = 0; for (size_t i = 0; i < n; i++) - #if JL_LLVM_VERSION >= 170000 cnt += llvm::popcount(eles[i]); - #else - cnt += llvm::countPopulation(eles[i]); - #endif return cnt; } inline bool empty() const diff --git a/src/runtime_ccall.cpp b/src/runtime_ccall.cpp index 56f8487d8fb73..2a6cb00961594 100644 --- a/src/runtime_ccall.cpp +++ b/src/runtime_ccall.cpp @@ -4,11 +4,7 @@ #include #include #include -#if JL_LLVM_VERSION >= 170000 #include -#else -#include -#endif #include #include "julia.h" diff --git a/src/runtime_intrinsics.c b/src/runtime_intrinsics.c index 450096eef5b01..80281b733bf44 100644 --- a/src/runtime_intrinsics.c +++ b/src/runtime_intrinsics.c @@ -1574,7 +1574,6 @@ bi_iintrinsic_cnvtb_fast(LLVMAShr, ashr_op, ashr_int, , 1) //un_iintrinsic_fast(LLVMByteSwap, bswap_op, bswap_int, u) un_iintrinsic_slow(LLVMByteSwap, bswap_int, u) //#define ctpop_op(a) __builtin_ctpop(a) -#if JL_LLVM_VERSION >= 170000 //uu_iintrinsic_fast(LLVMPopcount, ctpop_op, ctpop_int, u) uu_iintrinsic_slow(LLVMPopcount, ctpop_int, u) //#define ctlz_op(a) __builtin_ctlz(a) @@ -1583,16 +1582,6 @@ uu_iintrinsic_slow(LLVMCountl_zero, ctlz_int, u) //#define cttz_op(a) __builtin_cttz(a) //uu_iintrinsic_fast(LLVMCountr_zero, cttz_op, cttz_int, u) uu_iintrinsic_slow(LLVMCountr_zero, cttz_int, u) -#else -//uu_iintrinsic_fast(LLVMCountPopulation, ctpop_op, ctpop_int, u) -uu_iintrinsic_slow(LLVMCountPopulation, ctpop_int, u) -//#define ctlz_op(a) __builtin_ctlz(a) -//uu_iintrinsic_fast(LLVMCountLeadingZeros, ctlz_op, ctlz_int, u) -uu_iintrinsic_slow(LLVMCountLeadingZeros, ctlz_int, u) -//#define cttz_op(a) __builtin_cttz(a) -//uu_iintrinsic_fast(LLVMCountTrailingZeros, cttz_op, cttz_int, u) -uu_iintrinsic_slow(LLVMCountTrailingZeros, cttz_int, u) -#endif #define not_op(a) ~a un_iintrinsic_fast(LLVMFlipAllBits, not_op, not_int, u) diff --git a/src/support/win32-clang-ABI-bug/optional b/src/support/win32-clang-ABI-bug/optional index a2ecdad1e33ce..fd2f7646e1766 100644 --- a/src/support/win32-clang-ABI-bug/optional +++ b/src/support/win32-clang-ABI-bug/optional @@ -57,7 +57,6 @@ namespace optional_detail { // // The move constructible / assignable conditions emulate the remaining behavior // of std::is_trivially_copyable. -#if JL_LLVM_VERSION >= 170000 template ::value && std::is_trivially_copy_assignable::value && @@ -65,15 +64,6 @@ template ::value) && (std::is_trivially_move_assignable::value || !std::is_move_assignable::value))> -#else -template ::value && - std::is_trivially_copy_assignable::value && - (llvm::is_trivially_move_constructible::value || - !std::is_move_constructible::value) && - (std::is_trivially_move_assignable::value || - !std::is_move_assignable::value))> -#endif class OptionalStorage { union { char empty; From fe2617378cb6ea56a1b5e41ff33b7ad34bfa71ac Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 6 Dec 2024 05:32:45 -0700 Subject: [PATCH 035/342] Address some post-commit review from #56660 (#56747) Some more questions still to be answered, but this should address the immediate actionable review items. --- .../extras/CompilerDevTools/src/CompilerDevTools.jl | 12 ++---------- Compiler/src/abstractinterpretation.jl | 9 +++++---- Compiler/src/stmtinfo.jl | 2 +- base/docs/basedocs.jl | 4 ++-- base/optimized_generics.jl | 2 +- src/builtins.c | 10 ++++++---- 6 files changed, 17 insertions(+), 22 deletions(-) diff --git a/Compiler/extras/CompilerDevTools/src/CompilerDevTools.jl b/Compiler/extras/CompilerDevTools/src/CompilerDevTools.jl index cd3f7b7b4bdac..5d0df5ccaa4e4 100644 --- a/Compiler/extras/CompilerDevTools/src/CompilerDevTools.jl +++ b/Compiler/extras/CompilerDevTools/src/CompilerDevTools.jl @@ -34,19 +34,11 @@ import Core.OptimizedGenerics.CompilerPlugins: typeinf, typeinf_edge Compiler.typeinf_edge(interp, mi.def, mi.specTypes, Core.svec(), parent_frame, false, false) end -# TODO: This needs special compiler support to properly case split for multiple -# method matches, etc. -@noinline function mi_for_tt(tt, world=Base.tls_world_age()) - interp = SplitCacheInterp(; world) - match, _ = Compiler.findsup(tt, Compiler.method_table(interp)) - Base.specialize_method(match) -end - function with_new_compiler(f, args...) - tt = Base.signature_type(f, typeof(args)) + mi = @ccall jl_method_lookup(Any[f, args...]::Ptr{Any}, (1+length(args))::Csize_t, Base.tls_world_age()::Csize_t)::Ref{Core.MethodInstance} world = Base.tls_world_age() new_compiler_ci = Core.OptimizedGenerics.CompilerPlugins.typeinf( - SplitCacheOwner(), mi_for_tt(tt), Compiler.SOURCE_MODE_ABI + SplitCacheOwner(), mi, Compiler.SOURCE_MODE_ABI ) invoke(f, new_compiler_ci, args...) end diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index 24daaf1e6f626..2efd8a2b7264f 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -2223,11 +2223,12 @@ function abstract_invoke(interp::AbstractInterpreter, arginfo::ArgInfo, si::Stmt if isa(method_or_ci, CodeInstance) our_world = sv.world.this argtype = argtypes_to_type(pushfirst!(argtype_tail(argtypes, 4), ft)) - sig = method_or_ci.def.specTypes + specsig = method_or_ci.def.specTypes + defdef = method_or_ci.def.def exct = method_or_ci.exctype - if !hasintersect(argtype, sig) + if !hasintersect(argtype, specsig) return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo())) - elseif !(argtype <: sig) + elseif !(argtype <: specsig) || (isa(defdef, Method) && !(argtype <: defdef.sig)) exct = Union{exct, TypeError} end callee_valid_range = WorldRange(method_or_ci.min_world, method_or_ci.max_world) @@ -2257,7 +2258,7 @@ function abstract_invoke(interp::AbstractInterpreter, arginfo::ArgInfo, si::Stmt # Fall through to generic invoke handling end else - widenconst(types) >: Union{Method, CodeInstance} && return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) + hasintersect(widenconst(types), Union{Method, CodeInstance}) && return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) (types, isexact, isconcrete, istype) = instanceof_tfunc(argtype_by_index(argtypes, 3), false) isexact || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) unwrapped = unwrap_unionall(types) diff --git a/Compiler/src/stmtinfo.jl b/Compiler/src/stmtinfo.jl index 9f0f1f38d4c8a..4f55f068e9456 100644 --- a/Compiler/src/stmtinfo.jl +++ b/Compiler/src/stmtinfo.jl @@ -277,7 +277,7 @@ struct InvokeCICallInfo <: CallInfo edge::CodeInstance end add_edges_impl(edges::Vector{Any}, info::InvokeCICallInfo) = - add_one_edge!(edges, info.edge) + add_inlining_edge!(edges, info.edge) """ info::InvokeCallInfo diff --git a/base/docs/basedocs.jl b/base/docs/basedocs.jl index 141950f5e92ff..c62c980fae1e1 100644 --- a/base/docs/basedocs.jl +++ b/base/docs/basedocs.jl @@ -2064,8 +2064,8 @@ to `invoke(f, method.sig, args...)`. The `argtypes` argument may be a `CodeInstance`, bypassing both method lookup and specialization. The semantics of this invocation are similar to a function pointer call of the `CodeInstance`'s `invoke` pointer. It is an error to invoke a `CodeInstance` with arguments that do not match its -parent MethodInstance or from a world age not included in the `min_world`/`max_world` range. -It is undefined behavior to invoke a CodeInstance whose behavior does not match the constraints +parent `MethodInstance` or from a world age not included in the `min_world`/`max_world` range. +It is undefined behavior to invoke a `CodeInstance` whose behavior does not match the constraints specified in its fields. For some code instances with `owner !== nothing` (i.e. those generated by external compilers), it may be an error to invoke them after passing through precompilation. This is an advanced interface intended for use with external compiler plugins. diff --git a/base/optimized_generics.jl b/base/optimized_generics.jl index c0b953777ca94..6b1d146b6172b 100644 --- a/base/optimized_generics.jl +++ b/base/optimized_generics.jl @@ -61,7 +61,7 @@ end Implements a pair of functions `typeinf`/`typeinf_edge`. When the optimizer sees a call to `typeinf`, it has license to instead call `typeinf_edge`, supplying the current inference stack in `parent_frame` (but otherwise supplying the arguments -to `typeinf`). typeinf_edge will return the `CodeInstance` that `typeinf` would +to `typeinf`). `typeinf_edge` will return the `CodeInstance` that `typeinf` would have returned at runtime. The optimizer may perform a non-IPO replacement of the call to `typeinf` by the result of `typeinf_edge`. In addition, the IPO-safe fields of the `CodeInstance` may be propagated in IPO mode. diff --git a/src/builtins.c b/src/builtins.c index 3f555da9d2a83..4b9c1ad6043c2 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1590,8 +1590,10 @@ JL_CALLABLE(jl_f_invoke) } else if (jl_is_code_instance(argtypes)) { jl_code_instance_t *codeinst = (jl_code_instance_t*)args[1]; jl_callptr_t invoke = jl_atomic_load_acquire(&codeinst->invoke); - if (jl_tuple1_isa(args[0], &args[2], nargs - 2, (jl_datatype_t*)codeinst->def->specTypes)) { - jl_type_error("invoke: argument type error", codeinst->def->specTypes, arg_tuple(args[0], &args[2], nargs - 2)); + // N.B.: specTypes need not be a subtype of the method signature. We need to check both. + if (!jl_tuple1_isa(args[0], &args[2], nargs - 1, (jl_datatype_t*)codeinst->def->specTypes) || + (jl_is_method(codeinst->def->def.value) && !jl_tuple1_isa(args[0], &args[2], nargs - 1, (jl_datatype_t*)codeinst->def->def.method->sig))) { + jl_type_error("invoke: argument type error", codeinst->def->specTypes, arg_tuple(args[0], &args[2], nargs - 1)); } if (jl_atomic_load_relaxed(&codeinst->min_world) > jl_current_task->world_age || jl_current_task->world_age > jl_atomic_load_relaxed(&codeinst->max_world)) { @@ -1604,10 +1606,10 @@ JL_CALLABLE(jl_f_invoke) if (invoke) { return invoke(args[0], &args[2], nargs - 2, codeinst); } else { - if (codeinst->owner != jl_nothing || !jl_is_method(codeinst->def->def.value)) { + if (codeinst->owner != jl_nothing) { jl_error("Failed to invoke or compile external codeinst"); } - return jl_gf_invoke_by_method(codeinst->def->def.method, args[0], &args[2], nargs - 1); + return jl_invoke(args[0], &args[2], nargs - 1, codeinst->def); } } if (!jl_is_tuple_type(jl_unwrap_unionall(argtypes))) From 184ad5bcc955a86638cbc4cc3147b12f0eafb513 Mon Sep 17 00:00:00 2001 From: Nick Robinson Date: Fri, 6 Dec 2024 22:09:44 +0000 Subject: [PATCH 036/342] Add per-task metrics (#56320) Close https://github.com/JuliaLang/julia/issues/47351 (builds on top of https://github.com/JuliaLang/julia/pull/48416) Adds two per-task metrics: - running time = amount of time the task was actually running (according to our scheduler). Note: currently inclusive of GC time, but would be good to be able to separate that out (in a future PR) - wall time = amount of time between the scheduler becoming aware of this task and the task entering a terminal state (i.e. done or failed). We record running time in `wait()`, where the scheduler stops running the task as well as in `yield(t)`, `yieldto(t)` and `throwto(t)`, which bypass the scheduler. Other places where a task stops running (for `Channel`, `ReentrantLock`, `Event`, `Timer` and `Semaphore` are all implemented in terms of `wait(Condition)`, which in turn calls `wait()`. `LibuvStream` similarly calls `wait()`. This should capture everything (albeit, slightly over-counting task CPU time by including any enqueuing work done before we hit `wait()`). The various metrics counters could be a separate inlined struct if we think that's a useful abstraction, but for now i've just put them directly in `jl_task_t`. They are all atomic, except the `metrics_enabled` flag itself (which we now have to check on task start/switch/done even if metrics are not enabled) which is set on task construction and marked `const` on the julia side. In future PRs we could add more per-task metrics, e.g. compilation time, GC time, allocations, potentially a wait-time breakdown (time waiting on locks, channels, in the scheduler run queue, etc.), potentially the number of yields. Perhaps in future there could be ways to enable this on a per-thread and per-task basis. And potentially in future these same timings could be used by `@time` (e.g. writing this same timing data to a ScopedValue like in https://github.com/JuliaLang/julia/pull/55103 but only for tasks lexically scoped to inside the `@time` block). Timings are off by default but can be turned on globally via starting Julia with `--task-metrics=yes` or calling `Base.Experimental.task_metrics(true)`. Metrics are collected for all tasks created when metrics are enabled. In other words, enabling/disabling timings via `Base.Experimental.task_metrics` does not affect existing `Task`s, only new `Task`s. The other new APIs are `Base.Experimental.task_running_time_ns(::Task)` and `Base.Experimental.task_wall_time_ns(::Task)` for retrieving the new metrics. These are safe to call on any task (including the current task, or a task running on another thread). All these are in `Base.Experimental` to give us room to change up the APIs as we add more metrics in future PRs (without worrying about release timelines). cc @NHDaly @kpamnany @d-netto --------- Co-authored-by: Pete Vilter Co-authored-by: K Pamnany Co-authored-by: Nathan Daly Co-authored-by: Valentin Churavy --- NEWS.md | 5 + base/boot.jl | 26 ++- base/experimental.jl | 74 ++++++++ base/options.jl | 1 + base/task.jl | 53 +++++- doc/man/julia.1 | 4 + doc/src/base/multi-threading.md | 8 + doc/src/manual/command-line-interface.md | 1 + src/init.c | 4 + src/jlapi.c | 22 +++ src/jloptions.c | 12 ++ src/jloptions.h | 1 + src/jltypes.c | 46 ++++- src/julia.h | 26 ++- src/julia_internal.h | 3 + src/task.c | 31 ++++ src/threading.c | 2 + test/cmdlineargs.jl | 9 + test/core.jl | 3 +- test/threads_exec.jl | 224 +++++++++++++++++++++++ 20 files changed, 529 insertions(+), 26 deletions(-) diff --git a/NEWS.md b/NEWS.md index b77a786c24823..641b84b480bb4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -17,6 +17,11 @@ New language features - atomic set once (`@atomiconce v[3] = 2`), - atomic swap (`x = @atomicswap v[3] = 2`), and - atomic replace (`x = @atomicreplace v[3] 2=>5`). +- New option `--task-metrics=yes` to enable the collection of per-task timing information, + which can also be enabled/disabled at runtime with `Base.Experimental.task_metrics(::Bool)`. ([#56320]) + The available metrics are: + - actual running time for the task (`Base.Experimental.task_running_time_ns`), and + - wall-time for the task (`Base.Experimental.task_wall_time_ns`). Language changes ---------------- diff --git a/base/boot.jl b/base/boot.jl index f66ee69780193..4badedae3cfb7 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -175,15 +175,33 @@ #end #mutable struct Task -# parent::Task +# next::Any +# queue::Any # storage::Any -# state::Symbol # donenotify::Any # result::Any -# exception::Any -# backtrace::Any # scope::Any # code::Any +# @atomic _state::UInt8 +# sticky::UInt8 +# priority::UInt16 +# @atomic _isexception::UInt8 +# pad00::UInt8 +# pad01::UInt8 +# pad02::UInt8 +# rngState0::UInt64 +# rngState1::UInt64 +# rngState2::UInt64 +# rngState3::UInt64 +# rngState4::UInt64 +# const metrics_enabled::Bool +# pad10::UInt8 +# pad11::UInt8 +# pad12::UInt8 +# @atomic first_enqueued_at::UInt64 +# @atomic last_started_running_at::UInt64 +# @atomic running_time_ns::UInt64 +# @atomic finished_at::UInt64 #end export diff --git a/base/experimental.jl b/base/experimental.jl index 411bb2407cdc5..17871b4f346d6 100644 --- a/base/experimental.jl +++ b/base/experimental.jl @@ -503,4 +503,78 @@ usage, by eliminating the tracking of those possible invalidation. """ disable_new_worlds() = ccall(:jl_disable_new_worlds, Cvoid, ()) +### Task metrics + +""" + Base.Experimental.task_metrics(::Bool) + +Enable or disable the collection of per-task metrics. +A `Task` created when `Base.Experimental.task_metrics(true)` is in effect will have +[`Base.Experimental.task_running_time_ns`](@ref) and [`Base.Experimental.task_wall_time_ns`](@ref) +timing information available. + +!!! note + Task metrics can be enabled at start-up via the `--task-metrics=yes` command line option. +""" +function task_metrics(b::Bool) + if b + ccall(:jl_task_metrics_enable, Cvoid, ()) + else + ccall(:jl_task_metrics_disable, Cvoid, ()) + end + return nothing end + +""" + Base.Experimental.task_running_time_ns(t::Task) -> Union{UInt64, Nothing} + +Return the total nanoseconds that the task `t` has spent running. +This metric is only updated when `t` yields or completes unless `t` is the current task, in +which it will be updated continuously. +See also [`Base.Experimental.task_wall_time_ns`](@ref). + +Returns `nothing` if task timings are not enabled. +See [`Base.Experimental.task_metrics`](@ref). + +!!! note "This metric is from the Julia scheduler" + A task may be running on an OS thread that is descheduled by the OS + scheduler, this time still counts towards the metric. + +!!! compat "Julia 1.12" + This method was added in Julia 1.12. +""" +function task_running_time_ns(t::Task=current_task()) + t.metrics_enabled || return nothing + if t == current_task() + # These metrics fields can't update while we're running. + # But since we're running we need to include the time since we last started running! + return t.running_time_ns + (time_ns() - t.last_started_running_at) + else + return t.running_time_ns + end +end + +""" + Base.Experimental.task_wall_time_ns(t::Task) -> Union{UInt64, Nothing} + +Return the total nanoseconds that the task `t` was runnable. +This is the time since the task first entered the run queue until the time at which it +completed, or until the current time if the task has not yet completed. +See also [`Base.Experimental.task_running_time_ns`](@ref). + +Returns `nothing` if task timings are not enabled. +See [`Base.Experimental.task_metrics`](@ref). + +!!! compat "Julia 1.12" + This method was added in Julia 1.12. +""" +function task_wall_time_ns(t::Task=current_task()) + t.metrics_enabled || return nothing + start_at = t.first_enqueued_at + start_at == 0 && return UInt64(0) + end_at = t.finished_at + end_at == 0 && return time_ns() - start_at + return end_at - start_at +end + +end # module diff --git a/base/options.jl b/base/options.jl index 07baa3b51f65b..7e7808bd5c047 100644 --- a/base/options.jl +++ b/base/options.jl @@ -61,6 +61,7 @@ struct JLOptions heap_size_hint::UInt64 trace_compile_timing::Int8 trim::Int8 + task_metrics::Int8 end # This runs early in the sysimage != is not defined yet diff --git a/base/task.jl b/base/task.jl index 2a922c4b85f24..951e980ee903c 100644 --- a/base/task.jl +++ b/base/task.jl @@ -977,7 +977,11 @@ function enq_work(t::Task) return t end -schedule(t::Task) = enq_work(t) +function schedule(t::Task) + # [task] created -scheduled-> wait_time + maybe_record_enqueued!(t) + enq_work(t) +end """ schedule(t::Task, [val]; error=false) @@ -1031,6 +1035,8 @@ function schedule(t::Task, @nospecialize(arg); error=false) t.queue === nothing || Base.error("schedule: Task not runnable") setfield!(t, :result, arg) end + # [task] created -scheduled-> wait_time + maybe_record_enqueued!(t) enq_work(t) return t end @@ -1064,11 +1070,15 @@ immediately yields to `t` before calling the scheduler. Throws a `ConcurrencyViolationError` if `t` is the currently running task. """ function yield(t::Task, @nospecialize(x=nothing)) - current = current_task() - t === current && throw(ConcurrencyViolationError("Cannot yield to currently running task!")) + ct = current_task() + t === ct && throw(ConcurrencyViolationError("Cannot yield to currently running task!")) (t._state === task_state_runnable && t.queue === nothing) || throw(ConcurrencyViolationError("yield: Task not runnable")) + # [task] user_time -yield-> wait_time + record_running_time!(ct) + # [task] created -scheduled-> wait_time + maybe_record_enqueued!(t) t.result = x - enq_work(current) + enq_work(ct) set_next_task(t) return try_yieldto(ensure_rescheduled) end @@ -1082,6 +1092,7 @@ call to `yieldto`. This is a low-level call that only switches tasks, not consid or scheduling in any way. Its use is discouraged. """ function yieldto(t::Task, @nospecialize(x=nothing)) + ct = current_task() # TODO: these are legacy behaviors; these should perhaps be a scheduler # state error instead. if t._state === task_state_done @@ -1089,6 +1100,10 @@ function yieldto(t::Task, @nospecialize(x=nothing)) elseif t._state === task_state_failed throw(t.result) end + # [task] user_time -yield-> wait_time + record_running_time!(ct) + # [task] created -scheduled-unfairly-> wait_time + maybe_record_enqueued!(t) t.result = x set_next_task(t) return try_yieldto(identity) @@ -1102,6 +1117,10 @@ function try_yieldto(undo) rethrow() end ct = current_task() + # [task] wait_time -(re)started-> user_time + if ct.metrics_enabled + @atomic :monotonic ct.last_started_running_at = time_ns() + end if ct._isexception exc = ct.result ct.result = nothing @@ -1115,6 +1134,11 @@ end # yield to a task, throwing an exception in it function throwto(t::Task, @nospecialize exc) + ct = current_task() + # [task] user_time -yield-> wait_time + record_running_time!(ct) + # [task] created -scheduled-unfairly-> wait_time + maybe_record_enqueued!(t) t.result = exc t._isexception = true set_next_task(t) @@ -1167,6 +1191,9 @@ checktaskempty = Partr.multiq_check_empty end function wait() + ct = current_task() + # [task] user_time -yield-or-done-> wait_time + record_running_time!(ct) GC.safepoint() W = workqueue_for(Threads.threadid()) poptask(W) @@ -1181,3 +1208,21 @@ if Sys.iswindows() else pause() = ccall(:pause, Cvoid, ()) end + +# update the `running_time_ns` field of `t` to include the time since it last started running. +function record_running_time!(t::Task) + if t.metrics_enabled && !istaskdone(t) + @atomic :monotonic t.running_time_ns += time_ns() - t.last_started_running_at + end + return t +end + +# if this is the first time `t` has been added to the run queue +# (or the first time it has been unfairly yielded to without being added to the run queue) +# then set the `first_enqueued_at` field to the current time. +function maybe_record_enqueued!(t::Task) + if t.metrics_enabled && t.first_enqueued_at == 0 + @atomic :monotonic t.first_enqueued_at = time_ns() + end + return t +end diff --git a/doc/man/julia.1 b/doc/man/julia.1 index 56cb690d66eeb..2da11ae1b3f18 100644 --- a/doc/man/julia.1 +++ b/doc/man/julia.1 @@ -294,6 +294,10 @@ If --trace-compile is enabled show how long each took to compile in ms --trace-dispatch={stderr|name} Print precompile statements for methods dispatched during execution or save to stderr or a path. +.TP +--task-metrics={yes|no*} +Enable the collection of per-task metrics. + .TP -image-codegen Force generate code in imaging mode diff --git a/doc/src/base/multi-threading.md b/doc/src/base/multi-threading.md index 9e3bc49acf6dc..81d1d83d765ac 100644 --- a/doc/src/base/multi-threading.md +++ b/doc/src/base/multi-threading.md @@ -65,3 +65,11 @@ These building blocks are used to create the regular synchronization objects. ```@docs Base.Threads.SpinLock ``` + +## Task metrics (Experimental) + +```@docs +Base.Experimental.task_metrics +Base.Experimental.task_running_time_ns +Base.Experimental.task_wall_time_ns +``` diff --git a/doc/src/manual/command-line-interface.md b/doc/src/manual/command-line-interface.md index 734d7031db5e8..9b06deaf0ea8a 100644 --- a/doc/src/manual/command-line-interface.md +++ b/doc/src/manual/command-line-interface.md @@ -203,6 +203,7 @@ The following is a complete list of command-line switches available when launchi |`--code-coverage=tracefile.info` |Append coverage information to the LCOV tracefile (filename supports format tokens).| |`--track-allocation[={none*\|user\|all}]` |Count bytes allocated by each source line (omitting setting is equivalent to "user")| |`--track-allocation=@` |Count bytes but only in files that fall under the given file path/directory. The `@` prefix is required to select this option. A `@` with no path will track the current directory.| +|`--task-metrics={yes\|no*}` |Enable the collection of per-task metrics| |`--bug-report=KIND` |Launch a bug report session. It can be used to start a REPL, run a script, or evaluate expressions. It first tries to use BugReporting.jl installed in current environment and falls back to the latest compatible BugReporting.jl if not. For more information, see `--bug-report=help`.| |`--heap-size-hint=` |Forces garbage collection if memory usage is higher than the given value. The value may be specified as a number of bytes, optionally in units of KB, MB, GB, or TB, or as a percentage of physical memory with %.| |`--compile={yes*\|no\|all\|min}` |Enable or disable JIT compiler, or request exhaustive or minimal compilation| diff --git a/src/init.c b/src/init.c index 1cd14e8556cc6..7b41e63e98455 100644 --- a/src/init.c +++ b/src/init.c @@ -849,6 +849,10 @@ JL_DLLEXPORT void julia_init(JL_IMAGE_SEARCH rel) #if defined(_COMPILER_GCC_) && __GNUC__ >= 12 #pragma GCC diagnostic ignored "-Wdangling-pointer" #endif + if (jl_options.task_metrics == JL_OPTIONS_TASK_METRICS_ON) { + // enable before creating the root task so it gets timings too. + jl_atomic_fetch_add(&jl_task_metrics_enabled, 1); + } // warning: this changes `jl_current_task`, so be careful not to call that from this function jl_task_t *ct = jl_init_root_task(ptls, stack_lo, stack_hi); #pragma GCC diagnostic pop diff --git a/src/jlapi.c b/src/jlapi.c index a3621385a437e..defb2db6ac911 100644 --- a/src/jlapi.c +++ b/src/jlapi.c @@ -809,6 +809,28 @@ JL_DLLEXPORT uint64_t jl_cumulative_recompile_time_ns(void) return jl_atomic_load_relaxed(&jl_cumulative_recompile_time); } +/** + * @brief Enable per-task timing. + */ +JL_DLLEXPORT void jl_task_metrics_enable(void) +{ + // Increment the flag to allow reentrant callers. + jl_atomic_fetch_add(&jl_task_metrics_enabled, 1); +} + +/** + * @brief Disable per-task timing. + */ +JL_DLLEXPORT void jl_task_metrics_disable(void) +{ + // Prevent decrementing the counter below zero + uint8_t enabled = jl_atomic_load_relaxed(&jl_task_metrics_enabled); + while (enabled > 0) { + if (jl_atomic_cmpswap(&jl_task_metrics_enabled, &enabled, enabled-1)) + break; + } +} + /** * @brief Retrieve floating-point environment constants. * diff --git a/src/jloptions.c b/src/jloptions.c index f81cf0453db21..c68b5ce193d98 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -152,6 +152,7 @@ JL_DLLEXPORT void jl_init_options(void) 0, // heap-size-hint 0, // trace_compile_timing JL_TRIM_NO, // trim + 0, // task_metrics }; jl_options_initialized = 1; } @@ -316,6 +317,7 @@ static const char opts_hidden[] = " comment if color is not supported\n" " --trace-compile-timing If --trace-compile is enabled show how long each took to\n" " compile in ms\n" + " --task-metrics={yes|no*} Enable collection of per-task timing data.\n" " --image-codegen Force generate code in imaging mode\n" " --permalloc-pkgimg={yes|no*} Copy the data section of package images into memory\n" " --trim={no*|safe|unsafe|unsafe-warn}\n" @@ -347,6 +349,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) opt_trace_compile, opt_trace_compile_timing, opt_trace_dispatch, + opt_task_metrics, opt_math_mode, opt_worker, opt_bind_to, @@ -427,6 +430,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) { "trace-compile", required_argument, 0, opt_trace_compile }, { "trace-compile-timing", no_argument, 0, opt_trace_compile_timing }, { "trace-dispatch", required_argument, 0, opt_trace_dispatch }, + { "task-metrics", required_argument, 0, opt_task_metrics }, { "math-mode", required_argument, 0, opt_math_mode }, { "handle-signals", required_argument, 0, opt_handle_signals }, // hidden command line options @@ -978,6 +982,14 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) else jl_errorf("julia: invalid argument to --trim={safe|no|unsafe|unsafe-warn} (%s)", optarg); break; + case opt_task_metrics: + if (!strcmp(optarg, "no")) + jl_options.task_metrics = JL_OPTIONS_TASK_METRICS_OFF; + else if (!strcmp(optarg, "yes")) + jl_options.task_metrics = JL_OPTIONS_TASK_METRICS_ON; + else + jl_errorf("julia: invalid argument to --task-metrics={yes|no} (%s)", optarg); + break; default: jl_errorf("julia: unhandled option -- %c\n" "This is a bug, please report it.", c); diff --git a/src/jloptions.h b/src/jloptions.h index b9910702f3f9b..211122242cbbd 100644 --- a/src/jloptions.h +++ b/src/jloptions.h @@ -65,6 +65,7 @@ typedef struct { uint64_t heap_size_hint; int8_t trace_compile_timing; int8_t trim; + int8_t task_metrics; } jl_options_t; #endif diff --git a/src/jltypes.c b/src/jltypes.c index 6c6325d84a5ff..abd1f62092035 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3746,7 +3746,7 @@ void jl_init_types(void) JL_GC_DISABLED NULL, jl_any_type, jl_emptysvec, - jl_perm_symsvec(16, + jl_perm_symsvec(27, "next", "queue", "storage", @@ -3754,16 +3754,27 @@ void jl_init_types(void) JL_GC_DISABLED "result", "scope", "code", + "_state", + "sticky", + "priority", + "_isexception", + "pad00", + "pad01", + "pad02", "rngState0", "rngState1", "rngState2", "rngState3", "rngState4", - "_state", - "sticky", - "_isexception", - "priority"), - jl_svec(16, + "metrics_enabled", + "pad10", + "pad11", + "pad12", + "first_enqueued_at", + "last_started_running_at", + "running_time_ns", + "finished_at"), + jl_svec(27, jl_any_type, jl_any_type, jl_any_type, @@ -3771,21 +3782,36 @@ void jl_init_types(void) JL_GC_DISABLED jl_any_type, jl_any_type, jl_any_type, + jl_uint8_type, + jl_bool_type, + jl_uint16_type, + jl_bool_type, + jl_uint8_type, + jl_uint8_type, + jl_uint8_type, jl_uint64_type, jl_uint64_type, jl_uint64_type, jl_uint64_type, jl_uint64_type, - jl_uint8_type, jl_bool_type, - jl_bool_type, - jl_uint16_type), + jl_uint8_type, + jl_uint8_type, + jl_uint8_type, + jl_uint64_type, + jl_uint64_type, + jl_uint64_type, + jl_uint64_type), jl_emptysvec, 0, 1, 6); XX(task); jl_value_t *listt = jl_new_struct(jl_uniontype_type, jl_task_type, jl_nothing_type); jl_svecset(jl_task_type->types, 0, listt); - const static uint32_t task_atomicfields[1] = {0x00001000}; // Set fields 13 as atomic + // Set field 20 (metrics_enabled) as const + // Set fields 8 (_state) and 24-27 (metric counters) as atomic + const static uint32_t task_constfields[1] = { 0b00000000000010000000000000000000 }; + const static uint32_t task_atomicfields[1] = { 0b00000111100000000000000010000000 }; + jl_task_type->name->constfields = task_constfields; jl_task_type->name->atomicfields = task_atomicfields; tv = jl_svec2(tvar("A"), tvar("R")); diff --git a/src/julia.h b/src/julia.h index 6c0dd700f9472..a9864aad16ccc 100644 --- a/src/julia.h +++ b/src/julia.h @@ -2276,16 +2276,25 @@ typedef struct _jl_task_t { jl_value_t *result; jl_value_t *scope; jl_function_t *start; - // 4 byte padding on 32-bit systems - // uint32_t padding0; - uint64_t rngState[JL_RNG_SIZE]; _Atomic(uint8_t) _state; uint8_t sticky; // record whether this Task can be migrated to a new thread - _Atomic(uint8_t) _isexception; // set if `result` is an exception to throw or that we exited with - // 1 byte padding - // uint8_t padding1; - // multiqueue priority uint16_t priority; + _Atomic(uint8_t) _isexception; // set if `result` is an exception to throw or that we exited with + uint8_t pad0[3]; + // === 64 bytes (cache line) + uint64_t rngState[JL_RNG_SIZE]; + // flag indicating whether or not to record timing metrics for this task + uint8_t metrics_enabled; + uint8_t pad1[3]; + // timestamp this task first entered the run queue + _Atomic(uint64_t) first_enqueued_at; + // timestamp this task was most recently scheduled to run + _Atomic(uint64_t) last_started_running_at; + // time this task has spent running; updated when it yields or finishes. + _Atomic(uint64_t) running_time_ns; + // === 64 bytes (cache line) + // timestamp this task finished (i.e. entered state DONE or FAILED). + _Atomic(uint64_t) finished_at; // hidden state: // cached floating point environment @@ -2612,6 +2621,9 @@ JL_DLLEXPORT int jl_generating_output(void) JL_NOTSAFEPOINT; #define JL_TRIM_UNSAFE 2 #define JL_TRIM_UNSAFE_WARN 3 +#define JL_OPTIONS_TASK_METRICS_OFF 0 +#define JL_OPTIONS_TASK_METRICS_ON 1 + // Version information #include // Generated file diff --git a/src/julia_internal.h b/src/julia_internal.h index 2178f603441e0..4741316093f95 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -316,6 +316,9 @@ extern JL_DLLEXPORT _Atomic(uint8_t) jl_measure_compile_time_enabled; extern JL_DLLEXPORT _Atomic(uint64_t) jl_cumulative_compile_time; extern JL_DLLEXPORT _Atomic(uint64_t) jl_cumulative_recompile_time; +// Global *atomic* integer controlling *process-wide* task timing. +extern JL_DLLEXPORT _Atomic(uint8_t) jl_task_metrics_enabled; + #define jl_return_address() ((uintptr_t)__builtin_return_address(0)) STATIC_INLINE uint32_t jl_int32hash_fast(uint32_t a) diff --git a/src/task.c b/src/task.c index 5e1172a96a409..1a50d6fcbcf65 100644 --- a/src/task.c +++ b/src/task.c @@ -313,6 +313,13 @@ void JL_NORETURN jl_finish_task(jl_task_t *ct) { JL_PROBE_RT_FINISH_TASK(ct); JL_SIGATOMIC_BEGIN(); + if (ct->metrics_enabled) { + // [task] user_time -finished-> wait_time + assert(jl_atomic_load_relaxed(&ct->first_enqueued_at) != 0); + uint64_t now = jl_hrtime(); + jl_atomic_store_relaxed(&ct->finished_at, now); + jl_atomic_fetch_add_relaxed(&ct->running_time_ns, now - jl_atomic_load_relaxed(&ct->last_started_running_at)); + } if (jl_atomic_load_relaxed(&ct->_isexception)) jl_atomic_store_release(&ct->_state, JL_TASK_STATE_FAILED); else @@ -1146,6 +1153,11 @@ JL_DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, jl_value_t *completion t->ptls = NULL; t->world_age = ct->world_age; t->reentrant_timing = 0; + t->metrics_enabled = jl_atomic_load_relaxed(&jl_task_metrics_enabled) != 0; + jl_atomic_store_relaxed(&t->first_enqueued_at, 0); + jl_atomic_store_relaxed(&t->last_started_running_at, 0); + jl_atomic_store_relaxed(&t->running_time_ns, 0); + jl_atomic_store_relaxed(&t->finished_at, 0); jl_timing_task_init(t); if (t->ctx.copy_stack) @@ -1245,6 +1257,12 @@ CFI_NORETURN fesetenv(&ct->fenv); ct->ctx.started = 1; + if (ct->metrics_enabled) { + // [task] wait_time -started-> user_time + assert(jl_atomic_load_relaxed(&ct->first_enqueued_at) != 0); + assert(jl_atomic_load_relaxed(&ct->last_started_running_at) == 0); + jl_atomic_store_relaxed(&ct->last_started_running_at, jl_hrtime()); + } JL_PROBE_RT_START_TASK(ct); jl_timing_block_task_enter(ct, ptls, NULL); if (jl_atomic_load_relaxed(&ct->_isexception)) { @@ -1596,6 +1614,19 @@ jl_task_t *jl_init_root_task(jl_ptls_t ptls, void *stack_lo, void *stack_hi) ct->ptls = ptls; ct->world_age = 1; // OK to run Julia code on this task ct->reentrant_timing = 0; + jl_atomic_store_relaxed(&ct->running_time_ns, 0); + jl_atomic_store_relaxed(&ct->finished_at, 0); + ct->metrics_enabled = jl_atomic_load_relaxed(&jl_task_metrics_enabled) != 0; + if (ct->metrics_enabled) { + // [task] created -started-> user_time + uint64_t now = jl_hrtime(); + jl_atomic_store_relaxed(&ct->first_enqueued_at, now); + jl_atomic_store_relaxed(&ct->last_started_running_at, now); + } + else { + jl_atomic_store_relaxed(&ct->first_enqueued_at, 0); + jl_atomic_store_relaxed(&ct->last_started_running_at, 0); + } ptls->root_task = ct; jl_atomic_store_relaxed(&ptls->current_task, ct); JL_GC_PROMISE_ROOTED(ct); diff --git a/src/threading.c b/src/threading.c index 8f0dfb3330885..ac9cc276d613a 100644 --- a/src/threading.c +++ b/src/threading.c @@ -49,6 +49,8 @@ JL_DLLEXPORT _Atomic(uint8_t) jl_measure_compile_time_enabled = 0; JL_DLLEXPORT _Atomic(uint64_t) jl_cumulative_compile_time = 0; JL_DLLEXPORT _Atomic(uint64_t) jl_cumulative_recompile_time = 0; +JL_DLLEXPORT _Atomic(uint8_t) jl_task_metrics_enabled = 0; + JL_DLLEXPORT void *jl_get_ptls_states(void) { // mostly deprecated: use current_task instead diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index cc3f8950f0dc0..5df174694049d 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -783,6 +783,15 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no` "Int(Base.JLOptions().fast_math)"`)) == JL_OPTIONS_FAST_MATH_DEFAULT end + let JL_OPTIONS_TASK_METRICS_OFF = 0, JL_OPTIONS_TASK_METRICS_ON = 1 + @test parse(Int,readchomp(`$exename -E + "Int(Base.JLOptions().task_metrics)"`)) == JL_OPTIONS_TASK_METRICS_OFF + @test parse(Int, readchomp(`$exename --task-metrics=yes -E + "Int(Base.JLOptions().task_metrics)"`)) == JL_OPTIONS_TASK_METRICS_ON + @test !parse(Bool, readchomp(`$exename -E "current_task().metrics_enabled"`)) + @test parse(Bool, readchomp(`$exename --task-metrics=yes -E "current_task().metrics_enabled"`)) + end + # --worker takes default / custom as argument (default/custom arguments # tested in test/parallel.jl) @test errors_not_signals(`$exename --worker=true`) diff --git a/test/core.jl b/test/core.jl index 63952e8728e1e..ba1803a137392 100644 --- a/test/core.jl +++ b/test/core.jl @@ -25,6 +25,7 @@ for (T, c) in ( (TypeVar, [:name, :ub, :lb]), (Core.Memory, [:length, :ptr]), (Core.GenericMemoryRef, [:mem, :ptr_or_offset]), + (Task, [:metrics_enabled]), ) @test Set((fieldname(T, i) for i in 1:fieldcount(T) if isconst(T, i))) == Set(c) end @@ -42,7 +43,7 @@ for (T, c) in ( (DataType, [:types, :layout]), (Core.Memory, []), (Core.GenericMemoryRef, []), - (Task, [:_state]) + (Task, [:_state, :running_time_ns, :finished_at, :first_enqueued_at, :last_started_running_at]), ) @test Set((fieldname(T, i) for i in 1:fieldcount(T) if Base.isfieldatomic(T, i))) == Set(c) end diff --git a/test/threads_exec.jl b/test/threads_exec.jl index ac54dd009390c..d77cf06905f44 100644 --- a/test/threads_exec.jl +++ b/test/threads_exec.jl @@ -3,6 +3,7 @@ using Test using Base.Threads using Base.Threads: SpinLock, threadpoolsize +using LinearAlgebra: peakflops # for cfunction_closure include("testenv.jl") @@ -1312,4 +1313,227 @@ end end end end + +@testset "Base.Experimental.task_metrics" begin + t = Task(() -> nothing) + @test_throws "const field" t.metrics_enabled = true + is_task_metrics_enabled() = fetch(Threads.@spawn current_task().metrics_enabled) + @test !is_task_metrics_enabled() + try + @testset "once" begin + Base.Experimental.task_metrics(true) + @test is_task_metrics_enabled() + Base.Experimental.task_metrics(false) + @test !is_task_metrics_enabled() + end + @testset "multiple" begin + Base.Experimental.task_metrics(true) # 1 + Base.Experimental.task_metrics(true) # 2 + Base.Experimental.task_metrics(true) # 3 + @test is_task_metrics_enabled() + Base.Experimental.task_metrics(false) # 2 + @test is_task_metrics_enabled() + Base.Experimental.task_metrics(false) # 1 + @test is_task_metrics_enabled() + @sync for i in 1:5 # 0 (not negative) + Threads.@spawn Base.Experimental.task_metrics(false) + end + @test !is_task_metrics_enabled() + Base.Experimental.task_metrics(true) # 1 + @test is_task_metrics_enabled() + end + finally + while is_task_metrics_enabled() + Base.Experimental.task_metrics(false) + end + end +end + +@testset "task time counters" begin + @testset "enabled" begin + try + Base.Experimental.task_metrics(true) + start_time = time_ns() + t = Threads.@spawn peakflops() + wait(t) + end_time = time_ns() + wall_time_delta = end_time - start_time + @test t.metrics_enabled + @test Base.Experimental.task_running_time_ns(t) > 0 + @test Base.Experimental.task_wall_time_ns(t) > 0 + @test Base.Experimental.task_wall_time_ns(t) >= Base.Experimental.task_running_time_ns(t) + @test wall_time_delta > Base.Experimental.task_wall_time_ns(t) + finally + Base.Experimental.task_metrics(false) + end + end + @testset "disabled" begin + t = Threads.@spawn peakflops() + wait(t) + @test !t.metrics_enabled + @test isnothing(Base.Experimental.task_running_time_ns(t)) + @test isnothing(Base.Experimental.task_wall_time_ns(t)) + end + @testset "task not run" begin + t1 = Task(() -> nothing) + @test !t1.metrics_enabled + @test isnothing(Base.Experimental.task_running_time_ns(t1)) + @test isnothing(Base.Experimental.task_wall_time_ns(t1)) + try + Base.Experimental.task_metrics(true) + t2 = Task(() -> nothing) + @test t2.metrics_enabled + @test Base.Experimental.task_running_time_ns(t2) == 0 + @test Base.Experimental.task_wall_time_ns(t2) == 0 + finally + Base.Experimental.task_metrics(false) + end + end + @testset "task failure" begin + try + Base.Experimental.task_metrics(true) + t = Threads.@spawn error("this task failed") + @test_throws "this task failed" wait(t) + @test Base.Experimental.task_running_time_ns(t) > 0 + @test Base.Experimental.task_wall_time_ns(t) > 0 + @test Base.Experimental.task_wall_time_ns(t) >= Base.Experimental.task_running_time_ns(t) + finally + Base.Experimental.task_metrics(false) + end + end + @testset "direct yield(t)" begin + try + Base.Experimental.task_metrics(true) + start = time_ns() + t_outer = Threads.@spawn begin + t_inner = Task(() -> peakflops()) + t_inner.sticky = false + # directly yield to `t_inner` rather calling `schedule(t_inner)` + yield(t_inner) + wait(t_inner) + @test Base.Experimental.task_running_time_ns(t_inner) > 0 + @test Base.Experimental.task_wall_time_ns(t_inner) > 0 + @test Base.Experimental.task_wall_time_ns(t_inner) >= Base.Experimental.task_running_time_ns(t_inner) + end + wait(t_outer) + delta = time_ns() - start + @test Base.Experimental.task_running_time_ns(t_outer) > 0 + @test Base.Experimental.task_wall_time_ns(t_outer) > 0 + @test Base.Experimental.task_wall_time_ns(t_outer) >= Base.Experimental.task_running_time_ns(t_outer) + @test Base.Experimental.task_wall_time_ns(t_outer) < delta + finally + Base.Experimental.task_metrics(false) + end + end + @testset "bad schedule" begin + try + Base.Experimental.task_metrics(true) + t1 = Task((x) -> 1) + schedule(t1) # MethodError + yield() + @assert istaskfailed(t1) + @test Base.Experimental.task_running_time_ns(t1) > 0 + @test Base.Experimental.task_wall_time_ns(t1) > 0 + foo(a, b) = a + b + t2 = Task(() -> (peakflops(); foo(wait()))) + schedule(t2) + yield() + @assert istaskstarted(t1) && !istaskdone(t2) + schedule(t2, 1) + yield() + @assert istaskfailed(t2) + @test Base.Experimental.task_running_time_ns(t2) > 0 + @test Base.Experimental.task_wall_time_ns(t2) > 0 + finally + Base.Experimental.task_metrics(false) + end + end + @testset "continuously update until task done" begin + try + Base.Experimental.task_metrics(true) + last_running_time = Ref(typemax(Int)) + last_wall_time = Ref(typemax(Int)) + t = Threads.@spawn begin + running_time = Base.Experimental.task_running_time_ns() + wall_time = Base.Experimental.task_wall_time_ns() + for _ in 1:5 + x = time_ns() + while time_ns() < x + 100 + end + new_running_time = Base.Experimental.task_running_time_ns() + new_wall_time = Base.Experimental.task_wall_time_ns() + @test new_running_time > running_time + @test new_wall_time > wall_time + running_time = new_running_time + wall_time = new_wall_time + end + last_running_time[] = running_time + last_wall_time[] = wall_time + end + wait(t) + final_running_time = Base.Experimental.task_running_time_ns(t) + final_wall_time = Base.Experimental.task_wall_time_ns(t) + @test last_running_time[] < final_running_time + @test last_wall_time[] < final_wall_time + # ensure many more tasks are run to make sure the counters are + # not being updated after a task is done e.g. only when a new task is found + @sync for _ in 1:Threads.nthreads() + Threads.@spawn rand() + end + @test final_running_time == Base.Experimental.task_running_time_ns(t) + @test final_wall_time == Base.Experimental.task_wall_time_ns(t) + finally + Base.Experimental.task_metrics(false) + end + end +end + +@testset "task time counters: lots of spawns" begin + using Dates + try + Base.Experimental.task_metrics(true) + # create more tasks than we have threads. + # - all tasks must have: cpu time <= wall time + # - some tasks must have: cpu time < wall time + # - summing across all tasks we must have: total cpu time <= available cpu time + n_tasks = 2 * Threads.nthreads(:default) + cpu_times = Vector{UInt64}(undef, n_tasks) + wall_times = Vector{UInt64}(undef, n_tasks) + start_time = time_ns() + @sync begin + for i in 1:n_tasks + start_time_i = time_ns() + task_i = Threads.@spawn peakflops() + Threads.@spawn begin + wait(task_i) + end_time_i = time_ns() + wall_time_delta_i = end_time_i - start_time_i + cpu_times[$i] = cpu_time_i = Base.Experimental.task_running_time_ns(task_i) + wall_times[$i] = wall_time_i = Base.Experimental.task_wall_time_ns(task_i) + # task should have recorded some cpu-time and some wall-time + @test cpu_time_i > 0 + @test wall_time_i > 0 + # task cpu-time cannot be greater than its wall-time + @test wall_time_i >= cpu_time_i + # task wall-time must be less than our manually measured wall-time + # between calling `@spawn` and returning from `wait`. + @test wall_time_delta_i > wall_time_i + end + end + end + end_time = time_ns() + wall_time_delta = (end_time - start_time) + available_cpu_time = wall_time_delta * Threads.nthreads(:default) + summed_cpu_time = sum(cpu_times) + # total CPU time from all tasks can't exceed what was actually available. + @test available_cpu_time > summed_cpu_time + # some tasks must have cpu-time less than their wall-time, because we had more tasks + # than threads. + summed_wall_time = sum(wall_times) + @test summed_wall_time > summed_cpu_time + finally + Base.Experimental.task_metrics(false) + end +end + end # main testset From 3a68b035ccbc4837448119099e059defaa6d5b98 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 6 Dec 2024 21:58:52 -0700 Subject: [PATCH 037/342] Fully outline all GlobalRefs (#56746) This is an alternative to #56714 that goes in the opposite direction - just outline all GlobalRefs during lowering. It is a lot simpler that #56714 at the cost of some size increase. Numbers: sys.so .ldata size: This PR: 159.8 MB Master: 158.9 MB I don't have numbers of #56714, because it's not fully complete. Additionally, it's possible that restricting GlobalRefs from arguments position would let us use a more efficient encoding in the future. --- Compiler/test/inference.jl | 9 +++--- doc/src/base/reflection.md | 10 ++++--- src/ast.c | 37 ----------------------- src/jlfrontend.scm | 1 - src/julia-syntax.scm | 1 - stdlib/Test/src/Test.jl | 5 ++-- test/core.jl | 61 ++++++++++++++++++++++++-------------- test/staged.jl | 12 ++++---- 8 files changed, 57 insertions(+), 79 deletions(-) diff --git a/Compiler/test/inference.jl b/Compiler/test/inference.jl index b3099897faf51..c8b599adb1323 100644 --- a/Compiler/test/inference.jl +++ b/Compiler/test/inference.jl @@ -3031,14 +3031,13 @@ end # issue #28279 # ensure that lowering doesn't move these into statement position, which would require renumbering -using Base: +, - -function f28279(b::Bool) +@eval function f28279(b::Bool) let i = 1 - while i > b - i -= 1 + while $(>)(i, b) + i = $(-)(i, 1) end if b end - return i + 1 + return $(+)(i, 1) end end code28279 = code_lowered(f28279, (Bool,))[1].code diff --git a/doc/src/base/reflection.md b/doc/src/base/reflection.md index 9228fb38322df..d88c3c8b0d0cf 100644 --- a/doc/src/base/reflection.md +++ b/doc/src/base/reflection.md @@ -100,10 +100,12 @@ as assignments, branches, and calls: ```jldoctest; setup = (using Base: +, sin) julia> Meta.lower(@__MODULE__, :( [1+2, sin(0.5)] )) :($(Expr(:thunk, CodeInfo( -1 ─ %1 = dynamic 1 + 2 -│ %2 = dynamic sin(0.5) -│ %3 = dynamic Base.vect(%1, %2) -└── return %3 +1 ─ %1 = :+ +│ %2 = dynamic (%1)(1, 2) +│ %3 = sin +│ %4 = dynamic (%3)(0.5) +│ %5 = dynamic Base.vect(%2, %4) +└── return %5 )))) ``` diff --git a/src/ast.c b/src/ast.c index 474c0661f5230..959bac26c2c15 100644 --- a/src/ast.c +++ b/src/ast.c @@ -181,42 +181,6 @@ static value_t fl_defined_julia_global(fl_context_t *fl_ctx, value_t *args, uint return (bpart != NULL && decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)) == BINDING_KIND_GLOBAL) ? fl_ctx->T : fl_ctx->F; } -static value_t fl_nothrow_julia_global(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) -{ - // tells whether a var is defined, in the sense that accessing it is nothrow - // can take either a symbol or a module and a symbol - jl_ast_context_t *ctx = jl_ast_ctx(fl_ctx); - jl_module_t *mod = ctx->module; - jl_sym_t *var = NULL; - if (nargs == 1) { - (void)tosymbol(fl_ctx, args[0], "nothrow-julia-global"); - var = scmsym_to_julia(fl_ctx, args[0]); - } - else { - argcount(fl_ctx, "nothrow-julia-global", nargs, 2); - value_t argmod = args[0]; - if (iscvalue(argmod) && cv_class((cvalue_t*)ptr(argmod)) == jl_ast_ctx(fl_ctx)->jvtype) { - mod = *(jl_module_t**)cv_data((cvalue_t*)ptr(argmod)); - JL_GC_PROMISE_ROOTED(mod); - } else { - if (!iscons(argmod) || !issymbol(car_(argmod)) || scmsym_to_julia(fl_ctx, car_(argmod)) != jl_thismodule_sym) { - lerrorf(fl_ctx, fl_ctx->ArgError, "nothrow-julia-global: Unknown globalref module kind"); - } - } - (void)tosymbol(fl_ctx, args[1], "nothrow-julia-global"); - var = scmsym_to_julia(fl_ctx, args[1]); - } - jl_binding_t *b = jl_get_module_binding(mod, var, 0); - jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - jl_ptr_kind_union_t pku = jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); - if (!bpart) - return fl_ctx->F; - if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) - return fl_ctx->F; - return (jl_bkind_is_some_constant(decode_restriction_kind(pku)) ? - decode_restriction_value(pku) : jl_atomic_load_relaxed(&b->value)) != NULL ? fl_ctx->T : fl_ctx->F; -} - // Used to generate a unique suffix for a given symbol (e.g. variable or type name) // first argument contains a stack of method definitions seen so far by `closure-convert` in flisp. // if the top of the stack is non-NIL, we use it to augment the suffix so that it becomes @@ -288,7 +252,6 @@ static jl_value_t *scm_to_julia_(fl_context_t *fl_ctx, value_t e, jl_module_t *m static const builtinspec_t julia_flisp_ast_ext[] = { { "defined-julia-global", fl_defined_julia_global }, // TODO: can we kill this safepoint - { "nothrow-julia-global", fl_nothrow_julia_global }, { "current-julia-module-counter", fl_module_unique_name }, { "julia-scalar?", fl_julia_scalar }, { NULL, NULL } diff --git a/src/jlfrontend.scm b/src/jlfrontend.scm index 3d46940d6fcbb..9c69da199c0cd 100644 --- a/src/jlfrontend.scm +++ b/src/jlfrontend.scm @@ -31,7 +31,6 @@ ;; this is overwritten when we run in actual julia (define (defined-julia-global v) #f) -(define (nothrow-julia-global v) #f) ;; parser entry points diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index c7ca5d553bb31..c522a565f462a 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -4356,7 +4356,6 @@ f(x) = yt(x) (define (valid-ir-argument? e) (or (simple-atom? e) - (and (globalref? e) (nothrow-julia-global (cadr e) (caddr e))) (and (pair? e) (memq (car e) '(quote inert top core slot static_parameter))))) diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index 7c985828d47f2..464cb2ac9de9c 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -1965,8 +1965,9 @@ Arguments #self#::Core.Const(f) a::Int64 Body::UNION{FLOAT64, INT64} -1 ─ %1 = (a > 1)::Bool -└── goto #3 if not %1 +1 ─ %1 = :>::Core.Const(>) +│ %2 = (%1)(a, 1)::Bool +└── goto #3 if not %2 2 ─ return 1 3 ─ return 1.0 diff --git a/test/core.jl b/test/core.jl index ba1803a137392..7e4f655222ea5 100644 --- a/test/core.jl +++ b/test/core.jl @@ -7435,6 +7435,7 @@ end @test isa(Core.eval(@__MODULE__, :(Bar31062(()))), Bar31062) @test precompile(identity, (Foo31062,)) +using Core: SSAValue ftype_eval = Ref(0) FieldTypeA = String FieldTypeE = UInt32 @@ -7458,27 +7459,41 @@ let fc = FieldConvert(1.0, [2.0], 0x3, 0x4, 0x5) end @test ftype_eval[] == 1 let code = code_lowered(FieldConvert)[1].code - local fc_global_ssa, sp1_ssa, apply_type_ssa, field_type_ssa, - field_type2_ssa, field_type4_ssa, field_type5_ssa, - slot_read_1, slot_read_2, slot_read_3, slot_read_4, - new_ssa - @test code[(fc_global_ssa = 1;)] == GlobalRef(@__MODULE__, :FieldConvert) - @test code[(sp1_ssa = 2;)] == Expr(:static_parameter, 1) - @test code[(apply_type_ssa = 3;)] == Expr(:call, GlobalRef(Core, :apply_type), Core.SSAValue(fc_global_ssa), GlobalRef(@__MODULE__, :FieldTypeA), Core.SSAValue(sp1_ssa)) - @test code[(field_type_ssa = 4;)] == Expr(:call, GlobalRef(Core, :fieldtype), Core.SSAValue(apply_type_ssa), 1) - @test code[10] == Expr(:(=), Core.SlotNumber(10), Expr(:call, GlobalRef(Base, :convert), Core.SSAValue(field_type_ssa), Core.SlotNumber(10))) - @test code[(slot_read_1 = 11;)] == Core.SlotNumber(10) - @test code[(field_type2_ssa = 12;)] == Expr(:call, GlobalRef(Core, :fieldtype), Core.SSAValue(apply_type_ssa), 2) - @test code[18] == Expr(:(=), Core.SlotNumber(9), Expr(:call, GlobalRef(Base, :convert), Core.SSAValue(field_type2_ssa), Core.SlotNumber(9))) - @test code[(slot_read_2 = 19;)] == Core.SlotNumber(9) - @test code[(field_type4_ssa = 20;)] == Expr(:call, GlobalRef(Core, :fieldtype), Core.SSAValue(apply_type_ssa), 4) - @test code[26] == Expr(:(=), Core.SlotNumber(8), Expr(:call, GlobalRef(Base, :convert), Core.SSAValue(field_type4_ssa), Core.SlotNumber(8))) - @test code[(slot_read_3 = 27;)] == Core.SlotNumber(8) - @test code[(field_type5_ssa = 28;)] == Expr(:call, GlobalRef(Core, :fieldtype), Core.SSAValue(apply_type_ssa), 5) - @test code[34] == Expr(:(=), Core.SlotNumber(7), Expr(:call, GlobalRef(Base, :convert), Core.SSAValue(field_type5_ssa), Core.SlotNumber(7))) - @test code[(slot_read_4 = 35;)] == Core.SlotNumber(7) - @test code[(new_ssa = 36;)] == Expr(:new, Core.SSAValue(apply_type_ssa), Core.SSAValue(slot_read_1), Core.SSAValue(slot_read_2), Core.SlotNumber(4), Core.SSAValue(slot_read_3), Core.SSAValue(slot_read_4)) - @test code[37] == Core.ReturnNode(Core.SSAValue(new_ssa)) + calls = Vector{Pair{SSAValue, Expr}}(undef, 0) + for i = 1:length(code) + expr = code[i] + if Meta.isexpr(expr, :call) || (Meta.isexpr(expr, :(=)) && Meta.isexpr(expr.args[2], :call)) + push!(calls, SSAValue(i)=>expr) + end + end + + function is_globalref(arg, gr) + while isa(arg, SSAValue) + arg = code[arg.id] + end + arg == gr + end + + # calls[1] + @test all(is_globalref.(calls[1][2].args[1:3], (GlobalRef(Core, :apply_type), GlobalRef(@__MODULE__, :FieldConvert), GlobalRef(@__MODULE__, :FieldTypeA)))) + + # calls[2] + @test all(is_globalref.(calls[2][2].args[1:1], (GlobalRef(Core, :fieldtype),))) + @test all(calls[2][2].args[2:3] .== (calls[1][1], 1)) + + # calls[3] - isa + + # calls[4] + let calle = calls[4][2] + @test Meta.isexpr(calle, :(=)) + call = calle.args[2] + @test is_globalref(call.args[1], GlobalRef(Base, :convert)) + @test call.args[2] == calls[2][1] + end + + # calls[5] + @test all(is_globalref.(calls[5][2].args[1:1], (GlobalRef(Core, :fieldtype),))) + @test all(calls[5][2].args[2:3] .== (calls[1][1], 2)) end # Issue #32820 @@ -8156,7 +8171,7 @@ end @test Core.Compiler.is_foldable(Base.infer_effects(length, (Core.SimpleVector,))) @test Core.Compiler.is_foldable(Base.infer_effects(getindex, (Core.SimpleVector,Int))) -# Test that a nothrow-globalref doesn't get outlined during lowering +# Test that a the lowering of nothrow globalref module WellKnownGlobal global well_known = 1 end @@ -8165,7 +8180,7 @@ macro insert_global() end check_globalref_lowering() = @insert_global let src = code_lowered(check_globalref_lowering)[1] - @test length(src.code) == 2 + @test length(src.code) == 4 end # Test correctness of widen_diagonal diff --git a/test/staged.jl b/test/staged.jl index 1b28144639f97..6cb99950a7bb2 100644 --- a/test/staged.jl +++ b/test/staged.jl @@ -270,12 +270,12 @@ end # PR #23168 -function f23168(a, x) +@eval function f23168(a, x) push!(a, 1) if @generated - :(y = x + x) + :(y = $(+)(x, x)) else - y = 2x + y = $(*)(2, x) end push!(a, y) if @generated @@ -290,9 +290,9 @@ end let a = Any[] @test f23168(a, 3) == (6, Int) @test a == [1, 6, 3] - @test occursin(" + ", string(code_lowered(f23168, (Vector{Any},Int)))) - @test occursin("2 * ", string(Base.uncompressed_ir(first(methods(f23168))))) - @test occursin("2 * ", string(code_lowered(f23168, (Vector{Any},Int), generated=false))) + @test occursin("(+)(", string(code_lowered(f23168, (Vector{Any},Int)))) + @test occursin("(*)(2", string(Base.uncompressed_ir(first(methods(f23168))))) + @test occursin("(*)(2", string(code_lowered(f23168, (Vector{Any},Int), generated=false))) @test occursin("Base.add_int", string(code_typed(f23168, (Vector{Any},Int)))) end From 6cb9f04c1ec562f800669ba13a9a096203aea7cf Mon Sep 17 00:00:00 2001 From: Julius Krumbiegel <22495855+jkrumbiegel@users.noreply.github.com> Date: Sat, 7 Dec 2024 19:56:09 +0100 Subject: [PATCH 038/342] Add #54800 to NEWS (#56774) Show glyphs for latex or emoji shortcodes being suggested in the REPL --- NEWS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS.md b/NEWS.md index 641b84b480bb4..2ad92701dd638 100644 --- a/NEWS.md +++ b/NEWS.md @@ -171,6 +171,7 @@ Standard library changes in the REPL will now issue a warning the first time occurs. ([#54872]) - When an object is printed automatically (by being returned in the REPL), its display is now truncated after printing 20 KiB. This does not affect manual calls to `show`, `print`, and so forth. ([#53959]) +- Backslash completions now print the respective glyph or emoji next to each matching backslash shortcode. ([#54800]) #### SuiteSparse From c897a13c45c1222b4b16cf941348beef25f97ee0 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Sat, 7 Dec 2024 19:43:15 -0300 Subject: [PATCH 039/342] Add the actual datatype to the heapsnapshot. This groups objects of the same type together (#56596) --- src/gc-heap-snapshot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gc-heap-snapshot.cpp b/src/gc-heap-snapshot.cpp index 72eb17115f4c7..f3793939610b5 100644 --- a/src/gc-heap-snapshot.cpp +++ b/src/gc-heap-snapshot.cpp @@ -380,7 +380,7 @@ size_t record_node_to_gc_snapshot(jl_value_t *a) JL_NOTSAFEPOINT ios_mem(&str_, 0); JL_STREAM* str = (JL_STREAM*)&str_; jl_static_show(str, (jl_value_t*)type); - + node_type = StringRef((const char*)str_.buf, str_.size); name = StringRef((const char*)str_.buf, str_.size); } From 54755adb1d96539fdd125ea9c442d0fcf206d5cc Mon Sep 17 00:00:00 2001 From: clonefetch <166312854+clonefetch@users.noreply.github.com> Date: Sun, 8 Dec 2024 21:21:58 +0800 Subject: [PATCH 040/342] Fix typos in docstring, comments, and news (#56778) --- NEWS.md | 2 +- base/deprecated.jl | 2 +- base/pointer.jl | 2 +- base/sysimg.jl | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index 2ad92701dd638..78d1d9b4bc7b8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -36,7 +36,7 @@ Language changes may pave the way for inference to be able to intelligently re-use the old results, once the new method is deleted. ([#53415]) - - Macro expansion will no longer eagerly recurse into into `Expr(:toplevel)` + - Macro expansion will no longer eagerly recurse into `Expr(:toplevel)` expressions returned from macros. Instead, macro expansion of `:toplevel` expressions will be delayed until evaluation time. This allows a later expression within a given `:toplevel` expression to make use of macros diff --git a/base/deprecated.jl b/base/deprecated.jl index 84ef89e44b473..cffff05d954d1 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -4,7 +4,7 @@ # Instructions for Julia Core Developers: # 1. When making a breaking change that is known to be depnedet upon by an # important and closely coupled package, decide on a unique `change_name` -# for your PR and add it to the list below. In general, is is better to +# for your PR and add it to the list below. In general, it is better to # err on the side of caution and assign a `change_name` even if it is not # clear that it is required. `change_name`s may also be assigned after the # fact in a separate PR. (Note that this may cause packages to misbehave diff --git a/base/pointer.jl b/base/pointer.jl index b1580ef17d562..de2f413d8f881 100644 --- a/base/pointer.jl +++ b/base/pointer.jl @@ -169,7 +169,7 @@ The `unsafe` prefix on this function indicates that no validation is performed o pointer `p` to ensure that it is valid. Like C, the programmer is responsible for ensuring that referenced memory is not freed or garbage collected while invoking this function. Incorrect usage may segfault your program. Unlike C, storing memory region allocated as -different type may be valid provided that that the types are compatible. +different type may be valid provided that the types are compatible. !!! compat "Julia 1.10" The `order` argument is available as of Julia 1.10. diff --git a/base/sysimg.jl b/base/sysimg.jl index e57ec1c99bfe6..42f54a849f157 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -1,6 +1,6 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -# Can be be loaded on top of either an existing system image built from +# Can be loaded on top of either an existing system image built from # `Base_compiler.jl` or standalone, in which case we will build it now. let had_compiler = isdefined(Main, :Base) if had_compiler; else From e0656ac017a427f739f985809017a33c269b3af1 Mon Sep 17 00:00:00 2001 From: Lilith Orion Hafner Date: Sun, 8 Dec 2024 15:48:54 -0600 Subject: [PATCH 041/342] Add sort for NTuples (#54494) This is partially a reland of #46104, but without the controversial `sort(x) = sort!(copymutable(x))` and with some extensibility improvements. Implements #54489. --- NEWS.md | 1 + base/sort.jl | 43 ++++++++++++++++++++++++++++++++++++++++--- test/sorting.jl | 30 ++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/NEWS.md b/NEWS.md index 78d1d9b4bc7b8..3c893566c7219 100644 --- a/NEWS.md +++ b/NEWS.md @@ -110,6 +110,7 @@ New library features * `invoke` now supports passing a Method instead of a type signature making this interface somewhat more flexible for certain uncommon use cases ([#56692]). * `invoke` now supports passing a CodeInstance instead of a type, which can enable certain compiler plugin workflows ([#56660]). +* `sort` now supports `NTuple`s ([#54494]) Standard library changes ------------------------ diff --git a/base/sort.jl b/base/sort.jl index 29e67a3eb8d8c..f9d74f626fe58 100644 --- a/base/sort.jl +++ b/base/sort.jl @@ -4,7 +4,7 @@ module Sort using Base.Order -using Base: copymutable, midpoint, require_one_based_indexing, uinttype, +using Base: copymutable, midpoint, require_one_based_indexing, uinttype, tail, sub_with_overflow, add_with_overflow, OneTo, BitSigned, BitIntegerType, top_set_bit import Base: @@ -1482,8 +1482,9 @@ InitialOptimizations(next) = SubArrayOptimization( `DefaultStable` is an algorithm which indicates that a fast, general purpose sorting algorithm should be used, but does not specify exactly which algorithm. -Currently, it is composed of two parts: the [`InitialOptimizations`](@ref) and a hybrid of -Radix, Insertion, Counting, Quick sorts. +Currently, when sorting short NTuples, this is an unrolled mergesort, and otherwise it is +composed of two parts: the [`InitialOptimizations`](@ref) and a hybrid of Radix, Insertion, +Counting, Quick sorts. We begin with MissingOptimization because it has no runtime cost when it is not triggered and can enable other optimizations to be applied later. For example, @@ -1619,6 +1620,7 @@ defalg(v::AbstractArray) = DEFAULT_STABLE defalg(v::AbstractArray{<:Union{Number, Missing}}) = DEFAULT_UNSTABLE defalg(v::AbstractArray{Missing}) = DEFAULT_UNSTABLE # for method disambiguation defalg(v::AbstractArray{Union{}}) = DEFAULT_UNSTABLE # for method disambiguation +defalg(v::NTuple) = DEFAULT_STABLE """ sort!(v; alg::Base.Sort.Algorithm=Base.Sort.defalg(v), lt=isless, by=identity, rev::Bool=false, order::Base.Order.Ordering=Base.Order.Forward) @@ -1757,6 +1759,41 @@ julia> v """ sort(v::AbstractVector; kws...) = sort!(copymutable(v); kws...) +function sort(x::NTuple; + alg::Algorithm=defalg(x), + lt=isless, + by=identity, + rev::Union{Bool,Nothing}=nothing, + order::Ordering=Forward, + scratch::Union{Vector, Nothing}=nothing) + # Can't do this check with type parameters because of https://github.com/JuliaLang/julia/issues/56698 + scratch === nothing || eltype(x) == eltype(scratch) || throw(ArgumentError("scratch has the wrong eltype")) + _sort(x, alg, ord(lt,by,rev,order), (;scratch))::typeof(x) +end +# Folks who want to hack internals can define a new _sort(x::NTuple, ::TheirAlg, o::Ordering) +# or _sort(x::NTuple{N, TheirType}, ::DefaultStable, o::Ordering) where N +function _sort(x::NTuple, a::Union{DefaultStable, DefaultUnstable}, o::Ordering, kw) + # The unrolled tuple sort is prohibitively slow to compile for length > 9. + # See https://github.com/JuliaLang/julia/pull/46104#issuecomment-1435688502 for benchmarks + if length(x) > 9 + v = copymutable(x) + _sort!(v, a, o, kw) + typeof(x)(v) + else + _mergesort(x, o) + end +end +_mergesort(x::Union{NTuple{0}, NTuple{1}}, o::Ordering) = x +function _mergesort(x::NTuple, o::Ordering) + a, b = Base.IteratorsMD.split(x, Val(length(x)>>1)) + merge(_mergesort(a, o), _mergesort(b, o), o) +end +merge(x::NTuple, y::NTuple{0}, o::Ordering) = x +merge(x::NTuple{0}, y::NTuple, o::Ordering) = y +merge(x::NTuple{0}, y::NTuple{0}, o::Ordering) = x # Method ambiguity +merge(x::NTuple, y::NTuple, o::Ordering) = + (lt(o, y[1], x[1]) ? (y[1], merge(x, tail(y), o)...) : (x[1], merge(tail(x), y, o)...)) + ## partialsortperm: the permutation to sort the first k elements of an array ## """ diff --git a/test/sorting.jl b/test/sorting.jl index 71af50429027a..e16b30de5bfc8 100644 --- a/test/sorting.jl +++ b/test/sorting.jl @@ -94,6 +94,22 @@ end vcat(2000, (x:x+99 for x in 1900:-100:100)..., 1:99) end +function tuple_sort_test(x) + @test issorted(sort(x)) + length(x) > 9 && return # length > 9 uses a vector fallback + @test 0 == @allocated sort(x) +end +@testset "sort(::NTuple)" begin + @test sort(()) == () + @test sort((9,8,3,3,6,2,0,8)) == (0,2,3,3,6,8,8,9) + @test sort((9,8,3,3,6,2,0,8), by=x->x÷3) == (2,0,3,3,8,6,8,9) + for i in 1:40 + tuple_sort_test(rand(NTuple{i, Float64})) + end + @test_throws MethodError sort((1,2,3.0)) + @test Base.infer_return_type(sort, Tuple{Tuple{Vararg{Int}}}) == Tuple{Vararg{Int}} +end + @testset "partialsort" begin @test partialsort([3,6,30,1,9],3) == 6 @test partialsort([3,6,30,1,9],3:4) == [6,9] @@ -913,6 +929,20 @@ end end @test sort([1,2,3], alg=MySecondAlg()) == [9,9,9] @test all(sort(v, alg=Base.Sort.InitialOptimizations(MySecondAlg())) .=== vcat(fill(9, 100), fill(missing, 10))) + + # Tuple extensions (custom alg) + @test_throws MethodError sort((1,2,3), alg=MyFirstAlg()) + Base.Sort._sort(v::NTuple, ::MyFirstAlg, o::Base.Order.Ordering, kw) = (17,2,9) + @test sort((1,2,3), alg=MyFirstAlg()) == (17,2,9) + + struct TupleFoo + x::Int + end + + # Tuple extensions (custom type) + @test_throws MethodError sort(TupleFoo.((3,1,2))) + Base.Sort._sort(v::NTuple{N, TupleFoo}, ::Base.Sort.DefaultStable, o::Base.Order.Ordering, kw) where N = v + @test sort(TupleFoo.((3,1,2))) === TupleFoo.((3,1,2)) end @testset "sort!(v, lo, hi, alg, order)" begin From dfe6a13e5038c8cbe0f1720d190629225ec1a19b Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 9 Dec 2024 16:41:30 -0500 Subject: [PATCH 042/342] precompile: don't waste memory on useless inferred code (#56749) We never have a reason to reference this data again since we already have native code generated for it, so it is simply wasting memory and download space. $ du -sh {old,new}/usr/share/julia/compiled 256M old 227M new --- Compiler/src/effects.jl | 1 + src/codegen.cpp | 8 ++++---- src/staticdata.c | 30 ++++++++++++++++++++++++++++-- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/Compiler/src/effects.jl b/Compiler/src/effects.jl index e521166fd61fa..9aea4cb204ec6 100644 --- a/Compiler/src/effects.jl +++ b/Compiler/src/effects.jl @@ -335,6 +335,7 @@ is_inaccessiblemem_or_argmemonly(effects::Effects) = effects.inaccessiblememonly is_consistent_overlay(effects::Effects) = effects.nonoverlayed === CONSISTENT_OVERLAY +# (sync this with codegen.cpp and staticdata.c effects_foldable functions) function encode_effects(e::Effects) return ((e.consistent % UInt32) << 0) | ((e.effect_free % UInt32) << 3) | diff --git a/src/codegen.cpp b/src/codegen.cpp index b9d42b9b5af16..21591acedc632 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -10124,10 +10124,10 @@ jl_llvm_functions_t jl_emit_codeinst( else if (jl_is_method(def) && // don't delete toplevel code def->source != NULL && // don't delete code from optimized opaque closures that can't be reconstructed inferred != jl_nothing && // and there is something to delete (test this before calling jl_ir_inlining_cost) - !effects_foldable(jl_atomic_load_relaxed(&codeinst->ipo_purity_bits)) && // don't delete code we may want for irinterp - ((jl_ir_inlining_cost(inferred) == UINT16_MAX) || // don't delete inlineable code - jl_atomic_load_relaxed(&codeinst->invoke) == jl_fptr_const_return_addr) && // unless it is constant - !(params.imaging_mode || jl_options.incremental)) { // don't delete code when generating a precompile file + ((!effects_foldable(jl_atomic_load_relaxed(&codeinst->ipo_purity_bits)) && // don't delete code we may want for irinterp + (jl_ir_inlining_cost(inferred) == UINT16_MAX) && // don't delete inlineable code + !jl_generating_output()) || // don't delete code when generating a precompile file, trading memory in the short term for avoiding likely duplicating inference work for aotcompile + jl_atomic_load_relaxed(&codeinst->invoke) == jl_fptr_const_return_addr)) { // unless it is constant (although this shouldn't have had code in the first place) // Never end up in a situation where the codeinst has no invoke, but also no source, so we never fall // through the cracks of SOURCE_MODE_ABI. jl_callptr_t expected = NULL; diff --git a/src/staticdata.c b/src/staticdata.c index 65584c015e228..1665b5be4ed0f 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -769,6 +769,16 @@ static uintptr_t jl_fptr_id(void *fptr) return *(uintptr_t*)pbp; } +static int effects_foldable(uint32_t effects) +{ + // N.B.: This needs to be kept in sync with Core.Compiler.is_foldable(effects, true) + return ((effects & 0x7) == 0) && // is_consistent(effects) + (((effects >> 10) & 0x03) == 0) && // is_noub(effects) + (((effects >> 3) & 0x03) == 0) && // is_effect_free(effects) + ((effects >> 6) & 0x01); // is_terminates(effects) +} + + // `jl_queue_for_serialization` adds items to `serialization_order` #define jl_queue_for_serialization(s, v) jl_queue_for_serialization_((s), (jl_value_t*)(v), 1, 0) static void jl_queue_for_serialization_(jl_serializer_state *s, jl_value_t *v, int recursive, int immediate) JL_GC_DISABLED; @@ -908,8 +918,24 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_ // TODO: if (ci in ci->defs->cache) record_field_change((jl_value_t**)&ci->next, NULL); } - if (jl_atomic_load_relaxed(&ci->inferred) && !is_relocatable_ci(&relocatable_ext_cis, ci)) - record_field_change((jl_value_t**)&ci->inferred, jl_nothing); + jl_value_t *inferred = jl_atomic_load_relaxed(&ci->inferred); + if (inferred && inferred != jl_nothing) { // disregard if there is nothing here to delete (e.g. builtins, unspecialized) + if (!is_relocatable_ci(&relocatable_ext_cis, ci)) + record_field_change((jl_value_t**)&ci->inferred, jl_nothing); + else if (jl_is_method(ci->def->def.method) && // don't delete toplevel code + ci->def->def.method->source) { // don't delete code from optimized opaque closures that can't be reconstructed (and builtins) + if (jl_atomic_load_relaxed(&ci->max_world) != ~(size_t)0 || // delete all code that cannot run + jl_atomic_load_relaxed(&ci->invoke) == jl_fptr_const_return) { // delete all code that just returns a constant + record_field_change((jl_value_t**)&ci->inferred, jl_nothing); + } + else if (native_functions && // don't delete any code if making a ji file + !effects_foldable(jl_atomic_load_relaxed(&ci->ipo_purity_bits)) && // don't delete code we may want for irinterp + jl_ir_inlining_cost(inferred) == UINT16_MAX) { // don't delete inlineable code + // delete the code now: if we thought it was worth keeping, it would have been converted to object code + record_field_change((jl_value_t**)&ci->inferred, jl_nothing); + } + } + } } if (immediate) // must be things that can be recursively handled, and valid as type parameters From 7192df7e900a6e4562e1670f544b8be8878ee359 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 9 Dec 2024 16:42:27 -0500 Subject: [PATCH 043/342] various globals cleanups (#56750) While doing some work on analyzing what code runs at toplevel, I found a few things to simplify or fix: - simplify float.jl loop not to call functions just defined to get back the value just stored there - add method to the correct checkbounds function (instead of a local) - missing world push/pop around jl_interpret_toplevel_thunk after #56509 - jl_lineno use maybe missed in #53799 - add some debugging dump for scm_to_julia_ mistakes --- base/float.jl | 13 ++++++++----- base/range.jl | 2 +- src/ast.c | 2 ++ src/interpreter.c | 3 --- src/toplevel.c | 25 ++++++++++++------------- 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/base/float.jl b/base/float.jl index c7230459d0822..faded5cd5978c 100644 --- a/base/float.jl +++ b/base/float.jl @@ -122,13 +122,16 @@ significand_mask(::Type{Float16}) = 0x03ff mantissa(x::T) where {T} = reinterpret(Unsigned, x) & significand_mask(T) for T in (Float16, Float32, Float64) - @eval significand_bits(::Type{$T}) = $(trailing_ones(significand_mask(T))) - @eval exponent_bits(::Type{$T}) = $(sizeof(T)*8 - significand_bits(T) - 1) - @eval exponent_bias(::Type{$T}) = $(Int(exponent_one(T) >> significand_bits(T))) + sb = trailing_ones(significand_mask(T)) + em = exponent_mask(T) + eb = Int(exponent_one(T) >> sb) + @eval significand_bits(::Type{$T}) = $(sb) + @eval exponent_bits(::Type{$T}) = $(sizeof(T)*8 - sb - 1) + @eval exponent_bias(::Type{$T}) = $(eb) # maximum float exponent - @eval exponent_max(::Type{$T}) = $(Int(exponent_mask(T) >> significand_bits(T)) - exponent_bias(T) - 1) + @eval exponent_max(::Type{$T}) = $(Int(em >> sb) - eb - 1) # maximum float exponent without bias - @eval exponent_raw_max(::Type{$T}) = $(Int(exponent_mask(T) >> significand_bits(T))) + @eval exponent_raw_max(::Type{$T}) = $(Int(em >> sb)) end """ diff --git a/base/range.jl b/base/range.jl index b05dddb025a7c..39428ab741955 100644 --- a/base/range.jl +++ b/base/range.jl @@ -954,7 +954,7 @@ function _getindex(v::UnitRange{T}, i::Integer) where {T<:OverflowSafe} end let BitInteger64 = Union{Int8,Int16,Int32,Int64,UInt8,UInt16,UInt32,UInt64} # for bootstrapping - function checkbounds(::Type{Bool}, v::StepRange{<:BitInteger64, <:BitInteger64}, i::BitInteger64) + global function checkbounds(::Type{Bool}, v::StepRange{<:BitInteger64, <:BitInteger64}, i::BitInteger64) res = widemul(step(v), i-oneunit(i)) + first(v) (0 < i) & ifelse(0 < step(v), res <= last(v), res >= last(v)) end diff --git a/src/ast.c b/src/ast.c index 959bac26c2c15..0f24d96393f2f 100644 --- a/src/ast.c +++ b/src/ast.c @@ -669,6 +669,8 @@ static jl_value_t *scm_to_julia_(fl_context_t *fl_ctx, value_t e, jl_module_t *m if (iscvalue(e) && cv_class((cvalue_t*)ptr(e)) == jl_ast_ctx(fl_ctx)->jvtype) { return *(jl_value_t**)cv_data((cvalue_t*)ptr(e)); } + fl_print(fl_ctx, ios_stderr, e); + ios_putc('\n', ios_stderr); jl_error("malformed tree"); } diff --git a/src/interpreter.c b/src/interpreter.c index fa4fba94a60a5..a465fe27f5084 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -893,10 +893,7 @@ jl_value_t *NOINLINE jl_interpret_toplevel_thunk(jl_module_t *m, jl_code_info_t s->mi = NULL; s->ci = NULL; JL_GC_ENABLEFRAME(s); - jl_task_t *ct = jl_current_task; - size_t last_age = ct->world_age; jl_value_t *r = eval_body(stmts, s, 0, 1); - ct->world_age = last_age; JL_GC_POP(); return r; } diff --git a/src/toplevel.c b/src/toplevel.c index 21737119af9a6..44b503d4e1463 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -1065,7 +1065,10 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val if (has_opaque) { jl_resolve_globals_in_ir((jl_array_t*)thk->code, m, NULL, 0); } + size_t world = jl_atomic_load_acquire(&jl_world_counter); + ct->world_age = world; result = jl_interpret_toplevel_thunk(m, thk); + ct->world_age = last_age; } JL_GC_POP(); @@ -1075,8 +1078,8 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val JL_DLLEXPORT jl_value_t *jl_toplevel_eval(jl_module_t *m, jl_value_t *v) { const char *filename = jl_filename; - int lieno = jl_lineno; - return jl_toplevel_eval_flex(m, v, 1, 0, &filename, &lieno); + int lineno = jl_lineno; + return jl_toplevel_eval_flex(m, v, 1, 0, &filename, &lineno); } // Check module `m` is open for `eval/include`, or throw an error. @@ -1177,14 +1180,13 @@ static jl_value_t *jl_parse_eval_all(jl_module_t *module, jl_value_t *text, jl_task_t *ct = jl_current_task; int last_lineno = jl_lineno; const char *last_filename = jl_filename; - size_t last_age = ct->world_age; int lineno = 0; jl_lineno = 0; const char *filename_str = jl_string_data(filename); jl_filename = filename_str; - int err = 0; JL_TRY { + size_t last_age = ct->world_age; ct->world_age = jl_atomic_load_acquire(&jl_world_counter); for (size_t i = 0; i < jl_expr_nargs(ast); i++) { expression = jl_exprarg(ast, i); @@ -1200,23 +1202,20 @@ static jl_value_t *jl_parse_eval_all(jl_module_t *module, jl_value_t *text, ct->world_age = jl_atomic_load_relaxed(&jl_world_counter); result = jl_toplevel_eval_flex(module, expression, 1, 1, &filename_str, &lineno); } + ct->world_age = last_age; } JL_CATCH { - result = jl_box_long(jl_lineno); // (ab)use result to root error line - err = 1; - goto finally; // skip jl_restore_excstack - } -finally: - ct->world_age = last_age; - jl_lineno = last_lineno; - jl_filename = last_filename; - if (err) { + result = jl_box_long(lineno); // (ab)use result to root error line + jl_lineno = last_lineno; + jl_filename = last_filename; if (jl_loaderror_type == NULL) jl_rethrow(); else jl_rethrow_other(jl_new_struct(jl_loaderror_type, filename, result, jl_current_exception(ct))); } + jl_lineno = last_lineno; + jl_filename = last_filename; JL_GC_POP(); return result; } From 32ea18ecfb545c6abae8013d133d683987b9e323 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Tue, 10 Dec 2024 03:51:46 -0500 Subject: [PATCH 044/342] Fix test report alignment (#56789) --- stdlib/Test/src/Test.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index 464cb2ac9de9c..3a60527a26e11 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -1194,7 +1194,7 @@ function print_test_results(ts::AbstractTestSet, depth_pad=0) duration_width = max(textwidth("Time"), textwidth(tc.duration)) # Calculate the alignment of the test result counts by # recursively walking the tree of test sets - align = max(get_alignment(ts, 0), textwidth("Test Summary:")) + align = max(get_alignment(ts, depth_pad), textwidth("Test Summary:")) # Print the outer test set header once printstyled(rpad("Test Summary:", align, " "), " |", " "; bold=true) if pass_width > 0 From 42bd79144ea5363ce7cd4c2d5b3785aaecb60f4b Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Tue, 10 Dec 2024 03:53:16 -0500 Subject: [PATCH 045/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?Pkg=20stdlib=20from=20d84a1a38b=20to=20e7c37f342=20(#56786)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Pkg-d84a1a38b6466fa7400e9ad2874a0ef963a10456.tar.gz/md5 | 1 - .../Pkg-d84a1a38b6466fa7400e9ad2874a0ef963a10456.tar.gz/sha512 | 1 - .../Pkg-e7c37f34293ab12051258828884755ea116b77df.tar.gz/md5 | 1 + .../Pkg-e7c37f34293ab12051258828884755ea116b77df.tar.gz/sha512 | 1 + stdlib/Pkg.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/Pkg-d84a1a38b6466fa7400e9ad2874a0ef963a10456.tar.gz/md5 delete mode 100644 deps/checksums/Pkg-d84a1a38b6466fa7400e9ad2874a0ef963a10456.tar.gz/sha512 create mode 100644 deps/checksums/Pkg-e7c37f34293ab12051258828884755ea116b77df.tar.gz/md5 create mode 100644 deps/checksums/Pkg-e7c37f34293ab12051258828884755ea116b77df.tar.gz/sha512 diff --git a/deps/checksums/Pkg-d84a1a38b6466fa7400e9ad2874a0ef963a10456.tar.gz/md5 b/deps/checksums/Pkg-d84a1a38b6466fa7400e9ad2874a0ef963a10456.tar.gz/md5 deleted file mode 100644 index f5f87b3f2fa9e..0000000000000 --- a/deps/checksums/Pkg-d84a1a38b6466fa7400e9ad2874a0ef963a10456.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -1a5c995237815e0d7d5ee1ec50006c1c diff --git a/deps/checksums/Pkg-d84a1a38b6466fa7400e9ad2874a0ef963a10456.tar.gz/sha512 b/deps/checksums/Pkg-d84a1a38b6466fa7400e9ad2874a0ef963a10456.tar.gz/sha512 deleted file mode 100644 index 839cd4704a135..0000000000000 --- a/deps/checksums/Pkg-d84a1a38b6466fa7400e9ad2874a0ef963a10456.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -2e0b984c8272fe4468e0b527698a58d5010ef3f18d38d862665902e5a0e0b7ba65d3085b3d9de367a7b48a216e71d1611687804254503b3905b7b4d217a00f2f diff --git a/deps/checksums/Pkg-e7c37f34293ab12051258828884755ea116b77df.tar.gz/md5 b/deps/checksums/Pkg-e7c37f34293ab12051258828884755ea116b77df.tar.gz/md5 new file mode 100644 index 0000000000000..6627dc3683c65 --- /dev/null +++ b/deps/checksums/Pkg-e7c37f34293ab12051258828884755ea116b77df.tar.gz/md5 @@ -0,0 +1 @@ +7024326f0c033e3da419ed217754fbed diff --git a/deps/checksums/Pkg-e7c37f34293ab12051258828884755ea116b77df.tar.gz/sha512 b/deps/checksums/Pkg-e7c37f34293ab12051258828884755ea116b77df.tar.gz/sha512 new file mode 100644 index 0000000000000..cfc9d5f30f0e8 --- /dev/null +++ b/deps/checksums/Pkg-e7c37f34293ab12051258828884755ea116b77df.tar.gz/sha512 @@ -0,0 +1 @@ +bef19838be850f027fb3dedadce0efa762cd64797809030210ec95830f538ced1b2aede3bd2ca5f32d489e2dc517b7c8e38307adcba194db417ce792437cfb56 diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 9ef9ca4b04376..50105c42c642c 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = master -PKG_SHA1 = d84a1a38b6466fa7400e9ad2874a0ef963a10456 +PKG_SHA1 = e7c37f34293ab12051258828884755ea116b77df PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 From 9d28a0604a3bfb4c3838ec9ac4ca0997c2b0834c Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Tue, 10 Dec 2024 06:20:39 -0700 Subject: [PATCH 046/342] Bump JuliaSyntax to 0.4.10 (#56110) --- deps/JuliaSyntax.version | 2 +- .../md5 | 1 - .../sha512 | 1 - .../md5 | 1 + .../sha512 | 1 + test/syntax.jl | 2 +- 6 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 deps/checksums/JuliaSyntax-4f1731d6ce7c2465fc21ea245110b7a39f34658a.tar.gz/md5 delete mode 100644 deps/checksums/JuliaSyntax-4f1731d6ce7c2465fc21ea245110b7a39f34658a.tar.gz/sha512 create mode 100644 deps/checksums/JuliaSyntax-dfd1d69b153eb119873035e62993a109b27192f0.tar.gz/md5 create mode 100644 deps/checksums/JuliaSyntax-dfd1d69b153eb119873035e62993a109b27192f0.tar.gz/sha512 diff --git a/deps/JuliaSyntax.version b/deps/JuliaSyntax.version index 7f124715024ce..86f94135884a0 100644 --- a/deps/JuliaSyntax.version +++ b/deps/JuliaSyntax.version @@ -1,4 +1,4 @@ JULIASYNTAX_BRANCH = main -JULIASYNTAX_SHA1 = 4f1731d6ce7c2465fc21ea245110b7a39f34658a +JULIASYNTAX_SHA1 = dfd1d69b153eb119873035e62993a109b27192f0 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-4f1731d6ce7c2465fc21ea245110b7a39f34658a.tar.gz/md5 b/deps/checksums/JuliaSyntax-4f1731d6ce7c2465fc21ea245110b7a39f34658a.tar.gz/md5 deleted file mode 100644 index c2663955ec773..0000000000000 --- a/deps/checksums/JuliaSyntax-4f1731d6ce7c2465fc21ea245110b7a39f34658a.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -8c9d9579eeab1ba40f978a32c9db9900 diff --git a/deps/checksums/JuliaSyntax-4f1731d6ce7c2465fc21ea245110b7a39f34658a.tar.gz/sha512 b/deps/checksums/JuliaSyntax-4f1731d6ce7c2465fc21ea245110b7a39f34658a.tar.gz/sha512 deleted file mode 100644 index 46647cb3e432b..0000000000000 --- a/deps/checksums/JuliaSyntax-4f1731d6ce7c2465fc21ea245110b7a39f34658a.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -1bdad624f61482b55deba8727fea1c087bfaea9e1f8afa3b44b984441fb7e663dac067baa4a96ae2d4cbd4a46ae8c87e9d20d2dfcd17046ad194711304184e57 diff --git a/deps/checksums/JuliaSyntax-dfd1d69b153eb119873035e62993a109b27192f0.tar.gz/md5 b/deps/checksums/JuliaSyntax-dfd1d69b153eb119873035e62993a109b27192f0.tar.gz/md5 new file mode 100644 index 0000000000000..51b30461d3905 --- /dev/null +++ b/deps/checksums/JuliaSyntax-dfd1d69b153eb119873035e62993a109b27192f0.tar.gz/md5 @@ -0,0 +1 @@ +e58559668aabb0fa96d598970c4d648e diff --git a/deps/checksums/JuliaSyntax-dfd1d69b153eb119873035e62993a109b27192f0.tar.gz/sha512 b/deps/checksums/JuliaSyntax-dfd1d69b153eb119873035e62993a109b27192f0.tar.gz/sha512 new file mode 100644 index 0000000000000..63a513ec9ae63 --- /dev/null +++ b/deps/checksums/JuliaSyntax-dfd1d69b153eb119873035e62993a109b27192f0.tar.gz/sha512 @@ -0,0 +1 @@ +59e22f7db63a383beadf96a68d4db6ae173d61be6d766ea1792b3a3bd70125f73dd4df9e55bad4c66363aa0b6ff6ea5259d3c91abf42f5fe34446e3fa076cc87 diff --git a/test/syntax.jl b/test/syntax.jl index 315f2d8b0f38b..fca8b9e8ccdf5 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -476,7 +476,7 @@ let err = try catch e e end - @test err.line == 7 + @test err.line in (5, 7) end # PR #17393 From da43f11022e394009758379491bcb4de71ef321f Mon Sep 17 00:00:00 2001 From: CY Han Date: Tue, 10 Dec 2024 22:12:54 +0800 Subject: [PATCH 047/342] libgit2: update enums from v1.8.0 (#56764) --- stdlib/LibGit2/src/callbacks.jl | 8 ++++---- stdlib/LibGit2/src/error.jl | 15 ++++++++++++--- stdlib/LibGit2/test/libgit2-tests.jl | 2 +- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/stdlib/LibGit2/src/callbacks.jl b/stdlib/LibGit2/src/callbacks.jl index 043e04e0dfad6..c4156d4a44c71 100644 --- a/stdlib/LibGit2/src/callbacks.jl +++ b/stdlib/LibGit2/src/callbacks.jl @@ -43,7 +43,7 @@ end function user_abort() ensure_initialized() # Note: Potentially it could be better to just throw a Julia error. - ccall((:giterr_set_str, libgit2), Cvoid, + ccall((:git_error_set_str, libgit2), Cvoid, (Cint, Cstring), Cint(Error.Callback), "Aborting, user cancelled credential request.") return Cint(Error.EUSER) @@ -51,7 +51,7 @@ end function prompt_limit() ensure_initialized() - ccall((:giterr_set_str, libgit2), Cvoid, + ccall((:git_error_set_str, libgit2), Cvoid, (Cint, Cstring), Cint(Error.Callback), "Aborting, maximum number of prompts reached.") return Cint(Error.EAUTH) @@ -59,7 +59,7 @@ end function exhausted_abort() ensure_initialized() - ccall((:giterr_set_str, libgit2), Cvoid, + ccall((:git_error_set_str, libgit2), Cvoid, (Cint, Cstring), Cint(Error.Callback), "All authentication methods have failed.") return Cint(Error.EAUTH) @@ -339,7 +339,7 @@ function credentials_callback(libgit2credptr::Ptr{Ptr{Cvoid}}, url_ptr::Cstring, if err == 0 if p.explicit !== nothing ensure_initialized() - ccall((:giterr_set_str, libgit2), Cvoid, (Cint, Cstring), Cint(Error.Callback), + ccall((:git_error_set_str, libgit2), Cvoid, (Cint, Cstring), Cint(Error.Callback), "The explicitly provided credential is incompatible with the requested " * "authentication methods.") end diff --git a/stdlib/LibGit2/src/error.jl b/stdlib/LibGit2/src/error.jl index 1a493006ea1b5..6647d803d3193 100644 --- a/stdlib/LibGit2/src/error.jl +++ b/stdlib/LibGit2/src/error.jl @@ -19,7 +19,7 @@ export GitError EUNMERGED = Cint(-10), # merge in progress prevented op ENONFASTFORWARD = Cint(-11), # ref not fast-forwardable EINVALIDSPEC = Cint(-12), # name / ref not in valid format - EMERGECONFLICT = Cint(-13), # merge conflict prevented op + ECONFLICT = Cint(-13), # Checkout conflicts prevented operation ELOCKED = Cint(-14), # lock file prevented op EMODIFIED = Cint(-15), # ref value does not match expected EAUTH = Cint(-16), # authentication error @@ -27,6 +27,11 @@ export GitError EAPPLIED = Cint(-18), # patch/merge has already been applied EPEEL = Cint(-19), # the requested peel operation is not possible EEOF = Cint(-20), # unexpected EOF + EINVALID = Cint(-21), # Invalid operation or input + EUNCOMMITTED = Cint(-22), # Uncommitted changes in index prevented operation + EDIRECTORY = Cint(-23), # The operation is not valid for a directory + EMERGECONFLICT = Cint(-24), # A merge conflict exists and cannot continue + PASSTHROUGH = Cint(-30), # internal only ITEROVER = Cint(-31), # signals end of iteration RETRY = Cint(-32), # internal only @@ -34,7 +39,11 @@ export GitError EINDEXDIRTY = Cint(-34), # unsaved changes in the index would be overwritten EAPPLYFAIL = Cint(-35), # patch application failed EOWNER = Cint(-36), # the object is not owned by the current user - TIMEOUT = Cint(-37)) # The operation timed out + TIMEOUT = Cint(-37), # The operation timed out + EUNCHANGED = Cint(-38), # There were no changes + ENOTSUPPORTED = Cint(-39), # An option is not supported + EREADONLY = Cint(-40), # The subject is read-only +) @enum(Class, None, NoMemory, @@ -88,7 +97,7 @@ Base.show(io::IO, err::GitError) = print(io, "GitError(Code:$(err.code), Class:$ function last_error() ensure_initialized() - err = ccall((:giterr_last, libgit2), Ptr{ErrorStruct}, ()) + err = ccall((:git_error_last, libgit2), Ptr{ErrorStruct}, ()) if err != C_NULL err_obj = unsafe_load(err) err_class = Class(err_obj.class) diff --git a/stdlib/LibGit2/test/libgit2-tests.jl b/stdlib/LibGit2/test/libgit2-tests.jl index 9ab75ed1dc39b..1dfa5429368b6 100644 --- a/stdlib/LibGit2/test/libgit2-tests.jl +++ b/stdlib/LibGit2/test/libgit2-tests.jl @@ -1070,7 +1070,7 @@ mktempdir() do dir # test workaround for git_tree_walk issue # https://github.com/libgit2/libgit2/issues/4693 - ccall((:giterr_set_str, libgit2), Cvoid, (Cint, Cstring), + ccall((:git_error_set_str, libgit2), Cvoid, (Cint, Cstring), Cint(LibGit2.Error.Invalid), "previous error") try # file needs to exist in tree in order to trigger the stop walk condition From 19e06d39141e1e2f0f9c4664ba9b88867b587a6e Mon Sep 17 00:00:00 2001 From: Oscar Smith Date: Tue, 10 Dec 2024 09:33:41 -0500 Subject: [PATCH 048/342] fix `exp(weirdNaN)` (#56784) Fixes https://github.com/JuliaLang/julia/issues/56782 Fix `exp(reinterpret(Float64, 0x7ffbb14880000000))` returning non-NaN value. This should have minimal performance impact since it's already in the fallback branch. --- base/special/exp.jl | 2 ++ test/math.jl | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/base/special/exp.jl b/base/special/exp.jl index 312197339a086..38d7509807aed 100644 --- a/base/special/exp.jl +++ b/base/special/exp.jl @@ -216,6 +216,7 @@ end small_part = muladd(jU, expm1b_kernel(base, r), jL) + jU if !(abs(x) <= SUBNORM_EXP(base, T)) + isnan(x) && return x x >= MAX_EXP(base, T) && return Inf x <= MIN_EXP(base, T) && return 0.0 if k <= -53 @@ -243,6 +244,7 @@ end hi, lo = Base.canonicalize2(1.0, kern) small_part = fma(jU, hi, muladd(jU, (lo+xlo), very_small)) if !(abs(x) <= SUBNORM_EXP(base, T)) + isnan(x) && return x x >= MAX_EXP(base, T) && return Inf x <= MIN_EXP(base, T) && return 0.0 if k <= -53 diff --git a/test/math.jl b/test/math.jl index d794facb02d25..7070fe63ba931 100644 --- a/test/math.jl +++ b/test/math.jl @@ -382,6 +382,10 @@ end end end +@testset "https://github.com/JuliaLang/julia/issues/56782" begin + @test isnan(exp(reinterpret(Float64, 0x7ffbb14880000000))) +end + @testset "test abstractarray trig functions" begin TAA = rand(2,2) TAA = (TAA + TAA')/2. From 9160e048b343d34aaab64d816c52087ba24f24fc Mon Sep 17 00:00:00 2001 From: Michael Abbott <32575566+mcabbott@users.noreply.github.com> Date: Tue, 10 Dec 2024 09:39:03 -0500 Subject: [PATCH 049/342] Add note to Vararg/UnionAll warning about making it an error (#56662) This warning message ``` WARNING: Wrapping `Vararg` directly in UnionAll is deprecated (wrap the tuple instead). You may need to write `f(x::Vararg{T})` rather than `f(x::Vararg{<:T})` or `f(x::Vararg{T}) where T` instead of `f(x::Vararg{T} where T)`. ``` (last extended in #49558) seems clear enough if you wrote the code. But if it's coming from 10 packages deep, there's no information to track down the origin. Turns out you can do this with `--depwarn=error`. But the message doesn't tell you that, and doesn't call itself a deprecation warning at all. --- src/jltypes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jltypes.c b/src/jltypes.c index abd1f62092035..52b993cd5aa4d 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -910,7 +910,7 @@ JL_DLLEXPORT jl_value_t *jl_type_unionall(jl_tvar_t *v, jl_value_t *body) if (jl_options.depwarn) { if (jl_options.depwarn == JL_OPTIONS_DEPWARN_ERROR) jl_error("Wrapping `Vararg` directly in UnionAll is deprecated (wrap the tuple instead).\nYou may need to write `f(x::Vararg{T})` rather than `f(x::Vararg{<:T})` or `f(x::Vararg{T}) where T` instead of `f(x::Vararg{T} where T)`."); - jl_printf(JL_STDERR, "WARNING: Wrapping `Vararg` directly in UnionAll is deprecated (wrap the tuple instead).\nYou may need to write `f(x::Vararg{T})` rather than `f(x::Vararg{<:T})` or `f(x::Vararg{T}) where T` instead of `f(x::Vararg{T} where T)`.\n"); + jl_printf(JL_STDERR, "WARNING: Wrapping `Vararg` directly in UnionAll is deprecated (wrap the tuple instead).\nYou may need to write `f(x::Vararg{T})` rather than `f(x::Vararg{<:T})` or `f(x::Vararg{T}) where T` instead of `f(x::Vararg{T} where T)`.\nTo make this warning an error, and hence obtain a stack trace, use `julia --depwarn=error`.\n"); } jl_vararg_t *vm = (jl_vararg_t*)body; int T_has_tv = vm->T && jl_has_typevar(vm->T, v); From 29a7ce403fb1ed302183c5f87ebd859e98dc6ed4 Mon Sep 17 00:00:00 2001 From: Paul Melis Date: Tue, 10 Dec 2024 15:42:33 +0100 Subject: [PATCH 050/342] Add a note clearifying option parsing (#56285) To help with #56274 --- doc/src/manual/command-line-interface.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/src/manual/command-line-interface.md b/doc/src/manual/command-line-interface.md index 9b06deaf0ea8a..3477f61164c50 100644 --- a/doc/src/manual/command-line-interface.md +++ b/doc/src/manual/command-line-interface.md @@ -222,6 +222,10 @@ The following is a complete list of command-line switches available when launchi |`--permalloc-pkgimg={yes\|no*}` |Copy the data section of package images into memory| |`--trim={no*\|safe\|unsafe\|unsafe-warn}` |Build a sysimage including only code provably reachable from methods marked by calling `entrypoint`. The three non-default options differ in how they handle dynamic call sites. In safe mode, such sites result in compile-time errors. In unsafe mode, such sites are allowed but the resulting binary might be missing needed code and can throw runtime errors. With unsafe-warn, such sites will trigger warnings at compile-time and might error at runtime.| +Options that have the form `--option={...}` can be specified either as `--option=value` or as `--option value`. For example, `julia --banner=no` is equivalent to `julia --banner no`. This is especially relevant for options that take a filename for output, because forgetting to specifying the argument for (say) `--trace-compile` will cause the option following it to be interpreted as the filename, possibly unintentionally overwriting it. + +Note that options of the form `--option[=...]` can **not** be specified as `--option value`, but only as `--option=value` (or simply `--option`, when no argument is provided). + !!! compat "Julia 1.1" In Julia 1.0, the default `--project=@.` option did not search up from the root directory of a Git repository for the `Project.toml` file. From Julia 1.1 forward, it From d269d7d375827a0279dc1fee7bb24c9418f06f03 Mon Sep 17 00:00:00 2001 From: Zentrik Date: Wed, 11 Dec 2024 08:31:11 +0000 Subject: [PATCH 051/342] Fix undefined symbol error in version script (#55363) lld 17 and above by default error if symbols listed in the version script are undefined. Julia has a few of these, as some symbols are defined conditionally in Julia (e.g. based on OS), others perhaps have been removed from Julia and other seem to be defined in other libraries. Further the version script is used in linking three times, each time linking together different objects and so having different symbols defined. Adding `-Wl,--undefined-version` is not a great solution as passing that to ld < 2.40 errors and there doesn't seem to be a great way to check if a linker supports this flag. I don't know how to get around these errors for symbols like `_IO_stdin_used` which Julia doesn't define and it seems to matter whether or not they are exported, see https://libc-alpha.sourceware.narkive.com/SevIQmU3/io-stdin-used-stripped-by-version-scripts. So I've converted all undefined symbols into wildcards to work around the error. Fixes #50414, fixes #54533 and replaces #55319. --------- Co-authored-by: Zentrik --- Make.inc | 2 +- src/julia.expmap.in | 38 +++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Make.inc b/Make.inc index 29512bbbe7f45..a60a95d21c3db 100644 --- a/Make.inc +++ b/Make.inc @@ -1470,7 +1470,7 @@ ifeq (,$(findstring aarch64,$(ARCH))) OSLIBS += -lgcc_s endif -OSLIBS += -Wl,--export-dynamic -Wl,--undefined-version -Wl,--version-script=$(BUILDROOT)/src/julia.expmap \ +OSLIBS += -Wl,--export-dynamic -Wl,--version-script=$(BUILDROOT)/src/julia.expmap \ $(NO_WHOLE_ARCHIVE) endif diff --git a/src/julia.expmap.in b/src/julia.expmap.in index 29366f6296a85..b28a714e75f69 100644 --- a/src/julia.expmap.in +++ b/src/julia.expmap.in @@ -2,7 +2,7 @@ global: pthread*; __stack_chk_*; - asprintf; + asprintf*; bitvector_*; ios_*; arraylist_*; @@ -10,33 +10,33 @@ jl_*; ijl_*; _jl_mutex_*; - rec_backtrace; + rec_backtrace*; julia_*; - libsupport_init; - localtime_r; - memhash; - memhash32; - memhash32_seed; - memhash_seed; - restore_signals; + libsupport_init*; + localtime_r*; + memhash*; + memhash32*; + memhash32_seed*; + memhash_seed*; + restore_signals*; u8_*; uv_*; - add_library_mapping; + add_library_mapping*; utf8proc_*; - jlbacktrace; - jlbacktracet; - _IO_stdin_used; - _Z24jl_coverage_data_pointerN4llvm9StringRefEi; - _Z22jl_coverage_alloc_lineN4llvm9StringRefEi; - _Z22jl_malloc_data_pointerN4llvm9StringRefEi; + jlbacktrace*; + jlbacktracet*; + _IO_stdin_used*; /* glibc expects this to be exported to detect which version of glibc is being used, see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=634261#109 for further details */ + _Z24jl_coverage_data_pointerN4llvm9StringRefEi*; + _Z22jl_coverage_alloc_lineN4llvm9StringRefEi*; + _Z22jl_malloc_data_pointerN4llvm9StringRefEi*; _jl_timing_*; LLVMExtra*; JLJIT*; - llvmGetPassPluginInfo; + llvmGetPassPluginInfo*; /* freebsd */ - environ; - __progname; + environ*; + __progname*; local: *; From 92d37025fd2c49abbdabd16bc6308b75e978e4d6 Mon Sep 17 00:00:00 2001 From: Nathan Boyer <65452054+nathanrboyer@users.noreply.github.com> Date: Wed, 11 Dec 2024 14:47:43 -0500 Subject: [PATCH 052/342] Update repr docstring to hint what it stands for. (#56761) - Change `repr` docstring from "Create a string from any value ..." to "Create a string representation of any value ...". - Document that it typically emits parseable Julia code --------- Co-authored-by: Ian Butterworth --- base/strings/io.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/base/strings/io.jl b/base/strings/io.jl index 116bcf71eeb7a..b4a3c7ad3e0c2 100644 --- a/base/strings/io.jl +++ b/base/strings/io.jl @@ -250,7 +250,9 @@ print(io::IO, s::Union{String,SubString{String}}) = (write(io, s); nothing) """ repr(x; context=nothing) -Create a string from any value using the 2-argument `show(io, x)` function. +Create a string representation of any value using the 2-argument `show(io, x)` function, +which aims to produce a string that is parseable Julia code, where possible. +i.e. `eval(Meta.parse(repr(x))) == x` should hold true. You should not add methods to `repr`; define a [`show`](@ref) method instead. The optional keyword argument `context` can be set to a `:key=>value` pair, a From 582585bfb0a5494d41fd28b47a9774d498c608d9 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Wed, 11 Dec 2024 16:59:25 -0500 Subject: [PATCH 053/342] Fix generate_precompile statement grouping & avoid defining new func (#56317) --- contrib/generate_precompile.jl | 100 ++++++++++++++++----------------- 1 file changed, 48 insertions(+), 52 deletions(-) diff --git a/contrib/generate_precompile.jl b/contrib/generate_precompile.jl index ffbbfd620997f..b075223d9c7e4 100644 --- a/contrib/generate_precompile.jl +++ b/contrib/generate_precompile.jl @@ -136,60 +136,56 @@ for match = Base._methods(+, (Int, Int), -1, Base.get_world_counter()) m = match.method delete!(push!(Set{Method}(), m), m) copy(Core.Compiler.retrieve_code_info(Core.Compiler.specialize_method(match), typemax(UInt))) - - empty!(Set()) - push!(push!(Set{Union{GlobalRef,Symbol}}(), :two), GlobalRef(Base, :two)) - (setindex!(Dict{String,Base.PkgId}(), Base.PkgId(Base), "file.jl"))["file.jl"] - (setindex!(Dict{Symbol,Vector{Int}}(), [1], :two))[:two] - (setindex!(Dict{Base.PkgId,String}(), "file.jl", Base.PkgId(Base)))[Base.PkgId(Base)] - (setindex!(Dict{Union{GlobalRef,Symbol}, Vector{Int}}(), [1], :two))[:two] - (setindex!(IdDict{Type, Union{Missing, Vector{Tuple{LineNumberNode, Expr}}}}(), missing, Int))[Int] - Dict{Symbol, Union{Nothing, Bool, Symbol}}(:one => false)[:one] - Dict(Base => [:(1+1)])[Base] - Dict(:one => [1])[:one] - Dict("abc" => Set())["abc"] - pushfirst!([], sum) - get(Base.pkgorigins, Base.PkgId(Base), nothing) - sort!([1,2,3]) - unique!([1,2,3]) - cumsum([1,2,3]) - append!(Int[], BitSet()) - isempty(BitSet()) - delete!(BitSet([1,2]), 3) - deleteat!(Int32[1,2,3], [1,3]) - deleteat!(Any[1,2,3], [1,3]) - Core.svec(1, 2) == Core.svec(3, 4) - any(t->t[1].line > 1, [(LineNumberNode(2,:none), :(1+1))]) - - # Code loading uses this - sortperm(mtime.(readdir(".")), rev=true) - # JLLWrappers uses these - Dict{Base.UUID,Set{String}}()[Base.UUID("692b3bcd-3c85-4b1f-b108-f13ce0eb3210")] = Set{String}() - get!(Set{String}, Dict{Base.UUID,Set{String}}(), Base.UUID("692b3bcd-3c85-4b1f-b108-f13ce0eb3210")) - eachindex(IndexLinear(), Expr[]) - push!(Expr[], Expr(:return, false)) - vcat(String[], String[]) - k, v = (:hello => nothing) - Base.print_time_imports_report(Base) - Base.print_time_imports_report_init(Base) - - # Preferences uses these - get(Dict{String,Any}(), "missing", nothing) - delete!(Dict{String,Any}(), "missing") - for (k, v) in Dict{String,Any}() - println(k) - end - - # interactive startup uses this - write(IOBuffer(), "") - - # Not critical, but helps hide unrelated compilation from @time when using --trace-compile. - f55729() = Base.Experimental.@force_compile - @time @eval f55729() - @time @eval f55729() - break # only actually need to do this once end +empty!(Set()) +push!(push!(Set{Union{GlobalRef,Symbol}}(), :two), GlobalRef(Base, :two)) +(setindex!(Dict{String,Base.PkgId}(), Base.PkgId(Base), "file.jl"))["file.jl"] +(setindex!(Dict{Symbol,Vector{Int}}(), [1], :two))[:two] +(setindex!(Dict{Base.PkgId,String}(), "file.jl", Base.PkgId(Base)))[Base.PkgId(Base)] +(setindex!(Dict{Union{GlobalRef,Symbol}, Vector{Int}}(), [1], :two))[:two] +(setindex!(IdDict{Type, Union{Missing, Vector{Tuple{LineNumberNode, Expr}}}}(), missing, Int))[Int] +Dict{Symbol, Union{Nothing, Bool, Symbol}}(:one => false)[:one] +Dict(Base => [:(1+1)])[Base] +Dict(:one => [1])[:one] +Dict("abc" => Set())["abc"] +pushfirst!([], sum) +get(Base.pkgorigins, Base.PkgId(Base), nothing) +sort!([1,2,3]) +unique!([1,2,3]) +cumsum([1,2,3]) +append!(Int[], BitSet()) +isempty(BitSet()) +delete!(BitSet([1,2]), 3) +deleteat!(Int32[1,2,3], [1,3]) +deleteat!(Any[1,2,3], [1,3]) +Core.svec(1, 2) == Core.svec(3, 4) +any(t->t[1].line > 1, [(LineNumberNode(2,:none), :(1+1))]) + +# Code loading uses this +sortperm(mtime.(readdir(".")), rev=true) +# JLLWrappers uses these +Dict{Base.UUID,Set{String}}()[Base.UUID("692b3bcd-3c85-4b1f-b108-f13ce0eb3210")] = Set{String}() +get!(Set{String}, Dict{Base.UUID,Set{String}}(), Base.UUID("692b3bcd-3c85-4b1f-b108-f13ce0eb3210")) +eachindex(IndexLinear(), Expr[]) +push!(Expr[], Expr(:return, false)) +vcat(String[], String[]) +k, v = (:hello => nothing) +Base.print_time_imports_report(Base) +Base.print_time_imports_report_init(Base) + +# Preferences uses these +get(Dict{String,Any}(), "missing", nothing) +delete!(Dict{String,Any}(), "missing") +for (k, v) in Dict{String,Any}() + println(k) +end + +# interactive startup uses this +write(IOBuffer(), "") + +# precompile @time report generation and printing +@time @eval Base.Experimental.@force_compile """ julia_exepath() = joinpath(Sys.BINDIR, Base.julia_exename()) From 48be7ca438dd607e47936660b5dbc38145e6399e Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Thu, 12 Dec 2024 12:40:00 +0100 Subject: [PATCH 054/342] remove LinearAlgebra specific bitarray tests since they have moved to the external LinearAlgebra.jl repo (#56800) Moved in https://github.com/JuliaLang/LinearAlgebra.jl/pull/1148. --- test/bitarray.jl | 69 +++--------------------------------------------- 1 file changed, 4 insertions(+), 65 deletions(-) diff --git a/test/bitarray.jl b/test/bitarray.jl index 67d8fae0eda6d..fd5c1421a256f 100644 --- a/test/bitarray.jl +++ b/test/bitarray.jl @@ -1,7 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license using Base: findprevnot, findnextnot -using Random, LinearAlgebra, Test +using Random, Test, LinearAlgebra # Ideally, these tests should not depend on LinearAlgebra isdefined(Main, :SizedArrays) || @eval Main include("testhelpers/SizedArrays.jl") using .Main.SizedArrays @@ -15,7 +15,6 @@ tc(r1,r2) = false bitcheck(b::BitArray) = Test._check_bitarray_consistency(b) bitcheck(x) = true -bcast_setindex!(b, x, I...) = (b[I...] .= x; b) function check_bitop_call(ret_type, func, args...; kwargs...) r2 = func(map(x->(isa(x, BitArray) ? Array(x) : x), args)...; kwargs...) @@ -34,6 +33,9 @@ macro check_bit_operation(ex) Expr(:call, :check_bitop_call, nothing, map(esc, ex.args)...) end +bcast_setindex!(b, x, I...) = (b[I...] .= x; b) + + let t0 = time_ns() global timesofar function timesofar(str) @@ -1641,69 +1643,6 @@ end timesofar("cat") -@testset "Linear algebra" begin - b1 = bitrand(v1) - b2 = bitrand(v1) - @check_bit_operation dot(b1, b2) Int - - b1 = bitrand(n1, n2) - @test_throws ArgumentError tril(b1, -n1 - 2) - @test_throws ArgumentError tril(b1, n2) - @test_throws ArgumentError triu(b1, -n1) - @test_throws ArgumentError triu(b1, n2 + 2) - for k in (-n1 - 1):(n2 - 1) - @check_bit_operation tril(b1, k) BitMatrix - end - for k in (-n1 + 1):(n2 + 1) - @check_bit_operation triu(b1, k) BitMatrix - end - - for sz = [(n1,n1), (n1,n2), (n2,n1)], (f,isf) = [(tril,istril), (triu,istriu)] - b1 = bitrand(sz...) - @check_bit_operation isf(b1) Bool - b1 = f(bitrand(sz...)) - @check_bit_operation isf(b1) Bool - end - - b1 = bitrand(n1,n1) - b1 .|= copy(b1') - @check_bit_operation issymmetric(b1) Bool - @check_bit_operation ishermitian(b1) Bool - - b1 = bitrand(n1) - b2 = bitrand(n2) - @check_bit_operation kron(b1, b2) BitVector - - b1 = bitrand(s1, s2) - b2 = bitrand(s3, s4) - @check_bit_operation kron(b1, b2) BitMatrix - - b1 = bitrand(v1) - @check_bit_operation diff(b1) Vector{Int} - - b1 = bitrand(n1, n2) - @check_bit_operation diff(b1, dims=1) Matrix{Int} - @check_bit_operation diff(b1, dims=2) Matrix{Int} - - b1 = bitrand(n1, n1) - @test ((svdb1, svdb1A) = (svd(b1), svd(Array(b1))); - svdb1.U == svdb1A.U && svdb1.S == svdb1A.S && svdb1.V == svdb1A.V) - @test ((qrb1, qrb1A) = (qr(b1), qr(Array(b1))); - Matrix(qrb1.Q) == Matrix(qrb1A.Q) && qrb1.R == qrb1A.R) - - b1 = bitrand(v1) - @check_bit_operation diagm(0 => b1) BitMatrix - - b1 = bitrand(v1) - b2 = bitrand(v1) - @check_bit_operation diagm(-1 => b1, 1 => b2) BitMatrix - - b1 = bitrand(n1, n1) - @check_bit_operation diag(b1) -end - -timesofar("linalg") - @testset "findmax, findmin" begin b1 = trues(0) @test_throws ArgumentError findmax(b1) From 9118ea7565feae13d5b47654a3c245c0df36e753 Mon Sep 17 00:00:00 2001 From: William Moses Date: Thu, 12 Dec 2024 07:46:25 -0600 Subject: [PATCH 055/342] Fix partially_inline for unreachable (#56787) --- base/meta.jl | 5 +++++ test/meta.jl | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/base/meta.jl b/base/meta.jl index bcf4fbf632ab2..0078e15bcd98b 100644 --- a/base/meta.jl +++ b/base/meta.jl @@ -363,10 +363,15 @@ function _partially_inline!(@nospecialize(x), slot_replacements::Vector{Any}, return x end if isa(x, Core.ReturnNode) + # Unreachable doesn't have val defined + if !isdefined(x, :val) + return x + else return Core.ReturnNode( _partially_inline!(x.val, slot_replacements, type_signature, static_param_values, slot_offset, statement_offset, boundscheck), ) + end end if isa(x, Core.GotoIfNot) return Core.GotoIfNot( diff --git a/test/meta.jl b/test/meta.jl index 5fb1ebc0d3647..2b235d3cc1b0d 100644 --- a/test/meta.jl +++ b/test/meta.jl @@ -276,6 +276,11 @@ ci = code_lowered(g, Tuple{Val{true}})[1] @test Meta.partially_inline!(copy(ci.code), Any[isdefined_globalref, 1], Tuple{typeof(isdefined_globalref), Int}, [], 0, 0, :propagate)[1] == Expr(:isdefined, GlobalRef(Base, :foo)) + withunreachable(s::String) = sin(s) + ci = code_lowered(withunreachable, Tuple{String})[1] + ci.code[end] = Core.ReturnNode() + @test Meta.partially_inline!(copy(ci.code), Any[withunreachable, "foo"], Tuple{typeof(withunreachable), String}, + [], 0, 0, :propagate)[end] == Core.ReturnNode() end @testset "Base.Meta docstrings" begin From cea6a9a6b7a605bb58798eee4ba1b068d7f893eb Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 12 Dec 2024 16:19:43 -0500 Subject: [PATCH 056/342] codegen: reduce recursion in cfunction generation (#56806) The regular code-path for this was only missing the age_ok handling, so add in that handling so we can delete the custom path here for the test and some of the brokenness that implied. --- src/aotcompile.cpp | 2 +- src/cgutils.cpp | 4 +- src/codegen.cpp | 240 ++++++++++++++--------------------------- src/gf.c | 6 +- src/jitlayers.cpp | 83 ++++++++------ src/jitlayers.h | 7 +- src/julia_internal.h | 2 +- src/precompile_utils.c | 4 +- test/llvmcall.jl | 2 +- 9 files changed, 146 insertions(+), 204 deletions(-) diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index ba9a3c05e41ff..198d7490cb092 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -505,7 +505,7 @@ static void compile_workqueue(jl_codegen_params_t ¶ms, egal_set &method_root size_t nrealargs = jl_nparams(mi->specTypes); // number of actual arguments being passed bool is_opaque_closure = jl_is_method(mi->def.value) && mi->def.method->is_for_opaque_closure; // TODO: maybe this can be cached in codeinst->specfptr? - emit_specsig_to_fptr1(proto.decl, proto.cc, proto.return_roots, mi->specTypes, codeinst->rettype, is_opaque_closure, nrealargs, params, pinvoke, 0, 0); + emit_specsig_to_fptr1(proto.decl, proto.cc, proto.return_roots, mi->specTypes, codeinst->rettype, is_opaque_closure, nrealargs, params, pinvoke); preal_decl = ""; // no need to fixup the name } if (!preal_decl.empty()) { diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 9e170555e6149..dd6ced04673e6 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -2279,7 +2279,7 @@ static jl_cgval_t typed_store(jl_codectx_t &ctx, const jl_cgval_t argv[3] = { cmp, lhs, rhs }; jl_cgval_t ret; if (modifyop) { - ret = emit_invoke(ctx, *modifyop, argv, 3, (jl_value_t*)jl_any_type); + ret = emit_invoke(ctx, *modifyop, argv, 3, (jl_value_t*)jl_any_type, nullptr); } else { if (trim_may_error(ctx.params->trim)) { @@ -4018,7 +4018,7 @@ static jl_cgval_t union_store(jl_codectx_t &ctx, emit_lockstate_value(ctx, needlock, false); const jl_cgval_t argv[3] = { cmp, oldval, rhs }; if (modifyop) { - rhs = emit_invoke(ctx, *modifyop, argv, 3, (jl_value_t*)jl_any_type); + rhs = emit_invoke(ctx, *modifyop, argv, 3, (jl_value_t*)jl_any_type, nullptr); } else { if (trim_may_error(ctx.params->trim)) { diff --git a/src/codegen.cpp b/src/codegen.cpp index 21591acedc632..fbd990857dd94 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2074,7 +2074,7 @@ static CallInst *emit_jlcall(jl_codectx_t &ctx, JuliaFunction<> *theFptr, Value static Value *emit_f_is(jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgval_t &arg2, Value *nullcheck1 = nullptr, Value *nullcheck2 = nullptr); static jl_cgval_t emit_new_struct(jl_codectx_t &ctx, jl_value_t *ty, size_t nargs, ArrayRef argv, bool is_promotable=false); -static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayRef argv, size_t nargs, jl_value_t *rt); +static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayRef argv, size_t nargs, jl_value_t *rt, Value *age_ok); static Value *literal_pointer_val(jl_codectx_t &ctx, jl_value_t *p); static unsigned julia_alignment(jl_value_t *jt); @@ -2141,18 +2141,18 @@ static jl_value_t *StackFrame( return frame; } -static void push_frames(jl_codectx_t &ctx, jl_method_instance_t *caller, jl_method_instance_t *callee, int no_debug=false) +static void push_frames(jl_codectx_t &ctx, jl_method_instance_t *caller, jl_method_instance_t *callee) { CallFrames frames; auto it = ctx.emission_context.enqueuers.find(callee); if (it != ctx.emission_context.enqueuers.end()) return; - if (no_debug) { // Used in tojlinvoke + auto DL = ctx.builder.getCurrentDebugLocation(); + if (caller == nullptr || !DL) { // Used in various places frames.push_back({ctx.funcName, "", 0}); ctx.emission_context.enqueuers.insert({callee, {caller, std::move(frames)}}); return; } - auto DL = ctx.builder.getCurrentDebugLocation(); auto filename = std::string(DL->getFilename()); auto line = DL->getLine(); auto fname = std::string(DL->getScope()->getSubprogram()->getName()); @@ -5205,14 +5205,12 @@ static CallInst *emit_jlcall(jl_codectx_t &ctx, JuliaFunction<> *theFptr, Value return emit_jlcall(ctx, prepare_call(theFptr), theF, argv, nargs, trampoline); } -static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_closure, jl_value_t *specTypes, jl_value_t *jlretty, jl_returninfo_t &returninfo, jl_code_instance_t *fromexternal, - ArrayRef argv, size_t nargs) +static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_closure, jl_value_t *specTypes, jl_value_t *jlretty, jl_returninfo_t &returninfo, ArrayRef argv, size_t nargs) { ++EmittedSpecfunCalls; // emit specialized call site bool gcstack_arg = JL_FEAT_TEST(ctx, gcstack_arg); - FunctionType *cft = returninfo.decl.getFunctionType(); - size_t nfargs = cft->getNumParams(); + size_t nfargs = returninfo.decl.getFunctionType()->getNumParams(); SmallVector argvals(nfargs); unsigned idx = 0; AllocaInst *result = nullptr; @@ -5304,23 +5302,7 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_clos idx++; } assert(idx == nfargs); - Value *TheCallee = returninfo.decl.getCallee(); - if (fromexternal) { - std::string namep("p"); - namep += cast(returninfo.decl.getCallee())->getName(); - GlobalVariable *GV = cast_or_null(jl_Module->getNamedValue(namep)); - if (GV == nullptr) { - GV = new GlobalVariable(*jl_Module, TheCallee->getType(), false, - GlobalVariable::ExternalLinkage, - Constant::getNullValue(TheCallee->getType()), - namep); - ctx.emission_context.external_fns[std::make_tuple(fromexternal, true)] = GV; - } - jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const); - TheCallee = ai.decorateInst(ctx.builder.CreateAlignedLoad(TheCallee->getType(), GV, Align(sizeof(void*)))); - setName(ctx.emission_context, TheCallee, namep); - } - CallInst *call = ctx.builder.CreateCall(cft, TheCallee, argvals); + CallInst *call = ctx.builder.CreateCall(returninfo.decl, argvals); call->setAttributes(returninfo.attrs); if (gcstack_arg && ctx.emission_context.use_swiftcc) call->setCallingConv(CallingConv::Swift); @@ -5362,7 +5344,7 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_clos } static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_closure, jl_value_t *specTypes, jl_value_t *jlretty, llvm::Value *callee, StringRef specFunctionObject, jl_code_instance_t *fromexternal, - ArrayRef argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *nreturn_roots, jl_value_t *inferred_retty) + ArrayRef argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *nreturn_roots, jl_value_t *inferred_retty, Value *age_ok) { ++EmittedSpecfunCalls; // emit specialized call site @@ -5370,21 +5352,52 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_clos jl_returninfo_t returninfo = get_specsig_function(ctx, jl_Module, callee, specFunctionObject, specTypes, jlretty, is_opaque_closure, gcstack_arg); *cc = returninfo.cc; *nreturn_roots = returninfo.return_roots; - jl_cgval_t retval = emit_call_specfun_other(ctx, is_opaque_closure, specTypes, jlretty, returninfo, fromexternal, argv, nargs); + if (fromexternal) { + std::string namep("p"); + Value *TheCallee = returninfo.decl.getCallee(); + namep += cast(TheCallee)->getName(); + GlobalVariable *GV = cast_or_null(jl_Module->getNamedValue(namep)); + if (GV == nullptr) { + GV = new GlobalVariable(*jl_Module, TheCallee->getType(), false, + GlobalVariable::ExternalLinkage, + Constant::getNullValue(TheCallee->getType()), + namep); + ctx.emission_context.external_fns[std::make_tuple(fromexternal, true)] = GV; + } + jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const); + TheCallee = ai.decorateInst(ctx.builder.CreateAlignedLoad(TheCallee->getType(), GV, Align(sizeof(void*)))); + setName(ctx.emission_context, TheCallee, namep); + returninfo.decl = FunctionCallee(returninfo.decl.getFunctionType(), TheCallee); + } + if (age_ok) { + std::string funcName(specFunctionObject); + funcName += "_gfthunk"; + Function *gf_thunk = Function::Create(returninfo.decl.getFunctionType(), + GlobalVariable::InternalLinkage, funcName, jl_Module); + jl_init_function(gf_thunk, ctx.emission_context.TargetTriple); + gf_thunk->setAttributes(AttributeList::get(gf_thunk->getContext(), {returninfo.attrs, gf_thunk->getAttributes()})); + // build a specsig -> jl_apply_generic converter thunk + // this builds a method that calls jl_apply_generic (as a closure over a singleton function pointer), + // but which has the signature of a specsig + emit_specsig_to_fptr1(gf_thunk, returninfo.cc, returninfo.return_roots, specTypes, jlretty, is_opaque_closure, nargs, ctx.emission_context, + prepare_call(jlapplygeneric_func)); + returninfo.decl = FunctionCallee(returninfo.decl.getFunctionType(), ctx.builder.CreateSelect(age_ok, returninfo.decl.getCallee(), gf_thunk)); + } + jl_cgval_t retval = emit_call_specfun_other(ctx, is_opaque_closure, specTypes, jlretty, returninfo, argv, nargs); // see if inference has a different / better type for the call than the lambda return update_julia_type(ctx, retval, inferred_retty); } static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, jl_method_instance_t *mi, jl_value_t *jlretty, StringRef specFunctionObject, jl_code_instance_t *fromexternal, - ArrayRef argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *return_roots, jl_value_t *inferred_retty) + ArrayRef argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *return_roots, jl_value_t *inferred_retty, Value *age_ok) { bool is_opaque_closure = jl_is_method(mi->def.value) && mi->def.method->is_for_opaque_closure; return emit_call_specfun_other(ctx, is_opaque_closure, mi->specTypes, jlretty, NULL, - specFunctionObject, fromexternal, argv, nargs, cc, return_roots, inferred_retty); + specFunctionObject, fromexternal, argv, nargs, cc, return_roots, inferred_retty, age_ok); } static jl_cgval_t emit_call_specfun_boxed(jl_codectx_t &ctx, jl_value_t *jlretty, StringRef specFunctionObject, jl_code_instance_t *fromexternal, - ArrayRef argv, size_t nargs, jl_value_t *inferred_retty) + ArrayRef argv, size_t nargs, jl_value_t *inferred_retty, Value *age_ok) { Value *theFptr; if (fromexternal) { @@ -5407,6 +5420,8 @@ static jl_cgval_t emit_call_specfun_boxed(jl_codectx_t &ctx, jl_value_t *jlretty theFptr = jl_Module->getOrInsertFunction(specFunctionObject, ctx.types().T_jlfunc).getCallee(); addRetAttr(cast(theFptr), Attribute::NonNull); } + if (age_ok) + theFptr = ctx.builder.CreateSelect(age_ok, theFptr, prepare_call(jlapplygeneric_func)); Value *ret = emit_jlcall(ctx, FunctionCallee(ctx.types().T_jlfunc, theFptr), nullptr, argv, nargs, julia_call); return update_julia_type(ctx, mark_julia_type(ctx, ret, true, jlretty), inferred_retty); } @@ -5425,10 +5440,10 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, jl_expr_t *ex, jl_value_t *rt) if (argv[i].typ == jl_bottom_type) return jl_cgval_t(); } - return emit_invoke(ctx, lival, argv, nargs, rt); + return emit_invoke(ctx, lival, argv, nargs, rt, nullptr); } -static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayRef argv, size_t nargs, jl_value_t *rt) +static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayRef argv, size_t nargs, jl_value_t *rt, Value *age_ok) { ++EmittedInvokes; bool handled = false; @@ -5451,12 +5466,12 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayR FunctionType *ft = ctx.f->getFunctionType(); StringRef protoname = ctx.f->getName(); if (ft == ctx.types().T_jlfunc) { - result = emit_call_specfun_boxed(ctx, ctx.rettype, protoname, nullptr, argv, nargs, rt); + result = emit_call_specfun_boxed(ctx, ctx.rettype, protoname, nullptr, argv, nargs, rt, age_ok); handled = true; } else if (ft != ctx.types().T_jlfuncparams) { unsigned return_roots = 0; - result = emit_call_specfun_other(ctx, mi, ctx.rettype, protoname, nullptr, argv, nargs, &cc, &return_roots, rt); + result = emit_call_specfun_other(ctx, mi, ctx.rettype, protoname, nullptr, argv, nargs, &cc, &return_roots, rt, age_ok); handled = true; } } @@ -5516,9 +5531,9 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayR jl_returninfo_t::CallingConv cc = jl_returninfo_t::CallingConv::Boxed; unsigned return_roots = 0; if (specsig) - result = emit_call_specfun_other(ctx, mi, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, &cc, &return_roots, rt); + result = emit_call_specfun_other(ctx, mi, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, &cc, &return_roots, rt, age_ok); else - result = emit_call_specfun_boxed(ctx, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, rt); + result = emit_call_specfun_boxed(ctx, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, rt, age_ok); handled = true; if (need_to_emit) { Function *trampoline_decl = cast(jl_Module->getNamedValue(protoname)); @@ -5542,8 +5557,8 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayR print_stacktrace(ctx, ctx.params->trim); } } - Value *r = emit_jlcall(ctx, jlinvoke_func, boxed(ctx, lival), argv, nargs, julia_call2); - result = mark_julia_type(ctx, r, true, rt); + Value *r = age_ok ? emit_jlcall(ctx, jlapplygeneric_func, nullptr, argv, nargs, julia_call) : emit_jlcall(ctx, jlinvoke_func, boxed(ctx, lival), argv, nargs, julia_call2); + result = mark_julia_type(ctx, r, true, age_ok ? (jl_value_t*)jl_any_type : rt); } if (result.typ == jl_bottom_type) { #ifndef JL_NDEBUG @@ -5636,7 +5651,7 @@ static jl_cgval_t emit_specsig_oc_call(jl_codectx_t &ctx, jl_value_t *oc_type, j Value *specptr = emit_unbox(ctx, ctx.types().T_size, closure_specptr, (jl_value_t*)jl_long_type); JL_GC_PUSH1(&sigtype); jl_cgval_t r = emit_call_specfun_other(ctx, true, sigtype, oc_rett, specptr, "", NULL, argv, nargs, - &cc, &return_roots, oc_rett); + &cc, &return_roots, oc_rett, nullptr); JL_GC_POP(); return r; } @@ -7189,8 +7204,7 @@ Function *emit_tojlinvoke(jl_code_instance_t *codeinst, StringRef theFptrName, M name, M); jl_init_function(f, params.TargetTriple); if (trim_may_error(params.params->trim)) { - // TODO: Debuginfo! - push_frames(ctx, ctx.linfo, codeinst->def, 1); + push_frames(ctx, ctx.linfo, codeinst->def); } jl_name_jlfunc_args(params, f); //f->setAlwaysInline(); @@ -7232,11 +7246,10 @@ void emit_specsig_to_fptr1( jl_value_t *calltype, jl_value_t *rettype, bool is_for_opaque_closure, size_t nargs, jl_codegen_params_t ¶ms, - Function *target, - size_t min_world, size_t max_world) + Function *target) { ++EmittedCFuncInvalidates; - jl_codectx_t ctx(gf_thunk->getParent()->getContext(), params, min_world, max_world); + jl_codectx_t ctx(gf_thunk->getParent()->getContext(), params, 0, 0); ctx.f = gf_thunk; BasicBlock *b0 = BasicBlock::Create(ctx.builder.getContext(), "top", gf_thunk); @@ -7353,12 +7366,11 @@ void emit_specsig_to_fptr1( } } -static Function* gen_cfun_wrapper( +static Function *gen_cfun_wrapper( Module *into, jl_codegen_params_t ¶ms, const function_sig_t &sig, jl_value_t *ff, const char *aliasname, jl_value_t *declrt, jl_method_instance_t *lam, - jl_unionall_t *unionall_env, jl_svec_t *sparam_vals, jl_array_t **closure_types, - size_t min_world, size_t max_world) + jl_unionall_t *unionall_env, jl_svec_t *sparam_vals, jl_array_t **closure_types) { ++GeneratedCFuncWrappers; // Generate a c-callable wrapper @@ -7366,36 +7378,17 @@ static Function* gen_cfun_wrapper( size_t nargs = sig.nccallargs; const char *name = "cfunction"; size_t world = jl_atomic_load_acquire(&jl_world_counter); - jl_code_instance_t *codeinst = NULL; bool nest = (!ff || unionall_env); jl_value_t *astrt = (jl_value_t*)jl_any_type; - void *callptr = NULL; - jl_callptr_t invoke = NULL; - int calltype = 0; if (aliasname) name = aliasname; else if (lam) name = jl_symbol_name(lam->def.method->name); - if (lam && params.cache) { + + jl_code_instance_t *codeinst = NULL; + if (lam) { // TODO: this isn't ideal to be unconditionally calling type inference (and compile) from here - codeinst = jl_compile_method_internal(lam, world); - uint8_t specsigflags; - void *fptr; - jl_read_codeinst_invoke(codeinst, &specsigflags, &invoke, &fptr, 0); - assert(invoke); - if (invoke == jl_fptr_args_addr) { - callptr = fptr; - calltype = 1; - } - else if (invoke == jl_fptr_const_return_addr) { - // don't need the fptr - callptr = (void*)codeinst->rettype_const; - calltype = 2; - } - else if (specsigflags & 0b1) { - callptr = fptr; - calltype = 3; - } + codeinst = jl_type_infer(lam, world, SOURCE_MODE_NOT_REQUIRED); astrt = codeinst->rettype; if (astrt != (jl_value_t*)jl_bottom_type && jl_type_intersection(astrt, declrt) == jl_bottom_type) { @@ -7471,7 +7464,7 @@ static Function* gen_cfun_wrapper( jl_init_function(cw, params.TargetTriple); cw->setAttributes(AttributeList::get(M->getContext(), {attributes, cw->getAttributes()})); - jl_codectx_t ctx(M->getContext(), params, min_world, max_world); + jl_codectx_t ctx(M->getContext(), params, 0, 0); ctx.f = cw; ctx.name = name; ctx.funcName = name; @@ -7490,8 +7483,8 @@ static Function* gen_cfun_wrapper( prepare_global_in(jl_Module, jlgetworld_global), ctx.types().alignof_ptr); cast(world_v)->setOrdering(AtomicOrdering::Acquire); - Value *age_ok = NULL; - if (calltype) { + Value *age_ok = nullptr; + if (codeinst) { LoadInst *lam_max = ctx.builder.CreateAlignedLoad( ctx.types().T_size, emit_ptrgep(ctx, literal_pointer_val(ctx, (jl_value_t*)codeinst), offsetof(jl_code_instance_t, max_world)), @@ -7655,79 +7648,9 @@ static Function* gen_cfun_wrapper( // Create the call bool jlfunc_sret; jl_cgval_t retval; - if (calltype == 2) { - nargs = 0; // arguments not needed -- TODO: not really true, should emit an age_ok test and jlcall - (void)nargs; // silence unused variable warning - jlfunc_sret = false; - retval = mark_julia_const(ctx, (jl_value_t*)callptr); - } - else if (calltype == 0 || calltype == 1) { - // emit a jlcall - jlfunc_sret = false; - Function *theFptr = NULL; - if (calltype == 1) { - StringRef fname = jl_ExecutionEngine->getFunctionAtAddress((uintptr_t)callptr, invoke, codeinst); - theFptr = cast_or_null(jl_Module->getNamedValue(fname)); - if (!theFptr) { - theFptr = Function::Create(ctx.types().T_jlfunc, GlobalVariable::ExternalLinkage, - fname, jl_Module); - jl_init_function(theFptr, ctx.emission_context.TargetTriple); - jl_name_jlfunc_args(ctx.emission_context, theFptr); - addRetAttr(theFptr, Attribute::NonNull); - } - else { - assert(theFptr->getFunctionType() == ctx.types().T_jlfunc); - } - } - BasicBlock *b_generic, *b_jlcall, *b_after; - Value *ret_jlcall; - if (age_ok) { - assert(theFptr); - b_generic = BasicBlock::Create(ctx.builder.getContext(), "generic", cw); - b_jlcall = BasicBlock::Create(ctx.builder.getContext(), "apply", cw); - b_after = BasicBlock::Create(ctx.builder.getContext(), "after", cw); - ctx.builder.CreateCondBr(age_ok, b_jlcall, b_generic); - ctx.builder.SetInsertPoint(b_jlcall); - // for jlcall, we need to pass the function object even if it is a ghost. - Value *theF = boxed(ctx, inputargs[0]); - assert(theF); - ret_jlcall = emit_jlcall(ctx, theFptr, theF, ArrayRef(inputargs).drop_front(), nargs, julia_call); - ctx.builder.CreateBr(b_after); - ctx.builder.SetInsertPoint(b_generic); - } - Value *ret = emit_jlcall(ctx, jlapplygeneric_func, NULL, inputargs, nargs + 1, julia_call); - if (age_ok) { - ctx.builder.CreateBr(b_after); - ctx.builder.SetInsertPoint(b_after); - PHINode *retphi = ctx.builder.CreatePHI(ctx.types().T_prjlvalue, 2); - retphi->addIncoming(ret_jlcall, b_jlcall); - retphi->addIncoming(ret, b_generic); - ret = retphi; - } - retval = mark_julia_type(ctx, ret, true, astrt); - } - else { - bool is_opaque_closure = jl_is_method(lam->def.value) && lam->def.method->is_for_opaque_closure; - assert(calltype == 3); - // emit a specsig call - StringRef protoname = jl_ExecutionEngine->getFunctionAtAddress((uintptr_t)callptr, invoke, codeinst); - bool gcstack_arg = JL_FEAT_TEST(ctx, gcstack_arg); - jl_returninfo_t returninfo = get_specsig_function(ctx, M, NULL, protoname, lam->specTypes, astrt, is_opaque_closure, gcstack_arg); - if (age_ok) { - funcName += "_gfthunk"; - Function *gf_thunk = Function::Create(returninfo.decl.getFunctionType(), - GlobalVariable::InternalLinkage, funcName, M); - jl_init_function(gf_thunk, ctx.emission_context.TargetTriple); - gf_thunk->setAttributes(AttributeList::get(M->getContext(), {returninfo.attrs, gf_thunk->getAttributes()})); - // build a specsig -> jl_apply_generic converter thunk - // this builds a method that calls jl_apply_generic (as a closure over a singleton function pointer), - // but which has the signature of a specsig - emit_specsig_to_fptr1(gf_thunk, returninfo.cc, returninfo.return_roots, lam->specTypes, codeinst->rettype, is_opaque_closure, nargs + 1, ctx.emission_context, - prepare_call_in(gf_thunk->getParent(), jlapplygeneric_func), min_world, max_world); - returninfo.decl = FunctionCallee(returninfo.decl.getFunctionType(), ctx.builder.CreateSelect(age_ok, returninfo.decl.getCallee(), gf_thunk)); - } - retval = emit_call_specfun_other(ctx, is_opaque_closure, lam->specTypes, codeinst->rettype, returninfo, nullptr, inputargs, nargs + 1); - jlfunc_sret = (returninfo.cc == jl_returninfo_t::SRet); + if (codeinst) { + retval = emit_invoke(ctx, mark_julia_const(ctx, (jl_value_t*)codeinst), inputargs, nargs + 1, astrt, age_ok); + jlfunc_sret = retval.V && isa(retval.V) && !retval.TIndex && retval.inline_roots.empty(); if (jlfunc_sret && sig.sret) { // fuse the two sret together assert(retval.ispointer()); @@ -7737,6 +7660,12 @@ static Function* gen_cfun_wrapper( result->eraseFromParent(); } } + else { + // emit a dispatch + jlfunc_sret = false; + Value *ret = emit_jlcall(ctx, jlapplygeneric_func, NULL, inputargs, nargs + 1, julia_call); + retval = mark_julia_type(ctx, ret, true, astrt); + } // inline a call to typeassert here, if required emit_typecheck(ctx, retval, declrt, "cfunction"); @@ -7909,15 +7838,13 @@ static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, con } } size_t world = jl_atomic_load_acquire(&jl_world_counter); - size_t min_valid = 0; - size_t max_valid = ~(size_t)0; // try to look up this function for direct invoking - jl_method_instance_t *lam = sigt ? jl_get_specialization1((jl_tupletype_t*)sigt, world, &min_valid, &max_valid, 0) : NULL; + jl_method_instance_t *lam = sigt ? jl_get_specialization1((jl_tupletype_t*)sigt, world, 0) : NULL; Value *F = gen_cfun_wrapper( jl_Module, ctx.emission_context, sig, fexpr_rt.constant, NULL, declrt, lam, - unionall_env, sparam_vals, &closure_types, min_valid, max_valid); + unionall_env, sparam_vals, &closure_types); bool outboxed; if (nest) { // F is actually an init_trampoline function that returns the real address @@ -7977,7 +7904,7 @@ static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, con // do codegen to create a C-callable alias/wrapper, or if sysimg_handle is set, // restore one from a loaded system image. -const char *jl_generate_ccallable(LLVMOrcThreadSafeModuleRef llvmmod, void *sysimg_handle, jl_value_t *declrt, jl_value_t *sigt, jl_codegen_params_t ¶ms) +const char *jl_generate_ccallable(Module *llvmmod, void *sysimg_handle, jl_value_t *declrt, jl_value_t *sigt, jl_codegen_params_t ¶ms) { ++GeneratedCCallables; jl_datatype_t *ft = (jl_datatype_t*)jl_tparam0(sigt); @@ -8006,8 +7933,6 @@ const char *jl_generate_ccallable(LLVMOrcThreadSafeModuleRef llvmmod, void *sysi argtypes, NULL, false, CallingConv::C, false, ¶ms); if (sig.err_msg.empty()) { size_t world = jl_atomic_load_acquire(&jl_world_counter); - size_t min_valid = 0; - size_t max_valid = ~(size_t)0; if (sysimg_handle) { // restore a ccallable from the system image void *addr; @@ -8020,9 +7945,9 @@ const char *jl_generate_ccallable(LLVMOrcThreadSafeModuleRef llvmmod, void *sysi } } else { - jl_method_instance_t *lam = jl_get_specialization1((jl_tupletype_t*)sigt, world, &min_valid, &max_valid, 0); + jl_method_instance_t *lam = jl_get_specialization1((jl_tupletype_t*)sigt, world, 0); //Safe b/c params holds context lock - gen_cfun_wrapper(unwrap(llvmmod)->getModuleUnlocked(), params, sig, ff, name, declrt, lam, NULL, NULL, NULL, min_valid, max_valid); + gen_cfun_wrapper(llvmmod, params, sig, ff, name, declrt, lam, NULL, NULL, NULL); } JL_GC_POP(); return name; @@ -8084,7 +8009,7 @@ static void gen_invoke_wrapper(jl_method_instance_t *lam, jl_value_t *jlretty, j } argv[i] = mark_julia_type(ctx, theArg, true, ty); } - jl_cgval_t retval = emit_call_specfun_other(ctx, is_opaque_closure, lam->specTypes, jlretty, f, nullptr, argv, nargs); + jl_cgval_t retval = emit_call_specfun_other(ctx, is_opaque_closure, lam->specTypes, jlretty, f, argv, nargs); if (retarg != -1) { Value *theArg; if (retarg == 0) @@ -10040,8 +9965,7 @@ static jl_llvm_functions_t jl_emit_oc_wrapper(orc::ThreadSafeModule &m, jl_codeg size_t nrealargs = jl_nparams(mi->specTypes); emit_specsig_to_fptr1(gf_thunk, returninfo.cc, returninfo.return_roots, mi->specTypes, rettype, true, nrealargs, ctx.emission_context, - prepare_call_in(gf_thunk->getParent(), jlopaque_closure_call_func), // TODO: this could call emit_oc_call directly - ctx.min_world, ctx.max_world); + prepare_call_in(gf_thunk->getParent(), jlopaque_closure_call_func)); // TODO: this could call emit_oc_call directly declarations.specFunctionObject = funcName; } return declarations; diff --git a/src/gf.c b/src/gf.c index bbf065a4fac0d..a5ba309784557 100644 --- a/src/gf.c +++ b/src/gf.c @@ -3084,7 +3084,7 @@ JL_DLLEXPORT jl_method_instance_t *jl_method_match_to_mi(jl_method_match_t *matc } // compile-time method lookup -jl_method_instance_t *jl_get_specialization1(jl_tupletype_t *types JL_PROPAGATES_ROOT, size_t world, size_t *min_valid, size_t *max_valid, int mt_cache) +jl_method_instance_t *jl_get_specialization1(jl_tupletype_t *types JL_PROPAGATES_ROOT, size_t world, int mt_cache) { if (jl_has_free_typevars((jl_value_t*)types)) return NULL; // don't poison the cache due to a malformed query @@ -3096,10 +3096,6 @@ jl_method_instance_t *jl_get_specialization1(jl_tupletype_t *types JL_PROPAGATES size_t max_valid2 = ~(size_t)0; int ambig = 0; jl_value_t *matches = jl_matching_methods(types, jl_nothing, 1, 1, world, &min_valid2, &max_valid2, &ambig); - if (*min_valid < min_valid2) - *min_valid = min_valid2; - if (*max_valid > max_valid2) - *max_valid = max_valid2; if (matches == jl_nothing || jl_array_nrows(matches) != 1 || ambig) return NULL; JL_GC_PUSH1(&matches); diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 80867daade267..25494ba57d257 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -382,7 +382,7 @@ static int jl_analyze_workqueue(jl_code_instance_t *callee, jl_codegen_params_t jl_method_instance_t *mi = codeinst->def; size_t nrealargs = jl_nparams(mi->specTypes); // number of actual arguments being passed bool is_opaque_closure = jl_is_method(mi->def.value) && mi->def.method->is_for_opaque_closure; - emit_specsig_to_fptr1(proto.decl, proto.cc, proto.return_roots, mi->specTypes, codeinst->rettype, is_opaque_closure, nrealargs, params, pinvoke, 0, 0); + emit_specsig_to_fptr1(proto.decl, proto.cc, proto.return_roots, mi->specTypes, codeinst->rettype, is_opaque_closure, nrealargs, params, pinvoke); jl_gc_unsafe_leave(ct->ptls, gc_state); preal_decl = ""; // no need to fixup the name } @@ -713,7 +713,7 @@ static void jl_emit_codeinst_to_jit( int waiting = jl_analyze_workqueue(codeinst, params); if (waiting) { auto release = std::move(params.tsctx_lock); // unlock again before moving from it - incompletemodules.insert(std::pair(codeinst, std::make_tuple(std::move(params), waiting))); + incompletemodules.try_emplace(codeinst, std::move(params), waiting); } else { finish_params(result_m.getModuleUnlocked(), params); @@ -760,7 +760,7 @@ static void _jl_compile_codeinst( } -const char *jl_generate_ccallable(LLVMOrcThreadSafeModuleRef llvmmod, void *sysimg_handle, jl_value_t *declrt, jl_value_t *sigt, jl_codegen_params_t ¶ms); +const char *jl_generate_ccallable(Module *llvmmod, void *sysimg_handle, jl_value_t *declrt, jl_value_t *sigt, jl_codegen_params_t ¶ms); // compile a C-callable alias extern "C" JL_DLLEXPORT_CODEGEN @@ -774,45 +774,68 @@ int jl_compile_extern_c_impl(LLVMOrcThreadSafeModuleRef llvmmod, void *p, void * uint8_t measure_compile_time_enabled = jl_atomic_load_relaxed(&jl_measure_compile_time_enabled); if (measure_compile_time_enabled) compiler_start_time = jl_hrtime(); + jl_codegen_params_t *pparams = (jl_codegen_params_t*)p; + DataLayout DL = pparams ? pparams->DL : jl_ExecutionEngine->getDataLayout(); + Triple TargetTriple = pparams ? pparams->TargetTriple : jl_ExecutionEngine->getTargetTriple(); orc::ThreadSafeContext ctx; auto into = unwrap(llvmmod); - jl_codegen_params_t *pparams = (jl_codegen_params_t*)p; orc::ThreadSafeModule backing; + bool success = true; + const char *name = ""; + SmallVector dependencies; if (into == NULL) { - if (!pparams) { - ctx = jl_ExecutionEngine->makeContext(); - } - backing = jl_create_ts_module("cextern", pparams ? pparams->tsctx : ctx, pparams ? pparams->DL : jl_ExecutionEngine->getDataLayout(), pparams ? pparams->TargetTriple : jl_ExecutionEngine->getTargetTriple()); + ctx = pparams ? pparams->tsctx : jl_ExecutionEngine->makeContext(); + backing = jl_create_ts_module("cextern", ctx, DL, TargetTriple); into = &backing; } - bool success = true; - { - auto Lock = into->getContext().getLock(); - Module *M = into->getModuleUnlocked(); - jl_codegen_params_t params(into->getContext(), M->getDataLayout(), Triple(M->getTargetTriple())); - params.imaging_mode = imaging_default(); + { // params scope + jl_codegen_params_t params(into->getContext(), DL, TargetTriple); if (pparams == NULL) { - M->getContext().setDiscardValueNames(true); + params.cache = p == NULL; + params.imaging_mode = imaging_default(); + params.tsctx.getContext()->setDiscardValueNames(true); pparams = ¶ms; } - assert(pparams->tsctx.getContext() == into->getContext().getContext()); - const char *name = jl_generate_ccallable(wrap(into), sysimg, declrt, sigt, *pparams); - if (!sysimg) { - jl_unique_gcsafe_lock lock(extern_c_lock); - if (jl_ExecutionEngine->getGlobalValueAddress(name)) { - success = false; + Module &M = *into->getModuleUnlocked(); + assert(pparams->tsctx.getContext() == &M.getContext()); + name = jl_generate_ccallable(&M, sysimg, declrt, sigt, *pparams); + if (!sysimg && !p) { + { // drop lock to keep analyzer happy (since it doesn't know we have the only reference to it) + auto release = std::move(params.tsctx_lock); } - if (success && p == NULL) { - jl_jit_globals(params.global_targets); - assert(params.workqueue.empty()); - if (params._shared_module) { - jl_ExecutionEngine->optimizeDLSyms(*params._shared_module); // safepoint - jl_ExecutionEngine->addModule(orc::ThreadSafeModule(std::move(params._shared_module), params.tsctx)); + { // lock scope + jl_unique_gcsafe_lock lock(extern_c_lock); + if (jl_ExecutionEngine->getGlobalValueAddress(name)) + success = false; + } + params.tsctx_lock = params.tsctx.getLock(); // re-acquire lock + if (success && params.cache) { + for (auto &it : params.workqueue) { + jl_code_instance_t *codeinst = it.first; + JL_GC_PROMISE_ROOTED(codeinst); + dependencies.push_back(codeinst); + recursive_compile_graph(codeinst, nullptr); } + jl_analyze_workqueue(nullptr, params, true); + assert(params.workqueue.empty()); + finish_params(&M, params); } - if (success && llvmmod == NULL) { - jl_ExecutionEngine->optimizeDLSyms(*M); // safepoint - jl_ExecutionEngine->addModule(std::move(*into)); + } + pparams = nullptr; + } + if (!sysimg && success && llvmmod == NULL) { + { // lock scope + jl_unique_gcsafe_lock lock(extern_c_lock); + if (!jl_ExecutionEngine->getGlobalValueAddress(name)) { + for (auto dep : dependencies) + jl_compile_codeinst_now(dep); + { + auto Lock = backing.getContext().getLock(); + jl_ExecutionEngine->optimizeDLSyms(*backing.getModuleUnlocked()); // safepoint + } + jl_ExecutionEngine->addModule(std::move(backing)); + success = jl_ExecutionEngine->getGlobalValueAddress(name); + assert(success); } } } diff --git a/src/jitlayers.h b/src/jitlayers.h index 6665be6a33faa..b6f1e9ec20c6b 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -260,7 +260,7 @@ struct jl_codegen_params_t { bool external_linkage = false; bool imaging_mode; bool use_swiftcc = true; - jl_codegen_params_t(orc::ThreadSafeContext ctx, DataLayout DL, Triple triple) + jl_codegen_params_t(orc::ThreadSafeContext ctx, DataLayout DL, Triple triple) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER : tsctx(std::move(ctx)), tsctx_lock(tsctx.getLock()), DL(std::move(DL)), @@ -271,6 +271,8 @@ struct jl_codegen_params_t { if (TargetTriple.isRISCV()) use_swiftcc = false; } + jl_codegen_params_t(jl_codegen_params_t &&) JL_NOTSAFEPOINT = default; + ~jl_codegen_params_t() JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE = default; }; jl_llvm_functions_t jl_emit_code( @@ -299,8 +301,7 @@ void emit_specsig_to_fptr1( jl_value_t *calltype, jl_value_t *rettype, bool is_for_opaque_closure, size_t nargs, jl_codegen_params_t ¶ms, - Function *target, - size_t min_world, size_t max_world) JL_NOTSAFEPOINT; + Function *target) JL_NOTSAFEPOINT; Function *get_or_emit_fptr1(StringRef Name, Module *M) JL_NOTSAFEPOINT; void jl_init_function(Function *F, const Triple &TT) JL_NOTSAFEPOINT; diff --git a/src/julia_internal.h b/src/julia_internal.h index 4741316093f95..e0e8158f8e0d9 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -1195,7 +1195,7 @@ _Atomic(jl_value_t*) *jl_table_peek_bp(jl_genericmemory_t *a, jl_value_t *key) J JL_DLLEXPORT jl_method_t *jl_new_method_uninit(jl_module_t*); JL_DLLEXPORT jl_methtable_t *jl_new_method_table(jl_sym_t *name, jl_module_t *module); -JL_DLLEXPORT jl_method_instance_t *jl_get_specialization1(jl_tupletype_t *types, size_t world, size_t *min_valid, size_t *max_valid, int mt_cache); +JL_DLLEXPORT jl_method_instance_t *jl_get_specialization1(jl_tupletype_t *types, size_t world, int mt_cache); jl_method_instance_t *jl_get_specialized(jl_method_t *m, jl_value_t *types, jl_svec_t *sp); JL_DLLEXPORT jl_value_t *jl_rettype_inferred(jl_value_t *owner, jl_method_instance_t *li JL_PROPAGATES_ROOT, size_t min_world, size_t max_world); JL_DLLEXPORT jl_value_t *jl_rettype_inferred_native(jl_method_instance_t *mi, size_t min_world, size_t max_world) JL_NOTSAFEPOINT; diff --git a/src/precompile_utils.c b/src/precompile_utils.c index 81c60ba70d29f..4717351d499b0 100644 --- a/src/precompile_utils.c +++ b/src/precompile_utils.c @@ -264,10 +264,8 @@ static void *jl_precompile_(jl_array_t *m, int external_linkage) jl_value_t *item = jl_array_ptr_ref(m, i); if (jl_is_method_instance(item)) { mi = (jl_method_instance_t*)item; - size_t min_world = 0; - size_t max_world = ~(size_t)0; if (mi != jl_atomic_load_relaxed(&mi->def.method->unspecialized) && !jl_isa_compileable_sig((jl_tupletype_t*)mi->specTypes, mi->sparam_vals, mi->def.method)) - mi = jl_get_specialization1((jl_tupletype_t*)mi->specTypes, jl_atomic_load_acquire(&jl_world_counter), &min_world, &max_world, 0); + mi = jl_get_specialization1((jl_tupletype_t*)mi->specTypes, jl_atomic_load_acquire(&jl_world_counter), 0); if (mi) jl_array_ptr_1d_push(m2, (jl_value_t*)mi); } diff --git a/test/llvmcall.jl b/test/llvmcall.jl index c83ac05b1ec48..ddf66ca680d45 100644 --- a/test/llvmcall.jl +++ b/test/llvmcall.jl @@ -157,7 +157,7 @@ module ObjLoadTest nothing end @test_throws(ErrorException("@ccallable was already defined for this method name"), - @eval @ccallable Cvoid jl_the_callback(not_the_method::Int) = "other") + @eval @ccallable String jl_the_callback(not_the_method::Int) = "other") # Make sure everything up until here gets compiled @test jl_the_callback() === nothing @test jl_the_callback(1) == "other" From 309021d138b16156b969f59bb2c33742b62a4c31 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 12 Dec 2024 16:20:06 -0500 Subject: [PATCH 057/342] gc: simplify sweep_weak_refs logic (#56816) [NFCI] --- src/gc-stock.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/gc-stock.c b/src/gc-stock.c index 61a013f347975..2c285d9a6d369 100644 --- a/src/gc-stock.c +++ b/src/gc-stock.c @@ -388,24 +388,18 @@ static void sweep_weak_refs(void) jl_ptls_t ptls2 = gc_all_tls_states[i]; if (ptls2 != NULL) { size_t n = 0; - size_t ndel = 0; + size_t i = 0; size_t l = ptls2->gc_tls_common.heap.weak_refs.len; void **lst = ptls2->gc_tls_common.heap.weak_refs.items; - if (l == 0) - continue; - while (1) { - jl_weakref_t *wr = (jl_weakref_t*)lst[n]; - if (gc_marked(jl_astaggedvalue(wr)->bits.gc)) + // filter with preserving order + for (i = 0; i < l; i++) { + jl_weakref_t *wr = (jl_weakref_t*)lst[i]; + if (gc_marked(jl_astaggedvalue(wr)->bits.gc)) { + lst[n] = wr; n++; - else - ndel++; - if (n >= l - ndel) - break; - void *tmp = lst[n]; - lst[n] = lst[n + ndel]; - lst[n + ndel] = tmp; + } } - ptls2->gc_tls_common.heap.weak_refs.len -= ndel; + ptls2->gc_tls_common.heap.weak_refs.len = n; } } } From 03a0247eb04bda17d34518b59c61ab1bcacfb6b5 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 12 Dec 2024 21:54:30 -0500 Subject: [PATCH 058/342] gc: improve mallocarrays locality (#56801) --- src/gc-common.c | 13 ++----------- src/gc-common.h | 6 ------ src/gc-debug.c | 10 ++++------ src/gc-stock.c | 36 ++++++++++++++++-------------------- src/gc-tls-common.h | 5 ++--- src/mtarraylist.c | 4 ++-- src/support/arraylist.h | 10 +++++----- 7 files changed, 31 insertions(+), 53 deletions(-) diff --git a/src/gc-common.c b/src/gc-common.c index c751b54f059f5..3d578b81578b1 100644 --- a/src/gc-common.c +++ b/src/gc-common.c @@ -557,17 +557,8 @@ size_t jl_genericmemory_nbytes(jl_genericmemory_t *m) JL_NOTSAFEPOINT // tracking Memorys with malloc'd storage void jl_gc_track_malloced_genericmemory(jl_ptls_t ptls, jl_genericmemory_t *m, int isaligned){ // This is **NOT** a GC safe point. - mallocmemory_t *ma; - if (ptls->gc_tls_common.heap.mafreelist == NULL) { - ma = (mallocmemory_t*)malloc_s(sizeof(mallocmemory_t)); - } - else { - ma = ptls->gc_tls_common.heap.mafreelist; - ptls->gc_tls_common.heap.mafreelist = ma->next; - } - ma->a = (jl_genericmemory_t*)((uintptr_t)m | !!isaligned); - ma->next = ptls->gc_tls_common.heap.mallocarrays; - ptls->gc_tls_common.heap.mallocarrays = ma; + void *a = (void*)((uintptr_t)m | !!isaligned); + small_arraylist_push(&ptls->gc_tls_common.heap.mallocarrays, a); } // =========================================================================== // diff --git a/src/gc-common.h b/src/gc-common.h index 3007151009f7d..1745df17950f9 100644 --- a/src/gc-common.h +++ b/src/gc-common.h @@ -61,12 +61,6 @@ extern jl_gc_callback_list_t *gc_cblist_notify_gc_pressure; // malloc wrappers, aligned allocation // =========================================================================== // -// data structure for tracking malloc'd genericmemory. -typedef struct _mallocmemory_t { - jl_genericmemory_t *a; // lowest bit is tagged if this is aligned memory - struct _mallocmemory_t *next; -} mallocmemory_t; - #if defined(_OS_WINDOWS_) STATIC_INLINE void *jl_malloc_aligned(size_t sz, size_t align) { diff --git a/src/gc-debug.c b/src/gc-debug.c index 7c479484cde45..6e51064035b7b 100644 --- a/src/gc-debug.c +++ b/src/gc-debug.c @@ -1025,12 +1025,11 @@ void gc_stats_big_obj(void) v = v->next; } - mallocmemory_t *ma = ptls2->gc_tls.heap.mallocarrays; - while (ma != NULL) { - uint8_t bits =jl_astaggedvalue(ma->a)->bits.gc; + void **lst = ptls2->gc_tls.heap.mallocarrays.items; + for (size_t i = 0, l = ptls2->gc_tls.heap.mallocarrays.len; i < l; i++) { + jl_genericmemory_t *m = (jl_genericmemory_t*)((uintptr_t)lst[i] & ~(uintptr_t)1); + uint8_t bits = jl_astaggedvalue(m)->bits.gc; if (gc_marked(bits)) { - jl_genericmemory_t *m = (jl_genericmemory_t*)ma->a; - m = (jl_genericmemory_t*)((uintptr_t)m & ~(uintptr_t)1); size_t sz = jl_genericmemory_nbytes(m); if (gc_old(bits)) { assert(bits == GC_OLD_MARKED); @@ -1042,7 +1041,6 @@ void gc_stats_big_obj(void) stat.nbytes_used += sz; } } - ma = ma->next; } } jl_safe_printf("%lld kB (%lld%% old) in %lld large objects (%lld%% old)\n", diff --git a/src/gc-stock.c b/src/gc-stock.c index 2c285d9a6d369..c1bc1d64ae199 100644 --- a/src/gc-stock.c +++ b/src/gc-stock.c @@ -623,10 +623,9 @@ void jl_gc_reset_alloc_count(void) JL_NOTSAFEPOINT reset_thread_gc_counts(); } -static void jl_gc_free_memory(jl_value_t *v, int isaligned) JL_NOTSAFEPOINT +static void jl_gc_free_memory(jl_genericmemory_t *m, int isaligned) JL_NOTSAFEPOINT { - assert(jl_is_genericmemory(v)); - jl_genericmemory_t *m = (jl_genericmemory_t*)v; + assert(jl_is_genericmemory(m)); assert(jl_genericmemory_how(m) == 1 || jl_genericmemory_how(m) == 2); char *d = (char*)m->ptr; size_t freed_bytes = memory_block_usable_size(d, isaligned); @@ -648,25 +647,23 @@ static void sweep_malloced_memory(void) JL_NOTSAFEPOINT for (int t_i = 0; t_i < gc_n_threads; t_i++) { jl_ptls_t ptls2 = gc_all_tls_states[t_i]; if (ptls2 != NULL) { - mallocmemory_t *ma = ptls2->gc_tls_common.heap.mallocarrays; - mallocmemory_t **pma = &ptls2->gc_tls_common.heap.mallocarrays; - while (ma != NULL) { - mallocmemory_t *nxt = ma->next; - jl_value_t *a = (jl_value_t*)((uintptr_t)ma->a & ~1); - int bits = jl_astaggedvalue(a)->bits.gc; - if (gc_marked(bits)) { - pma = &ma->next; + size_t n = 0; + size_t l = ptls2->gc_tls_common.heap.mallocarrays.len; + void **lst = ptls2->gc_tls_common.heap.mallocarrays.items; + // filter without preserving order + while (n < l) { + jl_genericmemory_t *m = (jl_genericmemory_t*)((uintptr_t)lst[n] & ~1); + if (gc_marked(jl_astaggedvalue(m)->bits.gc)) { + n++; } else { - *pma = nxt; - int isaligned = (uintptr_t)ma->a & 1; - jl_gc_free_memory(a, isaligned); - ma->next = ptls2->gc_tls_common.heap.mafreelist; - ptls2->gc_tls_common.heap.mafreelist = ma; + int isaligned = (uintptr_t)lst[n] & 1; + jl_gc_free_memory(m, isaligned); + l--; + lst[n] = lst[l]; } - gc_time_count_mallocd_memory(bits); - ma = nxt; } + ptls2->gc_tls_common.heap.mallocarrays.len = l; } } gc_time_mallocd_memory_end(); @@ -3433,8 +3430,7 @@ void jl_init_thread_heap(jl_ptls_t ptls) small_arraylist_new(&common_heap->live_tasks, 0); for (int i = 0; i < JL_N_STACK_POOLS; i++) small_arraylist_new(&common_heap->free_stacks[i], 0); - common_heap->mallocarrays = NULL; - common_heap->mafreelist = NULL; + small_arraylist_new(&common_heap->mallocarrays, 0); heap->young_generation_of_bigvals = (bigval_t*)calloc_s(sizeof(bigval_t)); // sentinel assert(gc_bigval_sentinel_tag != 0); // make sure the sentinel is initialized heap->young_generation_of_bigvals->header = gc_bigval_sentinel_tag; diff --git a/src/gc-tls-common.h b/src/gc-tls-common.h index ba36f5c1c238e..473668d648294 100644 --- a/src/gc-tls-common.h +++ b/src/gc-tls-common.h @@ -21,9 +21,8 @@ typedef struct { // that are holding onto a stack from the pool small_arraylist_t live_tasks; - // variables for tracking malloc'd arrays - struct _mallocmemory_t *mallocarrays; - struct _mallocmemory_t *mafreelist; + // variable for tracking malloc'd arrays + small_arraylist_t mallocarrays; #define JL_N_STACK_POOLS 16 small_arraylist_t free_stacks[JL_N_STACK_POOLS]; diff --git a/src/mtarraylist.c b/src/mtarraylist.c index 7af265a86ab63..0a0f3fe867e39 100644 --- a/src/mtarraylist.c +++ b/src/mtarraylist.c @@ -14,8 +14,8 @@ extern "C" { // but there can be any number of observers typedef struct { - _Atomic(uint32_t) len; - uint32_t max; + _Atomic(size_t) len; + size_t max; _Atomic(_Atomic(void*)*) items; _Atomic(void*) _space[SMALL_AL_N_INLINE]; } small_mtarraylist_t; diff --git a/src/support/arraylist.h b/src/support/arraylist.h index a83bd2808756c..8d4ef61ba251c 100644 --- a/src/support/arraylist.h +++ b/src/support/arraylist.h @@ -5,7 +5,7 @@ #define AL_N_INLINE 29 -#define SMALL_AL_N_INLINE 6 +#define SMALL_AL_N_INLINE 5 #ifdef __cplusplus extern "C" { @@ -13,7 +13,7 @@ extern "C" { #include "analyzer_annotations.h" -typedef struct { +typedef struct { // 32 words size_t len; size_t max; void **items; @@ -27,9 +27,9 @@ JL_DLLEXPORT void arraylist_push(arraylist_t *a, void *elt) JL_NOTSAFEPOINT; JL_DLLEXPORT void *arraylist_pop(arraylist_t *a) JL_NOTSAFEPOINT; JL_DLLEXPORT void arraylist_grow(arraylist_t *a, size_t n) JL_NOTSAFEPOINT; -typedef struct { - uint32_t len; - uint32_t max; +typedef struct { // 8 words + size_t len; + size_t max; void **items; void *_space[SMALL_AL_N_INLINE]; } small_arraylist_t; From ece1c70184022341439a774eb27915daf377b02c Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Fri, 13 Dec 2024 11:09:19 -0300 Subject: [PATCH 059/342] Fix codegen not handling invoke exprs with Codeinstances iwith jl_fptr_sparam_addr invoke types. (#56817) fixes https://github.com/JuliaLang/julia/issues/56739 I didn't succeed in making a test for this. The sole trigger seems to be ```julia using HMMGradients T = Float32 A = T[0.0 1.0 0.0; 0.0 0.5 0.5; 1.0 0.0 0.0] t2tr = Dict{Int,Vector{Int}}[Dict(1 => [2]),] t2IJ= HMMGradients.t2tr2t2IJ(t2tr) Nt = length(t2tr)+1 Ns = size(A,1) y = rand(T,Nt,Ns) c = rand(Float32, Nt) beta = backward(Nt,A,c,t2IJ,y) gamma = posterior(Nt,t2IJ,A,y) ``` in @oscardssmith memorynew PR One other option is to have the builtin handle receiving a CI. That might make the code cleaner and does handle the case where we receive a dynamic CI (is that even a thing) --- Compiler/test/codegen.jl | 9 ++++ src/codegen.cpp | 106 +++++++++++++++++++++------------------ 2 files changed, 66 insertions(+), 49 deletions(-) diff --git a/Compiler/test/codegen.jl b/Compiler/test/codegen.jl index b6805a77124ca..9ba268fe95be8 100644 --- a/Compiler/test/codegen.jl +++ b/Compiler/test/codegen.jl @@ -1027,3 +1027,12 @@ for a in ((@noinline Ref{Int}(2)), @test ex === a end end + +# Make sure that code that has unbound sparams works +#https://github.com/JuliaLang/julia/issues/56739 + +f56739(a) where {T} = a + +@test f56739(1) == 1 +g56739(x) = @noinline f56739(x) +@test g56739(1) == 1 diff --git a/src/codegen.cpp b/src/codegen.cpp index fbd990857dd94..5656fb594044b 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5484,62 +5484,70 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayR result = mark_julia_const(ctx, codeinst->rettype_const); handled = true; } - else if (invoke != jl_fptr_sparam_addr) { + else { bool specsig, needsparams; std::tie(specsig, needsparams) = uses_specsig(mi, codeinst->rettype, ctx.params->prefer_specsig); - std::string name; - StringRef protoname; - bool need_to_emit = true; - bool cache_valid = ctx.use_cache || ctx.external_linkage; - bool external = false; - - // Check if we already queued this up - auto it = ctx.call_targets.find(codeinst); - if (need_to_emit && it != ctx.call_targets.end()) { - assert(it->second.specsig == specsig); - protoname = it->second.decl->getName(); - need_to_emit = cache_valid = false; - } + if (needsparams) { + if (trim_may_error(ctx.params->trim)) + push_frames(ctx, ctx.linfo, mi); + Value *r = emit_jlcall(ctx, jlinvoke_func, track_pjlvalue(ctx, literal_pointer_val(ctx, (jl_value_t*)mi)), argv, nargs, julia_call2); + result = mark_julia_type(ctx, r, true, rt); + handled = true; + } else { + std::string name; + StringRef protoname; + bool need_to_emit = true; + bool cache_valid = ctx.use_cache || ctx.external_linkage; + bool external = false; + + // Check if we already queued this up + auto it = ctx.call_targets.find(codeinst); + if (need_to_emit && it != ctx.call_targets.end()) { + assert(it->second.specsig == specsig); + protoname = it->second.decl->getName(); + need_to_emit = cache_valid = false; + } - // Check if it is already compiled (either JIT or externally) - if (need_to_emit && cache_valid) { - // optimization: emit the correct name immediately, if we know it - // TODO: use `emitted` map here too to try to consolidate names? - uint8_t specsigflags; - jl_callptr_t invoke; - void *fptr; - jl_read_codeinst_invoke(codeinst, &specsigflags, &invoke, &fptr, 0); - if (specsig ? specsigflags & 0b1 : invoke == jl_fptr_args_addr) { - protoname = jl_ExecutionEngine->getFunctionAtAddress((uintptr_t)fptr, invoke, codeinst); - if (ctx.external_linkage) { - // TODO: Add !specsig support to aotcompile.cpp - // Check that the codeinst is containing native code - if (specsig && (specsigflags & 0b100)) { - external = true; + // Check if it is already compiled (either JIT or externally) + if (need_to_emit && cache_valid) { + // optimization: emit the correct name immediately, if we know it + // TODO: use `emitted` map here too to try to consolidate names? + uint8_t specsigflags; + jl_callptr_t invoke; + void *fptr; + jl_read_codeinst_invoke(codeinst, &specsigflags, &invoke, &fptr, 0); + if (specsig ? specsigflags & 0b1 : invoke == jl_fptr_args_addr) { + protoname = jl_ExecutionEngine->getFunctionAtAddress((uintptr_t)fptr, invoke, codeinst); + if (ctx.external_linkage) { + // TODO: Add !specsig support to aotcompile.cpp + // Check that the codeinst is containing native code + if (specsig && (specsigflags & 0b100)) { + external = true; + need_to_emit = false; + } + } + else { // ctx.use_cache need_to_emit = false; } } - else { // ctx.use_cache - need_to_emit = false; - } } - } - if (need_to_emit) { - raw_string_ostream(name) << (specsig ? "j_" : "j1_") << name_from_method_instance(mi) << "_" << jl_atomic_fetch_add_relaxed(&globalUniqueGeneratedNames, 1); - protoname = StringRef(name); - } - jl_returninfo_t::CallingConv cc = jl_returninfo_t::CallingConv::Boxed; - unsigned return_roots = 0; - if (specsig) - result = emit_call_specfun_other(ctx, mi, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, &cc, &return_roots, rt, age_ok); - else - result = emit_call_specfun_boxed(ctx, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, rt, age_ok); - handled = true; - if (need_to_emit) { - Function *trampoline_decl = cast(jl_Module->getNamedValue(protoname)); - ctx.call_targets[codeinst] = {cc, return_roots, trampoline_decl, nullptr, specsig}; - if (trim_may_error(ctx.params->trim)) - push_frames(ctx, ctx.linfo, mi); + if (need_to_emit) { + raw_string_ostream(name) << (specsig ? "j_" : "j1_") << name_from_method_instance(mi) << "_" << jl_atomic_fetch_add_relaxed(&globalUniqueGeneratedNames, 1); + protoname = StringRef(name); + } + jl_returninfo_t::CallingConv cc = jl_returninfo_t::CallingConv::Boxed; + unsigned return_roots = 0; + if (specsig) + result = emit_call_specfun_other(ctx, mi, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, &cc, &return_roots, rt, age_ok); + else + result = emit_call_specfun_boxed(ctx, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, rt, age_ok); + handled = true; + if (need_to_emit) { + Function *trampoline_decl = cast(jl_Module->getNamedValue(protoname)); + ctx.call_targets[codeinst] = {cc, return_roots, trampoline_decl, nullptr, specsig}; + if (trim_may_error(ctx.params->trim)) + push_frames(ctx, ctx.linfo, mi); + } } } } From fe5ed171ade0795902f21f05ef9defb60e25c4ff Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Sat, 14 Dec 2024 07:41:42 -0500 Subject: [PATCH 060/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?SparseArrays=20stdlib=20from=201b4933c=20to=204fd3aad=20(#56830?= =?UTF-8?q?)?= 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: main Julia branch: master Old commit: 1b4933c New commit: 4fd3aad Julia version: 1.12.0-DEV SparseArrays version: 1.12.0 Bump invoked by: @DilumAluthge Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaSparse/SparseArrays.jl/compare/1b4933ccc7b1f97427ff88bd7ba58950021f2c60...4fd3aad5735e3b80eefe7b068f3407d7dd0c0924 ``` $ git log --oneline 1b4933c..4fd3aad 4fd3aad Generalize `istriu`/`istril` to accept a band index (#590) 780c4de Bump codecov/codecov-action from 4 to 5 (#589) 1beb0e4 Update LICENSE.md (#587) 268d390 QR: handle xtype/dtype returned from LibSuiteSparse that don't match matrix element type (#586) 9731aef get rid of UUID changing stuff (#582) ``` Co-authored-by: Dilum Aluthge --- .../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-1b4933ccc7b1f97427ff88bd7ba58950021f2c60.tar.gz/md5 delete mode 100644 deps/checksums/SparseArrays-1b4933ccc7b1f97427ff88bd7ba58950021f2c60.tar.gz/sha512 create mode 100644 deps/checksums/SparseArrays-4fd3aad5735e3b80eefe7b068f3407d7dd0c0924.tar.gz/md5 create mode 100644 deps/checksums/SparseArrays-4fd3aad5735e3b80eefe7b068f3407d7dd0c0924.tar.gz/sha512 diff --git a/deps/checksums/SparseArrays-1b4933ccc7b1f97427ff88bd7ba58950021f2c60.tar.gz/md5 b/deps/checksums/SparseArrays-1b4933ccc7b1f97427ff88bd7ba58950021f2c60.tar.gz/md5 deleted file mode 100644 index 41d78a15f2ddb..0000000000000 --- a/deps/checksums/SparseArrays-1b4933ccc7b1f97427ff88bd7ba58950021f2c60.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -a643f01ee101a274d86d6469dd6a9d48 diff --git a/deps/checksums/SparseArrays-1b4933ccc7b1f97427ff88bd7ba58950021f2c60.tar.gz/sha512 b/deps/checksums/SparseArrays-1b4933ccc7b1f97427ff88bd7ba58950021f2c60.tar.gz/sha512 deleted file mode 100644 index 1868f9a865af5..0000000000000 --- a/deps/checksums/SparseArrays-1b4933ccc7b1f97427ff88bd7ba58950021f2c60.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -09a86606b28b17f1066d608374f4f8b2fcdcd17d08a8fa37b08edea7b27a9e6becadc8e8e93b1dcc1477dc247255d6a8ded4f8e678f46d80c9fd0ad72a7f3973 diff --git a/deps/checksums/SparseArrays-4fd3aad5735e3b80eefe7b068f3407d7dd0c0924.tar.gz/md5 b/deps/checksums/SparseArrays-4fd3aad5735e3b80eefe7b068f3407d7dd0c0924.tar.gz/md5 new file mode 100644 index 0000000000000..4c75f5c1f619a --- /dev/null +++ b/deps/checksums/SparseArrays-4fd3aad5735e3b80eefe7b068f3407d7dd0c0924.tar.gz/md5 @@ -0,0 +1 @@ +308e26cc6171656caaa7f6ba07e83d1c diff --git a/deps/checksums/SparseArrays-4fd3aad5735e3b80eefe7b068f3407d7dd0c0924.tar.gz/sha512 b/deps/checksums/SparseArrays-4fd3aad5735e3b80eefe7b068f3407d7dd0c0924.tar.gz/sha512 new file mode 100644 index 0000000000000..ad389d6e42048 --- /dev/null +++ b/deps/checksums/SparseArrays-4fd3aad5735e3b80eefe7b068f3407d7dd0c0924.tar.gz/sha512 @@ -0,0 +1 @@ +62b94ad0dca0d62e5753f50aef806ebdb5c8b56b241a285957190845be21fc6b8c8f93089b6f627795f6d7f2b1b01118bcff87c21102a3f3bae6d4c408362681 diff --git a/stdlib/SparseArrays.version b/stdlib/SparseArrays.version index af6fac41ddf84..0ff7a761bffa3 100644 --- a/stdlib/SparseArrays.version +++ b/stdlib/SparseArrays.version @@ -1,4 +1,4 @@ SPARSEARRAYS_BRANCH = main -SPARSEARRAYS_SHA1 = 1b4933ccc7b1f97427ff88bd7ba58950021f2c60 +SPARSEARRAYS_SHA1 = 4fd3aad5735e3b80eefe7b068f3407d7dd0c0924 SPARSEARRAYS_GIT_URL := https://github.com/JuliaSparse/SparseArrays.jl.git SPARSEARRAYS_TAR_URL = https://api.github.com/repos/JuliaSparse/SparseArrays.jl/tarball/$1 From f84d0c4014decb2607c7a54285bb028311e22c77 Mon Sep 17 00:00:00 2001 From: Katharine Hyatt Date: Sat, 14 Dec 2024 16:07:22 -0500 Subject: [PATCH 061/342] Missing tests for IdSet (#56258) Co-authored-by: CY Han --- test/sets.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/sets.jl b/test/sets.jl index b78d2f15dd989..4d52cb243620c 100644 --- a/test/sets.jl +++ b/test/sets.jl @@ -1037,6 +1037,8 @@ end @test !isempty(A) A = empty!(A) @test isempty(A) + @test isnothing(sizehint!(A, 10)) + @test Base.copymutable(A) == copy(A) end @testset "⊊, ⊋" begin From 06f988b74150367ac7000f2db25e4864cf9cb036 Mon Sep 17 00:00:00 2001 From: Jakob Nybo Nissen Date: Sat, 14 Dec 2024 22:20:31 +0100 Subject: [PATCH 062/342] Fix eltype of flatten of tuple with non-2 length (#56802) In 4c076c80af, eltype of flatten of tuple was improved by computing a refined eltype at compile time. However, this implementation only worked for length-2 tuples, and errored for all others. Generalize this to all tuples. Closes #56783 --------- Co-authored-by: Neven Sajko --- base/iterators.jl | 12 +++++++++--- test/iterators.jl | 8 ++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/base/iterators.jl b/base/iterators.jl index 6b8d9fe75e302..c6278e6284d70 100644 --- a/base/iterators.jl +++ b/base/iterators.jl @@ -15,7 +15,8 @@ using .Base: AbstractRange, AbstractUnitRange, UnitRange, LinearIndices, TupleOrBottom, (:), |, +, -, *, !==, !, ==, !=, <=, <, >, >=, =>, missing, any, _counttuple, eachindex, ntuple, zero, prod, reduce, in, firstindex, lastindex, - tail, fieldtypes, min, max, minimum, zero, oneunit, promote, promote_shape, LazyString + tail, fieldtypes, min, max, minimum, zero, oneunit, promote, promote_shape, LazyString, + afoldl using Core: @doc using .Base: @@ -1202,8 +1203,13 @@ julia> [(x,y) for x in 0:1 for y in 'a':'c'] # collects generators involving It flatten(itr) = Flatten(itr) eltype(::Type{Flatten{I}}) where {I} = eltype(eltype(I)) -eltype(::Type{Flatten{I}}) where {I<:Union{Tuple,NamedTuple}} = promote_typejoin(map(eltype, fieldtypes(I))...) -eltype(::Type{Flatten{Tuple{}}}) = eltype(Tuple{}) + +# For tuples, we statically know the element type of each index, so we can compute +# this at compile time. +function eltype(::Type{Flatten{I}}) where {I<:Union{Tuple,NamedTuple}} + afoldl((T, i) -> promote_typejoin(T, eltype(i)), Union{}, fieldtypes(I)...) +end + IteratorEltype(::Type{Flatten{I}}) where {I} = _flatteneltype(I, IteratorEltype(I)) IteratorEltype(::Type{Flatten{Tuple{}}}) = IteratorEltype(Tuple{}) _flatteneltype(I, ::HasEltype) = IteratorEltype(eltype(I)) diff --git a/test/iterators.jl b/test/iterators.jl index d1e7525c43465..1feccf5fb1d3e 100644 --- a/test/iterators.jl +++ b/test/iterators.jl @@ -515,6 +515,14 @@ end @test eltype(flatten(UnitRange{Int8}[1:2, 3:4])) == Int8 @test eltype(flatten(([1, 2], [3.0, 4.0]))) == Real @test eltype(flatten((a = [1, 2], b = Int8[3, 4]))) == Signed +@test eltype(flatten((Int[], Nothing[], Int[]))) == Union{Int, Nothing} +@test eltype(flatten((String[],))) == String +@test eltype(flatten((Int[], UInt[], Int8[],))) == Integer +@test eltype(flatten((; a = Int[], b = Nothing[], c = Int[]))) == Union{Int, Nothing} +@test eltype(flatten((; a = String[],))) == String +@test eltype(flatten((; a = Int[], b = UInt[], c = Int8[],))) == Integer +@test eltype(flatten(())) == Union{} +@test eltype(flatten((;))) == Union{} @test length(flatten(zip(1:3, 4:6))) == 6 @test length(flatten(1:6)) == 6 @test collect(flatten(Any[])) == Any[] From 006f19c33ccb5563bff06168c7a952fbc4154279 Mon Sep 17 00:00:00 2001 From: Dilum Aluthge Date: Sat, 14 Dec 2024 19:42:17 -0500 Subject: [PATCH 063/342] Skip or loosen two `errorshow` tests on 32-bit Windows (#56837) Ref #55900. --- test/errorshow.jl | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/test/errorshow.jl b/test/errorshow.jl index 7a3d50d599f2e..f83bbe31b7cc4 100644 --- a/test/errorshow.jl +++ b/test/errorshow.jl @@ -791,8 +791,22 @@ backtrace() @test occursin("g28442", output[3]) @test lstrip(output[5])[1:3] == "[2]" @test occursin("f28442", output[5]) - @test occursin("the above 2 lines are repeated 5000 more times", output[7]) - @test lstrip(output[8])[1:7] == "[10003]" + is_windows_32_bit = Sys.iswindows() && (Sys.WORD_SIZE == 32) + if is_windows_32_bit + # These tests are currently broken (intermittently/non-determistically) on 32-bit Windows. + # https://github.com/JuliaLang/julia/issues/55900 + # Instead of skipping them entirely, we skip one, and we loosen the other. + + # Broken test: @test occursin("the above 2 lines are repeated 5000 more times", output[7]) + @test occursin("the above 2 lines are repeated ", output[7]) + @test occursin(" more times", output[7]) + + # Broken test: @test lstrip(output[8])[1:7] == "[10003]" + @test_broken false + else + @test occursin("the above 2 lines are repeated 5000 more times", output[7]) + @test lstrip(output[8])[1:7] == "[10003]" + end end @testset "Line number correction" begin From 5eb07d54e95ba58a595d51fd0b6d36d3c2472684 Mon Sep 17 00:00:00 2001 From: Priynsh <119518987+Priynsh@users.noreply.github.com> Date: Sun, 15 Dec 2024 09:40:56 +0530 Subject: [PATCH 064/342] Adding tests for AbstractArrayMath.jl (#56773) added tests for lines 7, 137-154 (insertdims function) from base/abstractarraymath.jl --------- Co-authored-by: Lilith Orion Hafner Co-authored-by: Dilum Aluthge --- test/abstractarray.jl | 21 +++++++++++++++ test/arrayops.jl | 62 ++++++++++++++++++++++++------------------- 2 files changed, 55 insertions(+), 28 deletions(-) diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 4af4099eced45..c7ec61704c1bc 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -2206,3 +2206,24 @@ end @test b.ref === a.ref end end +@testset "AbstractArrayMath" begin + @testset "IsReal" begin + A = [1, 2, 3, 4] + @test isreal(A) == true + B = [1.1, 2.2, 3.3, 4.4] + @test isreal(B) == true + C = [1, 2.2, 3] + @test isreal(C) == true + D = Real[] + @test isreal(D) == true + E = [1 + 1im, 2 - 2im] + @test isreal(E) == false + struct MyReal <: Real + value::Float64 + end + F = [MyReal(1.0), MyReal(2.0)] + @test isreal(F) == true + G = ["a", "b", "c"] + @test_throws MethodError isreal(G) + end +end diff --git a/test/arrayops.jl b/test/arrayops.jl index ca378c3f3036b..655e14675bfb4 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -307,34 +307,40 @@ end @test_throws ArgumentError dropdims(a, dims=3) @test_throws ArgumentError dropdims(a, dims=4) @test_throws ArgumentError dropdims(a, dims=6) - - - a = rand(8, 7) - @test @inferred(insertdims(a, dims=1)) == @inferred(insertdims(a, dims=(1,))) == reshape(a, (1, 8, 7)) - @test @inferred(insertdims(a, dims=3)) == @inferred(insertdims(a, dims=(3,))) == reshape(a, (8, 7, 1)) - @test @inferred(insertdims(a, dims=(1, 3))) == reshape(a, (1, 8, 1, 7)) - @test @inferred(insertdims(a, dims=(1, 2, 3))) == reshape(a, (1, 1, 1, 8, 7)) - @test @inferred(insertdims(a, dims=(1, 4))) == reshape(a, (1, 8, 7, 1)) - @test @inferred(insertdims(a, dims=(1, 3, 5))) == reshape(a, (1, 8, 1, 7, 1)) - @test @inferred(insertdims(a, dims=(1, 2, 4, 6))) == reshape(a, (1, 1, 8, 1, 7, 1)) - @test @inferred(insertdims(a, dims=(1, 3, 4, 6))) == reshape(a, (1, 8, 1, 1, 7, 1)) - @test @inferred(insertdims(a, dims=(1, 4, 6, 3))) == reshape(a, (1, 8, 1, 1, 7, 1)) - @test @inferred(insertdims(a, dims=(1, 3, 5, 6))) == reshape(a, (1, 8, 1, 7, 1, 1)) - - @test_throws ArgumentError insertdims(a, dims=(1, 1, 2, 3)) - @test_throws ArgumentError insertdims(a, dims=(1, 2, 2, 3)) - @test_throws ArgumentError insertdims(a, dims=(1, 2, 3, 3)) - @test_throws UndefKeywordError insertdims(a) - @test_throws ArgumentError insertdims(a, dims=0) - @test_throws ArgumentError insertdims(a, dims=(1, 2, 1)) - @test_throws ArgumentError insertdims(a, dims=4) - @test_throws ArgumentError insertdims(a, dims=6) - - # insertdims and dropdims are inverses - b = rand(1,1,1,5,1,1,7) - for dims in [1, (1,), 2, (2,), 3, (3,), (1,3), (1,2,3), (1,2), (1,3,5), (1,2,5,6), (1,3,5,6), (1,3,5,6), (1,6,5,3)] - @test dropdims(insertdims(a; dims); dims) == a - @test insertdims(dropdims(b; dims); dims) == b + @testset "insertdims" begin + a = rand(8, 7) + @test @inferred(insertdims(a, dims=1)) == @inferred(insertdims(a, dims=(1,))) == reshape(a, (1, 8, 7)) + @test @inferred(insertdims(a, dims=3)) == @inferred(insertdims(a, dims=(3,))) == reshape(a, (8, 7, 1)) + @test @inferred(insertdims(a, dims=(1, 3))) == reshape(a, (1, 8, 1, 7)) + @test @inferred(insertdims(a, dims=(1, 2, 3))) == reshape(a, (1, 1, 1, 8, 7)) + @test @inferred(insertdims(a, dims=(1, 4))) == reshape(a, (1, 8, 7, 1)) + @test @inferred(insertdims(a, dims=(1, 3, 5))) == reshape(a, (1, 8, 1, 7, 1)) + @test @inferred(insertdims(a, dims=(1, 2, 4, 6))) == reshape(a, (1, 1, 8, 1, 7, 1)) + @test @inferred(insertdims(a, dims=(1, 3, 4, 6))) == reshape(a, (1, 8, 1, 1, 7, 1)) + @test @inferred(insertdims(a, dims=(1, 4, 6, 3))) == reshape(a, (1, 8, 1, 1, 7, 1)) + @test @inferred(insertdims(a, dims=(1, 3, 5, 6))) == reshape(a, (1, 8, 1, 7, 1, 1)) + @test_throws ArgumentError insertdims(a, dims=(1, 1, 2, 3)) + @test_throws ArgumentError insertdims(a, dims=(1, 2, 2, 3)) + @test_throws ArgumentError insertdims(a, dims=(1, 2, 3, 3)) + @test_throws UndefKeywordError insertdims(a) + @test_throws ArgumentError insertdims(a, dims=0) + @test_throws ArgumentError insertdims(a, dims=(1, 2, 1)) + @test_throws ArgumentError insertdims(a, dims=4) + @test_throws ArgumentError insertdims(a, dims=6) + A = reshape(1:6, 2, 3) + @test_throws ArgumentError insertdims(A, dims=(2, 2)) + D = insertdims(A, dims=()) + @test size(D) == size(A) + @test D == A + E = ones(2, 3, 4) + F = insertdims(E, dims=(2, 4, 6)) + @test size(F) == (2, 1, 3, 1, 4, 1) + # insertdims and dropdims are inverses + b = rand(1,1,1,5,1,1,7) + for dims in [1, (1,), 2, (2,), 3, (3,), (1,3), (1,2,3), (1,2), (1,3,5), (1,2,5,6), (1,3,5,6), (1,3,5,6), (1,6,5,3)] + @test dropdims(insertdims(a; dims); dims) == a + @test insertdims(dropdims(b; dims); dims) == b + end end sz = (5,8,7) From 98a8ffc18b7df98fcebadfaa2de8281789ad92e9 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Sun, 15 Dec 2024 06:44:02 -0500 Subject: [PATCH 065/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?Downloads=20stdlib=20from=2089d3c7d=20to=20afd04be=20(#56826)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: Downloads URL: https://github.com/JuliaLang/Downloads.jl.git Stdlib branch: master Julia branch: master Old commit: 89d3c7d New commit: afd04be Julia version: 1.12.0-DEV Downloads version: 1.6.0(It's okay that it doesn't match) Bump invoked by: @DilumAluthge Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaLang/Downloads.jl/compare/89d3c7dded535a77551e763a437a6d31e4d9bf84...afd04be8aa94204c075c8aec83fca040ebb4ff98 ``` $ git log --oneline 89d3c7d..afd04be afd04be Bump codecov/codecov-action from 4 to 5 (#264) 39036e1 CI: Use Dependabot to automatically update external GitHub Actions (#263) 78e7c7c Bump CI actions versions (#252) ``` Co-authored-by: Dilum Aluthge --- .../md5 | 1 - .../sha512 | 1 - .../md5 | 1 + .../sha512 | 1 + stdlib/Downloads.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/Downloads-89d3c7dded535a77551e763a437a6d31e4d9bf84.tar.gz/md5 delete mode 100644 deps/checksums/Downloads-89d3c7dded535a77551e763a437a6d31e4d9bf84.tar.gz/sha512 create mode 100644 deps/checksums/Downloads-afd04be8aa94204c075c8aec83fca040ebb4ff98.tar.gz/md5 create mode 100644 deps/checksums/Downloads-afd04be8aa94204c075c8aec83fca040ebb4ff98.tar.gz/sha512 diff --git a/deps/checksums/Downloads-89d3c7dded535a77551e763a437a6d31e4d9bf84.tar.gz/md5 b/deps/checksums/Downloads-89d3c7dded535a77551e763a437a6d31e4d9bf84.tar.gz/md5 deleted file mode 100644 index 611f3dd448d98..0000000000000 --- a/deps/checksums/Downloads-89d3c7dded535a77551e763a437a6d31e4d9bf84.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -2472bd6434d21c4b3e3199437e6fdcf7 diff --git a/deps/checksums/Downloads-89d3c7dded535a77551e763a437a6d31e4d9bf84.tar.gz/sha512 b/deps/checksums/Downloads-89d3c7dded535a77551e763a437a6d31e4d9bf84.tar.gz/sha512 deleted file mode 100644 index 6937982e838f3..0000000000000 --- a/deps/checksums/Downloads-89d3c7dded535a77551e763a437a6d31e4d9bf84.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -0a3fa9a09de81aa9676dbc7448408c7503f45e42519a2667540ad890316c7da089c95de5464a2032171f963c6f3cba73d6b3c246f1c7ac6ede283fc8132d5209 diff --git a/deps/checksums/Downloads-afd04be8aa94204c075c8aec83fca040ebb4ff98.tar.gz/md5 b/deps/checksums/Downloads-afd04be8aa94204c075c8aec83fca040ebb4ff98.tar.gz/md5 new file mode 100644 index 0000000000000..f0d72ab470aeb --- /dev/null +++ b/deps/checksums/Downloads-afd04be8aa94204c075c8aec83fca040ebb4ff98.tar.gz/md5 @@ -0,0 +1 @@ +9dbfa6c0a76d20b2ca8de844d08f3af4 diff --git a/deps/checksums/Downloads-afd04be8aa94204c075c8aec83fca040ebb4ff98.tar.gz/sha512 b/deps/checksums/Downloads-afd04be8aa94204c075c8aec83fca040ebb4ff98.tar.gz/sha512 new file mode 100644 index 0000000000000..7abbb06818d75 --- /dev/null +++ b/deps/checksums/Downloads-afd04be8aa94204c075c8aec83fca040ebb4ff98.tar.gz/sha512 @@ -0,0 +1 @@ +f5d2469419f4a083f84c1f23e6e528f4115804e45bdfdbd897110bb346aaa70afc57c24f9166ae20fb4305c1d40f5a77de4cfed7b69aef93f09d0d4eff183e3d diff --git a/stdlib/Downloads.version b/stdlib/Downloads.version index b539771fbdb47..3d1da64bdfe11 100644 --- a/stdlib/Downloads.version +++ b/stdlib/Downloads.version @@ -1,4 +1,4 @@ DOWNLOADS_BRANCH = master -DOWNLOADS_SHA1 = 89d3c7dded535a77551e763a437a6d31e4d9bf84 +DOWNLOADS_SHA1 = afd04be8aa94204c075c8aec83fca040ebb4ff98 DOWNLOADS_GIT_URL := https://github.com/JuliaLang/Downloads.jl.git DOWNLOADS_TAR_URL = https://api.github.com/repos/JuliaLang/Downloads.jl/tarball/$1 From e9c007f1ff76111b463b6096ad0a08519ee6c79f Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Sun, 15 Dec 2024 06:44:54 -0500 Subject: [PATCH 066/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?SHA=20stdlib=20from=20aaf2df6=20to=208fa221d=20(#56834)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: SHA URL: https://github.com/JuliaCrypto/SHA.jl.git Stdlib branch: master Julia branch: master Old commit: aaf2df6 New commit: 8fa221d Julia version: 1.12.0-DEV SHA version: 0.7.0(Does not match) Bump invoked by: @inkydragon Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaCrypto/SHA.jl/compare/aaf2df61ff8c3898196587a375d3cf213bd40b41...8fa221ddc8f3b418d9929084f1644f4c32c9a27e ``` $ git log --oneline aaf2df6..8fa221d 8fa221d ci: update doctest config (#120) 346b359 ci: Update ci config (#115) aba9014 Fix type mismatch for `shake/digest!` and setup x86 ci (#117) 0b76d04 Merge pull request #114 from JuliaCrypto/dependabot/github_actions/codecov/codecov-action-5 5094d9d Update .github/workflows/CI.yml 45596b1 Bump codecov/codecov-action from 4 to 5 230ab51 test: remove outdate tests (#113) 7f25aa8 rm: Duplicated const alias (#111) aa72f73 [SHA3] Fix padding special-case (#108) 3a01401 Delete Manifest.toml (#109) da351bb Remvoe all getproperty funcs (#99) 4eee84f Bump codecov/codecov-action from 3 to 4 (#104) 15f7dbc Bump codecov/codecov-action from 1 to 3 (#102) 860e6b9 Bump actions/checkout from 2 to 4 (#103) 8e5f0ea Add dependabot to auto update github actions (#100) 4ab324c Merge pull request #98 from fork4jl/sha512-t a658829 SHA-512: add ref to NIST standard 11a4c73 Apply suggestions from code review 969f867 Merge pull request #97 from fingolfin/mh/Vector b1401fb SHA-512: add NIST test 4d7091b SHA-512: add to docs 09fef9a SHA-512: test SHA-512/224, SHA-512/256 7201b74 SHA-512: impl SHA-512/224, SHA-512/256 4ab85ad Array -> Vector 8ef91b6 fixed bug in padding for shake, addes testcases for full code coverage (#95) 88e1c83 Remove non-existent property (#75) 068f85d shake128,shake256: fixed typo in export declarations (#93) 176baaa SHA3 xof shake128 and shake256 (#92) e1af7dd Hardcode doc edit backlink ``` Co-authored-by: Dilum Aluthge --- .../SHA-8fa221ddc8f3b418d9929084f1644f4c32c9a27e.tar.gz/md5 | 1 + .../SHA-8fa221ddc8f3b418d9929084f1644f4c32c9a27e.tar.gz/sha512 | 1 + .../SHA-aaf2df61ff8c3898196587a375d3cf213bd40b41.tar.gz/md5 | 1 - .../SHA-aaf2df61ff8c3898196587a375d3cf213bd40b41.tar.gz/sha512 | 1 - stdlib/SHA.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/SHA-8fa221ddc8f3b418d9929084f1644f4c32c9a27e.tar.gz/md5 create mode 100644 deps/checksums/SHA-8fa221ddc8f3b418d9929084f1644f4c32c9a27e.tar.gz/sha512 delete mode 100644 deps/checksums/SHA-aaf2df61ff8c3898196587a375d3cf213bd40b41.tar.gz/md5 delete mode 100644 deps/checksums/SHA-aaf2df61ff8c3898196587a375d3cf213bd40b41.tar.gz/sha512 diff --git a/deps/checksums/SHA-8fa221ddc8f3b418d9929084f1644f4c32c9a27e.tar.gz/md5 b/deps/checksums/SHA-8fa221ddc8f3b418d9929084f1644f4c32c9a27e.tar.gz/md5 new file mode 100644 index 0000000000000..52e05f5e427ae --- /dev/null +++ b/deps/checksums/SHA-8fa221ddc8f3b418d9929084f1644f4c32c9a27e.tar.gz/md5 @@ -0,0 +1 @@ +e52615827242aae56422a4f73a8c6878 diff --git a/deps/checksums/SHA-8fa221ddc8f3b418d9929084f1644f4c32c9a27e.tar.gz/sha512 b/deps/checksums/SHA-8fa221ddc8f3b418d9929084f1644f4c32c9a27e.tar.gz/sha512 new file mode 100644 index 0000000000000..e6b8446587554 --- /dev/null +++ b/deps/checksums/SHA-8fa221ddc8f3b418d9929084f1644f4c32c9a27e.tar.gz/sha512 @@ -0,0 +1 @@ +7b1df257616aaa9067f822a88dddf52bc10f9f61e3a0728e33e595455bd7167e680c50371c41cb25f8c8a9fb9cf40225847df1523a6c6f3571a471f7163f563c diff --git a/deps/checksums/SHA-aaf2df61ff8c3898196587a375d3cf213bd40b41.tar.gz/md5 b/deps/checksums/SHA-aaf2df61ff8c3898196587a375d3cf213bd40b41.tar.gz/md5 deleted file mode 100644 index 3b51189e187a3..0000000000000 --- a/deps/checksums/SHA-aaf2df61ff8c3898196587a375d3cf213bd40b41.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -dec1d21e890c88e57a0d4eb085633d57 diff --git a/deps/checksums/SHA-aaf2df61ff8c3898196587a375d3cf213bd40b41.tar.gz/sha512 b/deps/checksums/SHA-aaf2df61ff8c3898196587a375d3cf213bd40b41.tar.gz/sha512 deleted file mode 100644 index cbe1ff2eea29e..0000000000000 --- a/deps/checksums/SHA-aaf2df61ff8c3898196587a375d3cf213bd40b41.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -fb611794a539c6725000ff6eda13e0af5dd3f82e22466bdff650ffa0e4edbba5ac4707195035531645a4161ecbb5f873f4f6b1040ce33e9b1adf9c1d34187718 diff --git a/stdlib/SHA.version b/stdlib/SHA.version index f22bb33dc7ea2..4b33964a6dcdb 100644 --- a/stdlib/SHA.version +++ b/stdlib/SHA.version @@ -1,4 +1,4 @@ SHA_BRANCH = master -SHA_SHA1 = aaf2df61ff8c3898196587a375d3cf213bd40b41 +SHA_SHA1 = 8fa221ddc8f3b418d9929084f1644f4c32c9a27e SHA_GIT_URL := https://github.com/JuliaCrypto/SHA.jl.git SHA_TAR_URL = https://api.github.com/repos/JuliaCrypto/SHA.jl/tarball/$1 From 0e7b621e56b8c8f84baf22d02a0106fe8325489b Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Sun, 15 Dec 2024 06:45:58 -0500 Subject: [PATCH 067/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?StyledStrings=20stdlib=20from=20056e843=20to=208985a37=20(#5683?= =?UTF-8?q?2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: StyledStrings URL: https://github.com/JuliaLang/StyledStrings.jl.git Stdlib branch: main Julia branch: master Old commit: 056e843 New commit: 8985a37 Julia version: 1.12.0-DEV StyledStrings version: 1.11.0(Does not match) Bump invoked by: @DilumAluthge Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaLang/StyledStrings.jl/compare/056e843b2d428bb9735b03af0cff97e738ac7e14...8985a37ac054c37d084a03ad2837208244824877 ``` $ git log --oneline 056e843..8985a37 8985a37 Fix interpolation edge case dropping annotations 729f56c Add typeasserts to `convert(::Type{Face}, ::Dict)` ``` Co-authored-by: Dilum Aluthge --- .../md5 | 1 - .../sha512 | 1 - .../md5 | 1 + .../sha512 | 1 + stdlib/StyledStrings.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/StyledStrings-056e843b2d428bb9735b03af0cff97e738ac7e14.tar.gz/md5 delete mode 100644 deps/checksums/StyledStrings-056e843b2d428bb9735b03af0cff97e738ac7e14.tar.gz/sha512 create mode 100644 deps/checksums/StyledStrings-8985a37ac054c37d084a03ad2837208244824877.tar.gz/md5 create mode 100644 deps/checksums/StyledStrings-8985a37ac054c37d084a03ad2837208244824877.tar.gz/sha512 diff --git a/deps/checksums/StyledStrings-056e843b2d428bb9735b03af0cff97e738ac7e14.tar.gz/md5 b/deps/checksums/StyledStrings-056e843b2d428bb9735b03af0cff97e738ac7e14.tar.gz/md5 deleted file mode 100644 index 8d78dd7b0a11b..0000000000000 --- a/deps/checksums/StyledStrings-056e843b2d428bb9735b03af0cff97e738ac7e14.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -f053c84279a8920f355f202e605842af diff --git a/deps/checksums/StyledStrings-056e843b2d428bb9735b03af0cff97e738ac7e14.tar.gz/sha512 b/deps/checksums/StyledStrings-056e843b2d428bb9735b03af0cff97e738ac7e14.tar.gz/sha512 deleted file mode 100644 index 5a8ca888c38f8..0000000000000 --- a/deps/checksums/StyledStrings-056e843b2d428bb9735b03af0cff97e738ac7e14.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -b6f4c1d6c0dc73a520472746c96adff506e5405154e4b93d419e07b577b01804d2fc87d4a6cac48a136777579bebf8388c2c1e54f849b51e233138d482146b4f diff --git a/deps/checksums/StyledStrings-8985a37ac054c37d084a03ad2837208244824877.tar.gz/md5 b/deps/checksums/StyledStrings-8985a37ac054c37d084a03ad2837208244824877.tar.gz/md5 new file mode 100644 index 0000000000000..0fd8e8966e068 --- /dev/null +++ b/deps/checksums/StyledStrings-8985a37ac054c37d084a03ad2837208244824877.tar.gz/md5 @@ -0,0 +1 @@ +411277f3701cc3e286ec8a84ccdf6f11 diff --git a/deps/checksums/StyledStrings-8985a37ac054c37d084a03ad2837208244824877.tar.gz/sha512 b/deps/checksums/StyledStrings-8985a37ac054c37d084a03ad2837208244824877.tar.gz/sha512 new file mode 100644 index 0000000000000..0b495aefef55d --- /dev/null +++ b/deps/checksums/StyledStrings-8985a37ac054c37d084a03ad2837208244824877.tar.gz/sha512 @@ -0,0 +1 @@ +95a7e92389f6fd02d3bec17ec0201ba41316aa2d7c321b14af88ccce8246fd0000ed2c0cc818f87cb81f7134304233db897f656426a00caac1bc7635056260c2 diff --git a/stdlib/StyledStrings.version b/stdlib/StyledStrings.version index 5e58a5456148a..c72f7a8399725 100644 --- a/stdlib/StyledStrings.version +++ b/stdlib/StyledStrings.version @@ -1,4 +1,4 @@ STYLEDSTRINGS_BRANCH = main -STYLEDSTRINGS_SHA1 = 056e843b2d428bb9735b03af0cff97e738ac7e14 +STYLEDSTRINGS_SHA1 = 8985a37ac054c37d084a03ad2837208244824877 STYLEDSTRINGS_GIT_URL := https://github.com/JuliaLang/StyledStrings.jl.git STYLEDSTRINGS_TAR_URL = https://api.github.com/repos/JuliaLang/StyledStrings.jl/tarball/$1 From 8924e6f6c4f61946e72fde783c59a7996d749051 Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Sun, 15 Dec 2024 13:37:43 +0100 Subject: [PATCH 068/342] xref `UnionAll` in the doc string of `where` (#56411) --- base/docs/basedocs.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/docs/basedocs.jl b/base/docs/basedocs.jl index c62c980fae1e1..cef5e12a9e0d8 100644 --- a/base/docs/basedocs.jl +++ b/base/docs/basedocs.jl @@ -1515,7 +1515,7 @@ kw"new" """ where -The `where` keyword creates a type that is an iterated union of other types, over all +The `where` keyword creates a [`UnionAll`](@ref) type, which may be thought of as an iterated union of other types, over all values of some variable. For example `Vector{T} where T<:Real` includes all [`Vector`](@ref)s where the element type is some kind of `Real` number. From b4c5e58a976cbe48a6e5ec27f4408312d8073218 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Sun, 15 Dec 2024 09:20:44 -0500 Subject: [PATCH 069/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?ArgTools=20stdlib=20from=20997089b=20to=201314758=20(#56839)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: ArgTools URL: https://github.com/JuliaIO/ArgTools.jl.git Stdlib branch: master Julia branch: master Old commit: 997089b New commit: 1314758 Julia version: 1.12.0-DEV ArgTools version: 1.1.2(Does not match) Bump invoked by: @DilumAluthge Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaIO/ArgTools.jl/compare/997089b9cd56404b40ff766759662e16dc1aab4b...1314758ad02ff5e9e5ca718920c6c633b467a84a ``` $ git log --oneline 997089b..1314758 1314758 build(deps): bump codecov/codecov-action from 4 to 5; also, use CODECOV_TOKEN (#40) 68bb888 Fix typo in `arg_write` docstring (#39) 5d56027 build(deps): bump julia-actions/setup-julia from 1 to 2 (#38) b6189c7 build(deps): bump codecov/codecov-action from 3 to 4 (#37) ``` Co-authored-by: Dilum Aluthge --- .../md5 | 1 + .../sha512 | 1 + .../md5 | 1 - .../sha512 | 1 - stdlib/ArgTools.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/ArgTools-1314758ad02ff5e9e5ca718920c6c633b467a84a.tar.gz/md5 create mode 100644 deps/checksums/ArgTools-1314758ad02ff5e9e5ca718920c6c633b467a84a.tar.gz/sha512 delete mode 100644 deps/checksums/ArgTools-997089b9cd56404b40ff766759662e16dc1aab4b.tar.gz/md5 delete mode 100644 deps/checksums/ArgTools-997089b9cd56404b40ff766759662e16dc1aab4b.tar.gz/sha512 diff --git a/deps/checksums/ArgTools-1314758ad02ff5e9e5ca718920c6c633b467a84a.tar.gz/md5 b/deps/checksums/ArgTools-1314758ad02ff5e9e5ca718920c6c633b467a84a.tar.gz/md5 new file mode 100644 index 0000000000000..e172379604478 --- /dev/null +++ b/deps/checksums/ArgTools-1314758ad02ff5e9e5ca718920c6c633b467a84a.tar.gz/md5 @@ -0,0 +1 @@ +d3209f45b8ea01a22ac7e9b265e3b84f diff --git a/deps/checksums/ArgTools-1314758ad02ff5e9e5ca718920c6c633b467a84a.tar.gz/sha512 b/deps/checksums/ArgTools-1314758ad02ff5e9e5ca718920c6c633b467a84a.tar.gz/sha512 new file mode 100644 index 0000000000000..991a457654113 --- /dev/null +++ b/deps/checksums/ArgTools-1314758ad02ff5e9e5ca718920c6c633b467a84a.tar.gz/sha512 @@ -0,0 +1 @@ +314981eee11356f14b6dc9e07389c51432e7862d6c767d87d6679385f5a36faef34902954a5dfa6b37d8f3f25eaa4f23ba9431cc78acd3513377955e7d73f210 diff --git a/deps/checksums/ArgTools-997089b9cd56404b40ff766759662e16dc1aab4b.tar.gz/md5 b/deps/checksums/ArgTools-997089b9cd56404b40ff766759662e16dc1aab4b.tar.gz/md5 deleted file mode 100644 index 3e85638390011..0000000000000 --- a/deps/checksums/ArgTools-997089b9cd56404b40ff766759662e16dc1aab4b.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -44175a2843f243a8f2e01cd1e781ecc9 diff --git a/deps/checksums/ArgTools-997089b9cd56404b40ff766759662e16dc1aab4b.tar.gz/sha512 b/deps/checksums/ArgTools-997089b9cd56404b40ff766759662e16dc1aab4b.tar.gz/sha512 deleted file mode 100644 index f5690055f63f4..0000000000000 --- a/deps/checksums/ArgTools-997089b9cd56404b40ff766759662e16dc1aab4b.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -8a9d0f20cd8fa0ed072966debc691597bb09b34836465f52595b9b2525e80b194c7176781495573dd2f9a02b142e832e59f0dccef15afa184543775d58dc7987 diff --git a/stdlib/ArgTools.version b/stdlib/ArgTools.version index 09090a62ce0bf..914746c1a6900 100644 --- a/stdlib/ArgTools.version +++ b/stdlib/ArgTools.version @@ -1,4 +1,4 @@ ARGTOOLS_BRANCH = master -ARGTOOLS_SHA1 = 997089b9cd56404b40ff766759662e16dc1aab4b +ARGTOOLS_SHA1 = 1314758ad02ff5e9e5ca718920c6c633b467a84a ARGTOOLS_GIT_URL := https://github.com/JuliaIO/ArgTools.jl.git ARGTOOLS_TAR_URL = https://api.github.com/repos/JuliaIO/ArgTools.jl/tarball/$1 From dafaa611ec45cbcefb67915ba754f001698869f6 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Sun, 15 Dec 2024 23:21:45 -0500 Subject: [PATCH 070/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?Statistics=20stdlib=20from=2068869af=20to=20d49c2bf=20(#56831)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: Statistics URL: https://github.com/JuliaStats/Statistics.jl.git Stdlib branch: master Julia branch: master Old commit: 68869af New commit: d49c2bf Julia version: 1.12.0-DEV Statistics version: 1.11.2(Does not match) Bump invoked by: @DilumAluthge Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaStats/Statistics.jl/compare/68869af06e8cdeb7aba1d5259de602da7328057f...d49c2bf4f81e1efb4980a35fe39c815ef8396297 ``` $ git log --oneline 68869af..d49c2bf d49c2bf Merge pull request #178 from JuliaStats/dw/ci d10d6a3 Update Project.toml 1b67c17 Merge pull request #168 from JuliaStats/andreasnoack-patch-2 c3721ed Add a coverage badge 8086523 Test earliest supported Julia version and prereleases 12a1976 Update codecov in ci.yml 2caf0eb Merge pull request #177 from JuliaStats/ViralBShah-patch-1 33e6e8b Update ci.yml to use julia-actions/cache a399c19 Merge pull request #176 from JuliaStats/dependabot/github_actions/julia-actions/setup-julia-2 6b8d58a Merge branch 'master' into dependabot/github_actions/julia-actions/setup-julia-2 c2fb201 Merge pull request #175 from JuliaStats/dependabot/github_actions/actions/cache-4 8f808e4 Merge pull request #174 from JuliaStats/dependabot/github_actions/codecov/codecov-action-4 7f82133 Merge pull request #173 from JuliaStats/dependabot/github_actions/actions/checkout-4 046fb6f Update ci.yml c0fc336 Bump julia-actions/setup-julia from 1 to 2 a95a57a Bump actions/cache from 1 to 4 b675501 Bump codecov/codecov-action from 1 to 4 0088c49 Bump actions/checkout from 2 to 4 ad95c08 Create dependabot.yml 40275e2 Merge pull request #167 from JuliaStats/andreasnoack-patch-1 fa5592a Merge pull request #170 from mbauman/patch-1 cf57562 Add more tests of mean and median of ranges 128dc11 Merge pull request #169 from stevengj/patch-1 48d7a02 docfix: abs2, not ^2 2ac5bec correct std docs: sqrt is elementwise 39f6332 Merge pull request #96 from josemanuel22/mean_may_return_incorrect_results db3682b Merge branch 'master' into mean_may_return_incorrect_results 9e96507 Update src/Statistics.jl 58e5986 Test prereleases 6e76739 Implement one-argument cov2cor! b8fee00 Stop testing on nightly 9addbb8 Merge pull request #162 from caleb-allen/patch-1 6e3d223 Merge pull request #164 from aplavin/patch-1 71ebe28 Merge pull request #166 from JuliaStats/dw/cov_cor_optimization 517afa6 add tests aa0f549 Optimize `cov` and `cor` with identical arguments cc11ea9 propagate NaN value in median cf7040f Use non-mobile Wikipedia urls 547bf4d adding docu to mean! explain target should not alias with the source 296650a adding docu to mean! explain target should not alias with the source ``` Co-authored-by: Dilum Aluthge --- .../md5 | 1 - .../sha512 | 1 - .../md5 | 1 + .../sha512 | 1 + stdlib/Statistics.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/Statistics-68869af06e8cdeb7aba1d5259de602da7328057f.tar.gz/md5 delete mode 100644 deps/checksums/Statistics-68869af06e8cdeb7aba1d5259de602da7328057f.tar.gz/sha512 create mode 100644 deps/checksums/Statistics-d49c2bf4f81e1efb4980a35fe39c815ef8396297.tar.gz/md5 create mode 100644 deps/checksums/Statistics-d49c2bf4f81e1efb4980a35fe39c815ef8396297.tar.gz/sha512 diff --git a/deps/checksums/Statistics-68869af06e8cdeb7aba1d5259de602da7328057f.tar.gz/md5 b/deps/checksums/Statistics-68869af06e8cdeb7aba1d5259de602da7328057f.tar.gz/md5 deleted file mode 100644 index 9ba42f555d535..0000000000000 --- a/deps/checksums/Statistics-68869af06e8cdeb7aba1d5259de602da7328057f.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -01b84d67052d1558e51619d5159e7a8b diff --git a/deps/checksums/Statistics-68869af06e8cdeb7aba1d5259de602da7328057f.tar.gz/sha512 b/deps/checksums/Statistics-68869af06e8cdeb7aba1d5259de602da7328057f.tar.gz/sha512 deleted file mode 100644 index 31c9c6ca42cec..0000000000000 --- a/deps/checksums/Statistics-68869af06e8cdeb7aba1d5259de602da7328057f.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -6ab55ba6f93d2e8b34b19f53cb51a4bfc97b336d451b98f7b95ff81f04fee4fb90a2e4d04aa4bbf3ccffc99c36d9c82c9d00dbae283474308de4a27a91c2e0b7 diff --git a/deps/checksums/Statistics-d49c2bf4f81e1efb4980a35fe39c815ef8396297.tar.gz/md5 b/deps/checksums/Statistics-d49c2bf4f81e1efb4980a35fe39c815ef8396297.tar.gz/md5 new file mode 100644 index 0000000000000..3956c67f7fd47 --- /dev/null +++ b/deps/checksums/Statistics-d49c2bf4f81e1efb4980a35fe39c815ef8396297.tar.gz/md5 @@ -0,0 +1 @@ +acf2bb0ea30132602e172e2f5f6274b4 diff --git a/deps/checksums/Statistics-d49c2bf4f81e1efb4980a35fe39c815ef8396297.tar.gz/sha512 b/deps/checksums/Statistics-d49c2bf4f81e1efb4980a35fe39c815ef8396297.tar.gz/sha512 new file mode 100644 index 0000000000000..051f2d0a862c3 --- /dev/null +++ b/deps/checksums/Statistics-d49c2bf4f81e1efb4980a35fe39c815ef8396297.tar.gz/sha512 @@ -0,0 +1 @@ +5e879fe79bae19b62f81659a102602271c73a424faf4be069ab31fb50e30b536a8c7b3692127763000cc1dbab69c93ac3da7bace5f093d05dce2d652fb221d52 diff --git a/stdlib/Statistics.version b/stdlib/Statistics.version index 1449dcee29b79..3df70d30ba7e6 100644 --- a/stdlib/Statistics.version +++ b/stdlib/Statistics.version @@ -1,4 +1,4 @@ STATISTICS_BRANCH = master -STATISTICS_SHA1 = 68869af06e8cdeb7aba1d5259de602da7328057f +STATISTICS_SHA1 = d49c2bf4f81e1efb4980a35fe39c815ef8396297 STATISTICS_GIT_URL := https://github.com/JuliaStats/Statistics.jl.git STATISTICS_TAR_URL = https://api.github.com/repos/JuliaStats/Statistics.jl/tarball/$1 From 055103901eb486e5b2e8d300ba7c531563beb618 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Mon, 16 Dec 2024 13:32:17 +0900 Subject: [PATCH 071/342] inference: don't allocate `TryCatchFrame` for `compute_trycatch(::IRCode)` (#56835) `TryCatchFrame` is only required for the abstract interpretation and is not necessary in `compute_trycatch` within slot2ssa.jl. @nanosoldier `runbenchmarks("inference", vs=":master")` --- Compiler/src/inferencestate.jl | 45 ++++++++++++++++++++++++---------- Compiler/src/ssair/slot2ssa.jl | 8 +++--- Compiler/test/inference.jl | 2 +- 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/Compiler/src/inferencestate.jl b/Compiler/src/inferencestate.jl index 6988e74310fc5..046f98df1f41d 100644 --- a/Compiler/src/inferencestate.jl +++ b/Compiler/src/inferencestate.jl @@ -219,16 +219,29 @@ const CACHE_MODE_GLOBAL = 0x01 << 0 # cached globally, optimization required const CACHE_MODE_LOCAL = 0x01 << 1 # cached locally, optimization required const CACHE_MODE_VOLATILE = 0x01 << 2 # not cached, optimization required -mutable struct TryCatchFrame +abstract type Handler end +get_enter_idx(handler::Handler) = get_enter_idx_impl(handler)::Int + +mutable struct TryCatchFrame <: Handler exct scopet const enter_idx::Int scope_uses::Vector{Int} - TryCatchFrame(@nospecialize(exct), @nospecialize(scopet), enter_idx::Int) = new(exct, scopet, enter_idx) + TryCatchFrame(@nospecialize(exct), @nospecialize(scopet), enter_idx::Int) = + new(exct, scopet, enter_idx) +end +TryCatchFrame(stmt::EnterNode, pc::Int) = + TryCatchFrame(Bottom, isdefined(stmt, :scope) ? Bottom : nothing, pc) +get_enter_idx_impl((; enter_idx)::TryCatchFrame) = enter_idx + +struct SimpleHandler <: Handler + enter_idx::Int end +SimpleHandler(::EnterNode, pc::Int) = SimpleHandler(pc) +get_enter_idx_impl((; enter_idx)::SimpleHandler) = enter_idx -struct HandlerInfo - handlers::Vector{TryCatchFrame} +struct HandlerInfo{T<:Handler} + handlers::Vector{T} handler_at::Vector{Tuple{Int,Int}} # tuple of current (handler, exception stack) value at the pc end @@ -261,7 +274,7 @@ mutable struct InferenceState currbb::Int currpc::Int ip::BitSet#=TODO BoundedMinPrioritySet=# # current active instruction pointers - handler_info::Union{Nothing,HandlerInfo} + handler_info::Union{Nothing,HandlerInfo{TryCatchFrame}} ssavalue_uses::Vector{BitSet} # ssavalue sparsity and restart info # TODO: Could keep this sparsely by doing structural liveness analysis ahead of time. bb_vartables::Vector{Union{Nothing,VarTable}} # nothing if not analyzed yet @@ -318,7 +331,7 @@ mutable struct InferenceState currbb = currpc = 1 ip = BitSet(1) # TODO BitSetBoundedMinPrioritySet(1) - handler_info = compute_trycatch(code) + handler_info = ComputeTryCatch{TryCatchFrame}()(code) nssavalues = src.ssavaluetypes::Int ssavalue_uses = find_ssavalue_uses(code, nssavalues) nstmts = length(code) @@ -421,10 +434,16 @@ is_inferred(result::InferenceResult) = result.result !== nothing was_reached(sv::InferenceState, pc::Int) = sv.ssavaluetypes[pc] !== NOT_FOUND -compute_trycatch(ir::IRCode) = compute_trycatch(ir.stmts.stmt, ir.cfg.blocks) +struct ComputeTryCatch{T<:Handler} end + +const compute_trycatch = ComputeTryCatch{SimpleHandler}() + +(compute_trycatch::ComputeTryCatch{SimpleHandler})(ir::IRCode) = + compute_trycatch(ir.stmts.stmt, ir.cfg.blocks) """ - compute_trycatch(code, [, bbs]) -> handler_info::Union{Nothing,HandlerInfo} + (::ComputeTryCatch{Handler})(code, [, bbs]) -> handler_info::Union{Nothing,HandlerInfo{Handler}} + const compute_trycatch = ComputeTryCatch{SimpleHandler}() Given the code of a function, compute, at every statement, the current try/catch handler, and the current exception stack top. This function returns @@ -433,9 +452,9 @@ a tuple of: 1. `handler_info.handler_at`: A statement length vector of tuples `(catch_handler, exception_stack)`, which are indices into `handlers` - 2. `handler_info.handlers`: A `TryCatchFrame` vector of handlers + 2. `handler_info.handlers`: A `Handler` vector of handlers """ -function compute_trycatch(code::Vector{Any}, bbs::Union{Vector{BasicBlock},Nothing}=nothing) +function (::ComputeTryCatch{Handler})(code::Vector{Any}, bbs::Union{Vector{BasicBlock},Nothing}=nothing) where Handler # The goal initially is to record the frame like this for the state at exit: # 1: (enter 3) # == 0 # 3: (expr) # == 1 @@ -454,10 +473,10 @@ function compute_trycatch(code::Vector{Any}, bbs::Union{Vector{BasicBlock},Nothi stmt = code[pc] if isa(stmt, EnterNode) (;handlers, handler_at) = handler_info = - (handler_info === nothing ? HandlerInfo(TryCatchFrame[], fill((0, 0), n)) : handler_info) + (handler_info === nothing ? HandlerInfo{Handler}(Handler[], fill((0, 0), n)) : handler_info) l = stmt.catch_dest (bbs !== nothing) && (l = first(bbs[l].stmts)) - push!(handlers, TryCatchFrame(Bottom, isdefined(stmt, :scope) ? Bottom : nothing, pc)) + push!(handlers, Handler(stmt, pc)) handler_id = length(handlers) handler_at[pc + 1] = (handler_id, 0) push!(ip, pc + 1) @@ -526,7 +545,7 @@ function compute_trycatch(code::Vector{Any}, bbs::Union{Vector{BasicBlock},Nothi end cur_hand = cur_stacks[1] for i = 1:l - cur_hand = handler_at[handlers[cur_hand].enter_idx][1] + cur_hand = handler_at[get_enter_idx(handlers[cur_hand])][1] end cur_stacks = (cur_hand, cur_stacks[2]) cur_stacks == (0, 0) && break diff --git a/Compiler/src/ssair/slot2ssa.jl b/Compiler/src/ssair/slot2ssa.jl index 6fc87934d3bc5..80dffdab23243 100644 --- a/Compiler/src/ssair/slot2ssa.jl +++ b/Compiler/src/ssair/slot2ssa.jl @@ -801,9 +801,11 @@ function construct_ssa!(ci::CodeInfo, ir::IRCode, sv::OptimizationState, has_pinode[id] = false enter_idx = idx while (handler = gethandler(handler_info, enter_idx)) !== nothing - (; enter_idx) = handler - leave_block = block_for_inst(cfg, (code[enter_idx]::EnterNode).catch_dest) - cidx = findfirst((; slot)::NewPhiCNode2->slot_id(slot)==id, new_phic_nodes[leave_block]) + enter_idx = get_enter_idx(handler) + enter_node = code[enter_idx]::EnterNode + leave_block = block_for_inst(cfg, enter_node.catch_dest) + cidx = findfirst((; slot)::NewPhiCNode2->slot_id(slot)==id, + new_phic_nodes[leave_block]) if cidx !== nothing node = thisdef ? UpsilonNode(thisval) : UpsilonNode() if incoming_vals[id] === UNDEF_TOKEN diff --git a/Compiler/test/inference.jl b/Compiler/test/inference.jl index c8b599adb1323..e272ff6de8d99 100644 --- a/Compiler/test/inference.jl +++ b/Compiler/test/inference.jl @@ -4436,7 +4436,7 @@ let x = Tuple{Int,Any}[ #=20=# (0, Core.ReturnNode(Core.SlotNumber(3))) ] (;handler_at, handlers) = Compiler.compute_trycatch(last.(x)) - @test map(x->x[1] == 0 ? 0 : handlers[x[1]].enter_idx, handler_at) == first.(x) + @test map(x->x[1] == 0 ? 0 : Compiler.get_enter_idx(handlers[x[1]]), handler_at) == first.(x) end @test only(Base.return_types((Bool,)) do y From 13f446e9f4d518b20faea68d2e239fcabd462ea9 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Mon, 16 Dec 2024 02:50:44 -0500 Subject: [PATCH 072/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?LazyArtifacts=20stdlib=20from=20e9a3633=20to=20a719c0e=20(#5682?= =?UTF-8?q?7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: LazyArtifacts URL: https://github.com/JuliaPackaging/LazyArtifacts.jl.git Stdlib branch: main Julia branch: master Old commit: e9a3633 New commit: a719c0e Julia version: 1.12.0-DEV LazyArtifacts version: 1.11.0(Does not match) Bump invoked by: @DilumAluthge Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaPackaging/LazyArtifacts.jl/compare/e9a36338d5d0dfa4b222f4e11b446cbb7ea5836c...a719c0e3d68a95c6f3dc9571459428ca8761fa2c ``` $ git log --oneline e9a3633..a719c0e a719c0e Add compat for LazyArtifacts ``` Co-authored-by: Dilum Aluthge --- .../md5 | 1 + .../sha512 | 1 + .../md5 | 1 - .../sha512 | 1 - stdlib/LazyArtifacts.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/LazyArtifacts-a719c0e3d68a95c6f3dc9571459428ca8761fa2c.tar.gz/md5 create mode 100644 deps/checksums/LazyArtifacts-a719c0e3d68a95c6f3dc9571459428ca8761fa2c.tar.gz/sha512 delete mode 100644 deps/checksums/LazyArtifacts-e9a36338d5d0dfa4b222f4e11b446cbb7ea5836c.tar.gz/md5 delete mode 100644 deps/checksums/LazyArtifacts-e9a36338d5d0dfa4b222f4e11b446cbb7ea5836c.tar.gz/sha512 diff --git a/deps/checksums/LazyArtifacts-a719c0e3d68a95c6f3dc9571459428ca8761fa2c.tar.gz/md5 b/deps/checksums/LazyArtifacts-a719c0e3d68a95c6f3dc9571459428ca8761fa2c.tar.gz/md5 new file mode 100644 index 0000000000000..363c289573765 --- /dev/null +++ b/deps/checksums/LazyArtifacts-a719c0e3d68a95c6f3dc9571459428ca8761fa2c.tar.gz/md5 @@ -0,0 +1 @@ +ce3754f1d195e1533fc1f3c51e2a2d4c diff --git a/deps/checksums/LazyArtifacts-a719c0e3d68a95c6f3dc9571459428ca8761fa2c.tar.gz/sha512 b/deps/checksums/LazyArtifacts-a719c0e3d68a95c6f3dc9571459428ca8761fa2c.tar.gz/sha512 new file mode 100644 index 0000000000000..62227971fe7f7 --- /dev/null +++ b/deps/checksums/LazyArtifacts-a719c0e3d68a95c6f3dc9571459428ca8761fa2c.tar.gz/sha512 @@ -0,0 +1 @@ +1e1beb6202f089b82f06c1f1fcb129a31d2b438df8a3a49c7367d3df4587d8b9b8fbcf74d3f5ff3c25c241314c71e5dfd72014338b822f01252890e2a14831d1 diff --git a/deps/checksums/LazyArtifacts-e9a36338d5d0dfa4b222f4e11b446cbb7ea5836c.tar.gz/md5 b/deps/checksums/LazyArtifacts-e9a36338d5d0dfa4b222f4e11b446cbb7ea5836c.tar.gz/md5 deleted file mode 100644 index 4d14c85460418..0000000000000 --- a/deps/checksums/LazyArtifacts-e9a36338d5d0dfa4b222f4e11b446cbb7ea5836c.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -8355c253fadfc3f9222e05cb67845dd6 diff --git a/deps/checksums/LazyArtifacts-e9a36338d5d0dfa4b222f4e11b446cbb7ea5836c.tar.gz/sha512 b/deps/checksums/LazyArtifacts-e9a36338d5d0dfa4b222f4e11b446cbb7ea5836c.tar.gz/sha512 deleted file mode 100644 index d44f215e67673..0000000000000 --- a/deps/checksums/LazyArtifacts-e9a36338d5d0dfa4b222f4e11b446cbb7ea5836c.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -6d965199ed02446e694789a38f05249ff60ac00f8295fe32bf91a79cca34649829e38eaf46cc0b0b72ff2df7e184c2eaeb610600ebb5158251b331c61e9dfc5d diff --git a/stdlib/LazyArtifacts.version b/stdlib/LazyArtifacts.version index 4246ec3ad5d1a..f740516eb9953 100644 --- a/stdlib/LazyArtifacts.version +++ b/stdlib/LazyArtifacts.version @@ -1,4 +1,4 @@ LAZYARTIFACTS_BRANCH = main -LAZYARTIFACTS_SHA1 = e9a36338d5d0dfa4b222f4e11b446cbb7ea5836c +LAZYARTIFACTS_SHA1 = a719c0e3d68a95c6f3dc9571459428ca8761fa2c LAZYARTIFACTS_GIT_URL := https://github.com/JuliaPackaging/LazyArtifacts.jl.git LAZYARTIFACTS_TAR_URL = https://api.github.com/repos/JuliaPackaging/LazyArtifacts.jl/tarball/$1 From 17857ca0f21eb0aa643fb630644a05cc69bc517b Mon Sep 17 00:00:00 2001 From: Oscar Smith Date: Mon, 16 Dec 2024 14:56:41 -0500 Subject: [PATCH 073/342] make `memorynew` intrinsic (#56803) Attempt to split up https://github.com/JuliaLang/julia/pull/55913 into 2 pieces. This piece now only adds the `memorynew` intrinsic without any of the optimizations enabled by https://github.com/JuliaLang/julia/pull/55913. As such, this PR should be ready to merge now. (and will make https://github.com/JuliaLang/julia/pull/55913 smaller and simpler) --------- Co-authored-by: gbaraldi --- Compiler/src/tfuncs.jl | 30 +++++++- Compiler/test/irpasses.jl | 7 +- base/boot.jl | 7 +- doc/src/manual/performance-tips.md | 22 +++--- src/array.c | 13 +--- src/builtin_proto.h | 1 + src/builtins.c | 10 +++ src/ccall.cpp | 27 ------- src/cgutils.cpp | 110 ++++++++++++++++++++++++++++- src/codegen.cpp | 45 ++++++++++++ src/genericmemory.c | 61 ++++++++-------- src/julia.h | 2 + src/rtutils.c | 7 ++ src/staticdata.c | 5 +- test/core.jl | 9 +++ 15 files changed, 264 insertions(+), 92 deletions(-) diff --git a/Compiler/src/tfuncs.jl b/Compiler/src/tfuncs.jl index af8863c1b3a3a..906bc9521adf9 100644 --- a/Compiler/src/tfuncs.jl +++ b/Compiler/src/tfuncs.jl @@ -2017,6 +2017,12 @@ function tuple_tfunc(𝕃::AbstractLattice, argtypes::Vector{Any}) return anyinfo ? PartialStruct(𝕃, typ, argtypes) : typ end +@nospecs function memorynew_tfunc(𝕃::AbstractLattice, memtype, m) + hasintersect(widenconst(m), Int) || return Bottom + return tmeet(𝕃, instanceof_tfunc(memtype, true)[1], GenericMemory) +end +add_tfunc(Core.memorynew, 2, 2, memorynew_tfunc, 10) + @nospecs function memoryrefget_tfunc(𝕃::AbstractLattice, mem, order, boundscheck) memoryref_builtin_common_errorcheck(mem, order, boundscheck) || return Bottom return memoryref_elemtype(mem) @@ -2238,13 +2244,31 @@ end return boundscheck ⊑ Bool && memtype ⊑ GenericMemoryRef && order ⊑ Symbol end +@nospecs function memorynew_nothrow(argtypes::Vector{Any}) + if !(argtypes[1] isa Const && argtypes[2] isa Const) + return false + end + MemT = argtypes[1].val + if !(isconcretetype(MemT) && MemT <: GenericMemory) + return false + end + len = argtypes[2].val + if !(len isa Int && 0 <= len < typemax(Int)) + return false + end + elsz = datatype_layoutsize(MemT) + overflows = checked_smul_int(len, elsz)[2] + return !overflows +end # Query whether the given builtin is guaranteed not to throw given the `argtypes`. # `argtypes` can be assumed not to contain varargs. function _builtin_nothrow(𝕃::AbstractLattice, @nospecialize(f::Builtin), argtypes::Vector{Any}, @nospecialize(rt)) ⊑ = partialorder(𝕃) na = length(argtypes) - if f === memoryrefnew + if f === Core.memorynew + return memorynew_nothrow(argtypes) + elseif f === memoryrefnew return memoryref_builtin_common_nothrow(argtypes) elseif f === memoryrefoffset length(argtypes) == 1 || return false @@ -2347,6 +2371,7 @@ const _EFFECT_FREE_BUILTINS = [ isa, UnionAll, getfield, + Core.memorynew, memoryrefnew, memoryrefoffset, memoryrefget, @@ -2381,6 +2406,7 @@ const _INACCESSIBLEMEM_BUILTINS = Any[ compilerbarrier, Core._typevar, donotdelete, + Core.memorynew, ] const _ARGMEM_BUILTINS = Any[ @@ -2543,7 +2569,7 @@ function builtin_effects(𝕃::AbstractLattice, @nospecialize(f::Builtin), argty consistent = ALWAYS_TRUE elseif f === memoryrefget || f === memoryrefset! || f === memoryref_isassigned consistent = CONSISTENT_IF_INACCESSIBLEMEMONLY - elseif f === Core._typevar + elseif f === Core._typevar || f === Core.memorynew consistent = CONSISTENT_IF_NOTRETURNED else consistent = ALWAYS_FALSE diff --git a/Compiler/test/irpasses.jl b/Compiler/test/irpasses.jl index e9d6f57337530..90d8c9dc6ab3d 100644 --- a/Compiler/test/irpasses.jl +++ b/Compiler/test/irpasses.jl @@ -1083,12 +1083,13 @@ end # test `flags_for_effects` and DCE # ================================ -let # effect-freeness computation for array allocation +@testset "effect-freeness computation for array allocation" begin # should eliminate dead allocations good_dims = [1, 2, 3, 4, 10] Ns = [1, 2, 3, 4, 10] - for dim = good_dims, N = Ns + Ts = Any[Int, Union{Missing,Nothing}, Nothing, Any] + @testset "$dim, $N" for dim in good_dims, N in Ns Int64(dim)^N > typemax(Int) && continue dims = ntuple(i->dim, N) @test @eval fully_eliminated() do @@ -1099,7 +1100,7 @@ let # effect-freeness computation for array allocation # shouldn't eliminate erroneous dead allocations bad_dims = [-1, typemax(Int)] - for dim in bad_dims, N in [1, 2, 3, 4, 10], T in Any[Int, Union{Missing,Nothing}, Nothing, Any] + @testset "$dim, $N, $T" for dim in bad_dims, N in Ns, T in Ts dims = ntuple(i->dim, N) @test @eval !fully_eliminated() do Array{$T,$N}(undef, $(dims...)) diff --git a/base/boot.jl b/base/boot.jl index 4badedae3cfb7..ed0a722c5e562 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -575,12 +575,7 @@ struct UndefInitializer end const undef = UndefInitializer() # type and dimensionality specified -(self::Type{GenericMemory{kind,T,addrspace}})(::UndefInitializer, m::Int) where {T,addrspace,kind} = - if isdefined(self, :instance) && m === 0 - self.instance - else - ccall(:jl_alloc_genericmemory, Ref{GenericMemory{kind,T,addrspace}}, (Any, Int), self, m) - end +(self::Type{GenericMemory{kind,T,addrspace}})(::UndefInitializer, m::Int) where {T,addrspace,kind} = memorynew(self, m) (self::Type{GenericMemory{kind,T,addrspace}})(::UndefInitializer, d::NTuple{1,Int}) where {T,kind,addrspace} = self(undef, getfield(d,1)) # empty vector constructor (self::Type{GenericMemory{kind,T,addrspace}})() where {T,kind,addrspace} = self(undef, 0) diff --git a/doc/src/manual/performance-tips.md b/doc/src/manual/performance-tips.md index 038000f55e761..1166164241c60 100644 --- a/doc/src/manual/performance-tips.md +++ b/doc/src/manual/performance-tips.md @@ -1058,12 +1058,12 @@ the output. As a trivial example, compare ```jldoctest prealloc julia> function xinc(x) - return [x, x+1, x+2] + return [x + i for i in 1:3000] end; julia> function loopinc() y = 0 - for i = 1:10^7 + for i = 1:10^5 ret = xinc(i) y += ret[2] end @@ -1075,16 +1075,16 @@ with ```jldoctest prealloc julia> function xinc!(ret::AbstractVector{T}, x::T) where T - ret[1] = x - ret[2] = x+1 - ret[3] = x+2 + for i in 1:3000 + ret[i] = x+i + end nothing end; julia> function loopinc_prealloc() - ret = Vector{Int}(undef, 3) + ret = Vector{Int}(undef, 3000) y = 0 - for i = 1:10^7 + for i = 1:10^5 xinc!(ret, i) y += ret[2] end @@ -1096,12 +1096,12 @@ Timing results: ```jldoctest prealloc; filter = r"[0-9\.]+ seconds \(.*?\)" julia> @time loopinc() - 0.529894 seconds (40.00 M allocations: 1.490 GiB, 12.14% gc time) -50000015000000 + 0.297454 seconds (200.00 k allocations: 2.239 GiB, 39.80% gc time) +5000250000 julia> @time loopinc_prealloc() - 0.030850 seconds (6 allocations: 288 bytes) -50000015000000 + 0.009410 seconds (2 allocations: 23.477 KiB) +5000250000 ``` Preallocation has other advantages, for example by allowing the caller to control the "output" diff --git a/src/array.c b/src/array.c index f0051ec17565a..da9cb24b4d0e9 100644 --- a/src/array.c +++ b/src/array.c @@ -16,12 +16,6 @@ extern "C" { #endif -#if defined(_P64) && defined(UINT128MAX) -typedef __uint128_t wideint_t; -#else -typedef uint64_t wideint_t; -#endif - #define MAXINTVAL (((size_t)-1)>>1) JL_DLLEXPORT int jl_array_validate_dims(size_t *nel, uint32_t ndims, size_t *dims) @@ -30,10 +24,9 @@ JL_DLLEXPORT int jl_array_validate_dims(size_t *nel, uint32_t ndims, size_t *dim size_t _nel = 1; for (i = 0; i < ndims; i++) { size_t di = dims[i]; - wideint_t prod = (wideint_t)_nel * (wideint_t)di; - if (prod >= (wideint_t) MAXINTVAL || di >= MAXINTVAL) + int overflow = __builtin_mul_overflow(_nel, di, &_nel); + if (overflow || di >= MAXINTVAL) return 1; - _nel = prod; } *nel = _nel; return 0; @@ -204,7 +197,7 @@ JL_DLLEXPORT void jl_array_grow_end(jl_array_t *a, size_t inc) int isbitsunion = jl_genericmemory_isbitsunion(a->ref.mem); size_t newnrows = n + inc; if (!isbitsunion && elsz == 0) { - jl_genericmemory_t *newmem = jl_alloc_genericmemory(mtype, MAXINTVAL - 1); + jl_genericmemory_t *newmem = jl_alloc_genericmemory(mtype, MAXINTVAL - 2); a->ref.mem = newmem; jl_gc_wb(a, newmem); a->dimsize[0] = newnrows; diff --git a/src/builtin_proto.h b/src/builtin_proto.h index 7fbd555758675..70ad67040991d 100644 --- a/src/builtin_proto.h +++ b/src/builtin_proto.h @@ -46,6 +46,7 @@ DECLARE_BUILTIN(is); DECLARE_BUILTIN(isa); DECLARE_BUILTIN(isdefined); DECLARE_BUILTIN(issubtype); +DECLARE_BUILTIN(memorynew); DECLARE_BUILTIN(memoryref); DECLARE_BUILTIN(memoryref_isassigned); DECLARE_BUILTIN(memoryrefget); diff --git a/src/builtins.c b/src/builtins.c index 4b9c1ad6043c2..06dbd84aff6c0 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1675,6 +1675,15 @@ JL_CALLABLE(jl_f__typevar) } // genericmemory --------------------------------------------------------------------- +JL_CALLABLE(jl_f_memorynew) +{ + JL_NARGS(memorynew, 2, 2); + jl_datatype_t *jl_genericmemory_type_type = jl_datatype_type; + JL_TYPECHK(memorynew, genericmemory_type, args[0]); + JL_TYPECHK(memorynew, long, args[1]); + size_t nel = jl_unbox_long(args[1]); + return (jl_value_t*)jl_alloc_genericmemory(args[0], nel); +} JL_CALLABLE(jl_f_memoryref) { @@ -2441,6 +2450,7 @@ void jl_init_primitives(void) JL_GC_DISABLED jl_builtin_setglobalonce = add_builtin_func("setglobalonce!", jl_f_setglobalonce); // memory primitives + jl_builtin_memorynew = add_builtin_func("memorynew", jl_f_memorynew); jl_builtin_memoryref = add_builtin_func("memoryrefnew", jl_f_memoryref); jl_builtin_memoryrefoffset = add_builtin_func("memoryrefoffset", jl_f_memoryrefoffset); jl_builtin_memoryrefget = add_builtin_func("memoryrefget", jl_f_memoryrefget); diff --git a/src/ccall.cpp b/src/ccall.cpp index 9aa1c56e2e78f..3937570896f82 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -1877,33 +1877,6 @@ static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs) JL_GC_POP(); return mark_julia_type(ctx, obj, true, jl_any_type); } - else if (is_libjulia_func(jl_alloc_genericmemory)) { - ++CCALL_STAT(jl_alloc_genericmemory); - assert(lrt == ctx.types().T_prjlvalue); - assert(!isVa && !llvmcall && nccallargs == 2); - const jl_cgval_t &typ = argv[0]; - const jl_cgval_t &nel = argv[1]; - auto arg_typename = [&] JL_NOTSAFEPOINT { - auto istyp = argv[0].constant; - std::string type_str; - if (istyp && jl_is_datatype(istyp) && jl_is_genericmemory_type(istyp)){ - auto eltype = jl_tparam1(istyp); - if (jl_is_datatype(eltype)) - type_str = jl_symbol_name(((jl_datatype_t*)eltype)->name->name); - else if (jl_is_uniontype(eltype)) - type_str = "Union"; - else - type_str = ""; - } - else - type_str = ""; - return "Memory{" + type_str + "}[]"; - }; - auto alloc = ctx.builder.CreateCall(prepare_call(jl_allocgenericmemory), { boxed(ctx,typ), emit_unbox(ctx, ctx.types().T_size, nel, (jl_value_t*)jl_ulong_type)}); - setName(ctx.emission_context, alloc, arg_typename); - JL_GC_POP(); - return mark_julia_type(ctx, alloc, true, jl_any_type); - } else if (is_libjulia_func(memcpy) && (rt == (jl_value_t*)jl_nothing_type || jl_is_cpointer_type(rt))) { ++CCALL_STAT(memcpy); const jl_cgval_t &dst = argv[0]; diff --git a/src/cgutils.cpp b/src/cgutils.cpp index dd6ced04673e6..6aabc459d2c91 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -1548,19 +1548,24 @@ static void emit_error(jl_codectx_t &ctx, const Twine &txt) } // DO NOT PASS IN A CONST CONDITION! -static void error_unless(jl_codectx_t &ctx, Value *cond, const Twine &msg) +static void error_unless(jl_codectx_t &ctx, Function *F, Value *cond, const Twine &msg) { ++EmittedConditionalErrors; BasicBlock *failBB = BasicBlock::Create(ctx.builder.getContext(), "fail", ctx.f); BasicBlock *passBB = BasicBlock::Create(ctx.builder.getContext(), "pass"); ctx.builder.CreateCondBr(cond, passBB, failBB); ctx.builder.SetInsertPoint(failBB); - just_emit_error(ctx, prepare_call(jlerror_func), msg); + just_emit_error(ctx, F, msg); ctx.builder.CreateUnreachable(); passBB->insertInto(ctx.f); ctx.builder.SetInsertPoint(passBB); } +static void error_unless(jl_codectx_t &ctx, Value *cond, const Twine &msg) +{ + error_unless(ctx, prepare_call(jlerror_func), cond, msg); +} + static void raise_exception(jl_codectx_t &ctx, Value *exc, BasicBlock *contBB=nullptr) { @@ -4427,6 +4432,107 @@ static int compare_cgparams(const jl_cgparams_t *a, const jl_cgparams_t *b) } #endif +static jl_cgval_t emit_memorynew(jl_codectx_t &ctx, jl_datatype_t *typ, jl_cgval_t nel, jl_genericmemory_t *inst) +{ + emit_typecheck(ctx, nel, (jl_value_t*)jl_long_type, "memorynew"); + nel = update_julia_type(ctx, nel, (jl_value_t*)jl_long_type); + if (nel.typ == jl_bottom_type) + return jl_cgval_t(); + + const jl_datatype_layout_t *layout = ((jl_datatype_t*)typ)->layout; + assert(((jl_datatype_t*)typ)->has_concrete_subtype && layout != NULL); + size_t elsz = layout->size; + int isboxed = layout->flags.arrayelem_isboxed; + int isunion = layout->flags.arrayelem_isunion; + int zi = ((jl_datatype_t*)typ)->zeroinit; + if (isboxed) + elsz = sizeof(void*); + + auto ptls = get_current_ptls(ctx); + auto T_size = ctx.types().T_size; + auto int8t = getInt8Ty(ctx.builder.getContext()); + BasicBlock *emptymemBB, *nonemptymemBB, *retvalBB; + emptymemBB = BasicBlock::Create(ctx.builder.getContext(), "emptymem"); + nonemptymemBB = BasicBlock::Create(ctx.builder.getContext(), "nonemptymem"); + retvalBB = BasicBlock::Create(ctx.builder.getContext(), "retval"); + auto nel_unboxed = emit_unbox(ctx, ctx.types().T_size, nel, (jl_value_t*)jl_long_type); + Value *memorynew_empty = ctx.builder.CreateICmpEQ(nel_unboxed, ConstantInt::get(T_size, 0)); + setName(ctx.emission_context, memorynew_empty, "memorynew_empty"); + ctx.builder.CreateCondBr(memorynew_empty, emptymemBB, nonemptymemBB); + // if nel == 0 + emptymemBB->insertInto(ctx.f); + ctx.builder.SetInsertPoint(emptymemBB); + auto emptyalloc = track_pjlvalue(ctx, literal_pointer_val(ctx, (jl_value_t*)inst)); + ctx.builder.CreateBr(retvalBB); + nonemptymemBB->insertInto(ctx.f); + ctx.builder.SetInsertPoint(nonemptymemBB); + // else actually allocate mem + auto arg_typename = [&] JL_NOTSAFEPOINT { + std::string type_str; + auto eltype = jl_tparam1(typ); + if (jl_is_datatype(eltype)) + type_str = jl_symbol_name(((jl_datatype_t*)eltype)->name->name); + else if (jl_is_uniontype(eltype)) + type_str = "Union"; + else + type_str = ""; + return "Memory{" + type_str + "}[]"; + }; + auto cg_typ = literal_pointer_val(ctx, (jl_value_t*) typ); + auto cg_elsz = ConstantInt::get(T_size, elsz); + + FunctionCallee intr = Intrinsic::getDeclaration(jl_Module, Intrinsic::smul_with_overflow, ArrayRef(T_size)); + // compute nbytes with possible overflow + Value *prod_with_overflow = ctx.builder.CreateCall(intr, {nel_unboxed, cg_elsz}); + Value *nbytes = ctx.builder.CreateExtractValue(prod_with_overflow, 0); + Value *overflow = ctx.builder.CreateExtractValue(prod_with_overflow, 1); + if (isunion) { + // if isunion, we need to allocate the union selector bytes as well + intr = Intrinsic::getDeclaration(jl_Module, Intrinsic::sadd_with_overflow, ArrayRef(T_size)); + Value *add_with_overflow = ctx.builder.CreateCall(intr, {nel_unboxed, nbytes}); + nbytes = ctx.builder.CreateExtractValue(add_with_overflow, 0); + Value *overflow1 = ctx.builder.CreateExtractValue(add_with_overflow, 1); + overflow = ctx.builder.CreateOr(overflow, overflow1); + } + Value *negnel = ctx.builder.CreateICmpSLT(nel_unboxed, ConstantInt::get(T_size, 0)); + overflow = ctx.builder.CreateOr(overflow, negnel); + auto cg_typemax_int = ConstantInt::get(T_size, (((size_t)-1)>>1)-1); + Value *tobignel = ctx.builder.CreateICmpSLT(cg_typemax_int, elsz == 0 ? nel_unboxed: nbytes); + overflow = ctx.builder.CreateOr(overflow, tobignel); + Value *notoverflow = ctx.builder.CreateNot(overflow); + error_unless(ctx, prepare_call(jlargumenterror_func), notoverflow, "invalid GenericMemory size: the number of elements is either negative or too large for system address width"); + // actually allocate + auto call = prepare_call(jl_alloc_genericmemory_unchecked_func); + Value *alloc = ctx.builder.CreateCall(call, { ptls, nbytes, cg_typ}); + // set length (jl_alloc_genericmemory_unchecked_func doesn't have it) + Value *decay_alloc = decay_derived(ctx, alloc); + Value *len_field = ctx.builder.CreateStructGEP(ctx.types().T_jlgenericmemory, decay_alloc, 0); + auto len_store = ctx.builder.CreateAlignedStore(nel_unboxed, len_field, Align(sizeof(void*))); + auto aliasinfo = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_memorylen); + aliasinfo.decorateInst(len_store); + //This avoids the length store from being deleted which is illegal + ctx.builder.CreateFence(AtomicOrdering::Release, SyncScope::SingleThread); + // zeroinit pointers and unions + if (zi) { + Value *memory_ptr = ctx.builder.CreateStructGEP(ctx.types().T_jlgenericmemory, decay_alloc, 1); + auto *load = ctx.builder.CreateAlignedLoad(ctx.types().T_ptr, memory_ptr, Align(sizeof(void*))); + aliasinfo = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_memoryptr); + aliasinfo.decorateInst(load); + ctx.builder.CreateMemSet(load, ConstantInt::get(int8t, 0), nbytes, Align(sizeof(void*))); + } + + setName(ctx.emission_context, alloc, arg_typename); + ctx.builder.CreateBr(retvalBB); + nonemptymemBB = ctx.builder.GetInsertBlock(); + // phi node to choose which side of branch + retvalBB->insertInto(ctx.f); + ctx.builder.SetInsertPoint(retvalBB); + auto phi = ctx.builder.CreatePHI(ctx.types().T_prjlvalue, 2); + phi->addIncoming(emptyalloc, emptymemBB); + phi->addIncoming(alloc, nonemptymemBB); + return mark_julia_type(ctx, phi, true, typ); +} + static jl_cgval_t _emit_memoryref(jl_codectx_t &ctx, Value *mem, Value *data, const jl_datatype_layout_t *layout, jl_value_t *typ) { //jl_cgval_t argv[] = { diff --git a/src/codegen.cpp b/src/codegen.cpp index 5656fb594044b..86c9afd134d9a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -801,6 +801,12 @@ static const auto jlerror_func = new JuliaFunction<>{ {getPointerTy(C)}, false); }, get_attrs_noreturn, }; +static const auto jlargumenterror_func = new JuliaFunction<>{ + XSTR(jl_argument_error), + [](LLVMContext &C) { return FunctionType::get(getVoidTy(C), + {getPointerTy(C)}, false); }, + get_attrs_noreturn, +}; static const auto jlatomicerror_func = new JuliaFunction<>{ XSTR(jl_atomic_error), [](LLVMContext &C) { return FunctionType::get(getVoidTy(C), @@ -1153,6 +1159,29 @@ static const auto jl_alloc_obj_func = new JuliaFunction{ None); }, }; +static const auto jl_alloc_genericmemory_unchecked_func = new JuliaFunction{ + XSTR(jl_alloc_genericmemory_unchecked), + [](LLVMContext &C, Type *T_size) { + auto T_jlvalue = JuliaType::get_jlvalue_ty(C); + auto T_prjlvalue = PointerType::get(T_jlvalue, AddressSpace::Tracked); + auto T_pjlvalue = PointerType::get(T_jlvalue, 0); + return FunctionType::get(T_prjlvalue, + {T_pjlvalue, T_size, T_pjlvalue}, false); + }, + [](LLVMContext &C) { + auto FnAttrs = AttrBuilder(C); + FnAttrs.addMemoryAttr(MemoryEffects::argMemOnly(ModRefInfo::Ref) | MemoryEffects::inaccessibleMemOnly(ModRefInfo::ModRef)); + FnAttrs.addAttribute(Attribute::WillReturn); + FnAttrs.addAttribute(Attribute::NoUnwind); + auto RetAttrs = AttrBuilder(C); + RetAttrs.addAttribute(Attribute::NoAlias); + RetAttrs.addAttribute(Attribute::NonNull); + return AttributeList::get(C, + AttributeSet::get(C, FnAttrs), + AttributeSet::get(C, RetAttrs), + None); + }, +}; static const auto jl_newbits_func = new JuliaFunction<>{ XSTR(jl_new_bits), [](LLVMContext &C) { @@ -1574,6 +1603,7 @@ static const auto &builtin_func_map() { { jl_f_nfields_addr, new JuliaFunction<>{XSTR(jl_f_nfields), get_func_sig, get_func_attrs} }, { jl_f__expr_addr, new JuliaFunction<>{XSTR(jl_f__expr), get_func_sig, get_func_attrs} }, { jl_f__typevar_addr, new JuliaFunction<>{XSTR(jl_f__typevar), get_func_sig, get_func_attrs} }, + { jl_f_memorynew_addr, new JuliaFunction<>{XSTR(jl_f_memorynew), get_func_sig, get_func_attrs} }, { jl_f_memoryref_addr, new JuliaFunction<>{XSTR(jl_f_memoryref), get_func_sig, get_func_attrs} }, { jl_f_memoryrefoffset_addr, new JuliaFunction<>{XSTR(jl_f_memoryrefoffset), get_func_sig, get_func_attrs} }, { jl_f_memoryrefset_addr, new JuliaFunction<>{XSTR(jl_f_memoryrefset), get_func_sig, get_func_attrs} }, @@ -4421,6 +4451,20 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, return true; } + else if (f == jl_builtin_memorynew && (nargs == 2)) { + const jl_cgval_t &memty = argv[1]; + if (!memty.constant) + return false; + jl_datatype_t *typ = (jl_datatype_t*) memty.constant; + if (!jl_is_concrete_type((jl_value_t*)typ) || !jl_is_genericmemory_type(typ)) + return false; + jl_genericmemory_t *inst = (jl_genericmemory_t*)((jl_datatype_t*)typ)->instance; + if (inst == NULL) + return false; + *ret = emit_memorynew(ctx, typ, argv[2], inst); + return true; + } + else if (f == jl_builtin_memoryref && nargs == 1) { const jl_cgval_t &mem = argv[1]; jl_datatype_t *mty_dt = (jl_datatype_t*)jl_unwrap_unionall(mem.typ); @@ -10152,6 +10196,7 @@ static void init_jit_functions(void) add_named_global(jltypeassert_func, &jl_typeassert); add_named_global(jlapplytype_func, &jl_instantiate_type_in_env); add_named_global(jl_object_id__func, &jl_object_id_); + add_named_global(jl_alloc_genericmemory_unchecked_func, &jl_alloc_genericmemory_unchecked); add_named_global(jl_alloc_obj_func, (void*)NULL); add_named_global(jl_newbits_func, (void*)jl_new_bits); add_named_global(jl_typeof_func, (void*)NULL); diff --git a/src/genericmemory.c b/src/genericmemory.c index 2b02f021ccdd0..e435ec3b63c9f 100644 --- a/src/genericmemory.c +++ b/src/genericmemory.c @@ -24,49 +24,51 @@ JL_DLLEXPORT char *jl_genericmemory_typetagdata(jl_genericmemory_t *m) JL_NOTSAF return (char*)m->ptr + m->length * layout->size; } -#if defined(_P64) && defined(UINT128MAX) -typedef __uint128_t wideint_t; -#else -typedef uint64_t wideint_t; -#endif - #define MAXINTVAL (((size_t)-1)>>1) -jl_genericmemory_t *_new_genericmemory_(jl_value_t *mtype, size_t nel, int8_t isunion, int8_t zeroinit, size_t elsz) +// ONLY USE FROM CODEGEN. It only partially initializes the mem +JL_DLLEXPORT jl_genericmemory_t *jl_alloc_genericmemory_unchecked(jl_ptls_t ptls, size_t nbytes, jl_datatype_t *mtype) { - jl_task_t *ct = jl_current_task; - char *data; - jl_genericmemory_t *m; - if (nel == 0) // zero-sized allocation optimization - return (jl_genericmemory_t*)((jl_datatype_t*)mtype)->instance; - wideint_t prod = (wideint_t)nel * elsz; - if (isunion) { - // an extra byte for each isbits union memory element, stored at m->ptr + m->length - prod += nel; - } - if (nel >= MAXINTVAL || prod >= (wideint_t) MAXINTVAL) - jl_exceptionf(jl_argumenterror_type, "invalid GenericMemory size: the number of elements is either negative or too large for system address width"); - size_t tot = (size_t)prod + LLT_ALIGN(sizeof(jl_genericmemory_t),JL_SMALL_BYTE_ALIGNMENT); + size_t tot = nbytes + LLT_ALIGN(sizeof(jl_genericmemory_t),JL_SMALL_BYTE_ALIGNMENT); int pooled = tot <= GC_MAX_SZCLASS; + char *data; + jl_genericmemory_t *m; if (!pooled) { - data = (char*)jl_gc_managed_malloc(prod); + data = (char*)jl_gc_managed_malloc(nbytes); tot = sizeof(jl_genericmemory_t) + sizeof(void*); } - m = (jl_genericmemory_t*)jl_gc_alloc(ct->ptls, tot, mtype); + m = (jl_genericmemory_t*)jl_gc_alloc(ptls, tot, mtype); if (pooled) { data = (char*)m + JL_SMALL_BYTE_ALIGNMENT; } else { int isaligned = 1; // jl_gc_managed_malloc is always aligned - jl_gc_track_malloced_genericmemory(ct->ptls, m, isaligned); + jl_gc_track_malloced_genericmemory(ptls, m, isaligned); jl_genericmemory_data_owner_field(m) = (jl_value_t*)m; } - m->length = nel; + // length set by codegen m->ptr = data; + return m; +} +jl_genericmemory_t *_new_genericmemory_(jl_value_t *mtype, size_t nel, int8_t isunion, int8_t zeroinit, size_t elsz) +{ + if (nel == 0) // zero-sized allocation optimization + return (jl_genericmemory_t*)((jl_datatype_t*)mtype)->instance; + size_t nbytes; + int overflow = __builtin_mul_overflow(nel, elsz, &nbytes); + if (isunion) { + // an extra byte for each isbits union memory element, stored at m->ptr + m->length + overflow |= __builtin_add_overflow(nel, nbytes, &nbytes); + } + if ((nel >= MAXINTVAL-1) || (nbytes >= MAXINTVAL-1) || overflow) + jl_exceptionf(jl_argumenterror_type, "invalid GenericMemory size: the number of elements is either negative or too large for system address width"); + jl_task_t *ct = jl_current_task; + jl_genericmemory_t *m = jl_alloc_genericmemory_unchecked((jl_ptls_t) ct->ptls, nbytes, (jl_datatype_t*)mtype); + m->length = nel; if (zeroinit) - memset(data, 0, (size_t)prod); + memset((char*)m->ptr, 0, nbytes); return m; } @@ -150,13 +152,14 @@ JL_DLLEXPORT jl_genericmemory_t *jl_ptr_to_genericmemory(jl_value_t *mtype, void if (((uintptr_t)data) & ((align > JL_HEAP_ALIGNMENT ? JL_HEAP_ALIGNMENT : align) - 1)) jl_exceptionf(jl_argumenterror_type, "unsafe_wrap: pointer %p is not properly aligned to %u bytes", data, align); - wideint_t prod = (wideint_t)nel * elsz; + size_t nbytes; + int overflow = __builtin_mul_overflow(nel, elsz, &nbytes); if (isunion) { // an extra byte for each isbits union memory element, stored at m->ptr + m->length - prod += nel; + overflow |= __builtin_add_overflow(nel, nbytes, &nbytes); } - if (nel >= MAXINTVAL || prod >= (wideint_t) MAXINTVAL) - jl_exceptionf(jl_argumenterror_type, "invalid GenericMemory size: too large for system address width"); + if ((nel >= MAXINTVAL) || (nbytes >= MAXINTVAL) || overflow) + jl_exceptionf(jl_argumenterror_type, "invalid GenericMemory size: the number of elements is either negative or too large for system address width"); int tsz = sizeof(jl_genericmemory_t) + sizeof(void*); m = (jl_genericmemory_t*)jl_gc_alloc(ct->ptls, tsz, mtype); m->ptr = data; diff --git a/src/julia.h b/src/julia.h index a9864aad16ccc..049416a33336f 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1949,6 +1949,7 @@ JL_DLLEXPORT jl_genericmemory_t *jl_ptr_to_genericmemory(jl_value_t *mtype, void size_t nel, int own_buffer); JL_DLLEXPORT jl_genericmemory_t *jl_alloc_genericmemory(jl_value_t *mtype, size_t nel); JL_DLLEXPORT jl_genericmemory_t *jl_pchar_to_memory(const char *str, size_t len); +JL_DLLEXPORT jl_genericmemory_t *jl_alloc_genericmemory_unchecked(jl_ptls_t ptls, size_t nbytes, jl_datatype_t *mtype); JL_DLLEXPORT jl_value_t *jl_genericmemory_to_string(jl_genericmemory_t *m, size_t len); JL_DLLEXPORT jl_genericmemory_t *jl_alloc_memory_any(size_t n); JL_DLLEXPORT jl_value_t *jl_genericmemoryref(jl_genericmemory_t *m, size_t i); // 0-indexed @@ -2068,6 +2069,7 @@ JL_DLLEXPORT void JL_NORETURN jl_type_error_rt(const char *fname, jl_value_t *got JL_MAYBE_UNROOTED); JL_DLLEXPORT void JL_NORETURN jl_undefined_var_error(jl_sym_t *var, jl_value_t *scope JL_MAYBE_UNROOTED); JL_DLLEXPORT void JL_NORETURN jl_has_no_field_error(jl_datatype_t *t, jl_sym_t *var); +JL_DLLEXPORT void JL_NORETURN jl_argument_error(char *str); JL_DLLEXPORT void JL_NORETURN jl_atomic_error(char *str); JL_DLLEXPORT void JL_NORETURN jl_bounds_error(jl_value_t *v JL_MAYBE_UNROOTED, jl_value_t *t JL_MAYBE_UNROOTED); diff --git a/src/rtutils.c b/src/rtutils.c index fcc4a489d3f38..00a5b639d8683 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -157,6 +157,13 @@ JL_DLLEXPORT void JL_NORETURN jl_has_no_field_error(jl_datatype_t *t, jl_sym_t * jl_throw(jl_new_struct(jl_fielderror_type, t, var)); } +JL_DLLEXPORT void JL_NORETURN jl_argument_error(char *str) // == jl_exceptionf(jl_argumenterror_type, "%s", str) +{ + jl_value_t *msg = jl_pchar_to_string((char*)str, strlen(str)); + JL_GC_PUSH1(&msg); + jl_throw(jl_new_struct(jl_argumenterror_type, msg)); +} + JL_DLLEXPORT void JL_NORETURN jl_atomic_error(char *str) // == jl_exceptionf(jl_atomicerror_type, "%s", str) { jl_value_t *msg = jl_pchar_to_string((char*)str, strlen(str)); diff --git a/src/staticdata.c b/src/staticdata.c index 1665b5be4ed0f..a0d56f3e38f54 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -101,7 +101,7 @@ extern "C" { // TODO: put WeakRefs on the weak_refs list during deserialization // TODO: handle finalizers -#define NUM_TAGS 193 +#define NUM_TAGS 194 // An array of references that need to be restored from the sysimg // This is a manually constructed dual of the gvars array, which would be produced by codegen for Julia code, for C. @@ -290,6 +290,7 @@ jl_value_t **const*const get_tags(void) { INSERT_TAG(jl_builtin_replacefield); INSERT_TAG(jl_builtin_setfieldonce); INSERT_TAG(jl_builtin_fieldtype); + INSERT_TAG(jl_builtin_memorynew); INSERT_TAG(jl_builtin_memoryref); INSERT_TAG(jl_builtin_memoryrefoffset); INSERT_TAG(jl_builtin_memoryrefget); @@ -508,7 +509,7 @@ static const jl_fptr_args_t id_to_fptrs[] = { &jl_f__call_latest, &jl_f__call_in_world, &jl_f__call_in_world_total, &jl_f_isdefined, &jl_f_tuple, &jl_f_svec, &jl_f_intrinsic_call, &jl_f_getfield, &jl_f_setfield, &jl_f_swapfield, &jl_f_modifyfield, &jl_f_setfieldonce, - &jl_f_replacefield, &jl_f_fieldtype, &jl_f_nfields, &jl_f_apply_type, + &jl_f_replacefield, &jl_f_fieldtype, &jl_f_nfields, &jl_f_apply_type, &jl_f_memorynew, &jl_f_memoryref, &jl_f_memoryrefoffset, &jl_f_memoryrefget, &jl_f_memoryref_isassigned, &jl_f_memoryrefset, &jl_f_memoryrefswap, &jl_f_memoryrefmodify, &jl_f_memoryrefreplace, &jl_f_memoryrefsetonce, &jl_f_applicable, &jl_f_invoke, &jl_f_sizeof, &jl_f__expr, &jl_f__typevar, diff --git a/test/core.jl b/test/core.jl index 7e4f655222ea5..4bbb2ca368019 100644 --- a/test/core.jl +++ b/test/core.jl @@ -4505,6 +4505,15 @@ for T in (Any, ValueWrapper) end end +#test grow_end ccall directly since it's used in the C source +for ET in [Nothing, Int, Union{Int, Nothing}, Any] + for n in [0, 1, 10] + arr = Vector{ET}(undef, n) + ccall(:jl_array_grow_end, Cvoid, (Any, UInt), arr, 1) + @test length(arr) == n+1 + end +end + # check if we can run multiple finalizers at the same time # Use a `@noinline` function to make sure the inefficient gc root generation # doesn't keep the object alive. From da9f934112f2bc7b47ce2b2cf8156fa9e2886cfe Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Tue, 17 Dec 2024 19:16:38 +0900 Subject: [PATCH 074/342] fix `compute_trycatch` for `IRCode` /w `EnterNode` with `catch_dest==0` (#56846) --- Compiler/src/inferencestate.jl | 4 ++-- Compiler/test/irpasses.jl | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Compiler/src/inferencestate.jl b/Compiler/src/inferencestate.jl index 046f98df1f41d..0ea0fc684b689 100644 --- a/Compiler/src/inferencestate.jl +++ b/Compiler/src/inferencestate.jl @@ -475,7 +475,7 @@ function (::ComputeTryCatch{Handler})(code::Vector{Any}, bbs::Union{Vector{Basic (;handlers, handler_at) = handler_info = (handler_info === nothing ? HandlerInfo{Handler}(Handler[], fill((0, 0), n)) : handler_info) l = stmt.catch_dest - (bbs !== nothing) && (l = first(bbs[l].stmts)) + (bbs !== nothing) && (l != 0) && (l = first(bbs[l].stmts)) push!(handlers, Handler(stmt, pc)) handler_id = length(handlers) handler_at[pc + 1] = (handler_id, 0) @@ -519,7 +519,7 @@ function (::ComputeTryCatch{Handler})(code::Vector{Any}, bbs::Union{Vector{Basic break elseif isa(stmt, EnterNode) l = stmt.catch_dest - (bbs !== nothing) && (l = first(bbs[l].stmts)) + (bbs !== nothing) && (l != 0) && (l = first(bbs[l].stmts)) # We assigned a handler number above. Here we just merge that # with out current handler information. if l != 0 diff --git a/Compiler/test/irpasses.jl b/Compiler/test/irpasses.jl index 90d8c9dc6ab3d..27b6d75f86c93 100644 --- a/Compiler/test/irpasses.jl +++ b/Compiler/test/irpasses.jl @@ -1716,6 +1716,12 @@ end @test scope_folding_opt() == 1 @test_broken fully_eliminated(scope_folding) @test_broken fully_eliminated(scope_folding_opt) +let ir = first(only(Base.code_ircode(scope_folding, ()))) + @test Compiler.compute_trycatch(ir) isa Compiler.HandlerInfo +end +let ir = first(only(Base.code_ircode(scope_folding_opt, ()))) + @test Compiler.compute_trycatch(ir) isa Compiler.HandlerInfo +end # Function that happened to have lots of sroa that # happened to trigger a bad case in the renamer. We From e47670de3e2ed17e71535d9263c85939a8c6f87e Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Tue, 17 Dec 2024 23:16:13 +0900 Subject: [PATCH 075/342] EA: general cleanup (#56848) The handling of `Array` in EA was implemented before `Memory` was introduced and has now become stale. Analysis for `Array` should be reintroduced after the upcoming overhaul is completed. For now, I will remove the existing stale code. --- Compiler/src/ssair/EscapeAnalysis.jl | 292 +++---------- Compiler/src/ssair/disjoint_set.jl | 8 +- Compiler/test/EscapeAnalysis.jl | 617 +-------------------------- 3 files changed, 63 insertions(+), 854 deletions(-) diff --git a/Compiler/src/ssair/EscapeAnalysis.jl b/Compiler/src/ssair/EscapeAnalysis.jl index 4f32550d056b2..68a7aef1cbba4 100644 --- a/Compiler/src/ssair/EscapeAnalysis.jl +++ b/Compiler/src/ssair/EscapeAnalysis.jl @@ -13,22 +13,21 @@ export using Base: Base # imports -import Base: ==, getindex, setindex! +import Base: ==, copy, getindex, setindex! # usings -using Core: MethodMatch, SimpleVector, ifelse, sizeof +using Core: Builtin, IntrinsicFunction, SimpleVector, ifelse, sizeof using Core.IR using Base: # Base definitions @__MODULE__, @assert, @eval, @goto, @inbounds, @inline, @label, @noinline, - @nospecialize, @specialize, BitSet, Callable, Csize_t, IdDict, IdSet, UnitRange, Vector, - copy, delete!, empty!, enumerate, error, first, get, get!, haskey, in, isassigned, - isempty, ismutabletype, keys, last, length, max, min, missing, pop!, push!, pushfirst!, - unwrap_unionall, !, !=, !==, &, *, +, -, :, <, <<, =>, >, |, ∈, ∉, ∩, ∪, ≠, ≤, ≥, ⊆, - hasintersect + @nospecialize, @specialize, BitSet, IdDict, IdSet, UnitRange, Vector, + delete!, empty!, enumerate, first, get, get!, hasintersect, haskey, isassigned, + isempty, length, max, min, missing, println, push!, pushfirst!, + !, !==, &, *, +, -, :, <, <<, >, |, ∈, ∉, ∩, ∪, ≠, ≤, ≥, ⊆ using ..Compiler: # Compiler specific definitions - AbstractLattice, Bottom, IRCode, IR_FLAG_NOTHROW, InferenceResult, SimpleInferenceLattice, - argextype, fieldcount_noerror, hasintersect, has_flag, intrinsic_nothrow, - is_meta_expr_head, is_identity_free_argtype, isexpr, println, setfield!_nothrow, - singleton_type, try_compute_field, try_compute_fieldidx, widenconst, ⊑, Compiler + AbstractLattice, Compiler, IRCode, IR_FLAG_NOTHROW, + argextype, fieldcount_noerror, has_flag, intrinsic_nothrow, is_meta_expr_head, + is_identity_free_argtype, isexpr, setfield!_nothrow, singleton_type, try_compute_field, + try_compute_fieldidx, widenconst function include(x::String) if !isdefined(Base, :end_base_include) @@ -53,14 +52,13 @@ A lattice for escape information, which holds the following properties: * `pc ∈ x.ThrownEscape`: `x` may be thrown at the SSA statement at `pc` * `-1 ∈ x.ThrownEscape`: `x` may be thrown at arbitrary points of this call frame (the top) This information will be used by `escape_exception!` to propagate potential escapes via exception. -- `x.AliasInfo::Union{Bool,IndexableFields,IndexableElements,Unindexable}`: maintains all possible values +- `x.AliasInfo::Union{Bool,IndexableFields,Unindexable}`: maintains all possible values that can be aliased to fields or array elements of `x`: * `x.AliasInfo === false` indicates the fields/elements of `x` aren't analyzed yet * `x.AliasInfo === true` indicates the fields/elements of `x` can't be analyzed, e.g. the type of `x` is not known or is not concrete and thus its fields/elements can't be known precisely * `x.AliasInfo::IndexableFields` records all the possible values that can be aliased to fields of object `x` with precise index information - * `x.AliasInfo::IndexableElements` records all the possible values that can be aliased to elements of array `x` with precise index information * `x.AliasInfo::Unindexable` records all the possible values that can be aliased to fields/elements of `x` without precise index information - `x.Liveness::BitSet`: records SSA statement numbers where `x` should be live, e.g. to be used as a call argument, to be returned to a caller, or preserved for `:foreigncall`: @@ -87,14 +85,14 @@ struct EscapeInfo Analyzed::Bool ReturnEscape::Bool ThrownEscape::BitSet - AliasInfo #::Union{IndexableFields,IndexableElements,Unindexable,Bool} + AliasInfo #::Union{IndexableFields,Unindexable,Bool} Liveness::BitSet function EscapeInfo( Analyzed::Bool, ReturnEscape::Bool, ThrownEscape::BitSet, - AliasInfo#=::Union{IndexableFields,IndexableElements,Unindexable,Bool}=#, + AliasInfo#=::Union{IndexableFields,Unindexable,Bool}=#, Liveness::BitSet) @nospecialize AliasInfo return new( @@ -108,7 +106,7 @@ struct EscapeInfo x::EscapeInfo, # non-concrete fields should be passed as default arguments # in order to avoid allocating non-concrete `NamedTuple`s - AliasInfo#=::Union{IndexableFields,IndexableElements,Unindexable,Bool}=# = x.AliasInfo; + AliasInfo#=::Union{IndexableFields,Unindexable,Bool}=# = x.AliasInfo; Analyzed::Bool = x.Analyzed, ReturnEscape::Bool = x.ReturnEscape, ThrownEscape::BitSet = x.ThrownEscape, @@ -149,11 +147,11 @@ const ⊥, ⊤ = NotAnalyzed(), AllEscape() # Convenience names for some ⊑ₑ queries has_no_escape(x::EscapeInfo) = !x.ReturnEscape && isempty(x.ThrownEscape) && 0 ∉ x.Liveness -has_arg_escape(x::EscapeInfo) = 0 in x.Liveness +has_arg_escape(x::EscapeInfo) = 0 ∈ x.Liveness has_return_escape(x::EscapeInfo) = x.ReturnEscape -has_return_escape(x::EscapeInfo, pc::Int) = x.ReturnEscape && (-1 ∈ x.Liveness || pc in x.Liveness) +has_return_escape(x::EscapeInfo, pc::Int) = x.ReturnEscape && (-1 ∈ x.Liveness || pc ∈ x.Liveness) has_thrown_escape(x::EscapeInfo) = !isempty(x.ThrownEscape) -has_thrown_escape(x::EscapeInfo, pc::Int) = -1 ∈ x.ThrownEscape || pc in x.ThrownEscape +has_thrown_escape(x::EscapeInfo, pc::Int) = -1 ∈ x.ThrownEscape || pc ∈ x.ThrownEscape has_all_escape(x::EscapeInfo) = ⊤ ⊑ₑ x # utility lattice constructors @@ -166,14 +164,13 @@ ignore_liveness(x::EscapeInfo) = EscapeInfo(x; Liveness=BOT_LIVENESS) struct IndexableFields infos::Vector{AInfo} end -struct IndexableElements - infos::IdDict{Int,AInfo} -end struct Unindexable info::AInfo end IndexableFields(nflds::Int) = IndexableFields(AInfo[AInfo() for _ in 1:nflds]) Unindexable() = Unindexable(AInfo()) +copy(AliasInfo::IndexableFields) = IndexableFields(AInfo[copy(info) for info in AliasInfo.infos]) +copy(AliasInfo::Unindexable) = Unindexable(copy(AliasInfo.info)) merge_to_unindexable(AliasInfo::IndexableFields) = Unindexable(merge_to_unindexable(AliasInfo.infos)) merge_to_unindexable(AliasInfo::Unindexable, AliasInfos::IndexableFields) = Unindexable(merge_to_unindexable(AliasInfo.info, AliasInfos.infos)) @@ -184,15 +181,6 @@ function merge_to_unindexable(info::AInfo, infos::Vector{AInfo}) end return info end -merge_to_unindexable(AliasInfo::IndexableElements) = Unindexable(merge_to_unindexable(AliasInfo.infos)) -merge_to_unindexable(AliasInfo::Unindexable, AliasInfos::IndexableElements) = Unindexable(merge_to_unindexable(AliasInfo.info, AliasInfos.infos)) -merge_to_unindexable(infos::IdDict{Int,AInfo}) = merge_to_unindexable(AInfo(), infos) -function merge_to_unindexable(info::AInfo, infos::IdDict{Int,AInfo}) - for idx in keys(infos) - info = info ∪ infos[idx] - end - return info -end # we need to make sure this `==` operator corresponds to lattice equality rather than object equality, # otherwise `propagate_changes` can't detect the convergence @@ -215,9 +203,6 @@ x::EscapeInfo == y::EscapeInfo = begin elseif isa(xa, IndexableFields) isa(ya, IndexableFields) || return false xa.infos == ya.infos || return false - elseif isa(xa, IndexableElements) - isa(ya, IndexableElements) || return false - xa.infos == ya.infos || return false else xa = xa::Unindexable isa(ya, Unindexable) || return false @@ -269,8 +254,6 @@ x::EscapeInfo ⊑ₑ y::EscapeInfo = begin for i in 1:xn xinfos[i] ⊆ yinfos[i] || return false end - elseif isa(ya, IndexableElements) - return false elseif isa(ya, Unindexable) xinfos, yinfo = xa.infos, ya.info for i = length(xinfos) @@ -279,23 +262,6 @@ x::EscapeInfo ⊑ₑ y::EscapeInfo = begin else ya === true || return false end - elseif isa(xa, IndexableElements) - if isa(ya, IndexableElements) - xinfos, yinfos = xa.infos, ya.infos - keys(xinfos) ⊆ keys(yinfos) || return false - for idx in keys(xinfos) - xinfos[idx] ⊆ yinfos[idx] || return false - end - elseif isa(ya, IndexableFields) - return false - elseif isa(ya, Unindexable) - xinfos, yinfo = xa.infos, ya.info - for idx in keys(xinfos) - xinfos[idx] ⊆ yinfo || return false - end - else - ya === true || return false - end else xa = xa::Unindexable if isa(ya, Unindexable) @@ -401,33 +367,10 @@ function merge_alias_info(@nospecialize(xa), @nospecialize(ya)) else return true # handle conflicting case conservatively end - elseif isa(xa, IndexableElements) - if isa(ya, IndexableElements) - xinfos, yinfos = xa.infos, ya.infos - infos = IdDict{Int,AInfo}() - for idx in keys(xinfos) - if !haskey(yinfos, idx) - infos[idx] = xinfos[idx] - else - infos[idx] = xinfos[idx] ∪ yinfos[idx] - end - end - for idx in keys(yinfos) - haskey(xinfos, idx) && continue # unioned already - infos[idx] = yinfos[idx] - end - return IndexableElements(infos) - elseif isa(ya, Unindexable) - return merge_to_unindexable(ya, xa) - else - return true # handle conflicting case conservatively - end else xa = xa::Unindexable if isa(ya, IndexableFields) return merge_to_unindexable(xa, ya) - elseif isa(ya, IndexableElements) - return merge_to_unindexable(xa, ya) else ya = ya::Unindexable xinfo, yinfo = xa.info, ya.info @@ -439,8 +382,6 @@ end const AliasSet = IntDisjointSet{Int} -const ArrayInfo = IdDict{Int,Vector{Int}} - """ estate::EscapeState @@ -451,13 +392,12 @@ struct EscapeState escapes::Vector{EscapeInfo} aliasset::AliasSet nargs::Int - arrayinfo::Union{Nothing,ArrayInfo} end -function EscapeState(nargs::Int, nstmts::Int, arrayinfo::Union{Nothing,ArrayInfo}) +function EscapeState(nargs::Int, nstmts::Int) escapes = EscapeInfo[ 1 ≤ i ≤ nargs ? ArgEscape() : ⊥ for i in 1:(nargs+nstmts)] aliasset = AliasSet(nargs+nstmts) - return EscapeState(escapes, aliasset, nargs, arrayinfo) + return EscapeState(escapes, aliasset, nargs) end function getindex(estate::EscapeState, @nospecialize(x)) xidx = iridx(x, estate) @@ -503,8 +443,7 @@ that is analyzable in the context of `estate`. `iridx(irval(xidx, state), state) === xidx`. """ function irval(xidx::Int, estate::EscapeState) - x = xidx > estate.nargs ? SSAValue(xidx-estate.nargs) : Argument(xidx) - return x + return xidx > estate.nargs ? SSAValue(xidx-estate.nargs) : Argument(xidx) end function getaliases(x::Union{Argument,SSAValue}, estate::EscapeState) @@ -621,8 +560,8 @@ function analyze_escapes(ir::IRCode, nargs::Int, 𝕃ₒ::AbstractLattice, get_e stmts = ir.stmts nstmts = length(stmts) + length(ir.new_nodes.stmts) - tryregions, arrayinfo = compute_frameinfo(ir) - estate = EscapeState(nargs, nstmts, arrayinfo) + tryregions = compute_frameinfo(ir) + estate = EscapeState(nargs, nstmts) changes = Changes() # keeps changes that happen at current statement astate = AnalysisState(ir, estate, changes, 𝕃ₒ, get_escape_cache) @@ -712,21 +651,15 @@ function analyze_escapes(ir::IRCode, nargs::Int, 𝕃ₒ::AbstractLattice, get_e end """ - compute_frameinfo(ir::IRCode) -> (tryregions, arrayinfo) - -A preparatory linear scan before the escape analysis on `ir` to find: -- `tryregions::Union{Nothing,Vector{UnitRange{Int}}}`: regions in which potential `throw`s can be caught (used by `escape_exception!`) -- `arrayinfo::Union{Nothing,IdDict{Int,Vector{Int}}}`: array allocations whose dimensions are known precisely (with some very simple local analysis) + compute_frameinfo(ir::IRCode) -> tryregions -!!! note - This array dimension analysis to compute `arrayinfo` is very local and doesn't account - for flow-sensitivity nor complex aliasing. - Ideally this dimension analysis should be done as a part of type inference that - propagates array dimensions in a flow sensitive way. +A preparatory linear scan before the escape analysis on `ir` to find +`tryregions::Union{Nothing,Vector{UnitRange{Int}}}`, that represent regions in which +potential `throw`s can be caught (used by `escape_exception!`) """ function compute_frameinfo(ir::IRCode) nstmts, nnewnodes = length(ir.stmts), length(ir.new_nodes.stmts) - tryregions, arrayinfo = nothing, nothing + tryregions = nothing for idx in 1:nstmts+nnewnodes inst = ir[SSAValue(idx)] stmt = inst[:stmt] @@ -738,41 +671,9 @@ function compute_frameinfo(ir::IRCode) leave_pc = first(ir.cfg.blocks[leave_block].stmts) push!(tryregions, idx:leave_pc) end - elseif arrayinfo !== nothing - # TODO this super limited alias analysis is able to handle only very simple cases - # this should be replaced with a proper forward dimension analysis - if isa(stmt, PhiNode) - values = stmt.values - local dims = nothing - for i = 1:length(values) - if isassigned(values, i) - val = values[i] - if isa(val, SSAValue) && haskey(arrayinfo, val.id) - if dims === nothing - dims = arrayinfo[val.id] - continue - elseif dims == arrayinfo[val.id] - continue - end - end - end - @goto next_stmt - end - if dims !== nothing - arrayinfo[idx] = dims - end - elseif isa(stmt, PiNode) - if isdefined(stmt, :val) - val = stmt.val - if isa(val, SSAValue) && haskey(arrayinfo, val.id) - arrayinfo[idx] = arrayinfo[val.id] - end - end - end end - @label next_stmt end - return tryregions, arrayinfo + return tryregions end # propagate changes, and check convergence @@ -826,7 +727,7 @@ end info = estate.escapes[xidx] Liveness = info.Liveness Liveness === TOP_LIVENESS && return false - livepc in Liveness && return false + livepc ∈ Liveness && return false if Liveness === BOT_LIVENESS || Liveness === ARG_LIVENESS # if this Liveness is a constant, we shouldn't modify it and propagate this change as a new EscapeInfo Liveness = copy(Liveness) @@ -976,19 +877,6 @@ end is_nothrow(ir::IRCode, pc::Int) = has_flag(ir[SSAValue(pc)], IR_FLAG_NOTHROW) -# NOTE if we don't maintain the alias set that is separated from the lattice state, we can do -# something like below: it essentially incorporates forward escape propagation in our default -# backward propagation, and leads to inefficient convergence that requires more iterations -# # lhs = rhs: propagate escape information of `rhs` to `lhs` -# function escape_alias!(astate::AnalysisState, @nospecialize(lhs), @nospecialize(rhs)) -# if isa(rhs, SSAValue) || isa(rhs, Argument) -# vinfo = astate.estate[rhs] -# else -# return -# end -# add_escape_change!(astate, lhs, vinfo) -# end - """ escape_exception!(astate::AnalysisState, tryregions::Vector{UnitRange{Int}}) @@ -1044,7 +932,7 @@ function escape_exception!(astate::AnalysisState, tryregions::Vector{UnitRange{I xt === TOP_THROWN_ESCAPE && @goto propagate_exception_escape # fast pass for pc in xt for region in tryregions - pc in region && @goto propagate_exception_escape # early break because of AllEscape + pc ∈ region && @goto propagate_exception_escape # early break because of AllEscape end end continue @@ -1143,12 +1031,6 @@ function escape_foreigncall!(astate::AnalysisState, pc::Int, args::Vector{Any}) argtypes = args[3]::SimpleVector nargs = length(argtypes) name = args[1] - nn = normalize(name) - if isa(nn, Symbol) - # if nn === :jl_gc_add_finalizer_th - # # TODO add `FinalizerEscape` ? - # end - end # NOTE array allocations might have been proven as nothrow (https://github.com/JuliaLang/julia/pull/43565) nothrow = is_nothrow(astate.ir, pc) name_info = nothrow ? ⊥ : ThrownEscape(pc) @@ -1183,37 +1065,31 @@ function escape_gc_preserve!(astate::AnalysisState, pc::Int, args::Vector{Any}) add_liveness_changes!(astate, pc, beginargs) end -normalize(@nospecialize x) = isa(x, QuoteNode) ? x.value : x - function escape_call!(astate::AnalysisState, pc::Int, args::Vector{Any}) - ir = astate.ir - ft = argextype(first(args), ir, ir.sptypes, ir.argtypes) + ft = argextype(first(args), astate.ir) f = singleton_type(ft) - if isa(f, Core.IntrinsicFunction) - # XXX somehow `:call` expression can creep in here, ideally we should be able to do: - # argtypes = Any[argextype(args[i], astate.ir) for i = 2:length(args)] - argtypes = Any[] - for i = 2:length(args) - arg = args[i] - push!(argtypes, isexpr(arg, :call) ? Any : argextype(arg, ir)) + if f isa IntrinsicFunction + if is_nothrow(astate.ir, pc) + add_liveness_changes!(astate, pc, args, 2) + else + add_fallback_changes!(astate, pc, args, 2) end - if intrinsic_nothrow(f, argtypes) + # TODO needs to account for pointer operations? + elseif f isa Builtin + result = escape_builtin!(f, astate, pc, args) + if result === missing + # if this call hasn't been handled by any of pre-defined handlers, escape it conservatively + add_conservative_changes!(astate, pc, args) + elseif result === true + add_liveness_changes!(astate, pc, args, 2) + elseif is_nothrow(astate.ir, pc) add_liveness_changes!(astate, pc, args, 2) else add_fallback_changes!(astate, pc, args, 2) end - return # TODO accounts for pointer operations? - end - result = escape_builtin!(f, astate, pc, args) - if result === missing - # if this call hasn't been handled by any of pre-defined handlers, escape it conservatively - add_conservative_changes!(astate, pc, args) - elseif result === true - add_liveness_changes!(astate, pc, args, 2) - elseif is_nothrow(astate.ir, pc) - add_liveness_changes!(astate, pc, args, 2) else - add_fallback_changes!(astate, pc, args, 2) + # escape this generic function or unknown function call conservatively + add_conservative_changes!(astate, pc, args) end end @@ -1274,6 +1150,7 @@ function escape_new!(astate::AnalysisState, pc::Int, args::Vector{Any}) @goto escape_indexable_def end elseif isa(AliasInfo, IndexableFields) + AliasInfo = copy(AliasInfo) @label escape_indexable_def # fields are known precisely: propagate escape information imposed on recorded possibilities to the exact field values infos = AliasInfo.infos @@ -1290,6 +1167,7 @@ function escape_new!(astate::AnalysisState, pc::Int, args::Vector{Any}) end add_escape_change!(astate, obj, EscapeInfo(objinfo, AliasInfo)) # update with new AliasInfo elseif isa(AliasInfo, Unindexable) + AliasInfo = copy(AliasInfo) @label escape_unindexable_def # fields are known partially: propagate escape information imposed on recorded possibilities to all fields values info = AliasInfo.info @@ -1343,7 +1221,7 @@ function analyze_fields(ir::IRCode, @nospecialize(typ), @nospecialize(fld)) return IndexableFields(nflds), fidx end -function reanalyze_fields(ir::IRCode, AliasInfo::IndexableFields, @nospecialize(typ), @nospecialize(fld)) +function reanalyze_fields(AliasInfo::IndexableFields, ir::IRCode, @nospecialize(typ), @nospecialize(fld)) nflds = fieldcount_noerror(typ) if nflds === nothing return merge_to_unindexable(AliasInfo), 0 @@ -1357,6 +1235,7 @@ function reanalyze_fields(ir::IRCode, AliasInfo::IndexableFields, @nospecialize( if fidx === nothing return merge_to_unindexable(AliasInfo), 0 end + AliasInfo = copy(AliasInfo) infos = AliasInfo.infos ninfos = length(infos) if nflds > ninfos @@ -1393,12 +1272,13 @@ function escape_builtin!(::typeof(getfield), astate::AnalysisState, pc::Int, arg @goto record_unindexable_use end elseif isa(AliasInfo, IndexableFields) - AliasInfo, fidx = reanalyze_fields(ir, AliasInfo, typ, args[3]) + AliasInfo, fidx = reanalyze_fields(AliasInfo, ir, typ, args[3]) isa(AliasInfo, Unindexable) && @goto record_unindexable_use @label record_indexable_use push!(AliasInfo.infos[fidx], LocalUse(pc)) add_escape_change!(astate, obj, EscapeInfo(objinfo, AliasInfo)) # update with new AliasInfo elseif isa(AliasInfo, Unindexable) + AliasInfo = copy(AliasInfo) @label record_unindexable_use push!(AliasInfo.info, LocalUse(pc)) add_escape_change!(astate, obj, EscapeInfo(objinfo, AliasInfo)) # update with new AliasInfo @@ -1439,7 +1319,7 @@ function escape_builtin!(::typeof(setfield!), astate::AnalysisState, pc::Int, ar end elseif isa(AliasInfo, IndexableFields) typ = widenconst(argextype(obj, ir)) - AliasInfo, fidx = reanalyze_fields(ir, AliasInfo, typ, args[3]) + AliasInfo, fidx = reanalyze_fields(AliasInfo, ir, typ, args[3]) isa(AliasInfo, Unindexable) && @goto escape_unindexable_def @label escape_indexable_def add_alias_escapes!(astate, val, AliasInfo.infos[fidx]) @@ -1449,7 +1329,7 @@ function escape_builtin!(::typeof(setfield!), astate::AnalysisState, pc::Int, ar # propagate the escape information of this object ignoring field information add_escape_change!(astate, val, ignore_aliasinfo(objinfo)) elseif isa(AliasInfo, Unindexable) - info = AliasInfo.info + AliasInfo = copy(AliasInfo) @label escape_unindexable_def add_alias_escapes!(astate, val, AliasInfo.info) push!(AliasInfo.info, LocalDef(pc)) @@ -1483,64 +1363,6 @@ function escape_builtin!(::typeof(setfield!), astate::AnalysisState, pc::Int, ar end end -# NOTE this function models and thus should be synced with the implementation of: -# size_t array_nd_index(jl_array_t *a, jl_value_t **args, size_t nidxs, ...) -function array_nd_index(astate::AnalysisState, @nospecialize(ary), args::Vector{Any}, nidxs::Int = length(args)) - isa(ary, SSAValue) || return nothing - aryid = ary.id - arrayinfo = astate.estate.arrayinfo - isa(arrayinfo, ArrayInfo) || return nothing - haskey(arrayinfo, aryid) || return nothing - dims = arrayinfo[aryid] - local i = 0 - local k, stride = 0, 1 - local nd = length(dims) - while k < nidxs - arg = args[k+1] - argval = argextype(arg, astate.ir) - isa(argval, Const) || return nothing - argval = argval.val - isa(argval, Int) || return nothing - ii = argval - 1 - i += ii * stride - d = k ≥ nd ? 1 : dims[k+1] - k < nidxs - 1 && ii ≥ d && return nothing # BoundsError - stride *= d - k += 1 - end - while k < nd - stride *= dims[k+1] - k += 1 - end - i ≥ stride && return nothing # BoundsError - return i -end - -function mark_unindexable!(astate::AnalysisState, @nospecialize(ary)) - isa(ary, SSAValue) || return - aryinfo = astate.estate[ary] - AliasInfo = aryinfo.AliasInfo - isa(AliasInfo, IndexableElements) || return - AliasInfo = merge_to_unindexable(AliasInfo) - add_escape_change!(astate, ary, EscapeInfo(aryinfo, AliasInfo)) -end - -# FIXME this implementation is very conservative, improve the accuracy and solve broken test cases -function escape_array_copy!(astate::AnalysisState, pc::Int, args::Vector{Any}) - length(args) ≥ 6 || return add_fallback_changes!(astate, pc, args) - ary = args[6] - aryt = argextype(ary, astate.ir) - aryt ⊑ Array || return add_fallback_changes!(astate, pc, args) - if isa(ary, SSAValue) || isa(ary, Argument) - newary = SSAValue(pc) - aryinfo = astate.estate[ary] - newaryinfo = astate.estate[newary] - add_escape_change!(astate, newary, aryinfo) - add_escape_change!(astate, ary, newaryinfo) - end - add_liveness_changes!(astate, pc, args, 6) -end - function escape_builtin!(::typeof(Core.finalizer), astate::AnalysisState, pc::Int, args::Vector{Any}) if length(args) ≥ 3 obj = args[3] diff --git a/Compiler/src/ssair/disjoint_set.jl b/Compiler/src/ssair/disjoint_set.jl index 3f64fe643bd17..e000d7e8a582f 100644 --- a/Compiler/src/ssair/disjoint_set.jl +++ b/Compiler/src/ssair/disjoint_set.jl @@ -5,7 +5,7 @@ # imports import Base: length, eltype, union!, push! # usings -import Base: OneTo, collect, zero, zeros, one, typemax +using Base: OneTo, collect, zero, zeros, one, typemax # Disjoint-Set @@ -55,7 +55,7 @@ eltype(::Type{IntDisjointSet{T}}) where {T<:Integer} = T # path compression is implemented here function find_root_impl!(parents::Vector{T}, x::Integer) where {T<:Integer} p = parents[x] - @inbounds if parents[p] != p + @inbounds if parents[p] ≠ p parents[x] = p = _find_root_impl!(parents, p) end return p @@ -64,7 +64,7 @@ end # unsafe version of the above function _find_root_impl!(parents::Vector{T}, x::Integer) where {T<:Integer} @inbounds p = parents[x] - @inbounds if parents[p] != p + @inbounds if parents[p] ≠ p parents[x] = p = _find_root_impl!(parents, p) end return p @@ -95,7 +95,7 @@ function union!(s::IntDisjointSet{T}, x::T, y::T) where {T<:Integer} parents = s.parents xroot = find_root_impl!(parents, x) yroot = find_root_impl!(parents, y) - return xroot != yroot ? root_union!(s, xroot, yroot) : xroot + return xroot ≠ yroot ? root_union!(s, xroot, yroot) : xroot end """ diff --git a/Compiler/test/EscapeAnalysis.jl b/Compiler/test/EscapeAnalysis.jl index 1831bd355cd48..e1638e74e61fe 100644 --- a/Compiler/test/EscapeAnalysis.jl +++ b/Compiler/test/EscapeAnalysis.jl @@ -34,24 +34,9 @@ let utils_ex = quote Core.eval(@__MODULE__, utils_ex) end -using .EscapeAnalysis: - EscapeInfo, IndexableElements, IndexableFields, normalize +using .EscapeAnalysis: EscapeInfo, IndexableFields isϕ(@nospecialize x) = isa(x, Core.PhiNode) -function with_normalized_name(@nospecialize(f), @nospecialize(x)) - if Meta.isexpr(x, :foreigncall) - name = x.args[1] - nn = normalize(name) - return isa(nn, Symbol) && f(nn) - end - return false -end -isarrayalloc(@nospecialize x) = - with_normalized_name(nn::Symbol->false, x) -isarrayresize(@nospecialize x) = - with_normalized_name(nn::Symbol->false, x) -isarraycopy(@nospecialize x) = - with_normalized_name(nn::Symbol->false, x) """ is_load_forwardable(x::EscapeInfo) -> Bool @@ -61,7 +46,7 @@ function is_load_forwardable(x::EscapeInfo) AliasInfo = x.AliasInfo # NOTE technically we also need to check `!has_thrown_escape(x)` here as well, # but we can also do equivalent check during forwarding - return isa(AliasInfo, IndexableFields) || isa(AliasInfo, IndexableElements) + return isa(AliasInfo, IndexableFields) end @testset "EAUtils" begin @@ -1501,585 +1486,6 @@ let result = @code_escapes compute!(MPoint(1+.5im, 2+.5im), MPoint(2+.25im, 4+.7 end end -@testset "array primitives" begin - # arrayref - @test_skip let result = code_escapes((Vector{String},Int)) do xs, i - s = Base.arrayref(true, xs, i) - return s - end - r = only(findall(isreturn, result.ir.stmts.stmt)) - @test has_return_escape(result.state[Argument(2)], r) # xs - @test has_thrown_escape(result.state[Argument(2)]) # xs - @test !has_return_escape(result.state[Argument(3)], r) # i - end - @test_skip let result = code_escapes((Vector{String},Int)) do xs, i - s = Base.arrayref(false, xs, i) - return s - end - r = only(findall(isreturn, result.ir.stmts.stmt)) - @test has_return_escape(result.state[Argument(2)], r) # xs - @test !has_thrown_escape(result.state[Argument(2)]) # xs - @test !has_return_escape(result.state[Argument(3)], r) # i - end - @test_skip let result = code_escapes((Vector{String},Bool)) do xs, i - c = Base.arrayref(true, xs, i) # TypeError will happen here - return c - end - t = only(findall(iscall((result.ir, Base.arrayref)), result.ir.stmts.stmt)) - @test has_thrown_escape(result.state[Argument(2)], t) # xs - end - @test_skip let result = code_escapes((String,Int)) do xs, i - c = Base.arrayref(true, xs, i) # TypeError will happen here - return c - end - t = only(findall(iscall((result.ir, Base.arrayref)), result.ir.stmts.stmt)) - @test has_thrown_escape(result.state[Argument(2)], t) # xs - end - @test_skip let result = code_escapes((AbstractVector{String},Int)) do xs, i - c = Base.arrayref(true, xs, i) # TypeError may happen here - return c - end - t = only(findall(iscall((result.ir, Base.arrayref)), result.ir.stmts.stmt)) - @test has_thrown_escape(result.state[Argument(2)], t) # xs - end - @test_skip let result = code_escapes((Vector{String},Any)) do xs, i - c = Base.arrayref(true, xs, i) # TypeError may happen here - return c - end - t = only(findall(iscall((result.ir, Base.arrayref)), result.ir.stmts.stmt)) - @test has_thrown_escape(result.state[Argument(2)], t) # xs - end - - # arrayset - @test_skip let result = code_escapes((Vector{String},String,Int,)) do xs, x, i - Base.arrayset(true, xs, x, i) - return xs - end - r = only(findall(isreturn, result.ir.stmts.stmt)) - @test has_return_escape(result.state[Argument(2)], r) # xs - @test has_thrown_escape(result.state[Argument(2)]) # xs - @test has_return_escape(result.state[Argument(3)], r) # x - end - @test_skip let result = code_escapes((Vector{String},String,Int,)) do xs, x, i - Base.arrayset(false, xs, x, i) - return xs - end - r = only(findall(isreturn, result.ir.stmts.stmt)) - @test has_return_escape(result.state[Argument(2)], r) # xs - @test !has_thrown_escape(result.state[Argument(2)]) # xs - @test has_return_escape(result.state[Argument(3)], r) # x - end - @test_skip let result = code_escapes((String,String,String,)) do s, t, u - xs = Vector{String}(undef, 3) - Base.arrayset(true, xs, s, 1) - Base.arrayset(true, xs, t, 2) - Base.arrayset(true, xs, u, 3) - return xs - end - i = only(findall(isarrayalloc, result.ir.stmts.stmt)) - r = only(findall(isreturn, result.ir.stmts.stmt)) - @test has_return_escape(result.state[SSAValue(i)], r) - for i in 2:result.state.nargs - @test has_return_escape(result.state[Argument(i)], r) - end - end - @test_skip let result = code_escapes((Vector{String},String,Bool,)) do xs, x, i - Base.arrayset(true, xs, x, i) # TypeError will happen here - return xs - end - t = only(findall(iscall((result.ir, Base.arrayset)), result.ir.stmts.stmt)) - @test has_thrown_escape(result.state[Argument(2)], t) # xs - @test has_thrown_escape(result.state[Argument(3)], t) # x - end - @test_skip let result = code_escapes((String,String,Int,)) do xs, x, i - Base.arrayset(true, xs, x, i) # TypeError will happen here - return xs - end - t = only(findall(iscall((result.ir, Base.arrayset)), result.ir.stmts.stmt)) - @test has_thrown_escape(result.state[Argument(2)], t) # xs::String - @test has_thrown_escape(result.state[Argument(3)], t) # x::String - end - @test_skip let result = code_escapes((AbstractVector{String},String,Int,)) do xs, x, i - Base.arrayset(true, xs, x, i) # TypeError may happen here - return xs - end - t = only(findall(iscall((result.ir, Base.arrayset)), result.ir.stmts.stmt)) - @test has_thrown_escape(result.state[Argument(2)], t) # xs - @test has_thrown_escape(result.state[Argument(3)], t) # x - end - @test_skip let result = code_escapes((Vector{String},AbstractString,Int,)) do xs, x, i - Base.arrayset(true, xs, x, i) # TypeError may happen here - return xs - end - t = only(findall(iscall((result.ir, Base.arrayset)), result.ir.stmts.stmt)) - @test has_thrown_escape(result.state[Argument(2)], t) # xs - @test has_thrown_escape(result.state[Argument(3)], t) # x - end - - # arrayref and arrayset - @test_skip let result = code_escapes() do - a = Vector{Vector{Any}}(undef, 1) - b = Any[] - a[1] = b - return a[1] - end - r = only(findall(isreturn, result.ir.stmts.stmt)) - ai = only(findall(result.ir.stmts.stmt) do @nospecialize x - isarrayalloc(x) && x.args[2] === Vector{Vector{Any}} - end) - bi = only(findall(result.ir.stmts.stmt) do @nospecialize x - isarrayalloc(x) && x.args[2] === Vector{Any} - end) - @test !has_return_escape(result.state[SSAValue(ai)], r) - @test has_return_escape(result.state[SSAValue(bi)], r) - end - @test_skip let result = code_escapes() do - a = Vector{Vector{Any}}(undef, 1) - b = Any[] - a[1] = b - return a - end - r = only(findall(isreturn, result.ir.stmts.stmt)) - ai = only(findall(result.ir.stmts.stmt) do @nospecialize x - isarrayalloc(x) && x.args[2] === Vector{Vector{Any}} - end) - bi = only(findall(result.ir.stmts.stmt) do @nospecialize x - isarrayalloc(x) && x.args[2] === Vector{Any} - end) - @test has_return_escape(result.state[SSAValue(ai)], r) - @test has_return_escape(result.state[SSAValue(bi)], r) - end - @test_skip let result = code_escapes((Vector{Any},String,Int,Int)) do xs, s, i, j - x = SafeRef(s) - xs[i] = x - xs[j] # potential error - end - i = only(findall(isnew, result.ir.stmts.stmt)) - t = only(findall(iscall((result.ir, Base.arrayref)), result.ir.stmts.stmt)) - @test has_thrown_escape(result.state[Argument(3)], t) # s - @test has_thrown_escape(result.state[SSAValue(i)], t) # x - end - - # arraysize - @test_skip let result = code_escapes((Vector{Any},)) do xs - Core.arraysize(xs, 1) - end - t = only(findall(iscall((result.ir, Core.arraysize)), result.ir.stmts.stmt)) - @test !has_thrown_escape(result.state[Argument(2)], t) - end - @test_skip let result = code_escapes((Vector{Any},Int,)) do xs, dim - Core.arraysize(xs, dim) - end - t = only(findall(iscall((result.ir, Core.arraysize)), result.ir.stmts.stmt)) - @test !has_thrown_escape(result.state[Argument(2)], t) - end - @test_skip let result = code_escapes((Any,)) do xs - Core.arraysize(xs, 1) - end - t = only(findall(iscall((result.ir, Core.arraysize)), result.ir.stmts.stmt)) - @test has_thrown_escape(result.state[Argument(2)], t) - end - - # arraylen - @test_skip let result = code_escapes((Vector{Any},)) do xs - Base.arraylen(xs) - end - t = only(findall(iscall((result.ir, Base.arraylen)), result.ir.stmts.stmt)) - @test !has_thrown_escape(result.state[Argument(2)], t) # xs - end - @test_skip let result = code_escapes((String,)) do xs - Base.arraylen(xs) - end - t = only(findall(iscall((result.ir, Base.arraylen)), result.ir.stmts.stmt)) - @test has_thrown_escape(result.state[Argument(2)], t) # xs - end - @test_skip let result = code_escapes((Vector{Any},)) do xs - Base.arraylen(xs, 1) - end - t = only(findall(iscall((result.ir, Base.arraylen)), result.ir.stmts.stmt)) - @test has_thrown_escape(result.state[Argument(2)], t) # xs - end - - # array resizing - # without BoundsErrors - @test_skip let result = code_escapes((Vector{Any},String)) do xs, x - @ccall jl_array_grow_beg(xs::Any, 2::UInt)::Cvoid - xs[1] = x - xs - end - t = only(findall(isarrayresize, result.ir.stmts.stmt)) - @test !has_thrown_escape(result.state[Argument(2)], t) # xs - @test !has_thrown_escape(result.state[Argument(3)], t) # x - end - @test_skip let result = code_escapes((Vector{Any},String)) do xs, x - @ccall jl_array_grow_end(xs::Any, 2::UInt)::Cvoid - xs[1] = x - xs - end - t = only(findall(isarrayresize, result.ir.stmts.stmt)) - @test !has_thrown_escape(result.state[Argument(2)], t) # xs - @test !has_thrown_escape(result.state[Argument(3)], t) # x - end - # with possible BoundsErrors - @test_skip let result = code_escapes((String,)) do x - xs = Any[1,2,3] - xs[3] = x - @ccall jl_array_del_beg(xs::Any, 2::UInt)::Cvoid # can potentially throw - xs - end - i = only(findall(isarrayalloc, result.ir.stmts.stmt)) - t = only(findall(isarrayresize, result.ir.stmts.stmt)) - @test has_thrown_escape(result.state[SSAValue(i)], t) # xs - @test has_thrown_escape(result.state[Argument(2)], t) # x - end - @test_skip let result = code_escapes((String,)) do x - xs = Any[1,2,3] - xs[1] = x - @ccall jl_array_del_end(xs::Any, 2::UInt)::Cvoid # can potentially throw - xs - end - i = only(findall(isarrayalloc, result.ir.stmts.stmt)) - t = only(findall(isarrayresize, result.ir.stmts.stmt)) - @test has_thrown_escape(result.state[SSAValue(i)], t) # xs - @test has_thrown_escape(result.state[Argument(2)], t) # x - end - @test_skip let result = code_escapes((String,)) do x - xs = Any[x] - @ccall jl_array_grow_at(xs::Any, 1::UInt, 2::UInt)::Cvoid # can potentially throw - end - i = only(findall(isarrayalloc, result.ir.stmts.stmt)) - t = only(findall(isarrayresize, result.ir.stmts.stmt)) - @test has_thrown_escape(result.state[SSAValue(i)], t) # xs - @test has_thrown_escape(result.state[Argument(2)], t) # x - end - @test_skip let result = code_escapes((String,)) do x - xs = Any[x] - @ccall jl_array_del_at(xs::Any, 1::UInt, 2::UInt)::Cvoid # can potentially throw - end - i = only(findall(isarrayalloc, result.ir.stmts.stmt)) - t = only(findall(isarrayresize, result.ir.stmts.stmt)) - @test has_thrown_escape(result.state[SSAValue(i)], t) # xs - @test has_thrown_escape(result.state[Argument(2)], t) # x - end - - # array copy - @test_skip let result = code_escapes((Vector{Any},)) do xs - return copy(xs) - end - i = only(findall(isarraycopy, result.ir.stmts.stmt)) - r = only(findall(isreturn, result.ir.stmts.stmt)) - @test has_return_escape(result.state[SSAValue(i)], r) - @test !has_return_escape(result.state[Argument(2)], r) - end - @test_skip let result = code_escapes((String,)) do s - xs = String[s] - xs′ = copy(xs) - return xs′[1] - end - i1 = only(findall(isarrayalloc, result.ir.stmts.stmt)) - i2 = only(findall(isarraycopy, result.ir.stmts.stmt)) - r = only(findall(isreturn, result.ir.stmts.stmt)) - @test !has_return_escape(result.state[SSAValue(i1)]) - @test !has_return_escape(result.state[SSAValue(i2)]) - @test has_return_escape(result.state[Argument(2)], r) # s - end - @test_skip let result = code_escapes((Vector{Any},)) do xs - xs′ = copy(xs) - return xs′[1] # may potentially throw BoundsError, should escape `xs` conservatively (i.e. escape its elements) - end - i = only(findall(isarraycopy, result.ir.stmts.stmt)) - ref = only(findall(iscall((result.ir, Base.arrayref)), result.ir.stmts.stmt)) - ret = only(findall(isreturn, result.ir.stmts.stmt)) - @test_broken !has_thrown_escape(result.state[SSAValue(i)], ref) - @test_broken !has_return_escape(result.state[SSAValue(i)], ret) - @test has_thrown_escape(result.state[Argument(2)], ref) - @test has_return_escape(result.state[Argument(2)], ret) - end - @test_skip let result = code_escapes((String,)) do s - xs = Vector{String}(undef, 1) - xs[1] = s - xs′ = copy(xs) - length(xs′) > 2 && throw(xs′) - return xs′ - end - i1 = only(findall(isarrayalloc, result.ir.stmts.stmt)) - i2 = only(findall(isarraycopy, result.ir.stmts.stmt)) - t = only(findall(iscall((result.ir, throw)), result.ir.stmts.stmt)) - r = only(findall(isreturn, result.ir.stmts.stmt)) - @test_broken !has_thrown_escape(result.state[SSAValue(i1)], t) - @test_broken !has_return_escape(result.state[SSAValue(i1)], r) - @test has_thrown_escape(result.state[SSAValue(i2)], t) - @test has_return_escape(result.state[SSAValue(i2)], r) - @test has_thrown_escape(result.state[Argument(2)], t) - @test has_return_escape(result.state[Argument(2)], r) - end - - # isassigned - let result = code_escapes((Vector{Any},Int)) do xs, i - return isassigned(xs, i) - end - r = only(findall(isreturn, result.ir.stmts.stmt)) - @test_broken !has_return_escape(result.state[Argument(2)], r) - @test_broken !has_thrown_escape(result.state[Argument(2)]) - end - - # indexing analysis - # ----------------- - - # safe case - @test_skip let result = code_escapes((String,String)) do s, t - a = Vector{Any}(undef, 2) - a[1] = s - a[2] = t - return a[1] - end - r = only(findall(isreturn, result.ir.stmts.stmt)) - i = only(findall(isarrayalloc, result.ir.stmts.stmt)) - @test !has_return_escape(result.state[SSAValue(i)], r) - @test is_load_forwardable(result.state[SSAValue(i)]) - @test has_return_escape(result.state[Argument(2)], r) # s - @test !has_return_escape(result.state[Argument(3)], r) # t - end - @test_skip let result = code_escapes((String,String)) do s, t - a = Matrix{Any}(undef, 1, 2) - a[1, 1] = s - a[1, 2] = t - return a[1, 1] - end - r = only(findall(isreturn, result.ir.stmts.stmt)) - i = only(findall(isarrayalloc, result.ir.stmts.stmt)) - @test !has_return_escape(result.state[SSAValue(i)], r) - @test is_load_forwardable(result.state[SSAValue(i)]) - @test has_return_escape(result.state[Argument(2)], r) # s - @test !has_return_escape(result.state[Argument(3)], r) # t - end - @test_skip let result = code_escapes((Bool,String,String,String)) do c, s, t, u - a = Vector{Any}(undef, 2) - if c - a[1] = s - a[2] = u - else - a[1] = t - a[2] = u - end - return a[1] - end - r = only(findall(isreturn, result.ir.stmts.stmt)) - i = only(findall(isarrayalloc, result.ir.stmts.stmt)) - @test is_load_forwardable(result.state[SSAValue(i)]) - @test !has_return_escape(result.state[SSAValue(i)], r) - @test has_return_escape(result.state[Argument(3)], r) # s - @test has_return_escape(result.state[Argument(4)], r) # t - @test !has_return_escape(result.state[Argument(5)], r) # u - end - @test_skip let result = code_escapes((Bool,String,String,String)) do c, s, t, u - a = Any[nothing, nothing] # TODO how to deal with loop indexing? - if c - a[1] = s - a[2] = u - else - a[1] = t - a[2] = u - end - return a[1] - end - r = only(findall(isreturn, result.ir.stmts.stmt)) - i = only(findall(isarrayalloc, result.ir.stmts.stmt)) - @test !has_return_escape(result.state[SSAValue(i)], r) - @test_broken is_load_forwardable(result.state[SSAValue(i)]) - @test has_return_escape(result.state[Argument(3)], r) # s - @test has_return_escape(result.state[Argument(4)], r) # t - @test_broken !has_return_escape(result.state[Argument(5)], r) # u - end - @test_skip let result = code_escapes((String,)) do s - a = Vector{Vector{Any}}(undef, 1) - b = Any[s] - a[1] = b - return a[1][1] - end - r = only(findall(isreturn, result.ir.stmts.stmt)) - is = findall(isarrayalloc, result.ir.stmts.stmt) - @assert length(is) == 2 - ia, ib = is - @test !has_return_escape(result.state[SSAValue(ia)], r) - @test is_load_forwardable(result.state[SSAValue(ia)]) - @test !has_return_escape(result.state[SSAValue(ib)], r) - @test_broken is_load_forwardable(result.state[SSAValue(ib)]) - @test has_return_escape(result.state[Argument(2)], r) # s - end - @test_skip let result = code_escapes((Bool,String,String,Regex,Regex,)) do c, s1, s2, t1, t2 - if c - a = Vector{String}(undef, 2) - a[1] = s1 - a[2] = s2 - else - a = Vector{Regex}(undef, 2) - a[1] = t1 - a[2] = t2 - end - return a[1] - end - r = only(findall(isreturn, result.ir.stmts.stmt)) - for i in findall(isarrayalloc, result.ir.stmts.stmt) - @test !has_return_escape(result.state[SSAValue(i)], r) - @test is_load_forwardable(result.state[SSAValue(i)]) - end - @test has_return_escape(result.state[Argument(3)], r) # s1 - @test !has_return_escape(result.state[Argument(4)], r) # s2 - @test has_return_escape(result.state[Argument(5)], r) # t1 - @test !has_return_escape(result.state[Argument(6)], r) # t2 - end - @test_skip let result = code_escapes((String,String,Int)) do s, t, i - a = Any[s] - push!(a, t) - return a[2] - end - r = only(findall(isreturn, result.ir.stmts.stmt)) - i = only(findall(isarrayalloc, result.ir.stmts.stmt)) - @test !has_return_escape(result.state[SSAValue(i)], r) - @test_broken is_load_forwardable(result.state[SSAValue(i)]) - @test_broken !has_return_escape(result.state[Argument(2)], r) # s - @test has_return_escape(result.state[Argument(3)], r) # t - end - # unsafe cases - @test_skip let result = code_escapes((String,String,Int)) do s, t, i - a = Vector{Any}(undef, 2) - a[1] = s - a[2] = t - return a[i] - end - r = only(findall(isreturn, result.ir.stmts.stmt)) - i = only(findall(isarrayalloc, result.ir.stmts.stmt)) - @test !has_return_escape(result.state[SSAValue(i)], r) - @test !is_load_forwardable(result.state[SSAValue(i)]) - @test has_return_escape(result.state[Argument(2)], r) # s - @test has_return_escape(result.state[Argument(3)], r) # t - end - @test_skip let result = code_escapes((String,String,Int)) do s, t, i - a = Vector{Any}(undef, 2) - a[1] = s - a[i] = t - return a[1] - end - r = only(findall(isreturn, result.ir.stmts.stmt)) - i = only(findall(isarrayalloc, result.ir.stmts.stmt)) - @test !has_return_escape(result.state[SSAValue(i)], r) - @test !is_load_forwardable(result.state[SSAValue(i)]) - @test has_return_escape(result.state[Argument(2)], r) # s - @test has_return_escape(result.state[Argument(3)], r) # t - end - @test_skip let result = code_escapes((String,String,Int,Int,Int)) do s, t, i, j, k - a = Vector{Any}(undef, 2) - a[3] = s # BoundsError - a[1] = t - return a[1] - end - r = only(findall(isreturn, result.ir.stmts.stmt)) - i = only(findall(isarrayalloc, result.ir.stmts.stmt)) - @test !has_return_escape(result.state[SSAValue(i)], r) - @test !is_load_forwardable(result.state[SSAValue(i)]) - end - @test_skip let result = @eval Module() begin - @noinline some_resize!(a) = pushfirst!(a, nothing) - $code_escapes((String,String,Int)) do s, t, i - a = Vector{Any}(undef, 2) - a[1] = s - some_resize!(a) - return a[2] - end - end - r = only(findall(isreturn, result.ir.stmts.stmt)) - i = only(findall(isarrayalloc, result.ir.stmts.stmt)) - @test_broken !has_return_escape(result.state[SSAValue(i)], r) - @test !is_load_forwardable(result.state[SSAValue(i)]) - end - - # circular reference - @test_skip let result = code_escapes() do - xs = Vector{Any}(undef, 1) - xs[1] = xs - return xs[1] - end - i = only(findall(isarrayalloc, result.ir.stmts.stmt)) - r = only(findall(isreturn, result.ir.stmts.stmt)) - @test has_return_escape(result.state[SSAValue(i)], r) - end - @test_skip let result = @eval Module() begin - const Ax = Vector{Any}(undef, 1) - Ax[1] = Ax - $code_escapes() do - xs = Ax[1]::Vector{Any} - return xs[1] - end - end - r = only(findall(isreturn, result.ir.stmts.stmt)) - for i in findall(iscall((result.ir, Core.arrayref)), result.ir.stmts.stmt) - @test has_return_escape(result.state[SSAValue(i)], r) - end - end - let result = @eval Module() begin - @noinline function genxs() - xs = Vector{Any}(undef, 1) - xs[1] = xs - return xs - end - $code_escapes() do - xs = genxs() - return xs[1] - end - end - i = only(findall(isinvoke(:genxs), result.ir.stmts.stmt)) - r = only(findall(isreturn, result.ir.stmts.stmt)) - @test has_return_escape(result.state[SSAValue(i)], r) - end -end - -# demonstrate array primitive support with a realistic end to end example -@test_skip let result = code_escapes((Int,String,)) do n,s - xs = String[] - for i in 1:n - push!(xs, s) - end - xs - end - i = only(findall(isarrayalloc, result.ir.stmts.stmt)) - r = only(findall(isreturn, result.ir.stmts.stmt)) - @test has_return_escape(result.state[SSAValue(i)], r) - @test !has_thrown_escape(result.state[SSAValue(i)]) - @test has_return_escape(result.state[Argument(3)], r) # s - @test !has_thrown_escape(result.state[Argument(3)]) # s -end -@test_skip let result = code_escapes((Int,String,)) do n,s - xs = String[] - for i in 1:n - pushfirst!(xs, s) - end - xs - end - i = only(findall(isarrayalloc, result.ir.stmts.stmt)) - r = only(findall(isreturn, result.ir.stmts.stmt)) - @test has_return_escape(result.state[SSAValue(i)], r) # xs - @test !has_thrown_escape(result.state[SSAValue(i)]) # xs - @test has_return_escape(result.state[Argument(3)], r) # s - @test !has_thrown_escape(result.state[Argument(3)]) # s -end -@test_skip let result = code_escapes((String,String,String)) do s, t, u - xs = String[] - resize!(xs, 3) - xs[1] = s - xs[1] = t - xs[1] = u - xs - end - i = only(findall(isarrayalloc, result.ir.stmts.stmt)) - r = only(findall(isreturn, result.ir.stmts.stmt)) - @test has_return_escape(result.state[SSAValue(i)], r) - @test has_thrown_escape(result.state[SSAValue(i)]) # xs - @test has_return_escape(result.state[Argument(2)], r) # s - @test has_return_escape(result.state[Argument(3)], r) # t - @test has_return_escape(result.state[Argument(4)], r) # u -end - # demonstrate a simple type level analysis can sometimes improve the analysis accuracy # by compensating the lack of yet unimplemented analyses @testset "special-casing bitstype" begin @@ -2111,25 +1517,6 @@ end end end -# # TODO implement a finalizer elision pass -# mutable struct WithFinalizer -# v -# function WithFinalizer(v) -# x = new(v) -# f(t) = @async println("Finalizing $t.") -# return finalizer(x, x) -# end -# end -# make_m(v = 10) = MyMutable(v) -# function simple(cond) -# m = make_m() -# if cond -# # println(m.v) -# return nothing # <= insert `finalize` call here -# end -# return m -# end - # interprocedural analysis # ======================== From 2ed1a411e0a080f3107e75bb65105a15a0533a90 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Tue, 17 Dec 2024 09:57:16 -0500 Subject: [PATCH 076/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?Distributed=20stdlib=20from=206c7cdb5=20to=20c613685=20(#56825)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: Distributed URL: https://github.com/JuliaLang/Distributed.jl Stdlib branch: master Julia branch: master Old commit: 6c7cdb5 New commit: c613685 Julia version: 1.12.0-DEV Distributed version: 1.11.0(Does not match) Bump invoked by: @DilumAluthge Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaLang/Distributed.jl/compare/6c7cdb5860fa5cb9ca191ce9c52a3d25a9ab3781...c6136853451677f1957bec20ecce13419cde3a12 ``` $ git log --oneline 6c7cdb5..c613685 c613685 Merge pull request #116 from JuliaLang/ci-caching 20e2ce7 Use julia-actions/cache in CI 9c5d73a Merge pull request #112 from JuliaLang/dependabot/github_actions/codecov/codecov-action-5 ed12496 Merge pull request #107 from JamesWrigley/remotechannel-empty 010828a Update .github/workflows/ci.yml 11451a8 Bump codecov/codecov-action from 4 to 5 8b5983b Merge branch 'master' into remotechannel-empty 729ba6a Fix docstring of `@everywhere` (#110) af89e6c Adding better docs to exeflags kwarg (#108) 8537424 Implement Base.isempty(::RemoteChannel) 6a0383b Add a wait(::[Abstract]WorkerPool) (#106) 1cd2677 Bump codecov/codecov-action from 1 to 4 (#96) cde4078 Bump actions/cache from 1 to 4 (#98) 6c8245a Bump julia-actions/setup-julia from 1 to 2 (#97) 1ffaac8 Bump actions/checkout from 2 to 4 (#99) 8e3f849 Fix RemoteChannel iterator interface (#100) f4aaf1b Fix markdown errors in README.md (#95) 2017da9 Merge pull request #103 from JuliaLang/sf/sigquit_instead 07389dd Use `SIGQUIT` instead of `SIGTERM` ``` Co-authored-by: Dilum Aluthge --- .../md5 | 1 - .../sha512 | 1 - .../md5 | 1 + .../sha512 | 1 + stdlib/Distributed.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/Distributed-6c7cdb5860fa5cb9ca191ce9c52a3d25a9ab3781.tar.gz/md5 delete mode 100644 deps/checksums/Distributed-6c7cdb5860fa5cb9ca191ce9c52a3d25a9ab3781.tar.gz/sha512 create mode 100644 deps/checksums/Distributed-c6136853451677f1957bec20ecce13419cde3a12.tar.gz/md5 create mode 100644 deps/checksums/Distributed-c6136853451677f1957bec20ecce13419cde3a12.tar.gz/sha512 diff --git a/deps/checksums/Distributed-6c7cdb5860fa5cb9ca191ce9c52a3d25a9ab3781.tar.gz/md5 b/deps/checksums/Distributed-6c7cdb5860fa5cb9ca191ce9c52a3d25a9ab3781.tar.gz/md5 deleted file mode 100644 index 9904464c82b3b..0000000000000 --- a/deps/checksums/Distributed-6c7cdb5860fa5cb9ca191ce9c52a3d25a9ab3781.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -390521058a478a131ca49d349c9b9383 diff --git a/deps/checksums/Distributed-6c7cdb5860fa5cb9ca191ce9c52a3d25a9ab3781.tar.gz/sha512 b/deps/checksums/Distributed-6c7cdb5860fa5cb9ca191ce9c52a3d25a9ab3781.tar.gz/sha512 deleted file mode 100644 index a7fbe055c2251..0000000000000 --- a/deps/checksums/Distributed-6c7cdb5860fa5cb9ca191ce9c52a3d25a9ab3781.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -7f0f414d94739a25b7d713c46887e26cd349329828d42297f44928204b36d15ba9163ad6f670aba72ed9229557bb0f35ab4686429975d1f349fe12b1ba2b189f diff --git a/deps/checksums/Distributed-c6136853451677f1957bec20ecce13419cde3a12.tar.gz/md5 b/deps/checksums/Distributed-c6136853451677f1957bec20ecce13419cde3a12.tar.gz/md5 new file mode 100644 index 0000000000000..e1c0f9e87b7c7 --- /dev/null +++ b/deps/checksums/Distributed-c6136853451677f1957bec20ecce13419cde3a12.tar.gz/md5 @@ -0,0 +1 @@ +98b8b8bc0ea4bf24c4b2986a5b7ae3e9 diff --git a/deps/checksums/Distributed-c6136853451677f1957bec20ecce13419cde3a12.tar.gz/sha512 b/deps/checksums/Distributed-c6136853451677f1957bec20ecce13419cde3a12.tar.gz/sha512 new file mode 100644 index 0000000000000..ed816ebc21e97 --- /dev/null +++ b/deps/checksums/Distributed-c6136853451677f1957bec20ecce13419cde3a12.tar.gz/sha512 @@ -0,0 +1 @@ +4043933825bf716f2733f8e90632de34a95a437f3b31cda92edd510ffee208f8e374ec3c5922c8142342ae21b4ec4cbd1ecd4036b9057056a12c86169632ac7b diff --git a/stdlib/Distributed.version b/stdlib/Distributed.version index 02eac7eadf0ad..4a7ab49defed2 100644 --- a/stdlib/Distributed.version +++ b/stdlib/Distributed.version @@ -1,4 +1,4 @@ DISTRIBUTED_BRANCH = master -DISTRIBUTED_SHA1 = 6c7cdb5860fa5cb9ca191ce9c52a3d25a9ab3781 +DISTRIBUTED_SHA1 = c6136853451677f1957bec20ecce13419cde3a12 DISTRIBUTED_GIT_URL := https://github.com/JuliaLang/Distributed.jl DISTRIBUTED_TAR_URL = https://api.github.com/repos/JuliaLang/Distributed.jl/tarball/$1 From 35729d9fc588d14db92596cbc78ae2818e441661 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Wed, 18 Dec 2024 00:49:21 +0900 Subject: [PATCH 077/342] inference: handle cases where `:the_exception` is used independently (#56836) `Expr(:the_exception)` is handled by the interpreter in all cases, however, inference assumes it is only used within frames containing `try/catch`. This commit corrects that assumption. --- Compiler/src/abstractinterpretation.jl | 12 ++++++++++-- Compiler/test/inference.jl | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index 2efd8a2b7264f..0d0d4a2f80e9e 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -3240,8 +3240,16 @@ function abstract_eval_throw_undef_if_not(interp::AbstractInterpreter, e::Expr, end function abstract_eval_the_exception(::AbstractInterpreter, sv::InferenceState) - (;handlers, handler_at) = sv.handler_info::HandlerInfo - return the_exception_info(handlers[handler_at[sv.currpc][2]].exct) + (;handler_info) = sv + if handler_info === nothing + return the_exception_info(Any) + end + (;handlers, handler_at) = handler_info + handler_id = handler_at[sv.currpc][2] + if handler_id === 0 + return the_exception_info(Any) + end + return the_exception_info(handlers[handler_id].exct) end abstract_eval_the_exception(::AbstractInterpreter, ::IRInterpretationState) = the_exception_info(Any) the_exception_info(@nospecialize t) = RTEffects(t, Union{}, Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE)) diff --git a/Compiler/test/inference.jl b/Compiler/test/inference.jl index e272ff6de8d99..132e1e2c14bad 100644 --- a/Compiler/test/inference.jl +++ b/Compiler/test/inference.jl @@ -6125,3 +6125,17 @@ function func_swapglobal!_must_throw(x) end @test Base.infer_return_type(func_swapglobal!_must_throw, (Int,); interp=SwapGlobalInterp()) === Union{} @test !Compiler.is_effect_free(Base.infer_effects(func_swapglobal!_must_throw, (Int,); interp=SwapGlobalInterp()) ) + +@eval get_exception() = $(Expr(:the_exception)) +@test Base.infer_return_type() do + get_exception() +end <: Any +@test @eval Base.infer_return_type((Float64,)) do x + out = $(Expr(:the_exception)) + try + out = sin(x) + catch + out = $(Expr(:the_exception)) + end + return out +end == Union{Float64,DomainError} From 37740148e1120ec833d6648dde245c0c5b79d76e Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Tue, 17 Dec 2024 20:00:26 +0000 Subject: [PATCH 078/342] precompileplkgs: release parallel limiter when waiting for another process (#56844) --- base/precompilation.jl | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/base/precompilation.jl b/base/precompilation.jl index 6eebded8b2f93..f61169c6ca16d 100644 --- a/base/precompilation.jl +++ b/base/precompilation.jl @@ -944,7 +944,7 @@ function _precompilepkgs(pkgs::Vector{String}, try # allows processes to wait if another process is precompiling a given package to # a functionally identical package cache (except for preferences, which may differ) - t = @elapsed ret = precompile_pkgs_maybe_cachefile_lock(io, print_lock, fancyprint, pkg_config, pkgspidlocked, hascolor) do + t = @elapsed ret = precompile_pkgs_maybe_cachefile_lock(io, print_lock, fancyprint, pkg_config, pkgspidlocked, hascolor, parallel_limiter) do Base.with_logger(Base.NullLogger()) do # The false here means we ignore loaded modules, so precompile for a fresh session keep_loaded_modules = false @@ -1130,7 +1130,7 @@ function _color_string(cstr::String, col::Union{Int64, Symbol}, hascolor) end # Can be merged with `maybe_cachefile_lock` in loading? -function precompile_pkgs_maybe_cachefile_lock(f, io::IO, print_lock::ReentrantLock, fancyprint::Bool, pkg_config, pkgspidlocked, hascolor) +function precompile_pkgs_maybe_cachefile_lock(f, io::IO, print_lock::ReentrantLock, fancyprint::Bool, pkg_config, pkgspidlocked, hascolor, parallel_limiter::Base.Semaphore) if !(isdefined(Base, :mkpidlock_hook) && isdefined(Base, :trymkpidlock_hook) && Base.isdefined(Base, :parse_pidfile_hook)) return f() end @@ -1153,17 +1153,22 @@ function precompile_pkgs_maybe_cachefile_lock(f, io::IO, print_lock::ReentrantLo !fancyprint && lock(print_lock) do println(io, " ", pkg.name, _color_string(" Being precompiled by $(pkgspidlocked[pkg_config])", Base.info_color(), hascolor)) end - # wait until the lock is available - @invokelatest Base.mkpidlock_hook(() -> begin - # double-check in case the other process crashed or the lock expired - if Base.isprecompiled(pkg; ignore_loaded=true, flags=cacheflags) # don't use caches for this as the env state will have changed - return nothing # returning nothing indicates a process waited for another - else - delete!(pkgspidlocked, pkg_config) - return f() # precompile - end - end, - pidfile; stale_age) + Base.release(parallel_limiter) # release so other work can be done while waiting + try + # wait until the lock is available + @invokelatest Base.mkpidlock_hook(() -> begin + # double-check in case the other process crashed or the lock expired + if Base.isprecompiled(pkg; ignore_loaded=true, flags=cacheflags) # don't use caches for this as the env state will have changed + return nothing # returning nothing indicates a process waited for another + else + delete!(pkgspidlocked, pkg_config) + Base.acquire(f, parallel_limiter) # precompile + end + end, + pidfile; stale_age) + finally + Base.acquire(parallel_limiter) # re-acquire so the outer release is balanced + end end return cachefile end From bbaa6059fd4388f5d29bf19c5d7d76745cccc95f Mon Sep 17 00:00:00 2001 From: Katharine Hyatt Date: Wed, 18 Dec 2024 05:57:09 -0500 Subject: [PATCH 079/342] Tests for two AbstractString methods (#56247) Co-authored-by: Chengyu Han --- test/strings/basic.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/strings/basic.jl b/test/strings/basic.jl index bc4e5ae66419a..3fc611a660975 100644 --- a/test/strings/basic.jl +++ b/test/strings/basic.jl @@ -430,6 +430,8 @@ end @test Symbol(gstr) === Symbol("12") + @test eltype(gstr) == Char + @test firstindex(gstr) == 1 @test sizeof(gstr) == 2 @test ncodeunits(gstr) == 2 @test length(gstr) == 2 From e5b946c6b4b69040ae3adf638d9c3a057f8b98d8 Mon Sep 17 00:00:00 2001 From: Katharine Hyatt Date: Wed, 18 Dec 2024 05:58:10 -0500 Subject: [PATCH 080/342] Tests for annotated string/char c-tors (#56513) Co-authored-by: Chengyu Han --- test/strings/annotated.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/strings/annotated.jl b/test/strings/annotated.jl index a39d4b8d0eacb..dbb81cb48acbc 100644 --- a/test/strings/annotated.jl +++ b/test/strings/annotated.jl @@ -71,6 +71,9 @@ "AnnotatedString{String}(\"some string\", [(1:4, :thing, 0x01), (6:11, :other, 0x02), (1:11, :all, 0x03)])" @test eval(Meta.parse(repr(str))) == str @test sprint(show, MIME("text/plain"), str) == "\"some string\"" + + a = Base.AnnotatedString("hello", [(1:5, :label, 1)]) + @test first(a) == Base.AnnotatedChar('h', [(:label, 1)]) end @testset "AnnotatedChar" begin From b1007ce226501738f083486a03550d34a8cce140 Mon Sep 17 00:00:00 2001 From: Aaron Matthis Date: Wed, 18 Dec 2024 11:59:32 +0100 Subject: [PATCH 081/342] docs: fix example for `sort` and add new doctest (#56843) --- base/sort.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/base/sort.jl b/base/sort.jl index f9d74f626fe58..e1d46a8ba20ae 100644 --- a/base/sort.jl +++ b/base/sort.jl @@ -1700,13 +1700,16 @@ julia> v = [(1, "c"), (3, "a"), (2, "b")]; sort!(v, by = x -> x[2]); v (2, "b") (1, "c") -julia> sort(0:3, by=x->x-2, order=Base.Order.By(abs)) # same as sort(0:3, by=abs(x->x-2)) +julia> sort(0:3, by=x->x-2, order=Base.Order.By(abs)) 4-element Vector{Int64}: 2 1 3 0 +julia> sort(0:3, by=x->x-2, order=Base.Order.By(abs)) == sort(0:3, by=x->abs(x-2)) +true + julia> sort([2, NaN, 1, NaN, 3]) # correct sort with default lt=isless 5-element Vector{Float64}: 1.0 From 31ace712ed4b0eb54b22c1c7a3473890a4179aae Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 18 Dec 2024 06:36:51 -0500 Subject: [PATCH 082/342] jitlayers: re-delete deregisterEHFrames impl (#56854) Fixes https://github.com/maleadt/LLVM.jl/issues/496 --- src/jitlayers.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 25494ba57d257..a1b01af716bb4 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -1293,9 +1293,7 @@ class ForwardingMemoryManager : public RuntimeDyld::MemoryManager { size_t Size) override { return MemMgr->registerEHFrames(Addr, LoadAddr, Size); } - virtual void deregisterEHFrames() override { - return MemMgr->deregisterEHFrames(); - } + virtual void deregisterEHFrames() override { /* not actually supported or allowed with this */ } virtual bool finalizeMemory(std::string *ErrMsg = nullptr) override { bool b = false; if (MemMgr.use_count() == 2) From fc9e7c4a6a36d7d54ae7dd8b89ac14a8334a59c4 Mon Sep 17 00:00:00 2001 From: Priynsh <119518987+Priynsh@users.noreply.github.com> Date: Wed, 18 Dec 2024 20:04:45 +0530 Subject: [PATCH 083/342] docs: fix edge case in rational number conversion `float(a//b)` (#56772) Fixes #56726 added the changes that were suggested. fixing the mistake. --------- Co-authored-by: Max Horn Co-authored-by: Chengyu Han --- .../manual/complex-and-rational-numbers.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/doc/src/manual/complex-and-rational-numbers.md b/doc/src/manual/complex-and-rational-numbers.md index 9cab2ed1e4f24..d1d6ffeca245f 100644 --- a/doc/src/manual/complex-and-rational-numbers.md +++ b/doc/src/manual/complex-and-rational-numbers.md @@ -254,13 +254,30 @@ julia> float(3//4) ``` Conversion from rational to floating-point respects the following identity for any integral values -of `a` and `b`, with the exception of the two cases `b == 0` and `a == 0 && b < 0`: +of `a` and `b`, except when `a==0 && b <= 0`: ```jldoctest julia> a = 1; b = 2; julia> isequal(float(a//b), a/b) true + +julia> a, b = 0, 0 +(0, 0) + +julia> float(a//b) +ERROR: ArgumentError: invalid rational: zero(Int64)//zero(Int64) +Stacktrace: +[...] + +julia> a/b +NaN + +julia> a, b = 0, -1 +(0, -1) + +julia> float(a//b), a/b +(0.0, -0.0) ``` Constructing infinite rational values is acceptable: From 522624c35146f4a1ac05fb5d9234324dc0ff15a2 Mon Sep 17 00:00:00 2001 From: Arno Strouwen Date: Wed, 18 Dec 2024 15:39:08 +0100 Subject: [PATCH 084/342] docs: fix scope type of a `struct` to hard (#56755) Is struct not a hard scope? ```jl julia> b = 1 struct Tester tester Tester(tester) = new(tester) b = 2 Tester() = new(b) end b 1 ``` --- doc/src/manual/variables-and-scoping.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/src/manual/variables-and-scoping.md b/doc/src/manual/variables-and-scoping.md index 64a12ea88c7dd..99f7ba088311d 100644 --- a/doc/src/manual/variables-and-scoping.md +++ b/doc/src/manual/variables-and-scoping.md @@ -64,7 +64,7 @@ The constructs introducing scope blocks are: | Construct | Scope Type Introduced | Scope Types Able to Contain Construct | |:----------|:----------------------|:--------------------------------------| | [`module`](@ref), [`baremodule`](@ref) | global | global | -| [`struct`](@ref) | local (soft) | global | +| [`struct`](@ref) | local (hard) | global | | [`macro`](@ref) | local (hard) | global | | [`for`](@ref), [`while`](@ref), [`try`](@ref try) | local (soft) | global, local | | [`function`](@ref), [`do`](@ref), [`let`](@ref), [comprehensions](@ref man-comprehensions), [generators](@ref man-generators) | local (hard) | global, local | @@ -169,10 +169,10 @@ that location: 1. **Existing local:** If `x` is *already a local variable*, then the existing local `x` is assigned; 2. **Hard scope:** If `x` is *not already a local variable* and assignment occurs inside of any - hard scope construct (i.e. within a `let` block, function or macro body, comprehension, or + hard scope construct (i.e. within a `let` block, function, struct or macro body, comprehension, or generator), a new local named `x` is created in the scope of the assignment; 3. **Soft scope:** If `x` is *not already a local variable* and all of the scope constructs - containing the assignment are soft scopes (loops, `try`/`catch` blocks, or `struct` blocks), the + containing the assignment are soft scopes (loops, `try`/`catch` blocks), the behavior depends on whether the global variable `x` is defined: * if global `x` is *undefined*, a new local named `x` is created in the scope of the assignment; From 796d823b4fbb3ec94c09f7022f9b614fc846dced Mon Sep 17 00:00:00 2001 From: cossio Date: Wed, 18 Dec 2024 15:40:34 +0100 Subject: [PATCH 085/342] dict docs: document that ordering of keys/values/pairs match iterate (#56842) Fix #56841. Currently the documentation states that keys(dict) and values(dict) iterate in the same order. But it is not stated whether this is the same order as that used by pairs(dict), or when looping, for (k,v) in dict. This PR makes this guarantee explicit. --- base/abstractdict.jl | 12 ++++++++---- test/dict.jl | 7 +++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/base/abstractdict.jl b/base/abstractdict.jl index 85a726b4cdbf4..3be930151d4d4 100644 --- a/base/abstractdict.jl +++ b/base/abstractdict.jl @@ -88,8 +88,8 @@ Return an iterator over all keys in a dictionary. When the keys are stored internally in a hash table, as is the case for `Dict`, the order in which they are returned may vary. -But `keys(a)` and `values(a)` both iterate `a` and -return the elements in the same order. +But `keys(a)`, `values(a)` and `pairs(a)` all iterate `a` +and return the elements in the same order. # Examples ```jldoctest @@ -114,8 +114,8 @@ Return an iterator over all values in a collection. When the values are stored internally in a hash table, as is the case for `Dict`, the order in which they are returned may vary. -But `keys(a)` and `values(a)` both iterate `a` and -return the elements in the same order. +But `keys(a)`, `values(a)` and `pairs(a)` all iterate `a` +and return the elements in the same order. # Examples ```jldoctest @@ -138,6 +138,10 @@ values(a::AbstractDict) = ValueIterator(a) Return an iterator over `key => value` pairs for any collection that maps a set of keys to a set of values. This includes arrays, where the keys are the array indices. +When the entries are stored internally in a hash table, +as is the case for `Dict`, the order in which they are returned may vary. +But `keys(a)`, `values(a)` and `pairs(a)` all iterate `a` +and return the elements in the same order. # Examples ```jldoctest diff --git a/test/dict.jl b/test/dict.jl index 909afb3607907..83d35ae18bb85 100644 --- a/test/dict.jl +++ b/test/dict.jl @@ -787,6 +787,13 @@ end [v for (k, v) in d] == [d[x[1]] for (i, x) in enumerate(d)] end +@testset "consistency of dict iteration order (issue #56841)" begin + dict = Dict(randn() => randn() for _ = 1:100) + @test all(zip(dict, keys(dict), values(dict), pairs(dict))) do (d, k, v, p) + d == p && first(d) == first(p) == k && last(d) == last(p) == v + end +end + @testset "generators, similar" begin d = Dict(:a=>"a") # TODO: restore when 0.7 deprecation is removed From 65de0142f50c95ec75eb854ebfa5eaff2c8179d3 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 18 Dec 2024 13:09:33 -0500 Subject: [PATCH 086/342] fix abstract_eval_cfunction mistakes (#56856) Noticed in code reading, that 35e4a1f9689f4b98f301884e0683e4f07db7514b simplified this incorrectly resulting in all arguments being assigned to the function type, and then 7f8635f11cae5f3f592afcc7b55c8e0e23589c3d further broke the return type expected for the failure case. Co-authored-by: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> --- Compiler/src/abstractinterpretation.jl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index 0d0d4a2f80e9e..4ab09ca3c88cf 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -2894,20 +2894,21 @@ end function abstract_eval_cfunction(interp::AbstractInterpreter, e::Expr, sstate::StatementState, sv::AbsIntState) f = abstract_eval_value(interp, e.args[2], sstate, sv) - # rt = sp_type_rewrap(e.args[3], sv.linfo, true) + # rt = sp_type_rewrap(e.args[3], sv.linfo, true) # verify that the result type make sense? + # rt === Bottom && return RTEffects(Union{}, Any, EFFECTS_UNKNOWN) atv = e.args[4]::SimpleVector at = Vector{Any}(undef, length(atv) + 1) at[1] = f for i = 1:length(atv) - at[i + 1] = sp_type_rewrap(at[i], frame_instance(sv), false) - at[i + 1] === Bottom && return + atᵢ = at[i + 1] = sp_type_rewrap(atv[i], frame_instance(sv), false) + atᵢ === Bottom && return RTEffects(Union{}, Any, EFFECTS_UNKNOWN) end # this may be the wrong world for the call, # but some of the result is likely to be valid anyways # and that may help generate better codegen abstract_call(interp, ArgInfo(nothing, at), StmtInfo(false, false), sv)::Future rt = e.args[1] - isa(rt, Type) || (rt = Any) + isconcretetype(rt) || (rt = Any) return RTEffects(rt, Any, EFFECTS_UNKNOWN) end From 03017db3abd8ebf7424802fd9a4ad776bd761b24 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Thu, 19 Dec 2024 05:14:14 +0900 Subject: [PATCH 087/342] inference: use `ssa_def_slot` for `typeassert` refinement (#56859) Allows type refinement in the following kind of case: ```julia julia> @test Base.infer_return_type((Vector{Any},)) do args codeinst = first(args) if codeinst isa Core.MethodInstance mi = codeinst else codeinst::Core.CodeInstance mi = codeinst.def end return mi end == Core.MethodInstance Test Passed ``` --- Compiler/src/abstractinterpretation.jl | 2 +- Compiler/test/inference.jl | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index 4ab09ca3c88cf..59d382d8e4a34 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -2656,7 +2656,7 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f), if sv isa InferenceState && f === typeassert # perform very limited back-propagation of invariants after this type assertion if rt !== Bottom && isa(fargs, Vector{Any}) - farg2 = fargs[2] + farg2 = ssa_def_slot(fargs[2], sv) if farg2 isa SlotNumber refinements = SlotRefinement(farg2, rt) end diff --git a/Compiler/test/inference.jl b/Compiler/test/inference.jl index 132e1e2c14bad..7cd6989bd2423 100644 --- a/Compiler/test/inference.jl +++ b/Compiler/test/inference.jl @@ -4103,6 +4103,17 @@ end == [Union{Some{Float64}, Some{Int}, Some{UInt8}}] end return a end == Union{Int32,Int64} + + @test Base.infer_return_type((Vector{Any},)) do args + codeinst = first(args) + if codeinst isa Core.MethodInstance + mi = codeinst + else + codeinst::Core.CodeInstance + mi = codeinst.def + end + return mi + end == Core.MethodInstance end callsig_backprop_basic(::Int) = nothing From 5d72906c5e5ab871c912d0423a71651ec6266f07 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Thu, 19 Dec 2024 12:51:25 +0900 Subject: [PATCH 088/342] EA: use embedded `CodeInstance` directly for escape cache lookup (#56860) --- Compiler/src/optimize.jl | 8 ++- Compiler/src/ssair/EscapeAnalysis.jl | 10 +-- Compiler/test/EAUtils.jl | 97 +++++++++++++--------------- Compiler/test/EscapeAnalysis.jl | 12 +++- 4 files changed, 66 insertions(+), 61 deletions(-) diff --git a/Compiler/src/optimize.jl b/Compiler/src/optimize.jl index 1c02bd67b5bd4..bc3fc4f9705c4 100644 --- a/Compiler/src/optimize.jl +++ b/Compiler/src/optimize.jl @@ -647,9 +647,11 @@ struct GetNativeEscapeCache{CodeCache} GetNativeEscapeCache(code_cache::CodeCache) where CodeCache = new{CodeCache}(code_cache) end GetNativeEscapeCache(interp::AbstractInterpreter) = GetNativeEscapeCache(code_cache(interp)) -function ((; code_cache)::GetNativeEscapeCache)(mi::MethodInstance) - codeinst = get(code_cache, mi, nothing) - codeinst isa CodeInstance || return false +function ((; code_cache)::GetNativeEscapeCache)(codeinst::Union{CodeInstance,MethodInstance}) + if codeinst isa MethodInstance + codeinst = get(code_cache, codeinst, nothing) + codeinst isa CodeInstance || return false + end argescapes = traverse_analysis_results(codeinst) do @nospecialize result return result isa EscapeAnalysis.ArgEscapeCache ? result : nothing end diff --git a/Compiler/src/ssair/EscapeAnalysis.jl b/Compiler/src/ssair/EscapeAnalysis.jl index 68a7aef1cbba4..af8e9b1a4959e 100644 --- a/Compiler/src/ssair/EscapeAnalysis.jl +++ b/Compiler/src/ssair/EscapeAnalysis.jl @@ -944,14 +944,16 @@ end # escape statically-resolved call, i.e. `Expr(:invoke, ::MethodInstance, ...)` function escape_invoke!(astate::AnalysisState, pc::Int, args::Vector{Any}) - mi = first(args) - if !(mi isa MethodInstance) - mi = (mi::CodeInstance).def # COMBAK get escape info directly from CI instead? + codeinst = first(args) + if codeinst isa MethodInstance + mi = codeinst + else + mi = (codeinst::CodeInstance).def end first_idx, last_idx = 2, length(args) add_liveness_changes!(astate, pc, args, first_idx, last_idx) # TODO inspect `astate.ir.stmts[pc][:info]` and use const-prop'ed `InferenceResult` if available - cache = astate.get_escape_cache(mi) + cache = astate.get_escape_cache(codeinst) ret = SSAValue(pc) if cache isa Bool if cache diff --git a/Compiler/test/EAUtils.jl b/Compiler/test/EAUtils.jl index f124aea2544fd..64d2a62db8622 100644 --- a/Compiler/test/EAUtils.jl +++ b/Compiler/test/EAUtils.jl @@ -14,27 +14,11 @@ import .Compiler: AbstractInterpreter, NativeInterpreter, WorldView, WorldRange, InferenceParams, OptimizationParams, get_world_counter, get_inference_cache, ipo_dataflow_analysis! # usings -using Core: - CodeInstance, MethodInstance, CodeInfo -using .Compiler: - InferenceResult, InferenceState, OptimizationState, IRCode +using Core.IR +using .Compiler: InferenceResult, InferenceState, OptimizationState, IRCode using .EA: analyze_escapes, ArgEscapeCache, ArgEscapeInfo, EscapeInfo, EscapeState -struct EAToken end - -# when working outside of CC, -# cache entire escape state for later inspection and debugging -struct EscapeCacheInfo - argescapes::ArgEscapeCache - state::EscapeState # preserved just for debugging purpose - ir::IRCode # preserved just for debugging purpose -end - -struct EscapeCache - cache::IdDict{MethodInstance,EscapeCacheInfo} # TODO(aviatesk) Should this be CodeInstance to EscapeCacheInfo? -end -EscapeCache() = EscapeCache(IdDict{MethodInstance,EscapeCacheInfo}()) -const GLOBAL_ESCAPE_CACHE = EscapeCache() +mutable struct EscapeAnalyzerCacheToken end struct EscapeResultForEntry ir::IRCode @@ -47,15 +31,15 @@ mutable struct EscapeAnalyzer <: AbstractInterpreter const inf_params::InferenceParams const opt_params::OptimizationParams const inf_cache::Vector{InferenceResult} - const escape_cache::EscapeCache + const token::EscapeAnalyzerCacheToken const entry_mi::Union{Nothing,MethodInstance} result::EscapeResultForEntry - function EscapeAnalyzer(world::UInt, escape_cache::EscapeCache; + function EscapeAnalyzer(world::UInt, cache_token::EscapeAnalyzerCacheToken; entry_mi::Union{Nothing,MethodInstance}=nothing) inf_params = InferenceParams() opt_params = OptimizationParams() inf_cache = InferenceResult[] - return new(world, inf_params, opt_params, inf_cache, escape_cache, entry_mi) + return new(world, inf_params, opt_params, inf_cache, cache_token, entry_mi) end end @@ -63,20 +47,19 @@ Compiler.InferenceParams(interp::EscapeAnalyzer) = interp.inf_params Compiler.OptimizationParams(interp::EscapeAnalyzer) = interp.opt_params Compiler.get_inference_world(interp::EscapeAnalyzer) = interp.world Compiler.get_inference_cache(interp::EscapeAnalyzer) = interp.inf_cache -Compiler.cache_owner(::EscapeAnalyzer) = EAToken() -Compiler.get_escape_cache(interp::EscapeAnalyzer) = GetEscapeCache(interp) +Compiler.cache_owner(interp::EscapeAnalyzer) = interp.token +Compiler.get_escape_cache(::EscapeAnalyzer) = GetEscapeCache() function Compiler.ipo_dataflow_analysis!(interp::EscapeAnalyzer, opt::OptimizationState, - ir::IRCode, caller::InferenceResult) + ir::IRCode, caller::InferenceResult) # run EA on all frames that have been optimized nargs = Int(opt.src.nargs) 𝕃ₒ = Compiler.optimizer_lattice(interp) - get_escape_cache = GetEscapeCache(interp) estate = try - analyze_escapes(ir, nargs, 𝕃ₒ, get_escape_cache) + analyze_escapes(ir, nargs, 𝕃ₒ, GetEscapeCache()) catch err @error "error happened within EA, inspect `Main.failedanalysis`" - failedanalysis = FailedAnalysis(caller, ir, nargs, get_escape_cache) + failedanalysis = FailedAnalysis(caller, ir, nargs) Core.eval(Main, :(failedanalysis = $failedanalysis)) rethrow(err) end @@ -84,25 +67,31 @@ function Compiler.ipo_dataflow_analysis!(interp::EscapeAnalyzer, opt::Optimizati # return back the result interp.result = EscapeResultForEntry(Compiler.copy(ir), estate, caller.linfo) end - record_escapes!(interp, caller, estate, ir) + record_escapes!(caller, estate, ir) @invoke Compiler.ipo_dataflow_analysis!(interp::AbstractInterpreter, opt::OptimizationState, - ir::IRCode, caller::InferenceResult) + ir::IRCode, caller::InferenceResult) end -function record_escapes!(interp::EscapeAnalyzer, - caller::InferenceResult, estate::EscapeState, ir::IRCode) +# cache entire escape state for inspection and debugging +struct EscapeCacheInfo + argescapes::ArgEscapeCache + state::EscapeState # preserved just for debugging purpose + ir::IRCode # preserved just for debugging purpose +end + +function record_escapes!(caller::InferenceResult, estate::EscapeState, ir::IRCode) argescapes = ArgEscapeCache(estate) ecacheinfo = EscapeCacheInfo(argescapes, estate, ir) return Compiler.stack_analysis_result!(caller, ecacheinfo) end -struct GetEscapeCache - escape_cache::EscapeCache - GetEscapeCache(interp::EscapeAnalyzer) = new(interp.escape_cache) -end -function ((; escape_cache)::GetEscapeCache)(mi::MethodInstance) - ecacheinfo = get(escape_cache.cache, mi, nothing) +struct GetEscapeCache end +function (::GetEscapeCache)(codeinst::Union{CodeInstance,MethodInstance}) + codeinst isa CodeInstance || return false + ecacheinfo = Compiler.traverse_analysis_results(codeinst) do @nospecialize result + return result isa EscapeCacheInfo ? result : nothing + end return ecacheinfo === nothing ? false : ecacheinfo.argescapes end @@ -110,15 +99,6 @@ struct FailedAnalysis caller::InferenceResult ir::IRCode nargs::Int - get_escape_cache::GetEscapeCache -end - -function Compiler.finish!(interp::EscapeAnalyzer, state::InferenceState; can_discard_trees::Bool=Compiler.may_discard_trees(interp)) - ecacheinfo = Compiler.traverse_analysis_results(state.result) do @nospecialize result - return result isa EscapeCacheInfo ? result : nothing - end - ecacheinfo isa EscapeCacheInfo && (interp.escape_cache.cache[state.linfo] = ecacheinfo) - return @invoke Compiler.finish!(interp::AbstractInterpreter, state::InferenceState; can_discard_trees) end # printing @@ -313,23 +293,29 @@ while caching the analysis results. - `world::UInt = Base.get_world_counter()`: controls the world age to use when looking up methods, use current world age if not specified. -- `interp::EscapeAnalyzer = EscapeAnalyzer(world)`: - specifies the escape analyzer to use, by default a new analyzer with the global cache is created. +- `cache_token::EscapeAnalyzerCacheToken = EscapeAnalyzerCacheToken()`: + specifies the cache token to use, by default a new token is generated to ensure + that `code_escapes` uses a fresh cache and performs a new analysis on each invocation. + If you with to perform analysis with the global cache enabled, specify a particular token instance. +- `interp::EscapeAnalyzer = EscapeAnalyzer(world, cache_token)`: + specifies the escape analyzer to use. - `debuginfo::Symbol = :none`: controls the amount of code metadata present in the output, possible options are `:none` or `:source`. """ function code_escapes(@nospecialize(f), @nospecialize(types=Base.default_tt(f)); world::UInt = get_world_counter(), + cache_token::EscapeAnalyzerCacheToken = EscapeAnalyzerCacheToken(), debuginfo::Symbol = :none) tt = Base.signature_type(f, types) match = Base._which(tt; world, raise=true) mi = Compiler.specialize_method(match) - return code_escapes(mi; world, debuginfo) + return code_escapes(mi; world, cache_token, debuginfo) end function code_escapes(mi::MethodInstance; world::UInt = get_world_counter(), - interp::EscapeAnalyzer=EscapeAnalyzer(world, GLOBAL_ESCAPE_CACHE; entry_mi=mi), + cache_token::EscapeAnalyzerCacheToken = EscapeAnalyzerCacheToken(), + interp::EscapeAnalyzer=EscapeAnalyzer(world, cache_token; entry_mi=mi), debuginfo::Symbol = :none) frame = Compiler.typeinf_frame(interp, mi, #=run_optimizer=#true) isdefined(interp, :result) || error("optimization didn't happen: maybe everything has been constant folded?") @@ -351,12 +337,17 @@ Note that this version does not cache the analysis results. - `world::UInt = Base.get_world_counter()`: controls the world age to use when looking up methods, use current world age if not specified. -- `interp::AbstractInterpreter = EscapeAnalyzer(world, EscapeCache())`: +- `cache_token::EscapeAnalyzerCacheToken = EscapeAnalyzerCacheToken()`: + specifies the cache token to use, by default a new token is generated to ensure + that `code_escapes` uses a fresh cache and performs a new analysis on each invocation. + If you with to perform analysis with the global cache enabled, specify a particular token instance. +- `interp::AbstractInterpreter = EscapeAnalyzer(world, cache_token)`: specifies the abstract interpreter to use, by default a new `EscapeAnalyzer` with an empty cache is created. """ function code_escapes(ir::IRCode, nargs::Int; world::UInt = get_world_counter(), - interp::AbstractInterpreter=EscapeAnalyzer(world, EscapeCache())) + cache_token::EscapeAnalyzerCacheToken = EscapeAnalyzerCacheToken(), + interp::AbstractInterpreter=EscapeAnalyzer(world, cache_token)) estate = analyze_escapes(ir, nargs, Compiler.optimizer_lattice(interp), Compiler.get_escape_cache(interp)) return EscapeResult(ir, estate) # return back the result end diff --git a/Compiler/test/EscapeAnalysis.jl b/Compiler/test/EscapeAnalysis.jl index e1638e74e61fe..60364769c95a8 100644 --- a/Compiler/test/EscapeAnalysis.jl +++ b/Compiler/test/EscapeAnalysis.jl @@ -1527,7 +1527,17 @@ let result = code_escapes() do end i = last(findall(isnew, result.ir.stmts.stmt)) @test_broken !has_return_escape(result.state[SSAValue(i)]) # TODO interprocedural alias analysis - @test !has_thrown_escape(result.state[SSAValue(i)]) + @test_broken !has_thrown_escape(result.state[SSAValue(i)]) # IDEA embed const-prop'ed `CodeInstance` for `:invoke`? +end +let result = code_escapes((Base.RefValue{Base.RefValue{String}},)) do x + out1 = broadcast_noescape2(Ref(Ref("Hi"))) + out2 = broadcast_noescape2(x) + return out1, out2 + end + i = last(findall(isnew, result.ir.stmts.stmt)) + @test_broken !has_return_escape(result.state[SSAValue(i)]) # TODO interprocedural alias analysis + @test_broken !has_thrown_escape(result.state[SSAValue(i)]) # IDEA embed const-prop'ed `CodeInstance` for `:invoke`? + @test has_thrown_escape(result.state[Argument(2)]) end @noinline allescape_argument(a) = (global GV = a) # obvious escape let result = code_escapes() do From 82daca2c9f0c00274a05a4fc46ee36a62b73f8a2 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Thu, 19 Dec 2024 15:23:20 +0900 Subject: [PATCH 089/342] Compiler.jl: use `Base.[all|any]` instead of `Compiler`'s own versions (#56851) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current `Compiler` defines its own versions of `all` and `any`, which are separate generic functions from `Base.[all|any]`: https://github.com/JuliaLang/julia/blob/2ed1a411e0a080f3107e75bb65105a15a0533a90/Compiler/src/utilities.jl#L15-L32 On the other hand, at the point where `Base.Compiler` is bootstrapped, only a subset of `Base.[all|any]` are defined, specifically those related to `Tuple`: https://github.com/JuliaLang/julia/blob/2ed1a411e0a080f3107e75bb65105a15a0533a90/base/tuple.jl#L657-L668. Consequently, in the type inference world, functions like `Base.all(::Generator)` are unavailable. If `Base.Compiler` attempts to perform operations such as `::BitSet ⊆ ::BitSet` (which internally uses `Base.[all|any]`), a world age error occurs (while `Compiler.[all|any]` can handle these operations, `::BitSet ⊆ ::BitSet` uses `Base.[all|any]`, leading to this issue) To resolve this problem, this commit removes the custom `Compiler` versions of `[all|any]` and switches to using the Base versions. One concern is that the previous `Compiler` versions of `[all|any]` utilized `@nospecialize`. That annotation was introduced a long time ago to prevent over-specialization, but it is questionable whether it is still effective with the current compiler implementation. The results of the nanosoldier benchmarks conducted below also seem to confirm that the `@nospecialize`s are no longer necessary for those functions. --- Compiler/src/Compiler.jl | 54 ++++----- Compiler/src/utilities.jl | 19 ---- base/Base_compiler.jl | 2 + base/anyall.jl | 231 ++++++++++++++++++++++++++++++++++++++ base/reduce.jl | 230 ------------------------------------- 5 files changed, 260 insertions(+), 276 deletions(-) create mode 100644 base/anyall.jl diff --git a/Compiler/src/Compiler.jl b/Compiler/src/Compiler.jl index 8dd15462ed998..06cdbe09e06fc 100644 --- a/Compiler/src/Compiler.jl +++ b/Compiler/src/Compiler.jl @@ -41,36 +41,36 @@ ccall(:jl_set_module_uuid, Cvoid, (Any, NTuple{2, UInt64}), Compiler, using Core.Intrinsics, Core.IR -import Core: print, println, show, write, unsafe_write, - _apply_iterate, svec, apply_type, Builtin, IntrinsicFunction, - MethodInstance, CodeInstance, MethodTable, MethodMatch, PartialOpaque, - TypeofVararg, Core, SimpleVector, donotdelete, compilerbarrier, - memoryref_isassigned, memoryrefnew, memoryrefoffset, memoryrefget, - memoryrefset!, typename +using Core: Builtin, CodeInstance, IntrinsicFunction, MethodInstance, MethodMatch, + MethodTable, PartialOpaque, SimpleVector, TypeofVararg, + _apply_iterate, apply_type, compilerbarrier, donotdelete, memoryref_isassigned, + memoryrefget, memoryrefnew, memoryrefoffset, memoryrefset!, print, println, show, svec, + typename, unsafe_write, write using Base -using Base: Ordering, vect, EffectsOverride, BitVector, @_gc_preserve_begin, @_gc_preserve_end, RefValue, - @nospecializeinfer, @_foldable_meta, fieldindex, is_function_def, indexed_iterate, isexpr, methods, - get_world_counter, JLOptions, _methods_by_ftype, unwrap_unionall, cconvert, unsafe_convert, - issingletontype, isType, rewrap_unionall, has_free_typevars, isvarargtype, hasgenerator, - IteratorSize, SizeUnknown, _array_for, Bottom, generating_output, diff_names, - ismutationfree, NUM_EFFECTS_OVERRIDES, _NAMEDTUPLE_NAME, datatype_fieldtypes, - argument_datatype, isfieldatomic, unwrapva, iskindtype, _bits_findnext, copy_exprargs, - Generator, Filter, ismutabletypename, isvatuple, datatype_fieldcount, - isconcretedispatch, isdispatchelem, datatype_layoutsize, - datatype_arrayelem, unionlen, isidentityfree, _uniontypes, uniontypes, OneTo, Callable, - DataTypeFieldDesc, datatype_nfields, datatype_pointerfree, midpoint, is_valid_intrinsic_elptr, - allocatedinline, isbitsunion, widen_diagonal, unconstrain_vararg_length, - rename_unionall, may_invoke_generator, is_meta_expr_head, is_meta_expr, quoted, - specialize_method, hasintersect, is_nospecializeinfer, is_nospecialized, - get_nospecializeinfer_sig, tls_world_age, uniontype_layout, kwerr, - moduleroot, is_file_tracked, decode_effects_override, lookup_binding_partition, - is_some_imported, binding_kind, is_some_guard, is_some_const_binding, partition_restriction, - BINDING_KIND_GLOBAL, structdiff +using Base: @_foldable_meta, @_gc_preserve_begin, @_gc_preserve_end, @nospecializeinfer, + BINDING_KIND_GLOBAL, Base, BitVector, Bottom, Callable, DataTypeFieldDesc, + EffectsOverride, Filter, Generator, IteratorSize, JLOptions, NUM_EFFECTS_OVERRIDES, + OneTo, Ordering, RefValue, SizeUnknown, _NAMEDTUPLE_NAME, + _array_for, _bits_findnext, _methods_by_ftype, _uniontypes, all, allocatedinline, any, + argument_datatype, binding_kind, cconvert, copy_exprargs, datatype_arrayelem, + datatype_fieldcount, datatype_fieldtypes, datatype_layoutsize, datatype_nfields, + datatype_pointerfree, decode_effects_override, diff_names, fieldindex, + generating_output, get_nospecializeinfer_sig, get_world_counter, has_free_typevars, + hasgenerator, hasintersect, indexed_iterate, isType, is_file_tracked, is_function_def, + is_meta_expr, is_meta_expr_head, is_nospecialized, is_nospecializeinfer, + is_some_const_binding, is_some_guard, is_some_imported, is_valid_intrinsic_elptr, + isbitsunion, isconcretedispatch, isdispatchelem, isexpr, isfieldatomic, isidentityfree, + iskindtype, ismutabletypename, ismutationfree, issingletontype, isvarargtype, isvatuple, + kwerr, lookup_binding_partition, may_invoke_generator, methods, midpoint, moduleroot, + partition_restriction, quoted, rename_unionall, rewrap_unionall, specialize_method, + structdiff, tls_world_age, unconstrain_vararg_length, unionlen, uniontype_layout, + uniontypes, unsafe_convert, unwrap_unionall, unwrapva, vect, widen_diagonal using Base.Order -import Base: getindex, setindex!, length, iterate, push!, isempty, first, convert, ==, - copy, popfirst!, in, haskey, resize!, copy!, append!, last, get!, size, - get, iterate, findall, min_world, max_world, _topmod, isready + +import Base: ==, _topmod, append!, convert, copy, copy!, findall, first, get, get!, + getindex, haskey, in, isempty, isready, iterate, iterate, last, length, max_world, + min_world, popfirst!, push!, resize!, setindex!, size const getproperty = Core.getfield const setproperty! = Core.setfield! diff --git a/Compiler/src/utilities.jl b/Compiler/src/utilities.jl index da20f9aafbfb2..196722f8bca33 100644 --- a/Compiler/src/utilities.jl +++ b/Compiler/src/utilities.jl @@ -12,25 +12,6 @@ if !@isdefined(var"@timeit") end end -# avoid cycle due to over-specializing `any` when used by inference -function _any(@nospecialize(f), a) - for x in a - f(x) && return true - end - return false -end -any(@nospecialize(f), itr) = _any(f, itr) -any(itr) = _any(identity, itr) - -function _all(@nospecialize(f), a) - for x in a - f(x) || return false - end - return true -end -all(@nospecialize(f), itr) = _all(f, itr) -all(itr) = _all(identity, itr) - function contains_is(itr, @nospecialize(x)) for y in itr if y === x diff --git a/base/Base_compiler.jl b/base/Base_compiler.jl index 6014a6b7c9dd0..6582fe87e2045 100644 --- a/base/Base_compiler.jl +++ b/base/Base_compiler.jl @@ -249,6 +249,8 @@ using .Iterators: Flatten, Filter, product # for generators using .Iterators: Stateful # compat (was formerly used in reinterpretarray.jl) include("namedtuple.jl") +include("anyall.jl") + include("ordering.jl") using .Order diff --git a/base/anyall.jl b/base/anyall.jl new file mode 100644 index 0000000000000..e51515bb3187d --- /dev/null +++ b/base/anyall.jl @@ -0,0 +1,231 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +## all & any + +""" + any(itr) -> Bool + +Test whether any elements of a boolean collection are `true`, returning `true` as +soon as the first `true` value in `itr` is encountered (short-circuiting). To +short-circuit on `false`, use [`all`](@ref). + +If the input contains [`missing`](@ref) values, return `missing` if all non-missing +values are `false` (or equivalently, if the input contains no `true` value), following +[three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic). + +See also: [`all`](@ref), [`count`](@ref), [`sum`](@ref), [`|`](@ref), [`||`](@ref). + +# Examples +```jldoctest +julia> a = [true,false,false,true] +4-element Vector{Bool}: + 1 + 0 + 0 + 1 + +julia> any(a) +true + +julia> any((println(i); v) for (i, v) in enumerate(a)) +1 +true + +julia> any([missing, true]) +true + +julia> any([false, missing]) +missing +``` +""" +any(itr) = any(identity, itr) + +""" + all(itr) -> Bool + +Test whether all elements of a boolean collection are `true`, returning `false` as +soon as the first `false` value in `itr` is encountered (short-circuiting). To +short-circuit on `true`, use [`any`](@ref). + +If the input contains [`missing`](@ref) values, return `missing` if all non-missing +values are `true` (or equivalently, if the input contains no `false` value), following +[three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic). + +See also: [`all!`](@ref), [`any`](@ref), [`count`](@ref), [`&`](@ref), [`&&`](@ref), [`allunique`](@ref). + +# Examples +```jldoctest +julia> a = [true,false,false,true] +4-element Vector{Bool}: + 1 + 0 + 0 + 1 + +julia> all(a) +false + +julia> all((println(i); v) for (i, v) in enumerate(a)) +1 +2 +false + +julia> all([missing, false]) +false + +julia> all([true, missing]) +missing +``` +""" +all(itr) = all(identity, itr) + +""" + any(p, itr) -> Bool + +Determine whether predicate `p` returns `true` for any elements of `itr`, returning +`true` as soon as the first item in `itr` for which `p` returns `true` is encountered +(short-circuiting). To short-circuit on `false`, use [`all`](@ref). + +If the input contains [`missing`](@ref) values, return `missing` if all non-missing +values are `false` (or equivalently, if the input contains no `true` value), following +[three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic). + +# Examples +```jldoctest +julia> any(i->(4<=i<=6), [3,5,7]) +true + +julia> any(i -> (println(i); i > 3), 1:10) +1 +2 +3 +4 +true + +julia> any(i -> i > 0, [1, missing]) +true + +julia> any(i -> i > 0, [-1, missing]) +missing + +julia> any(i -> i > 0, [-1, 0]) +false +``` +""" +any(f, itr) = _any(f, itr, :) + +for ItrT = (Tuple,Any) + # define a generic method and a specialized version for `Tuple`, + # whose method bodies are identical, while giving better effects to the later + @eval function _any(f, itr::$ItrT, ::Colon) + $(ItrT === Tuple ? :(@_terminates_locally_meta) : :nothing) + anymissing = false + for x in itr + v = f(x) + if ismissing(v) + anymissing = true + else + v && return true + end + end + return anymissing ? missing : false + end +end + +# Specialized versions of any(f, ::Tuple) +# We fall back to the for loop implementation all elements have the same type or +# if the tuple is too large. +function any(f, itr::Tuple) + if itr isa NTuple || length(itr) > 32 + return _any(f, itr, :) + end + _any_tuple(f, false, itr...) +end + +@inline function _any_tuple(f, anymissing, x, rest...) + v = f(x) + if ismissing(v) + anymissing = true + elseif v + return true + end + return _any_tuple(f, anymissing, rest...) +end +@inline _any_tuple(f, anymissing) = anymissing ? missing : false + +""" + all(p, itr) -> Bool + +Determine whether predicate `p` returns `true` for all elements of `itr`, returning +`false` as soon as the first item in `itr` for which `p` returns `false` is encountered +(short-circuiting). To short-circuit on `true`, use [`any`](@ref). + +If the input contains [`missing`](@ref) values, return `missing` if all non-missing +values are `true` (or equivalently, if the input contains no `false` value), following +[three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic). + +# Examples +```jldoctest +julia> all(i->(4<=i<=6), [4,5,6]) +true + +julia> all(i -> (println(i); i < 3), 1:10) +1 +2 +3 +false + +julia> all(i -> i > 0, [1, missing]) +missing + +julia> all(i -> i > 0, [-1, missing]) +false + +julia> all(i -> i > 0, [1, 2]) +true +``` +""" +all(f, itr) = _all(f, itr, :) + +for ItrT = (Tuple,Any) + # define a generic method and a specialized version for `Tuple`, + # whose method bodies are identical, while giving better effects to the later + @eval function _all(f, itr::$ItrT, ::Colon) + $(ItrT === Tuple ? :(@_terminates_locally_meta) : :nothing) + anymissing = false + for x in itr + v = f(x) + if ismissing(v) + anymissing = true + else + v || return false + end + end + return anymissing ? missing : true + end +end + +# Specialized versions of all(f, ::Tuple), +# This is similar to any(f, ::Tuple) defined above. +function all(f, itr::Tuple) + if itr isa NTuple || length(itr) > 32 + return _all(f, itr, :) + end + _all_tuple(f, false, itr...) +end + +@inline function _all_tuple(f, anymissing, x, rest...) + v = f(x) + if ismissing(v) + anymissing = true + # this syntax allows throwing a TypeError for non-Bool, for consistency with any + elseif v + nothing + else + return false + end + return _all_tuple(f, anymissing, rest...) +end +@inline _all_tuple(f, anymissing) = anymissing ? missing : true + +all(::Tuple{Missing}) = missing diff --git a/base/reduce.jl b/base/reduce.jl index 6ceb76089d59c..25466eed4a105 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -1105,236 +1105,6 @@ julia> argmin([7, 1, 1, NaN]) """ argmin(itr) = findmin(itr)[2] -## all & any - -""" - any(itr) -> Bool - -Test whether any elements of a boolean collection are `true`, returning `true` as -soon as the first `true` value in `itr` is encountered (short-circuiting). To -short-circuit on `false`, use [`all`](@ref). - -If the input contains [`missing`](@ref) values, return `missing` if all non-missing -values are `false` (or equivalently, if the input contains no `true` value), following -[three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic). - -See also: [`all`](@ref), [`count`](@ref), [`sum`](@ref), [`|`](@ref), [`||`](@ref). - -# Examples -```jldoctest -julia> a = [true,false,false,true] -4-element Vector{Bool}: - 1 - 0 - 0 - 1 - -julia> any(a) -true - -julia> any((println(i); v) for (i, v) in enumerate(a)) -1 -true - -julia> any([missing, true]) -true - -julia> any([false, missing]) -missing -``` -""" -any(itr) = any(identity, itr) - -""" - all(itr) -> Bool - -Test whether all elements of a boolean collection are `true`, returning `false` as -soon as the first `false` value in `itr` is encountered (short-circuiting). To -short-circuit on `true`, use [`any`](@ref). - -If the input contains [`missing`](@ref) values, return `missing` if all non-missing -values are `true` (or equivalently, if the input contains no `false` value), following -[three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic). - -See also: [`all!`](@ref), [`any`](@ref), [`count`](@ref), [`&`](@ref), [`&&`](@ref), [`allunique`](@ref). - -# Examples -```jldoctest -julia> a = [true,false,false,true] -4-element Vector{Bool}: - 1 - 0 - 0 - 1 - -julia> all(a) -false - -julia> all((println(i); v) for (i, v) in enumerate(a)) -1 -2 -false - -julia> all([missing, false]) -false - -julia> all([true, missing]) -missing -``` -""" -all(itr) = all(identity, itr) - -""" - any(p, itr) -> Bool - -Determine whether predicate `p` returns `true` for any elements of `itr`, returning -`true` as soon as the first item in `itr` for which `p` returns `true` is encountered -(short-circuiting). To short-circuit on `false`, use [`all`](@ref). - -If the input contains [`missing`](@ref) values, return `missing` if all non-missing -values are `false` (or equivalently, if the input contains no `true` value), following -[three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic). - -# Examples -```jldoctest -julia> any(i->(4<=i<=6), [3,5,7]) -true - -julia> any(i -> (println(i); i > 3), 1:10) -1 -2 -3 -4 -true - -julia> any(i -> i > 0, [1, missing]) -true - -julia> any(i -> i > 0, [-1, missing]) -missing - -julia> any(i -> i > 0, [-1, 0]) -false -``` -""" -any(f, itr) = _any(f, itr, :) - -for ItrT = (Tuple,Any) - # define a generic method and a specialized version for `Tuple`, - # whose method bodies are identical, while giving better effects to the later - @eval function _any(f, itr::$ItrT, ::Colon) - $(ItrT === Tuple ? :(@_terminates_locally_meta) : :nothing) - anymissing = false - for x in itr - v = f(x) - if ismissing(v) - anymissing = true - else - v && return true - end - end - return anymissing ? missing : false - end -end - -# Specialized versions of any(f, ::Tuple) -# We fall back to the for loop implementation all elements have the same type or -# if the tuple is too large. -function any(f, itr::Tuple) - if itr isa NTuple || length(itr) > 32 - return _any(f, itr, :) - end - _any_tuple(f, false, itr...) -end - -@inline function _any_tuple(f, anymissing, x, rest...) - v = f(x) - if ismissing(v) - anymissing = true - elseif v - return true - end - return _any_tuple(f, anymissing, rest...) -end -@inline _any_tuple(f, anymissing) = anymissing ? missing : false - -""" - all(p, itr) -> Bool - -Determine whether predicate `p` returns `true` for all elements of `itr`, returning -`false` as soon as the first item in `itr` for which `p` returns `false` is encountered -(short-circuiting). To short-circuit on `true`, use [`any`](@ref). - -If the input contains [`missing`](@ref) values, return `missing` if all non-missing -values are `true` (or equivalently, if the input contains no `false` value), following -[three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic). - -# Examples -```jldoctest -julia> all(i->(4<=i<=6), [4,5,6]) -true - -julia> all(i -> (println(i); i < 3), 1:10) -1 -2 -3 -false - -julia> all(i -> i > 0, [1, missing]) -missing - -julia> all(i -> i > 0, [-1, missing]) -false - -julia> all(i -> i > 0, [1, 2]) -true -``` -""" -all(f, itr) = _all(f, itr, :) - -for ItrT = (Tuple,Any) - # define a generic method and a specialized version for `Tuple`, - # whose method bodies are identical, while giving better effects to the later - @eval function _all(f, itr::$ItrT, ::Colon) - $(ItrT === Tuple ? :(@_terminates_locally_meta) : :nothing) - anymissing = false - for x in itr - v = f(x) - if ismissing(v) - anymissing = true - else - v || return false - end - end - return anymissing ? missing : true - end -end - -# Specialized versions of all(f, ::Tuple), -# This is similar to any(f, ::Tuple) defined above. -function all(f, itr::Tuple) - if itr isa NTuple || length(itr) > 32 - return _all(f, itr, :) - end - _all_tuple(f, false, itr...) -end - -@inline function _all_tuple(f, anymissing, x, rest...) - v = f(x) - if ismissing(v) - anymissing = true - # this syntax allows throwing a TypeError for non-Bool, for consistency with any - elseif v - nothing - else - return false - end - return _all_tuple(f, anymissing, rest...) -end -@inline _all_tuple(f, anymissing) = anymissing ? missing : true - -all(::Tuple{Missing}) = missing - ## count _bool(f) = x->f(x)::Bool From d3c26b7ecce7e8319788bc0a035241d6dfd21ac0 Mon Sep 17 00:00:00 2001 From: Sebastian Stock <42280794+sostock@users.noreply.github.com> Date: Thu, 19 Dec 2024 10:38:45 +0100 Subject: [PATCH 090/342] Extend `Base.rationalize` instead of defining new function (#56793) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #55886 accidentally created a new function `Base.MathConstants.rationalize` instead of extending `Base.rationalize`, which is the reason why `Base.rationalize(Int, π)` isn’t constant-folded in Julia 1.10 and 1.11: ``` julia> @btime rationalize(Int,π); 1.837 ns (0 allocations: 0 bytes) # v1.9: constant-folded 88.416 μs (412 allocations: 15.00 KiB) # v1.10: not constant-folded ``` This PR fixes that. It should probably be backported to 1.10 and 1.11. --- base/mathconstants.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/mathconstants.jl b/base/mathconstants.jl index de6b98cea634d..d26f5115b5ccb 100644 --- a/base/mathconstants.jl +++ b/base/mathconstants.jl @@ -29,7 +29,7 @@ end Base.@assume_effects :foldable function (::Type{T})(x::_KnownIrrational, r::RoundingMode) where {T<:Union{Float32,Float64}} Base._irrational_to_float(T, x, r) end -Base.@assume_effects :foldable function rationalize(::Type{T}, x::_KnownIrrational; tol::Real=0) where {T<:Integer} +Base.@assume_effects :foldable function Base.rationalize(::Type{T}, x::_KnownIrrational; tol::Real=0) where {T<:Integer} Base._rationalize_irrational(T, x, tol) end Base.@assume_effects :foldable function Base.lessrational(rx::Rational, x::_KnownIrrational) From 6e04a0bbdd61685624594f1fd1ffcb3de25035bf Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Thu, 19 Dec 2024 13:22:16 -0500 Subject: [PATCH 091/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?LinearAlgebra=20stdlib=20from=2056d561c=20to=201137b4c=20(#5682?= =?UTF-8?q?8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: LinearAlgebra URL: https://github.com/JuliaLang/LinearAlgebra.jl.git Stdlib branch: master Julia branch: master Old commit: 56d561c New commit: 1137b4c Julia version: 1.12.0-DEV LinearAlgebra version: 1.11.0(Does not match) Bump invoked by: @DilumAluthge Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaLang/LinearAlgebra.jl/compare/56d561c22e1ab8e0421160edbdd42f3f194ecfa8...1137b4c7fa8297cef17c4ae0982d7d89d4ab7dd8 ``` $ git log --oneline 56d561c..1137b4c 1137b4c Port structured opnorm changes from main julia PR (#1138) ade3654 port bitarray tests to LinearAlgebra.jl (#1148) 130b94a Fix documentation bug in QR docstring (#1145) 128518e setup coverage (#1144) 15f7e32 ci: add linux-i686 (#1142) b6f87af Fallback `newindex` method with a `BandIndex` (#1143) d1e267f bring back [l/r]mul! shortcuts for (kn)own triangular types (#1137) 5cdeb46 don't refer to internal variable names in gemv exceptions (#1141) 4a3dbf8 un-revert "Simplify some views of Adjoint matrices" (#1122) 7b34d81 [CI] Install DependaBot (#1115) f567112 Port structured opnorm changes from main julia PR Originally written by mcognetta d406524 implements a `rank(::SVD)` method and adds unit tests. fixes #1126 (#1127) f13f940 faster implementation of rank(::QRPivoted) fixes #1128 (#1129) 8ab7e09 Merge pull request #1132 from JuliaLang/jishnub/qr_ldiv_R_cache 85919e6 Merge pull request #1108 from JuliaLang/jishnub/tri_muldiv_stride 195e678 Cache and reuse `R` in adjoint `QR` `ldiv!` cd0da66 Update comments LAPACK -> BLAS b3ec55f Fix argument name in stride d3a9a3e Non-contiguous matrices in triangular mul and div aecb714 Reduce number of test combinations in test/triangular.jl (#1123) 62e45d1 Update .github/dependabot.yml ff78c38 use an explicit file extension when creating sysimage (#1119) 43b541e try use updated windows compilers in PackageCompiler (#1120) c00cb77 [CI] Install DependaBot b285b1c Update LICENSE (#1113) 7efc3ba remove REPL from custom sysimage (#1112) b7f82ec add a README ``` Co-authored-by: Dilum Aluthge --- .../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-1137b4c7fa8297cef17c4ae0982d7d89d4ab7dd8.tar.gz/md5 create mode 100644 deps/checksums/LinearAlgebra-1137b4c7fa8297cef17c4ae0982d7d89d4ab7dd8.tar.gz/sha512 delete mode 100644 deps/checksums/LinearAlgebra-56d561c22e1ab8e0421160edbdd42f3f194ecfa8.tar.gz/md5 delete mode 100644 deps/checksums/LinearAlgebra-56d561c22e1ab8e0421160edbdd42f3f194ecfa8.tar.gz/sha512 diff --git a/deps/checksums/LinearAlgebra-1137b4c7fa8297cef17c4ae0982d7d89d4ab7dd8.tar.gz/md5 b/deps/checksums/LinearAlgebra-1137b4c7fa8297cef17c4ae0982d7d89d4ab7dd8.tar.gz/md5 new file mode 100644 index 0000000000000..5bd44506fd874 --- /dev/null +++ b/deps/checksums/LinearAlgebra-1137b4c7fa8297cef17c4ae0982d7d89d4ab7dd8.tar.gz/md5 @@ -0,0 +1 @@ +eb4df255412ad9a05b807010f626afc8 diff --git a/deps/checksums/LinearAlgebra-1137b4c7fa8297cef17c4ae0982d7d89d4ab7dd8.tar.gz/sha512 b/deps/checksums/LinearAlgebra-1137b4c7fa8297cef17c4ae0982d7d89d4ab7dd8.tar.gz/sha512 new file mode 100644 index 0000000000000..23617698dd26e --- /dev/null +++ b/deps/checksums/LinearAlgebra-1137b4c7fa8297cef17c4ae0982d7d89d4ab7dd8.tar.gz/sha512 @@ -0,0 +1 @@ +3b4bf7b761d9585fb2d5c5b8418770be4d1d4399a5f25dd5b2e08785506f0732c8e140ada6f82f6d8a7a77a2c2f79e2feecd6eb0e19eda0c3ee519ba554c19ec diff --git a/deps/checksums/LinearAlgebra-56d561c22e1ab8e0421160edbdd42f3f194ecfa8.tar.gz/md5 b/deps/checksums/LinearAlgebra-56d561c22e1ab8e0421160edbdd42f3f194ecfa8.tar.gz/md5 deleted file mode 100644 index e240a1083833c..0000000000000 --- a/deps/checksums/LinearAlgebra-56d561c22e1ab8e0421160edbdd42f3f194ecfa8.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -00198e6d92d033fb33e75cf4eac34dca diff --git a/deps/checksums/LinearAlgebra-56d561c22e1ab8e0421160edbdd42f3f194ecfa8.tar.gz/sha512 b/deps/checksums/LinearAlgebra-56d561c22e1ab8e0421160edbdd42f3f194ecfa8.tar.gz/sha512 deleted file mode 100644 index 5eeceaf1dbed3..0000000000000 --- a/deps/checksums/LinearAlgebra-56d561c22e1ab8e0421160edbdd42f3f194ecfa8.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -ba4b390d99644c31d64594352da888e9ef18021cc9b7700c37a6cdb0c1ff2532eb208ecaccf93217e3183e1db8e6c089456fa5d93633b8ff037e8796199934e7 diff --git a/stdlib/LinearAlgebra.version b/stdlib/LinearAlgebra.version index d6a33ea421adf..3dac27119172a 100644 --- a/stdlib/LinearAlgebra.version +++ b/stdlib/LinearAlgebra.version @@ -1,4 +1,4 @@ LINEARALGEBRA_BRANCH = master -LINEARALGEBRA_SHA1 = 56d561c22e1ab8e0421160edbdd42f3f194ecfa8 +LINEARALGEBRA_SHA1 = 1137b4c7fa8297cef17c4ae0982d7d89d4ab7dd8 LINEARALGEBRA_GIT_URL := https://github.com/JuliaLang/LinearAlgebra.jl.git LINEARALGEBRA_TAR_URL = https://api.github.com/repos/JuliaLang/LinearAlgebra.jl/tarball/$1 From 9bc27ad0f7315b8f89635c666973e84568b2f6ab Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 20 Dec 2024 04:45:01 +0100 Subject: [PATCH 092/342] Add ABIOverride type for def field (#56555) Together with #54899, this PR is intending to replicate the functionality of #54373, which allowed particular specializations to have a different ABI signature than what would be suggested by the MethodInstance's `specTypes` field. This PR handles that by adding a special `ABIOverwrite` type, which, when placed in the `owner` field of a `CodeInstance` instructs the system to use the given signature instead. --- Compiler/src/Compiler.jl | 2 +- Compiler/src/abstractinterpretation.jl | 18 +++++- Compiler/src/ssair/show.jl | 8 ++- Compiler/src/stmtinfo.jl | 8 +-- Compiler/src/typeinfer.jl | 2 +- Compiler/test/inference.jl | 7 ++- base/arrayshow.jl | 2 +- base/boot.jl | 8 ++- base/show.jl | 8 ++- src/aotcompile.cpp | 16 +++--- src/builtins.c | 16 ++++-- src/clangsa/GCChecker.cpp | 1 + src/codegen.cpp | 77 +++++++++++++++----------- src/debuginfo.cpp | 4 +- src/engine.cpp | 2 +- src/gf.c | 17 +++--- src/interpreter.c | 4 +- src/ircode.c | 2 +- src/jitlayers.cpp | 14 ++--- src/jitlayers.h | 1 + src/jl_exported_data.inc | 1 + src/jltypes.c | 3 +- src/julia.h | 11 +++- src/julia_internal.h | 7 +++ src/precompile_utils.c | 2 +- src/staticdata.c | 16 +++--- src/staticdata_utils.c | 16 +++--- test/precompile.jl | 4 +- 28 files changed, 177 insertions(+), 100 deletions(-) diff --git a/Compiler/src/Compiler.jl b/Compiler/src/Compiler.jl index 06cdbe09e06fc..2f4efda51da9b 100644 --- a/Compiler/src/Compiler.jl +++ b/Compiler/src/Compiler.jl @@ -41,7 +41,7 @@ ccall(:jl_set_module_uuid, Cvoid, (Any, NTuple{2, UInt64}), Compiler, using Core.Intrinsics, Core.IR -using Core: Builtin, CodeInstance, IntrinsicFunction, MethodInstance, MethodMatch, +using Core: ABIOverride, Builtin, CodeInstance, IntrinsicFunction, MethodInstance, MethodMatch, MethodTable, PartialOpaque, SimpleVector, TypeofVararg, _apply_iterate, apply_type, compilerbarrier, donotdelete, memoryref_isassigned, memoryrefget, memoryrefnew, memoryrefoffset, memoryrefset!, print, println, show, svec, diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index 59d382d8e4a34..f2d4461a9874a 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -2212,6 +2212,18 @@ function abstract_call_unionall(interp::AbstractInterpreter, argtypes::Vector{An return CallMeta(ret, Any, Effects(EFFECTS_TOTAL; nothrow), call.info) end +function ci_abi(ci::CodeInstance) + def = ci.def + isa(def, ABIOverride) && return def.abi + (def::MethodInstance).specTypes +end + +function get_ci_mi(ci::CodeInstance) + def = ci.def + isa(def, ABIOverride) && return def.def + return def::MethodInstance +end + function abstract_invoke(interp::AbstractInterpreter, arginfo::ArgInfo, si::StmtInfo, sv::AbsIntState) argtypes = arginfo.argtypes ft′ = argtype_by_index(argtypes, 2) @@ -2223,12 +2235,12 @@ function abstract_invoke(interp::AbstractInterpreter, arginfo::ArgInfo, si::Stmt if isa(method_or_ci, CodeInstance) our_world = sv.world.this argtype = argtypes_to_type(pushfirst!(argtype_tail(argtypes, 4), ft)) - specsig = method_or_ci.def.specTypes - defdef = method_or_ci.def.def + specsig = ci_abi(method_or_ci) + defdef = get_ci_mi(method_or_ci).def exct = method_or_ci.exctype if !hasintersect(argtype, specsig) return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo())) - elseif !(argtype <: specsig) || (isa(defdef, Method) && !(argtype <: defdef.sig)) + elseif !(argtype <: specsig) || ((!isa(method_or_ci.def, ABIOverride) && isa(defdef, Method)) && !(argtype <: defdef.sig)) exct = Union{exct, TypeError} end callee_valid_range = WorldRange(method_or_ci.min_world, method_or_ci.max_world) diff --git a/Compiler/src/ssair/show.jl b/Compiler/src/ssair/show.jl index 7d7b182655db7..e63d7b5cf640e 100644 --- a/Compiler/src/ssair/show.jl +++ b/Compiler/src/ssair/show.jl @@ -100,11 +100,17 @@ function print_stmt(io::IO, idx::Int, @nospecialize(stmt), code::Union{IRCode,Co if !(mi isa Core.MethodInstance) mi = (mi::Core.CodeInstance).def end + if isa(mi, Core.ABIOverride) + abi = mi.abi + mi = mi.def + else + abi = mi.specTypes + end show_unquoted(io, stmt.args[2], indent) print(io, "(") # XXX: this is wrong if `sig` is not a concretetype method # more correct would be to use `fieldtype(sig, i)`, but that would obscure / discard Varargs information in show - sig = mi.specTypes == Tuple ? Core.svec() : Base.unwrap_unionall(mi.specTypes).parameters::Core.SimpleVector + sig = abi == Tuple ? Core.svec() : Base.unwrap_unionall(abi).parameters::Core.SimpleVector print_arg(i) = sprint(; context=io) do io show_unquoted(io, stmt.args[i], indent) if (i - 1) <= length(sig) diff --git a/Compiler/src/stmtinfo.jl b/Compiler/src/stmtinfo.jl index 4f55f068e9456..a42a9e47b328e 100644 --- a/Compiler/src/stmtinfo.jl +++ b/Compiler/src/stmtinfo.jl @@ -71,7 +71,7 @@ function _add_edges_impl(edges::Vector{Any}, info::MethodMatchInfo, mi_edge::Boo mi = specialize_method(m) # don't allow `Method`-edge for this optimized format edge = mi else - mi = edge.def + mi = edge.def::MethodInstance end if mi.specTypes === m.spec_types add_one_edge!(edges, edge) @@ -103,7 +103,7 @@ function add_one_edge!(edges::Vector{Any}, edge::MethodInstance) while i <= length(edges) edgeᵢ = edges[i] edgeᵢ isa Int && (i += 2 + edgeᵢ; continue) - edgeᵢ isa CodeInstance && (edgeᵢ = edgeᵢ.def) + edgeᵢ isa CodeInstance && (edgeᵢ = get_ci_mi(edgeᵢ)) edgeᵢ isa MethodInstance || (i += 1; continue) if edgeᵢ === edge && !(i > 1 && edges[i-1] isa Type) return # found existing covered edge @@ -118,7 +118,7 @@ function add_one_edge!(edges::Vector{Any}, edge::CodeInstance) while i <= length(edges) edgeᵢ_orig = edgeᵢ = edges[i] edgeᵢ isa Int && (i += 2 + edgeᵢ; continue) - edgeᵢ isa CodeInstance && (edgeᵢ = edgeᵢ.def) + edgeᵢ isa CodeInstance && (edgeᵢ = get_ci_mi(edgeᵢ)) edgeᵢ isa MethodInstance || (i += 1; continue) if edgeᵢ === edge.def && !(i > 1 && edges[i-1] isa Type) if edgeᵢ_orig isa MethodInstance @@ -385,7 +385,7 @@ function add_inlining_edge!(edges::Vector{Any}, edge::CodeInstance) i += 1 end # add_invoke_edge alone - push!(edges, (edge.def.def::Method).sig) + push!(edges, (get_ci_mi(edge).def::Method).sig) push!(edges, edge) nothing end diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index 20c0a5000bd39..2e9fcf497faf6 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -528,7 +528,7 @@ function store_backedges(caller::CodeInstance, edges::SimpleVector) i += 2 continue elseif isa(callee, CodeInstance) - callee = callee.def + callee = get_ci_mi(callee) end ccall(:jl_method_instance_add_backedge, Cvoid, (Any, Any, Any), callee, item, caller) i += 2 diff --git a/Compiler/test/inference.jl b/Compiler/test/inference.jl index 7cd6989bd2423..9301a2809daf3 100644 --- a/Compiler/test/inference.jl +++ b/Compiler/test/inference.jl @@ -4110,7 +4110,12 @@ end == [Union{Some{Float64}, Some{Int}, Some{UInt8}}] mi = codeinst else codeinst::Core.CodeInstance - mi = codeinst.def + def = codeinst.def + if isa(def, Core.ABIOverride) + mi = def.def + else + mi = def::Core.MethodInstance + end end return mi end == Core.MethodInstance diff --git a/base/arrayshow.jl b/base/arrayshow.jl index 3bc69e563a967..623111ef0883d 100644 --- a/base/arrayshow.jl +++ b/base/arrayshow.jl @@ -41,7 +41,7 @@ Accept keyword args `c` for alternate single character marker. """ function replace_with_centered_mark(s::AbstractString;c::AbstractChar = '⋅') N = textwidth(ANSIIterator(s)) - return join(setindex!([" " for i=1:N],string(c),ceil(Int,N/2))) + return N == 0 ? string(c) : join(setindex!([" " for i=1:N],string(c),ceil(Int,N/2))) end const undef_ref_alignment = (3,3) diff --git a/base/boot.jl b/base/boot.jl index ed0a722c5e562..4652524530703 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -465,6 +465,12 @@ struct InitError <: WrappedException error end +struct ABIOverride + abi::Type + def::MethodInstance + ABIOverride(@nospecialize(abi::Type), def::MethodInstance) = new(abi, def) +end + struct PrecompilableError <: Exception end String(s::String) = s # no constructor yet @@ -552,7 +558,7 @@ end function CodeInstance( - mi::MethodInstance, owner, @nospecialize(rettype), @nospecialize(exctype), @nospecialize(inferred_const), + mi::Union{MethodInstance, ABIOverride}, owner, @nospecialize(rettype), @nospecialize(exctype), @nospecialize(inferred_const), @nospecialize(inferred), const_flags::Int32, min_world::UInt, max_world::UInt, effects::UInt32, @nospecialize(analysis_results), relocatability::UInt8, di::Union{DebugInfo,Nothing}, edges::SimpleVector) diff --git a/base/show.jl b/base/show.jl index cb36488b92bc1..d2f43e1ae92cc 100644 --- a/base/show.jl +++ b/base/show.jl @@ -1353,7 +1353,13 @@ end show(io::IO, mi::Core.MethodInstance) = show_mi(io, mi) function show(io::IO, codeinst::Core.CodeInstance) print(io, "CodeInstance for ") - show_mi(io, codeinst.def) + def = codeinst.def + if isa(def, Core.ABIOverride) + show_mi(io, def.def) + print(io, " (ABI Overridden)") + else + show_mi(io, def::MethodInstance) + end end function show_mi(io::IO, mi::Core.MethodInstance, from_stackframe::Bool=false) diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 198d7490cb092..b238c44c52676 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -105,7 +105,7 @@ jl_get_llvm_mis_impl(void *native_code, size_t *num_elements, jl_method_instance assert(*num_elements == map.size()); size_t i = 0; for (auto &ci : map) { - data[i++] = ci.first->def; + data[i++] = jl_get_ci_mi(ci.first); } } @@ -455,14 +455,14 @@ static void compile_workqueue(jl_codegen_params_t ¶ms, egal_set &method_root if ((policy != CompilationPolicy::Default || params.params->trim) && jl_atomic_load_relaxed(&codeinst->inferred) == jl_nothing) { // XXX: SOURCE_MODE_FORCE_SOURCE is wrong here (neither sufficient nor necessary) - codeinst = jl_type_infer(codeinst->def, jl_atomic_load_relaxed(&codeinst->max_world), SOURCE_MODE_FORCE_SOURCE); + codeinst = jl_type_infer(jl_get_ci_mi(codeinst), jl_atomic_load_relaxed(&codeinst->max_world), SOURCE_MODE_FORCE_SOURCE); } if (codeinst) { orc::ThreadSafeModule result_m = - jl_create_ts_module(name_from_method_instance(codeinst->def), + jl_create_ts_module(name_from_method_instance(jl_get_ci_mi(codeinst)), params.tsctx, params.DL, params.TargetTriple); auto decls = jl_emit_codeinst(result_m, codeinst, NULL, params); - record_method_roots(method_roots, codeinst->def); + record_method_roots(method_roots, jl_get_ci_mi(codeinst)); if (result_m) it = compiled_functions.insert(std::make_pair(codeinst, std::make_pair(std::move(result_m), std::move(decls)))).first; } @@ -501,7 +501,7 @@ static void compile_workqueue(jl_codegen_params_t ¶ms, egal_set &method_root proto.decl->setLinkage(GlobalVariable::InternalLinkage); //protodecl->setAlwaysInline(); jl_init_function(proto.decl, params.TargetTriple); - jl_method_instance_t *mi = codeinst->def; + jl_method_instance_t *mi = jl_get_ci_mi(codeinst); size_t nrealargs = jl_nparams(mi->specTypes); // number of actual arguments being passed bool is_opaque_closure = jl_is_method(mi->def.value) && mi->def.method->is_for_opaque_closure; // TODO: maybe this can be cached in codeinst->specfptr? @@ -641,12 +641,12 @@ void *jl_create_native_impl(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvm data->jl_fvar_map[codeinst] = std::make_tuple((uint32_t)-3, (uint32_t)-3); } else { - orc::ThreadSafeModule result_m = jl_create_ts_module(name_from_method_instance(codeinst->def), + orc::ThreadSafeModule result_m = jl_create_ts_module(name_from_method_instance(jl_get_ci_mi(codeinst)), params.tsctx, clone.getModuleUnlocked()->getDataLayout(), Triple(clone.getModuleUnlocked()->getTargetTriple())); jl_llvm_functions_t decls = jl_emit_codeinst(result_m, codeinst, NULL, params); JL_GC_PROMISE_ROOTED(codeinst->def); // analyzer seems confused - record_method_roots(method_roots, codeinst->def); + record_method_roots(method_roots, jl_get_ci_mi(codeinst)); if (result_m) compiled_functions[codeinst] = {std::move(result_m), std::move(decls)}; else if (jl_options.trim != JL_TRIM_NO) { @@ -2267,7 +2267,7 @@ void jl_get_llvmf_defn_impl(jl_llvmf_dump_t* dump, jl_method_instance_t *mi, jl_ // To get correct names in the IR this needs to be at least 2 output.temporary_roots = jl_alloc_array_1d(jl_array_any_type, 0); JL_GC_PUSH1(&output.temporary_roots); - auto decls = jl_emit_code(m, mi, src, output); + auto decls = jl_emit_code(m, mi, src, NULL, output); output.temporary_roots = nullptr; JL_GC_POP(); // GC the global_targets array contents now since reflection doesn't need it diff --git a/src/builtins.c b/src/builtins.c index 06dbd84aff6c0..c326e53ea968d 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1589,11 +1589,19 @@ JL_CALLABLE(jl_f_invoke) return jl_gf_invoke_by_method(m, args[0], &args[2], nargs - 1); } else if (jl_is_code_instance(argtypes)) { jl_code_instance_t *codeinst = (jl_code_instance_t*)args[1]; + jl_method_instance_t *mi = jl_get_ci_mi(codeinst); jl_callptr_t invoke = jl_atomic_load_acquire(&codeinst->invoke); // N.B.: specTypes need not be a subtype of the method signature. We need to check both. - if (!jl_tuple1_isa(args[0], &args[2], nargs - 1, (jl_datatype_t*)codeinst->def->specTypes) || - (jl_is_method(codeinst->def->def.value) && !jl_tuple1_isa(args[0], &args[2], nargs - 1, (jl_datatype_t*)codeinst->def->def.method->sig))) { - jl_type_error("invoke: argument type error", codeinst->def->specTypes, arg_tuple(args[0], &args[2], nargs - 1)); + if (jl_is_abioverride(codeinst->def)) { + jl_datatype_t *abi = (jl_datatype_t*)((jl_abi_override_t*)(codeinst->def))->abi; + if (!jl_tuple1_isa(args[0], &args[2], nargs - 1, abi)) { + jl_type_error("invoke: argument type error (ABI overwrite)", (jl_value_t*)abi, arg_tuple(args[0], &args[2], nargs - 1)); + } + } else { + if (!jl_tuple1_isa(args[0], &args[2], nargs - 1, (jl_datatype_t*)mi->specTypes) || + (jl_is_method(mi->def.value) && !jl_tuple1_isa(args[0], &args[2], nargs - 1, (jl_datatype_t*)mi->def.method->sig))) { + jl_type_error("invoke: argument type error", mi->specTypes, arg_tuple(args[0], &args[2], nargs - 1)); + } } if (jl_atomic_load_relaxed(&codeinst->min_world) > jl_current_task->world_age || jl_current_task->world_age > jl_atomic_load_relaxed(&codeinst->max_world)) { @@ -1609,7 +1617,7 @@ JL_CALLABLE(jl_f_invoke) if (codeinst->owner != jl_nothing) { jl_error("Failed to invoke or compile external codeinst"); } - return jl_invoke(args[0], &args[2], nargs - 1, codeinst->def); + return jl_invoke(args[0], &args[2], nargs - 1, mi); } } if (!jl_is_tuple_type(jl_unwrap_unionall(argtypes))) diff --git a/src/clangsa/GCChecker.cpp b/src/clangsa/GCChecker.cpp index 40093ca15859b..fdbe5ec9d9e29 100644 --- a/src/clangsa/GCChecker.cpp +++ b/src/clangsa/GCChecker.cpp @@ -847,6 +847,7 @@ bool GCChecker::isGCTrackedType(QualType QT) { Name.ends_with_insensitive("jl_vararg_t") || Name.ends_with_insensitive("jl_opaque_closure_t") || Name.ends_with_insensitive("jl_globalref_t") || + Name.ends_with_insensitive("jl_abi_override_t") || // Probably not technically true for these, but let's allow it as a root Name.ends_with_insensitive("jl_ircode_state") || Name.ends_with_insensitive("typemap_intersection_env") || diff --git a/src/codegen.cpp b/src/codegen.cpp index 86c9afd134d9a..9ae905a8aba32 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3021,9 +3021,8 @@ static bool uses_specsig(jl_value_t *sig, bool needsparams, jl_value_t *rettype, return false; // jlcall sig won't require any box allocations } -static std::pair uses_specsig(jl_method_instance_t *lam, jl_value_t *rettype, bool prefer_specsig) +static std::pair uses_specsig(jl_value_t *abi, jl_method_instance_t *lam, jl_value_t *rettype, bool prefer_specsig) { - jl_value_t *sig = lam->specTypes; bool needsparams = false; if (jl_is_method(lam->def.method)) { if ((size_t)jl_subtype_env_size(lam->def.method->sig) != jl_svec_len(lam->sparam_vals)) @@ -3033,7 +3032,7 @@ static std::pair uses_specsig(jl_method_instance_t *lam, jl_value_t needsparams = true; } } - return std::make_pair(uses_specsig(sig, needsparams, rettype, prefer_specsig), needsparams); + return std::make_pair(uses_specsig(abi, needsparams, rettype, prefer_specsig), needsparams); } @@ -4341,6 +4340,7 @@ static jl_llvm_functions_t orc::ThreadSafeModule &TSM, jl_method_instance_t *lam, jl_code_info_t *src, + jl_value_t *abi, jl_value_t *rettype, jl_codegen_params_t ¶ms); @@ -5487,6 +5487,13 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, jl_expr_t *ex, jl_value_t *rt) return emit_invoke(ctx, lival, argv, nargs, rt, nullptr); } +static jl_value_t *get_ci_abi(jl_code_instance_t *ci) +{ + if (jl_typeof(ci->def) == (jl_value_t*)jl_abioverride_type) + return ((jl_abi_override_t*)ci->def)->abi; + return jl_get_ci_mi(ci)->specTypes; +} + static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayRef argv, size_t nargs, jl_value_t *rt, Value *age_ok) { ++EmittedInvokes; @@ -5501,7 +5508,7 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayR else { ci = lival.constant; assert(jl_is_code_instance(ci)); - mi = ((jl_code_instance_t*)ci)->def; + mi = jl_get_ci_mi((jl_code_instance_t*)ci); } assert(jl_is_method_instance(mi)); if (mi == ctx.linfo) { @@ -5530,7 +5537,7 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayR } else { bool specsig, needsparams; - std::tie(specsig, needsparams) = uses_specsig(mi, codeinst->rettype, ctx.params->prefer_specsig); + std::tie(specsig, needsparams) = uses_specsig(get_ci_abi(codeinst), mi, codeinst->rettype, ctx.params->prefer_specsig); if (needsparams) { if (trim_may_error(ctx.params->trim)) push_frames(ctx, ctx.linfo, mi); @@ -7256,7 +7263,7 @@ Function *emit_tojlinvoke(jl_code_instance_t *codeinst, StringRef theFptrName, M name, M); jl_init_function(f, params.TargetTriple); if (trim_may_error(params.params->trim)) { - push_frames(ctx, ctx.linfo, codeinst->def); + push_frames(ctx, ctx.linfo, jl_get_ci_mi(codeinst)); } jl_name_jlfunc_args(params, f); //f->setAlwaysInline(); @@ -7273,7 +7280,7 @@ Function *emit_tojlinvoke(jl_code_instance_t *codeinst, StringRef theFptrName, M } else { theFunc = prepare_call(jlinvoke_func); - theFarg = literal_pointer_val(ctx, (jl_value_t*)codeinst->def); + theFarg = literal_pointer_val(ctx, (jl_value_t*)jl_get_ci_mi(codeinst)); } theFarg = track_pjlvalue(ctx, theFarg); auto args = f->arg_begin(); @@ -8011,7 +8018,7 @@ const char *jl_generate_ccallable(Module *llvmmod, void *sysimg_handle, jl_value // generate a julia-callable function that calls f (AKA lam) // if is_opaque_closure, then generate the OC invoke, rather than a real invoke -static void gen_invoke_wrapper(jl_method_instance_t *lam, jl_value_t *jlretty, jl_returninfo_t &f, unsigned nargs, int retarg, bool is_opaque_closure, StringRef funcName, +static void gen_invoke_wrapper(jl_method_instance_t *lam, jl_value_t *abi, jl_value_t *jlretty, jl_returninfo_t &f, unsigned nargs, int retarg, bool is_opaque_closure, StringRef funcName, Module *M, jl_codegen_params_t ¶ms) { ++GeneratedInvokeWrappers; @@ -8047,7 +8054,7 @@ static void gen_invoke_wrapper(jl_method_instance_t *lam, jl_value_t *jlretty, j argv[i] = mark_julia_slot(funcArg, oc_type, NULL, ctx.tbaa().tbaa_const); continue; } - jl_value_t *ty = jl_nth_slot_type(lam->specTypes, i); + jl_value_t *ty = jl_nth_slot_type(abi, i); Value *theArg; if (i == 0) { theArg = funcArg; @@ -8061,7 +8068,7 @@ static void gen_invoke_wrapper(jl_method_instance_t *lam, jl_value_t *jlretty, j } argv[i] = mark_julia_type(ctx, theArg, true, ty); } - jl_cgval_t retval = emit_call_specfun_other(ctx, is_opaque_closure, lam->specTypes, jlretty, f, argv, nargs); + jl_cgval_t retval = emit_call_specfun_other(ctx, is_opaque_closure, abi, jlretty, f, argv, nargs); if (retarg != -1) { Value *theArg; if (retarg == 0) @@ -8293,13 +8300,13 @@ get_specsig_di(jl_codectx_t &ctx, jl_debugcache_t &debuginfo, jl_value_t *rt, jl } /* aka Core.Compiler.tuple_tfunc */ -static jl_datatype_t *compute_va_type(jl_method_instance_t *lam, size_t nreq) +static jl_datatype_t *compute_va_type(jl_value_t *sig, size_t nreq) { - size_t nvargs = jl_nparams(lam->specTypes)-nreq; + size_t nvargs = jl_nparams(sig)-nreq; jl_svec_t *tupargs = jl_alloc_svec(nvargs); JL_GC_PUSH1(&tupargs); - for (size_t i = nreq; i < jl_nparams(lam->specTypes); ++i) { - jl_value_t *argType = jl_nth_slot_type(lam->specTypes, i); + for (size_t i = nreq; i < jl_nparams(sig); ++i) { + jl_value_t *argType = jl_nth_slot_type(sig, i); // n.b. specTypes is required to be a datatype by construction for specsig if (is_uniquerep_Type(argType)) argType = jl_typeof(jl_tparam0(argType)); @@ -8339,6 +8346,7 @@ static jl_llvm_functions_t orc::ThreadSafeModule &TSM, jl_method_instance_t *lam, jl_code_info_t *src, + jl_value_t *abi, jl_value_t *jlrettype, jl_codegen_params_t ¶ms) { @@ -8417,7 +8425,7 @@ static jl_llvm_functions_t int n_ssavalues = jl_is_long(src->ssavaluetypes) ? jl_unbox_long(src->ssavaluetypes) : jl_array_nrows(src->ssavaluetypes); size_t vinfoslen = jl_array_dim0(src->slotflags); ctx.slots.resize(vinfoslen, jl_varinfo_t(ctx.builder.getContext())); - assert(lam->specTypes); // the specTypes field should always be assigned + assert(abi); // the specTypes field should always be assigned // create SAvalue locations for SSAValue objects @@ -8426,7 +8434,7 @@ static jl_llvm_functions_t ctx.ssavalue_usecount.assign(n_ssavalues, 0); bool specsig, needsparams; - std::tie(specsig, needsparams) = uses_specsig(lam, jlrettype, params.params->prefer_specsig); + std::tie(specsig, needsparams) = uses_specsig(abi, lam, jlrettype, params.params->prefer_specsig); // step 3. some variable analysis size_t i; @@ -8436,7 +8444,7 @@ static jl_llvm_functions_t jl_sym_t *argname = slot_symbol(ctx, i); if (argname == jl_unused_sym) continue; - jl_value_t *ty = jl_nth_slot_type(lam->specTypes, i); + jl_value_t *ty = jl_nth_slot_type(abi, i); // TODO: jl_nth_slot_type should call jl_rewrap_unionall // specTypes is required to be a datatype by construction for specsig, but maybe not otherwise // OpaqueClosure implicitly loads the env @@ -8454,7 +8462,7 @@ static jl_llvm_functions_t if (va && ctx.vaSlot != -1) { jl_varinfo_t &varinfo = ctx.slots[ctx.vaSlot]; varinfo.isArgument = true; - vatyp = specsig ? compute_va_type(lam, nreq) : (jl_tuple_type); + vatyp = specsig ? compute_va_type(abi, nreq) : (jl_tuple_type); varinfo.value = mark_julia_type(ctx, (Value*)NULL, false, vatyp); } @@ -8505,7 +8513,7 @@ static jl_llvm_functions_t ArgNames[i] = name; } } - returninfo = get_specsig_function(ctx, M, NULL, declarations.specFunctionObject, lam->specTypes, + returninfo = get_specsig_function(ctx, M, NULL, declarations.specFunctionObject, abi, jlrettype, ctx.is_opaque_closure, JL_FEAT_TEST(ctx,gcstack_arg), ArgNames, nreq); f = cast(returninfo.decl.getCallee()); @@ -8539,8 +8547,8 @@ static jl_llvm_functions_t std::string wrapName; raw_string_ostream(wrapName) << "jfptr_" << ctx.name << "_" << jl_atomic_fetch_add_relaxed(&globalUniqueGeneratedNames, 1); declarations.functionObject = wrapName; - size_t nparams = jl_nparams(lam->specTypes); - gen_invoke_wrapper(lam, jlrettype, returninfo, nparams, retarg, ctx.is_opaque_closure, declarations.functionObject, M, ctx.emission_context); + size_t nparams = jl_nparams(abi); + gen_invoke_wrapper(lam, abi, jlrettype, returninfo, nparams, retarg, ctx.is_opaque_closure, declarations.functionObject, M, ctx.emission_context); // TODO: add attributes: maybe_mark_argument_dereferenceable(Arg, argType) // TODO: add attributes: dereferenceable // TODO: (if needsparams) add attributes: dereferenceable, readonly, nocapture @@ -8562,7 +8570,7 @@ static jl_llvm_functions_t if (!params.getContext().shouldDiscardValueNames() && ctx.emission_context.params->debug_info_level >= 2 && lam->def.method && jl_is_method(lam->def.method) && lam->specTypes != (jl_value_t*)jl_emptytuple_type) { ios_t sigbuf; ios_mem(&sigbuf, 0); - jl_static_show_func_sig((JL_STREAM*) &sigbuf, (jl_value_t*)lam->specTypes); + jl_static_show_func_sig((JL_STREAM*) &sigbuf, (jl_value_t*)abi); f->addFnAttr("julia.fsig", StringRef(sigbuf.buf, sigbuf.size)); ios_close(&sigbuf); } @@ -8619,7 +8627,7 @@ static jl_llvm_functions_t else if (!specsig) subrty = debugcache.jl_di_func_sig; else - subrty = get_specsig_di(ctx, debugcache, jlrettype, lam->specTypes, dbuilder); + subrty = get_specsig_di(ctx, debugcache, jlrettype, abi, dbuilder); SP = dbuilder.createFunction(nullptr ,dbgFuncName // Name ,f->getName() // LinkageName @@ -8951,7 +8959,7 @@ static jl_llvm_functions_t nullptr, nullptr, /*isboxed*/true, AtomicOrdering::NotAtomic, false, sizeof(void*)); } else { - jl_value_t *argType = jl_nth_slot_type(lam->specTypes, i); + jl_value_t *argType = jl_nth_slot_type(abi, i); // TODO: jl_nth_slot_type should call jl_rewrap_unionall? // specTypes is required to be a datatype by construction for specsig, but maybe not otherwise bool isboxed = deserves_argbox(argType); @@ -9025,10 +9033,10 @@ static jl_llvm_functions_t assert(vi.boxroot == NULL); } else if (specsig) { - ctx.nvargs = jl_nparams(lam->specTypes) - nreq; + ctx.nvargs = jl_nparams(abi) - nreq; SmallVector vargs(ctx.nvargs); - for (size_t i = nreq; i < jl_nparams(lam->specTypes); ++i) { - jl_value_t *argType = jl_nth_slot_type(lam->specTypes, i); + for (size_t i = nreq; i < jl_nparams(abi); ++i) { + jl_value_t *argType = jl_nth_slot_type(abi, i); // n.b. specTypes is required to be a datatype by construction for specsig bool isboxed = deserves_argbox(argType); Type *llvmArgType = isboxed ? ctx.types().T_prjlvalue : julia_type_to_llvm(ctx, argType); @@ -9954,6 +9962,7 @@ jl_llvm_functions_t jl_emit_code( orc::ThreadSafeModule &m, jl_method_instance_t *li, jl_code_info_t *src, + jl_value_t *abi, jl_codegen_params_t ¶ms) { JL_TIMING(CODEGEN, CODEGEN_LLVM); @@ -9962,8 +9971,10 @@ jl_llvm_functions_t jl_emit_code( assert((params.params == &jl_default_cgparams /* fast path */ || !params.cache || compare_cgparams(params.params, &jl_default_cgparams)) && "functions compiled with custom codegen params must not be cached"); + if (!abi) + abi = li->specTypes; JL_TRY { - decls = emit_function(m, li, src, src->rettype, params); + decls = emit_function(m, li, src, abi, src->rettype, params); auto stream = *jl_ExecutionEngine->get_dump_emitted_mi_name_stream(); if (stream) { jl_printf(stream, "%s\t", decls.specFunctionObject.c_str()); @@ -10030,11 +10041,11 @@ jl_llvm_functions_t jl_emit_codeinst( jl_codegen_params_t ¶ms) { JL_TIMING(CODEGEN, CODEGEN_Codeinst); - jl_timing_show_method_instance(codeinst->def, JL_TIMING_DEFAULT_BLOCK); + jl_timing_show_method_instance(jl_get_ci_mi(codeinst), JL_TIMING_DEFAULT_BLOCK); JL_GC_PUSH1(&src); if (!src) { src = (jl_code_info_t*)jl_atomic_load_relaxed(&codeinst->inferred); - jl_method_instance_t *mi = codeinst->def; + jl_method_instance_t *mi = jl_get_ci_mi(codeinst); jl_method_t *def = mi->def.method; // Check if this is the generic method for opaque closure wrappers - // if so, this must compile specptr such that it holds the specptr -> invoke wrapper @@ -10052,7 +10063,7 @@ jl_llvm_functions_t jl_emit_codeinst( } } assert(jl_egal((jl_value_t*)jl_atomic_load_relaxed(&codeinst->debuginfo), (jl_value_t*)src->debuginfo) && "trying to generate code for a codeinst for an incompatible src"); - jl_llvm_functions_t decls = jl_emit_code(m, codeinst->def, src, params); + jl_llvm_functions_t decls = jl_emit_code(m, jl_get_ci_mi(codeinst), src, get_ci_abi(codeinst), params); const std::string &specf = decls.specFunctionObject; const std::string &f = decls.functionObject; @@ -10060,7 +10071,7 @@ jl_llvm_functions_t jl_emit_codeinst( // Prepare debug info to receive this function // record that this function name came from this linfo, // so we can build a reverse mapping for debug-info. - bool toplevel = !jl_is_method(codeinst->def->def.method); + bool toplevel = !jl_is_method(jl_get_ci_mi(codeinst)->def.method); if (!toplevel) { //Safe b/c params holds context lock const DataLayout &DL = m.getModuleUnlocked()->getDataLayout(); @@ -10076,7 +10087,7 @@ jl_llvm_functions_t jl_emit_codeinst( jl_value_t *inferred = jl_atomic_load_relaxed(&codeinst->inferred); // don't change inferred state if (inferred) { - jl_method_t *def = codeinst->def->def.method; + jl_method_t *def = jl_get_ci_mi(codeinst)->def.method; if (// keep code when keeping everything !(JL_DELETE_NON_INLINEABLE) || // aggressively keep code when debugging level >= 2 diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 31f1ba8281a89..ce8406bf91490 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -167,7 +167,7 @@ void jl_add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const D // Non-opaque-closure MethodInstances are considered globally rooted // through their methods, but for OC, we need to create a global root // here. - jl_method_instance_t *mi = codeinst->def; + jl_method_instance_t *mi = jl_get_ci_mi(codeinst); if (jl_is_method(mi->def.value) && mi->def.method->is_for_opaque_closure) jl_as_global_root((jl_value_t*)mi, 1); getJITDebugRegistry().add_code_in_flight(name, codeinst, DL); @@ -374,7 +374,7 @@ void JITDebugInfoRegistry::registerJITObject(const object::ObjectFile &Object, jl_method_instance_t *mi = NULL; if (codeinst) { JL_GC_PROMISE_ROOTED(codeinst); - mi = codeinst->def; + mi = jl_get_ci_mi(codeinst); } jl_profile_atomic([&]() JL_NOTSAFEPOINT { if (mi) diff --git a/src/engine.cpp b/src/engine.cpp index 2b68de731c4dd..858f37b55e85e 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -139,7 +139,7 @@ void jl_engine_fulfill(jl_code_instance_t *ci, jl_code_info_t *src) { jl_task_t *ct = jl_current_task; std::unique_lock lock(engine_lock); - auto record = Reservations.find(InferKey{ci->def, ci->owner}); + auto record = Reservations.find(InferKey{jl_get_ci_mi(ci), ci->owner}); if (record == Reservations.end() || record->second.ci != ci) return; assert(jl_atomic_load_relaxed(&ct->tid) == record->second.tid); diff --git a/src/gf.c b/src/gf.c index a5ba309784557..d220ad057176a 100644 --- a/src/gf.c +++ b/src/gf.c @@ -538,7 +538,7 @@ JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst( jl_task_t *ct = jl_current_task; jl_code_instance_t *codeinst = (jl_code_instance_t*)jl_gc_alloc(ct->ptls, sizeof(jl_code_instance_t), jl_code_instance_type); - codeinst->def = mi; + codeinst->def = (jl_value_t*)mi; codeinst->owner = owner; jl_atomic_store_relaxed(&codeinst->edges, edges); jl_atomic_store_relaxed(&codeinst->min_world, min_world); @@ -1772,17 +1772,18 @@ static void invalidate_code_instance(jl_code_instance_t *replaced, size_t max_wo JL_GC_POP(); } //jl_static_show(JL_STDERR, (jl_value_t*)replaced->def); - if (!jl_is_method(replaced->def->def.method)) + jl_method_instance_t *replaced_mi = jl_get_ci_mi(replaced); + if (!jl_is_method(replaced_mi->def.method)) return; // shouldn't happen, but better to be safe - JL_LOCK(&replaced->def->def.method->writelock); + JL_LOCK(&replaced_mi->def.method->writelock); if (jl_atomic_load_relaxed(&replaced->max_world) == ~(size_t)0) { assert(jl_atomic_load_relaxed(&replaced->min_world) - 1 <= max_world && "attempting to set illogical world constraints (probable race condition)"); jl_atomic_store_release(&replaced->max_world, max_world); } assert(jl_atomic_load_relaxed(&replaced->max_world) <= max_world); // recurse to all backedges to update their valid range also - _invalidate_backedges(replaced->def, max_world, depth + 1); - JL_UNLOCK(&replaced->def->def.method->writelock); + _invalidate_backedges(replaced_mi, max_world, depth + 1); + JL_UNLOCK(&replaced_mi->def.method->writelock); } static void _invalidate_backedges(jl_method_instance_t *replaced_mi, size_t max_world, int depth) { @@ -2329,7 +2330,7 @@ void jl_method_table_activate(jl_methtable_t *mt, jl_typemap_entry_t *newentry) int replaced_edge; if (invokeTypes) { // n.b. normally we must have mi.specTypes <: invokeTypes <: m.sig (though it might not strictly hold), so we only need to check the other subtypes - if (jl_egal(invokeTypes, caller->def->def.method->sig)) + if (jl_egal(invokeTypes, jl_get_ci_mi(caller)->def.method->sig)) replaced_edge = 0; // if invokeTypes == m.sig, then the only way to change this invoke is to replace the method itself else replaced_edge = jl_subtype(invokeTypes, type) && is_replacing(ambig, type, m, d, n, invokeTypes, NULL, morespec); @@ -2907,7 +2908,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t jl_callptr_t ucache_invoke = jl_atomic_load_acquire(&ucache->invoke); if (ucache_invoke == NULL) { if ((!jl_is_method(def) || def->source == jl_nothing) && - !jl_cached_uninferred(jl_atomic_load_relaxed(&ucache->def->cache), world)) { + !jl_cached_uninferred(jl_atomic_load_relaxed(&jl_get_ci_mi(ucache)->cache), world)) { jl_throw(jl_new_struct(jl_missingcodeerror_type, (jl_value_t*)mi)); } jl_generate_fptr_for_unspecialized(ucache); @@ -2953,7 +2954,7 @@ jl_value_t *jl_fptr_args(jl_value_t *f, jl_value_t **args, uint32_t nargs, jl_co jl_value_t *jl_fptr_sparam(jl_value_t *f, jl_value_t **args, uint32_t nargs, jl_code_instance_t *m) { - jl_svec_t *sparams = m->def->sparam_vals; + jl_svec_t *sparams = jl_get_ci_mi(m)->sparam_vals; assert(sparams != jl_emptysvec); jl_fptr_sparam_t invoke = jl_atomic_load_relaxed(&m->specptr.fptr3); assert(invoke && "Forgot to set specptr for jl_fptr_sparam!"); diff --git a/src/interpreter.c b/src/interpreter.c index a465fe27f5084..b9bd1997caa17 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -154,7 +154,7 @@ static jl_value_t *do_invoke(jl_value_t **args, size_t nargs, interpreter_state if (codeinst->owner != jl_nothing) { jl_error("Failed to invoke or compile external codeinst"); } - result = jl_invoke(argv[0], nargs == 2 ? NULL : &argv[1], nargs - 2, codeinst->def); + result = jl_invoke(argv[0], nargs == 2 ? NULL : &argv[1], nargs - 2, jl_get_ci_mi(codeinst)); } } else { result = jl_invoke(argv[0], nargs == 2 ? NULL : &argv[1], nargs - 2, (jl_method_instance_t*)c); @@ -767,7 +767,7 @@ jl_code_info_t *jl_code_for_interpreter(jl_method_instance_t *mi, size_t world) jl_value_t *NOINLINE jl_fptr_interpret_call(jl_value_t *f, jl_value_t **args, uint32_t nargs, jl_code_instance_t *codeinst) { interpreter_state *s; - jl_method_instance_t *mi = codeinst->def; + jl_method_instance_t *mi = jl_get_ci_mi(codeinst); jl_task_t *ct = jl_current_task; size_t world = ct->world_age; jl_code_info_t *src = NULL; diff --git a/src/ircode.c b/src/ircode.c index 9e64e3fe2b574..99c5833ac3be7 100644 --- a/src/ircode.c +++ b/src/ircode.c @@ -1194,7 +1194,7 @@ JL_DLLEXPORT jl_code_info_t *jl_uncompress_ir(jl_method_t *m, jl_code_instance_t ios_close(s.s); JL_UNLOCK(&m->writelock); // Might GC if (metadata) { - code->parent = metadata->def; + code->parent = jl_get_ci_mi(metadata); jl_gc_wb(code, code->parent); code->rettype = metadata->rettype; jl_gc_wb(code, code->rettype); diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index a1b01af716bb4..bdb8298df41a6 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -379,7 +379,7 @@ static int jl_analyze_workqueue(jl_code_instance_t *callee, jl_codegen_params_t jl_init_function(proto.decl, params.TargetTriple); // TODO: maybe this can be cached in codeinst->specfptr? int8_t gc_state = jl_gc_unsafe_enter(ct->ptls); // codegen may contain safepoints (such as jl_subtype calls) - jl_method_instance_t *mi = codeinst->def; + jl_method_instance_t *mi = jl_get_ci_mi(codeinst); size_t nrealargs = jl_nparams(mi->specTypes); // number of actual arguments being passed bool is_opaque_closure = jl_is_method(mi->def.value) && mi->def.method->is_for_opaque_closure; emit_specsig_to_fptr1(proto.decl, proto.cc, proto.return_roots, mi->specTypes, codeinst->rettype, is_opaque_closure, nrealargs, params, pinvoke); @@ -569,7 +569,7 @@ static void jl_compile_codeinst_now(jl_code_instance_t *codeinst) jl_ExecutionEngine->addModule(std::move(TSM)); // may safepoint // If logging of the compilation stream is enabled, // then dump the method-instance specialization type to the stream - jl_method_instance_t *mi = codeinst->def; + jl_method_instance_t *mi = jl_get_ci_mi(codeinst); if (jl_is_method(mi->def.method)) { auto stream = *jl_ExecutionEngine->get_dump_compiles_stream(); if (stream) { @@ -690,7 +690,7 @@ static void jl_emit_codeinst_to_jit( params.cache = true; params.imaging_mode = imaging_default(); orc::ThreadSafeModule result_m = - jl_create_ts_module(name_from_method_instance(codeinst->def), params.tsctx, params.DL, params.TargetTriple); + jl_create_ts_module(name_from_method_instance(jl_get_ci_mi(codeinst)), params.tsctx, params.DL, params.TargetTriple); params.temporary_roots = jl_alloc_array_1d(jl_array_any_type, 0); JL_GC_PUSH1(¶ms.temporary_roots); jl_llvm_functions_t decls = jl_emit_codeinst(result_m, codeinst, src, params); // contains safepoints @@ -698,7 +698,7 @@ static void jl_emit_codeinst_to_jit( JL_GC_POP(); return; } - jl_optimize_roots(params, codeinst->def, *result_m.getModuleUnlocked()); // contains safepoints + jl_optimize_roots(params, jl_get_ci_mi(codeinst), *result_m.getModuleUnlocked()); // contains safepoints params.temporary_roots = nullptr; JL_GC_POP(); { // drop lock before acquiring engine_lock @@ -922,14 +922,14 @@ void jl_generate_fptr_for_unspecialized_impl(jl_code_instance_t *unspec) compiler_start_time = jl_hrtime(); jl_code_info_t *src = NULL; JL_GC_PUSH1(&src); - jl_method_t *def = unspec->def->def.method; + jl_method_t *def = jl_get_ci_mi(unspec)->def.method; if (jl_is_method(def)) { src = (jl_code_info_t*)def->source; if (src && (jl_value_t*)src != jl_nothing) src = jl_uncompress_ir(def, NULL, (jl_value_t*)src); } else { - jl_method_instance_t *mi = unspec->def; + jl_method_instance_t *mi = jl_get_ci_mi(unspec); jl_code_instance_t *uninferred = jl_cached_uninferred( jl_atomic_load_relaxed(&mi->cache), 1); assert(uninferred); @@ -2234,7 +2234,7 @@ StringRef JuliaOJIT::getFunctionAtAddress(uint64_t Addr, jl_callptr_t invoke, jl else { stream_fname << "jlsys_"; } - const char* unadorned_name = jl_symbol_name(codeinst->def->def.method->name); + const char* unadorned_name = jl_symbol_name(jl_get_ci_mi(codeinst)->def.method->name); stream_fname << unadorned_name << "_" << RLST_inc++; *fname = std::move(stream_fname.str()); // store to ReverseLocalSymbolTable addGlobalMapping(*fname, Addr); diff --git a/src/jitlayers.h b/src/jitlayers.h index b6f1e9ec20c6b..342cb516debd7 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -279,6 +279,7 @@ jl_llvm_functions_t jl_emit_code( orc::ThreadSafeModule &M, jl_method_instance_t *mi, jl_code_info_t *src, + jl_value_t *abi, jl_codegen_params_t ¶ms); jl_llvm_functions_t jl_emit_codeinst( diff --git a/src/jl_exported_data.inc b/src/jl_exported_data.inc index 8711c14514145..62acce6ce1d65 100644 --- a/src/jl_exported_data.inc +++ b/src/jl_exported_data.inc @@ -116,6 +116,7 @@ XX(jl_simplevector_type) \ XX(jl_slotnumber_type) \ XX(jl_ssavalue_type) \ + XX(jl_abioverride_type) \ XX(jl_stackovf_exception) \ XX(jl_string_type) \ XX(jl_symbol_type) \ diff --git a/src/jltypes.c b/src/jltypes.c index 52b993cd5aa4d..fbdfe497ea312 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3656,7 +3656,7 @@ void jl_init_types(void) JL_GC_DISABLED "specsigflags", "precompile", "relocatability", "invoke", "specptr"), // function object decls jl_svec(18, - jl_method_instance_type, + jl_any_type, jl_any_type, jl_any_type, jl_ulong_type, @@ -3952,6 +3952,7 @@ void post_boot_hooks(void) jl_weakref_type = (jl_datatype_t*)core("WeakRef"); jl_vecelement_typename = ((jl_datatype_t*)jl_unwrap_unionall(core("VecElement")))->name; jl_nulldebuginfo = (jl_debuginfo_t*)core("NullDebugInfo"); + jl_abioverride_type = (jl_datatype_t*)core("ABIOverride"); jl_init_box_caches(); diff --git a/src/julia.h b/src/julia.h index 049416a33336f..a71f9db030274 100644 --- a/src/julia.h +++ b/src/julia.h @@ -426,7 +426,7 @@ typedef struct _jl_opaque_closure_t { // This type represents an executable operation typedef struct _jl_code_instance_t { JL_DATA_TYPE - jl_method_instance_t *def; // method this is specialized from + jl_value_t *def; // MethodInstance or ABIOverride jl_value_t *owner; // Compiler token this belongs to, `jl_nothing` is reserved for native _Atomic(struct _jl_code_instance_t*) next; // pointer to the next cache entry @@ -479,6 +479,13 @@ typedef struct _jl_code_instance_t { } specptr; // private data for `jlcall entry point } jl_code_instance_t; +// May be used as the ->def field of a CodeInstance to override the ABI +typedef struct _jl_abi_override_t { + JL_DATA_TYPE + jl_value_t *abi; + jl_method_instance_t *def; +} jl_abi_override_t; + // all values are callable as Functions typedef jl_value_t jl_function_t; @@ -935,6 +942,7 @@ extern JL_DLLIMPORT jl_datatype_t *jl_fielderror_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_atomicerror_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_missingcodeerror_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_datatype_t *jl_lineinfonode_type JL_GLOBALLY_ROOTED; +extern JL_DLLIMPORT jl_datatype_t *jl_abioverride_type JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_value_t *jl_stackovf_exception JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_value_t *jl_memory_exception JL_GLOBALLY_ROOTED; extern JL_DLLIMPORT jl_value_t *jl_readonlymemory_exception JL_GLOBALLY_ROOTED; @@ -1570,6 +1578,7 @@ static inline int jl_field_isconst(jl_datatype_t *st, int i) JL_NOTSAFEPOINT #define jl_is_llvmpointer(v) (((jl_datatype_t*)jl_typeof(v))->name == jl_llvmpointer_typename) #define jl_is_intrinsic(v) jl_typetagis(v,jl_intrinsic_type) #define jl_is_addrspacecore(v) jl_typetagis(v,jl_addrspacecore_type) +#define jl_is_abioverride(v) jl_typetagis(v,jl_abioverride_type) #define jl_genericmemory_isbitsunion(a) (((jl_datatype_t*)jl_typetagof(a))->layout->flags.arrayelem_isunion) JL_DLLEXPORT int jl_subtype(jl_value_t *a, jl_value_t *b); diff --git a/src/julia_internal.h b/src/julia_internal.h index e0e8158f8e0d9..e452ff315d527 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -693,6 +693,13 @@ JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst( uint32_t effects, jl_value_t *analysis_results, uint8_t relocatability, jl_debuginfo_t *di, jl_svec_t *edges /* , int absolute_max*/); +STATIC_INLINE jl_method_instance_t *jl_get_ci_mi(jl_code_instance_t *ci JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT +{ + if (jl_is_abioverride(ci->def)) + return ((jl_abi_override_t*)ci->def)->def; + return (jl_method_instance_t*)ci->def; +} + JL_DLLEXPORT const char *jl_debuginfo_file(jl_debuginfo_t *debuginfo) JL_NOTSAFEPOINT; JL_DLLEXPORT const char *jl_debuginfo_file1(jl_debuginfo_t *debuginfo) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_module_t *jl_debuginfo_module1(jl_value_t *debuginfo_def) JL_NOTSAFEPOINT; diff --git a/src/precompile_utils.c b/src/precompile_utils.c index 4717351d499b0..f2777455c4ed1 100644 --- a/src/precompile_utils.c +++ b/src/precompile_utils.c @@ -336,7 +336,7 @@ static void *jl_precompile_worklist(jl_array_t *worklist, jl_array_t *extext_met n = jl_array_nrows(new_ext_cis); for (i = 0; i < n; i++) { jl_code_instance_t *ci = (jl_code_instance_t*)jl_array_ptr_ref(new_ext_cis, i); - precompile_enq_specialization_(ci->def, m); + precompile_enq_specialization_(jl_get_ci_mi(ci), m); } } } diff --git a/src/staticdata.c b/src/staticdata.c index a0d56f3e38f54..ca335bd0fefee 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -101,7 +101,7 @@ extern "C" { // TODO: put WeakRefs on the weak_refs list during deserialization // TODO: handle finalizers -#define NUM_TAGS 194 +#define NUM_TAGS 195 // An array of references that need to be restored from the sysimg // This is a manually constructed dual of the gvars array, which would be produced by codegen for Julia code, for C. @@ -216,6 +216,7 @@ jl_value_t **const*const get_tags(void) { INSERT_TAG(jl_addrspace_typename); INSERT_TAG(jl_addrspacecore_type); INSERT_TAG(jl_debuginfo_type); + INSERT_TAG(jl_abioverride_type); // special typenames INSERT_TAG(jl_tuple_typename); @@ -909,13 +910,14 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_ } if (s->incremental && jl_is_code_instance(v)) { jl_code_instance_t *ci = (jl_code_instance_t*)v; + jl_method_instance_t *mi = jl_get_ci_mi(ci); // make sure we don't serialize other reachable cache entries of foreign methods // Should this now be: // if (ci !in ci->defs->cache) // record_field_change((jl_value_t**)&ci->next, NULL); // Why are we checking that the method/module this originates from is in_image? // and then disconnect this CI? - if (jl_object_in_image((jl_value_t*)ci->def->def.value)) { + if (jl_object_in_image((jl_value_t*)mi->def.value)) { // TODO: if (ci in ci->defs->cache) record_field_change((jl_value_t**)&ci->next, NULL); } @@ -923,8 +925,8 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_ if (inferred && inferred != jl_nothing) { // disregard if there is nothing here to delete (e.g. builtins, unspecialized) if (!is_relocatable_ci(&relocatable_ext_cis, ci)) record_field_change((jl_value_t**)&ci->inferred, jl_nothing); - else if (jl_is_method(ci->def->def.method) && // don't delete toplevel code - ci->def->def.method->source) { // don't delete code from optimized opaque closures that can't be reconstructed (and builtins) + else if (jl_is_method(mi->def.method) && // don't delete toplevel code + mi->def.method->source) { // don't delete code from optimized opaque closures that can't be reconstructed (and builtins) if (jl_atomic_load_relaxed(&ci->max_world) != ~(size_t)0 || // delete all code that cannot run jl_atomic_load_relaxed(&ci->invoke) == jl_fptr_const_return) { // delete all code that just returns a constant record_field_change((jl_value_t**)&ci->inferred, jl_nothing); @@ -1809,7 +1811,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED fptr_id = JL_API_CONST; } else { - if (jl_is_method(ci->def->def.method)) { + if (jl_is_method(jl_get_ci_mi(ci)->def.method)) { builtin_id = jl_fptr_id(jl_atomic_load_relaxed(&ci->specptr.fptr)); if (builtin_id) { // found in the table of builtins assert(builtin_id >= 2); @@ -2352,9 +2354,9 @@ static void jl_update_all_fptrs(jl_serializer_state *s, jl_image_t *image) offset = ~offset; } jl_code_instance_t *codeinst = (jl_code_instance_t*)(base + offset); - assert(jl_is_method(codeinst->def->def.method) && jl_atomic_load_relaxed(&codeinst->invoke) != jl_fptr_const_return); + assert(jl_is_method(jl_get_ci_mi(codeinst)->def.method) && jl_atomic_load_relaxed(&codeinst->invoke) != jl_fptr_const_return); assert(specfunc ? jl_atomic_load_relaxed(&codeinst->invoke) != NULL : jl_atomic_load_relaxed(&codeinst->invoke) == NULL); - linfos[i] = codeinst->def; // now it's a MethodInstance + linfos[i] = jl_get_ci_mi(codeinst); // now it's a MethodInstance void *fptr = fvars.ptrs[i]; for (; clone_idx < fvars.nclones; clone_idx++) { uint32_t idx = fvars.clone_idxs[clone_idx] & jl_sysimg_val_mask; diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index ea0b7216155bd..5ff7a7b1b1fc0 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -188,7 +188,7 @@ static int has_backedge_to_worklist(jl_method_instance_t *mi, htable_t *visited, jl_code_instance_t *be; i = get_next_edge(mi->backedges, i, NULL, &be); JL_GC_PROMISE_ROOTED(be); // get_next_edge propagates the edge for us here - int child_found = has_backedge_to_worklist(be->def, visited, stack); + int child_found = has_backedge_to_worklist(jl_get_ci_mi(be), visited, stack); if (child_found == 1 || child_found == 2) { // found what we were looking for, so terminate early found = 1; @@ -219,7 +219,7 @@ static int is_relocatable_ci(htable_t *relocatable_ext_cis, jl_code_instance_t * { if (!ci->relocatability) return 0; - jl_method_instance_t *mi = ci->def; + jl_method_instance_t *mi = jl_get_ci_mi(ci); jl_method_t *m = mi->def.method; if (!ptrhash_has(relocatable_ext_cis, ci) && jl_object_in_image((jl_value_t*)m) && (!jl_is_method(m) || jl_object_in_image((jl_value_t*)m->module))) return 0; @@ -249,7 +249,7 @@ static jl_array_t *queue_external_cis(jl_array_t *list) assert(jl_is_code_instance(ci)); if (!ci->relocatability) continue; - jl_method_instance_t *mi = ci->def; + 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)) { int found = has_backedge_to_worklist(mi, &visited, &stack); @@ -283,7 +283,7 @@ static void jl_collect_new_roots(htable_t *relocatable_ext_cis, jl_array_t *root for (size_t i = 0; i < l; i++) { jl_code_instance_t *ci = (jl_code_instance_t*)jl_array_ptr_ref(new_ext_cis, i); assert(jl_is_code_instance(ci)); - jl_method_t *m = ci->def->def.method; + jl_method_t *m = jl_get_ci_mi(ci)->def.method; assert(jl_is_method(m)); ptrhash_put(&mset, (void*)m, (void*)m); ptrhash_put(relocatable_ext_cis, (void*)ci, (void*)ci); @@ -864,7 +864,7 @@ static int jl_verify_method(jl_code_instance_t *codeinst, size_t *minworld, size *minworld = 1; size_t current_world = jl_atomic_load_relaxed(&jl_world_counter); *maxworld = current_world; - assert(jl_is_method_instance(codeinst->def) && jl_is_method(codeinst->def->def.method)); + assert(jl_is_method_instance(jl_get_ci_mi(codeinst)) && jl_is_method(jl_get_ci_mi(codeinst)->def.method)); void **bp = ptrhash_bp(visiting, codeinst); if (*bp != HT_NOTFOUND) return (char*)*bp - (char*)HT_NOTFOUND; // cycle idx @@ -893,7 +893,7 @@ static int jl_verify_method(jl_code_instance_t *codeinst, size_t *minworld, size size_t max_valid2; assert(!jl_is_method(edge)); // `Method`-edge isn't allowed for the optimized one-edge format if (jl_is_code_instance(edge)) - edge = (jl_value_t*)((jl_code_instance_t*)edge)->def; + edge = (jl_value_t*)jl_get_ci_mi((jl_code_instance_t*)edge); if (jl_is_method_instance(edge)) { jl_method_instance_t *mi = (jl_method_instance_t*)edge; sig = jl_type_intersection(mi->def.method->sig, (jl_value_t*)mi->specTypes); // TODO: ?? @@ -917,7 +917,7 @@ static int jl_verify_method(jl_code_instance_t *codeinst, size_t *minworld, size continue; } if (jl_is_code_instance(callee)) - callee = ((jl_code_instance_t*)callee)->def; + callee = jl_get_ci_mi((jl_code_instance_t*)callee); if (jl_is_method_instance(callee)) { meth = callee->def.method; } @@ -1048,7 +1048,7 @@ static void jl_insert_backedges(jl_array_t *edges, jl_array_t *ext_ci_list) for (size_t i = 0; i < nedges; i++) { jl_code_instance_t *codeinst = (jl_code_instance_t*)jl_array_ptr_ref(edges, i); jl_svec_t *callees = jl_atomic_load_relaxed(&codeinst->edges); - jl_method_instance_t *caller = codeinst->def; + jl_method_instance_t *caller = jl_get_ci_mi(codeinst); jl_verify_method_graph(codeinst, &stack, &visiting); size_t minvalid = jl_atomic_load_relaxed(&codeinst->min_world); size_t maxvalid = jl_atomic_load_relaxed(&codeinst->max_world); diff --git a/test/precompile.jl b/test/precompile.jl index 1607d4c6b502b..d9bbf524609c9 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -915,7 +915,7 @@ precompile_test_harness("code caching") do dir # external callers mods = Module[] for be in mi.backedges - push!(mods, (be.def.def::Method).module) # XXX + push!(mods, ((be.def::Core.MethodInstance).def::Method).module) # XXX end @test MA ∈ mods @test MB ∈ mods @@ -1837,7 +1837,7 @@ precompile_test_harness("PkgCacheInspector") do load_path m = only(external_methods).func::Method @test m.name == :repl_cmd && m.nargs < 2 @test new_ext_cis === nothing || any(new_ext_cis) do ci - mi = ci.def + mi = ci.def::Core.MethodInstance mi.specTypes == Tuple{typeof(Base.repl_cmd), Int, String} end end From ff97facbc94089f6964782f0d2b961a5c8f7b813 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Fri, 20 Dec 2024 15:30:47 +0900 Subject: [PATCH 093/342] EAUtils: perform `code_escapes` with a global cache by default (#56868) In JuliaLang/julia#56860, `EAUtils.EscapeAnalyzer` was updated to create a new cache for each invocation of `code_escapes`, similar to how Cthulhu.jl behaves. However, `code_escapes` is often used for performance analysis like `@benchmark code_escapes(...)`, and in such cases, a large number of `CodeInstance`s can be generated for each invocation. This could potentially impact native code execution. So this commit changes the default behavior so that `code_escapes` uses the same pre-existing cache by default. We can still opt-in to perform a fresh analysis by specifying `cache_token=EAUtils.EscapeAnalyzerCacheToken()`. --- Compiler/test/EAUtils.jl | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/Compiler/test/EAUtils.jl b/Compiler/test/EAUtils.jl index 64d2a62db8622..990a7de3b8141 100644 --- a/Compiler/test/EAUtils.jl +++ b/Compiler/test/EAUtils.jl @@ -19,6 +19,7 @@ using .Compiler: InferenceResult, InferenceState, OptimizationState, IRCode using .EA: analyze_escapes, ArgEscapeCache, ArgEscapeInfo, EscapeInfo, EscapeState mutable struct EscapeAnalyzerCacheToken end +global GLOBAL_EA_CACHE_TOKEN::EscapeAnalyzerCacheToken = EscapeAnalyzerCacheToken() struct EscapeResultForEntry ir::IRCode @@ -293,10 +294,10 @@ while caching the analysis results. - `world::UInt = Base.get_world_counter()`: controls the world age to use when looking up methods, use current world age if not specified. -- `cache_token::EscapeAnalyzerCacheToken = EscapeAnalyzerCacheToken()`: - specifies the cache token to use, by default a new token is generated to ensure - that `code_escapes` uses a fresh cache and performs a new analysis on each invocation. - If you with to perform analysis with the global cache enabled, specify a particular token instance. +- `cache_token::EscapeAnalyzerCacheToken = GLOBAL_EA_CACHE_TOKEN`: + specifies the cache token to use, by default a global token is used so that the analysis + can use the caches from previous invocations. If you with to use a fresh cache and perform + a new analysis, specify a new `EscapeAnalyzerCacheToken` instance. - `interp::EscapeAnalyzer = EscapeAnalyzer(world, cache_token)`: specifies the escape analyzer to use. - `debuginfo::Symbol = :none`: @@ -304,7 +305,7 @@ while caching the analysis results. """ function code_escapes(@nospecialize(f), @nospecialize(types=Base.default_tt(f)); world::UInt = get_world_counter(), - cache_token::EscapeAnalyzerCacheToken = EscapeAnalyzerCacheToken(), + cache_token::EscapeAnalyzerCacheToken = GLOBAL_EA_CACHE_TOKEN, debuginfo::Symbol = :none) tt = Base.signature_type(f, types) match = Base._which(tt; world, raise=true) @@ -314,7 +315,7 @@ end function code_escapes(mi::MethodInstance; world::UInt = get_world_counter(), - cache_token::EscapeAnalyzerCacheToken = EscapeAnalyzerCacheToken(), + cache_token::EscapeAnalyzerCacheToken = GLOBAL_EA_CACHE_TOKEN, interp::EscapeAnalyzer=EscapeAnalyzer(world, cache_token; entry_mi=mi), debuginfo::Symbol = :none) frame = Compiler.typeinf_frame(interp, mi, #=run_optimizer=#true) @@ -337,16 +338,16 @@ Note that this version does not cache the analysis results. - `world::UInt = Base.get_world_counter()`: controls the world age to use when looking up methods, use current world age if not specified. -- `cache_token::EscapeAnalyzerCacheToken = EscapeAnalyzerCacheToken()`: - specifies the cache token to use, by default a new token is generated to ensure - that `code_escapes` uses a fresh cache and performs a new analysis on each invocation. - If you with to perform analysis with the global cache enabled, specify a particular token instance. +- `cache_token::EscapeAnalyzerCacheToken = GLOBAL_EA_CACHE_TOKEN`: + specifies the cache token to use, by default a global token is used so that the analysis + can use the caches from previous invocations. If you with to use a fresh cache and perform + a new analysis, specify a new `EscapeAnalyzerCacheToken` instance. - `interp::AbstractInterpreter = EscapeAnalyzer(world, cache_token)`: specifies the abstract interpreter to use, by default a new `EscapeAnalyzer` with an empty cache is created. """ function code_escapes(ir::IRCode, nargs::Int; world::UInt = get_world_counter(), - cache_token::EscapeAnalyzerCacheToken = EscapeAnalyzerCacheToken(), + cache_token::EscapeAnalyzerCacheToken = GLOBAL_EA_CACHE_TOKEN, interp::AbstractInterpreter=EscapeAnalyzer(world, cache_token)) estate = analyze_escapes(ir, nargs, Compiler.optimizer_lattice(interp), Compiler.get_escape_cache(interp)) return EscapeResult(ir, estate) # return back the result From 083b24eaa4d5f5a0711791f16109e93d52cd6834 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 20 Dec 2024 20:38:01 +0100 Subject: [PATCH 094/342] Small ABIOverride follow up and add basic test (#56877) Just a basic `invoke` test for now. There's various other code paths that should also be tested with ABI overwrites, but this gives us the basic framework and more tests can be added as needed. --- Compiler/src/Compiler.jl | 3 ++- Compiler/src/typeinfer.jl | 3 --- Compiler/test/abioverride.jl | 52 ++++++++++++++++++++++++++++++++++++ Compiler/test/testgroups | 1 + base/reflection.jl | 13 ++++----- base/runtime_internals.jl | 11 ++++++++ src/codegen.cpp | 25 +++++++++++------ 7 files changed, 90 insertions(+), 18 deletions(-) create mode 100644 Compiler/test/abioverride.jl diff --git a/Compiler/src/Compiler.jl b/Compiler/src/Compiler.jl index 2f4efda51da9b..a9ab27a682ad7 100644 --- a/Compiler/src/Compiler.jl +++ b/Compiler/src/Compiler.jl @@ -65,7 +65,8 @@ using Base: @_foldable_meta, @_gc_preserve_begin, @_gc_preserve_end, @nospeciali kwerr, lookup_binding_partition, may_invoke_generator, methods, midpoint, moduleroot, partition_restriction, quoted, rename_unionall, rewrap_unionall, specialize_method, structdiff, tls_world_age, unconstrain_vararg_length, unionlen, uniontype_layout, - uniontypes, unsafe_convert, unwrap_unionall, unwrapva, vect, widen_diagonal + uniontypes, unsafe_convert, unwrap_unionall, unwrapva, vect, widen_diagonal, + _uncompressed_ir using Base.Order import Base: ==, _topmod, append!, convert, copy, copy!, findall, first, get, get!, diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index 2e9fcf497faf6..f7cd574abbcef 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -1092,9 +1092,6 @@ function ci_meets_requirement(code::CodeInstance, source_mode::UInt8) return false end -_uncompressed_ir(codeinst::CodeInstance, s::String) = - ccall(:jl_uncompress_ir, Ref{CodeInfo}, (Any, Any, Any), codeinst.def.def::Method, codeinst, s) - # compute (and cache) an inferred AST and return type function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance, source_mode::UInt8) start_time = ccall(:jl_typeinf_timing_begin, UInt64, ()) diff --git a/Compiler/test/abioverride.jl b/Compiler/test/abioverride.jl new file mode 100644 index 0000000000000..d35fa8876cf1c --- /dev/null +++ b/Compiler/test/abioverride.jl @@ -0,0 +1,52 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +using Base.Meta +include("irutils.jl") + +# In this test, we will manually construct a CodeInstance that specializes the `myplus` +# method on a constant for the second argument and test various, interfaces surrounding +# CodeInstances with ABI overrides. +myplus(x::Int, y::Int) = x + y + +struct SecondArgConstOverride + arg2::Int +end + +world = Base.tls_world_age() +mi = Base.specialize_method(only(Base._methods_by_ftype(Tuple{typeof(myplus), Int, Int}, -1, world))) +interp = Compiler.NativeInterpreter(world) +ci = Compiler.typeinf_ext(interp, mi, Compiler.SOURCE_MODE_FORCE_SOURCE) + +function is_known_call(@nospecialize(x), @nospecialize(func), src::Core.CodeInfo) + isexpr(x, :call) || return false + ft = Compiler.argextype(x.args[1], src, Compiler.VarState[]) + return Compiler.singleton_type(ft) === func +end + +# Construct a CodeInstance with an ABI override +new_ci = let new_source = copy(Base.uncompressed_ir(ci)) + ## Sanity check + @assert length(new_source.code) == 2 + add = new_source.code[1] + @assert is_known_call(add, Core.Intrinsics.add_int, new_source) && add.args[3] == Core.Argument(3) + + ## Replace x + y by x + 1 + add.args[3] = 1 + + ## Remove the argument + resize!(new_source.slotnames, 2) + resize!(new_source.slotflags, 2) + + # Construct the CodeInstance + new_ci = Core.CodeInstance(Core.ABIOverride(Tuple{typeof(myplus), Int}, mi), + SecondArgConstOverride(1), ci.rettype, ci.exctype, nothing, new_source, + Int32(0), ci.min_world, ci.max_world, ci.ipo_purity_bits, nothing, ci.relocatability, ci.debuginfo, ci.edges) + + # Poke the CI into the global cache + ccall(:jl_mi_cache_insert, Cvoid, (Any, Any), mi, new_ci) + + new_ci +end + +@test contains(repr(new_ci), "ABI Overridden") +@test invoke(myplus, new_ci, 10) == 11 diff --git a/Compiler/test/testgroups b/Compiler/test/testgroups index 5075caa8b34cf..d17735a52a025 100644 --- a/Compiler/test/testgroups +++ b/Compiler/test/testgroups @@ -15,3 +15,4 @@ ssair tarjan validation special_loading +abioverride diff --git a/base/reflection.jl b/base/reflection.jl index 9246b4cb0ac71..be344648f8f52 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -131,12 +131,13 @@ isempty(mt::Core.MethodTable) = (mt.defs === nothing) uncompressed_ir(m::Method) = isdefined(m, :source) ? _uncompressed_ir(m) : isdefined(m, :generator) ? error("Method is @generated; try `code_lowered` instead.") : error("Code for this Method is not available.") -function _uncompressed_ir(m::Method) - s = m.source - if s isa String - s = ccall(:jl_uncompress_ir, Ref{CodeInfo}, (Any, Ptr{Cvoid}, Any), m, C_NULL, s) - end - return s::CodeInfo + +function uncompressed_ir(ci::CodeInstance) + inferred = ci.inferred + isa(inferred, CodeInfo) && return inferred + isa(inferred, String) && return _uncompressed_ir(ci, inferred) + inferred === nothing && error("Inferred code was deleted.") + error(string("Unknown inferred code type ", typeof(inferred))) end # for backwards compat diff --git a/base/runtime_internals.jl b/base/runtime_internals.jl index cbbde7d9535a2..13c467667c51e 100644 --- a/base/runtime_internals.jl +++ b/base/runtime_internals.jl @@ -1391,6 +1391,17 @@ end hasgenerator(m::Method) = isdefined(m, :generator) hasgenerator(m::Core.MethodInstance) = hasgenerator(m.def::Method) +function _uncompressed_ir(m::Method) + s = m.source + if s isa String + s = ccall(:jl_uncompress_ir, Ref{CodeInfo}, (Any, Ptr{Cvoid}, Any), m, C_NULL, s) + end + return s::CodeInfo +end + +_uncompressed_ir(codeinst::CodeInstance, s::String) = + ccall(:jl_uncompress_ir, Ref{CodeInfo}, (Any, Any, Any), codeinst.def.def::Method, codeinst, s) + """ Base.generating_output([incremental::Bool])::Bool diff --git a/src/codegen.cpp b/src/codegen.cpp index 9ae905a8aba32..5bf7c74deedcb 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5440,6 +5440,22 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, jl_method_instance_ specFunctionObject, fromexternal, argv, nargs, cc, return_roots, inferred_retty, age_ok); } +static jl_value_t *get_ci_abi(jl_code_instance_t *ci) +{ + if (jl_typeof(ci->def) == (jl_value_t*)jl_abioverride_type) + return ((jl_abi_override_t*)ci->def)->abi; + return jl_get_ci_mi(ci)->specTypes; +} + +static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, jl_code_instance_t *ci, jl_value_t *jlretty, StringRef specFunctionObject, jl_code_instance_t *fromexternal, + ArrayRef argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *return_roots, jl_value_t *inferred_retty, Value *age_ok) +{ + jl_method_instance_t *mi = jl_get_ci_mi(ci); + bool is_opaque_closure = jl_is_method(mi->def.value) && mi->def.method->is_for_opaque_closure; + return emit_call_specfun_other(ctx, is_opaque_closure, get_ci_abi(ci), jlretty, NULL, + specFunctionObject, fromexternal, argv, nargs, cc, return_roots, inferred_retty, age_ok); +} + static jl_cgval_t emit_call_specfun_boxed(jl_codectx_t &ctx, jl_value_t *jlretty, StringRef specFunctionObject, jl_code_instance_t *fromexternal, ArrayRef argv, size_t nargs, jl_value_t *inferred_retty, Value *age_ok) { @@ -5487,13 +5503,6 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, jl_expr_t *ex, jl_value_t *rt) return emit_invoke(ctx, lival, argv, nargs, rt, nullptr); } -static jl_value_t *get_ci_abi(jl_code_instance_t *ci) -{ - if (jl_typeof(ci->def) == (jl_value_t*)jl_abioverride_type) - return ((jl_abi_override_t*)ci->def)->abi; - return jl_get_ci_mi(ci)->specTypes; -} - static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayRef argv, size_t nargs, jl_value_t *rt, Value *age_ok) { ++EmittedInvokes; @@ -5589,7 +5598,7 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayR jl_returninfo_t::CallingConv cc = jl_returninfo_t::CallingConv::Boxed; unsigned return_roots = 0; if (specsig) - result = emit_call_specfun_other(ctx, mi, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, &cc, &return_roots, rt, age_ok); + result = emit_call_specfun_other(ctx, codeinst, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, &cc, &return_roots, rt, age_ok); else result = emit_call_specfun_boxed(ctx, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, rt, age_ok); handled = true; From bb1892ebac9f4406a1360afa0d2882751792335b Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Sat, 21 Dec 2024 17:12:27 +0100 Subject: [PATCH 095/342] Package docstring: more peaceful README introduction (#56798) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hello! 👋 #39093 is great! This PR styles the banner ("Displaying contents of readme found at ...") differently: Before: ``` help?> DifferentialEquations search: DifferentialEquations No docstring found for module DifferentialEquations. Exported names ≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡ @derivatives, @ode_def, @ode_def_all, @ode_def_bare, ... (manually truncated) Displaying contents of readme found at /Users/ian/.julia/packages/DifferentialEquations/HSWeG/README.md ≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡ DifferentialEquations.jl ≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡ (Image: Join the chat at https://gitter.im/JuliaDiffEq/Lobby) (https://gitter.im/JuliaDiffEq/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) (Image: Build Status) (https://github.com/SciML/DifferentialEquations.jl/actions?query=workflow%3ACI) (Image: Stable) (http://diffeq.sciml.ai/stable/) (Image: Dev) (http://diffeq.sciml.ai/dev/) (Image: DOI) (https://zenodo.org/badge/latestdoi/58516043) This is a suite for numerically solving differential equations written in Julia and available for use in Julia, Python, and R. The purpose of this package is to supply efficient Julia implementations of solvers for various differential equations. Equations within the realm of this package include: • Discrete equations (function maps, discrete stochastic (Gillespie/Markov) simulations) • Ordinary differential equations (ODEs) ``` After: ``` help?> DifferentialEquations search: DifferentialEquations No docstring found for module DifferentialEquations. Exported names ≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡ @derivatives, @ode_def, @ode_def_all, @ode_def_bare, ... (manually truncated) ──────────────────────────────────────────────────────────────────────────── Package description from README.md: DifferentialEquations.jl ≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡ (Image: Join the chat at https://gitter.im/JuliaDiffEq/Lobby) (https://gitter.im/JuliaDiffEq/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) (Image: Build Status) (https://github.com/SciML/DifferentialEquations.jl/actions?query=workflow%3ACI) (Image: Stable) (http://diffeq.sciml.ai/stable/) (Image: Dev) (http://diffeq.sciml.ai/dev/) (Image: DOI) (https://zenodo.org/badge/latestdoi/58516043) This is a suite for numerically solving differential equations written in Julia and available for use in Julia, Python, and R. The purpose of this package is to supply efficient Julia implementations of solvers for various differential equations. Equations within the realm of this package include: • Discrete equations (function maps, discrete stochastic (Gillespie/Markov) simulations) • Ordinary differential equations (ODEs) ``` I think this makes it a bit less technical (the word "Displaying" and the long filename), and it improves the reading flow. --- stdlib/REPL/src/docview.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stdlib/REPL/src/docview.jl b/stdlib/REPL/src/docview.jl index 566046f325499..0868d3e80c824 100644 --- a/stdlib/REPL/src/docview.jl +++ b/stdlib/REPL/src/docview.jl @@ -416,7 +416,9 @@ function summarize(io::IO, m::Module, binding::Binding; nlines::Int = 200) if !isnothing(readme_path) readme_lines = readlines(readme_path) isempty(readme_lines) && return # don't say we are going to print empty file - println(io, "# Displaying contents of readme found at `$(readme_path)`") + println(io) + println(io, "---") + println(io, "_Package description from `$(basename(readme_path))`:_") for line in first(readme_lines, nlines) println(io, line) end From b772be322f737b7af15874ee49c0cb23218f211a Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Sun, 22 Dec 2024 03:21:01 +0530 Subject: [PATCH 096/342] Support indexing `Broadcasted` objects using `Integer`s (#56470) This adds support for `IndexLinear` `eachindex`, as well as bounds-checking and `getindex` for a `Broadcasted` with an `Integer` index. Instead of using the number of dimensions in `eachindex` to determine whether to use `CartesianIndices`, we may use the `IndexStyle`. This should not change anything currently, but this adds the possibility of `nD` broadcasting using linear indexing if the `IndexStyle` of the `Broadcasted` object is `IndexLinear`. After this, ```julia julia> bc = Broadcast.broadcasted(+, reshape(1:4, 2, 2), 1:2) Base.Broadcast.Broadcasted(+, ([1 3; 2 4], 1:2)) julia> eachindex(bc) CartesianIndices((2, 2)) julia> eachindex(IndexLinear(), bc) Base.OneTo(4) julia> [bc[I] for I in eachindex(IndexLinear(), bc)] 4-element Vector{Int64}: 2 4 4 6 julia> vec(collect(bc)) 4-element Vector{Int64}: 2 4 4 6 ``` This PR doesn't add true linear indexing support for `IndexCartesian` `Broadcasted` objects. In such cases, an `Integer` index is converted to a `CartesianIndex` before it is used in indexing. --- base/broadcast.jl | 26 +++++++++++++++++++++----- test/broadcast.jl | 25 +++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/base/broadcast.jl b/base/broadcast.jl index 927c946e53e02..7f278fc1ca66f 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -250,9 +250,11 @@ BroadcastStyle(::Type{<:Broadcasted{S}}) where {S<:Union{Nothing,Unknown}} = argtype(::Type{BC}) where {BC<:Broadcasted} = fieldtype(BC, :args) argtype(bc::Broadcasted) = argtype(typeof(bc)) -@inline Base.eachindex(bc::Broadcasted) = _eachindex(axes(bc)) -_eachindex(t::Tuple{Any}) = t[1] -_eachindex(t::Tuple) = CartesianIndices(t) +@inline Base.eachindex(bc::Broadcasted) = eachindex(IndexStyle(bc), bc) +@inline Base.eachindex(s::IndexStyle, bc::Broadcasted) = _eachindex(s, axes(bc)) +_eachindex(::IndexCartesian, t::Tuple) = CartesianIndices(t) +_eachindex(s::IndexLinear, t::Tuple) = eachindex(s, LinearIndices(t)) +_eachindex(::IndexLinear, t::Tuple{Any}) = t[1] Base.IndexStyle(bc::Broadcasted) = IndexStyle(typeof(bc)) Base.IndexStyle(::Type{<:Broadcasted{<:Any,<:Tuple{Any}}}) = IndexLinear() @@ -604,18 +606,32 @@ Base.@propagate_inbounds _newindex(ax::Tuple{}, I::Tuple{}) = () (Base.length(ind1)::Integer != 1, keep...), (first(ind1), Idefault...) end -@inline function Base.getindex(bc::Broadcasted, Is::Vararg{Union{Integer,CartesianIndex},N}) where {N} +Base.@propagate_inbounds function Base.getindex(bc::Broadcasted, Is::Vararg{Union{Integer,CartesianIndex},N}) where {N} I = to_index(Base.IteratorsMD.flatten(Is)) + _getindex(IndexStyle(bc), bc, I) +end +@inline function _getindex(::IndexStyle, bc, I) @boundscheck checkbounds(bc, I) @inbounds _broadcast_getindex(bc, I) end +Base.@propagate_inbounds function _getindex(s::IndexCartesian, bc, I::Integer) + C = CartesianIndices(axes(bc)) + _getindex(s, bc, C[I]) +end +Base.@propagate_inbounds function _getindex(s::IndexLinear, bc, I::CartesianIndex) + L = LinearIndices(axes(bc)) + _getindex(s, bc, L[I]) +end to_index(::Tuple{}) = CartesianIndex() to_index(Is::Tuple{Any}) = Is[1] to_index(Is::Tuple) = CartesianIndex(Is) -@inline Base.checkbounds(bc::Broadcasted, I::Union{Integer,CartesianIndex}) = +@inline Base.checkbounds(bc::Broadcasted, I::CartesianIndex) = Base.checkbounds_indices(Bool, axes(bc), (I,)) || Base.throw_boundserror(bc, (I,)) +@inline Base.checkbounds(bc::Broadcasted, I::Integer) = + Base.checkindex(Bool, eachindex(IndexLinear(), bc), I) || Base.throw_boundserror(bc, (I,)) + """ _broadcast_getindex(A, I) diff --git a/test/broadcast.jl b/test/broadcast.jl index b2232258744ac..57441de67c0ce 100644 --- a/test/broadcast.jl +++ b/test/broadcast.jl @@ -876,6 +876,31 @@ let @test copy(bc) == [v for v in bc] == collect(bc) @test eltype(copy(bc)) == eltype([v for v in bc]) == eltype(collect(bc)) @test ndims(copy(bc)) == ndims([v for v in bc]) == ndims(collect(bc)) == ndims(bc) + + struct MyFill{T,N} <: AbstractArray{T,N} + val :: T + sz :: NTuple{N,Int} + end + Base.size(M::MyFill) = M.sz + function Base.getindex(M::MyFill{<:Any,N}, i::Vararg{Int, N}) where {N} + checkbounds(M, i...) + M.val + end + Base.IndexStyle(::Type{<:Base.Broadcast.Broadcasted{<:Any,<:Any,<:Any,<:Tuple{MyFill}}}) = IndexLinear() + bc = Broadcast.instantiate(Broadcast.broadcasted(+, MyFill(2, (3,3)))) + @test IndexStyle(bc) == IndexLinear() + @test eachindex(bc) === Base.OneTo(9) + @test bc[2] == bc[CartesianIndex(2,1)] + + for bc in Any[ + Broadcast.broadcasted(+, collect(reshape(1:9, 3, 3)), 1:3), # IndexCartesian + Broadcast.broadcasted(+, [1,2], 2), # IndexLinear + ] + bci = Broadcast.instantiate(bc) + for (Ilin, Icart) in zip(eachindex(IndexLinear(), bc), eachindex(IndexCartesian(), bc)) + @test bc[Ilin] == bc[Icart] + end + end end # issue 43847: collect preserves shape of broadcasted From 9d80765516d15b662ecccce40d95943fde205205 Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Sun, 22 Dec 2024 03:49:49 +0530 Subject: [PATCH 097/342] Limit the scope of `@inbounds` in `searchsorted*` (#56882) This removes bounds-checking only in the indexing operation, instead of for the entire block. --- base/sort.jl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/base/sort.jl b/base/sort.jl index e1d46a8ba20ae..e1680d545bdc6 100644 --- a/base/sort.jl +++ b/base/sort.jl @@ -186,10 +186,10 @@ partialsort(v::AbstractVector, k::Union{Integer,OrdinalRange}; kws...) = function searchsortedfirst(v::AbstractVector, x, lo::T, hi::T, o::Ordering)::keytype(v) where T<:Integer hi = hi + T(1) len = hi - lo - @inbounds while len != 0 + while len != 0 half_len = len >>> 0x01 m = lo + half_len - if lt(o, v[m], x) + if lt(o, @inbounds(v[m]), x) lo = m + 1 len -= half_len + 1 else @@ -206,9 +206,9 @@ function searchsortedlast(v::AbstractVector, x, lo::T, hi::T, o::Ordering)::keyt u = T(1) lo = lo - u hi = hi + u - @inbounds while lo != hi - u + while lo != hi - u m = midpoint(lo, hi) - if lt(o, x, v[m]) + if lt(o, x, @inbounds(v[m])) hi = m else lo = m @@ -224,11 +224,11 @@ function searchsorted(v::AbstractVector, x, ilo::T, ihi::T, o::Ordering)::UnitRa u = T(1) lo = ilo - u hi = ihi + u - @inbounds while lo != hi - u + while lo != hi - u m = midpoint(lo, hi) - if lt(o, v[m], x) + if lt(o, @inbounds(v[m]), x) lo = m - elseif lt(o, x, v[m]) + elseif lt(o, x, @inbounds(v[m])) hi = m else a = searchsortedfirst(v, x, lo+u, m, o) From 5ee67b85513fc3e1a7bc4608bc850c6c046ccc07 Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Sun, 22 Dec 2024 18:25:27 +0530 Subject: [PATCH 098/342] Remove trailing comma in 0-dim `reshape` summary (#56853) Currently, there is an extra comma in displaying the summary for a 0-dim `ReshapedArray`: ```julia julia> reshape(1:1) 0-dimensional reshape(::UnitRange{Int64}, ) with eltype Int64: 1 ``` This PR only prints the comma if `dims` isn't empty, so that we now obtain ```julia julia> reshape(1:1) 0-dimensional reshape(::UnitRange{Int64}) with eltype Int64: 1 ``` --- base/show.jl | 4 +++- test/show.jl | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/base/show.jl b/base/show.jl index d2f43e1ae92cc..5b121fdac5e80 100644 --- a/base/show.jl +++ b/base/show.jl @@ -3265,7 +3265,9 @@ showindices(io) = nothing function showarg(io::IO, r::ReshapedArray, toplevel) print(io, "reshape(") showarg(io, parent(r), false) - print(io, ", ", join(r.dims, ", ")) + if !isempty(r.dims) + print(io, ", ", join(r.dims, ", ")) + end print(io, ')') toplevel && print(io, " with eltype ", eltype(r)) return nothing diff --git a/test/show.jl b/test/show.jl index 07916c249d533..75f04c1e02096 100644 --- a/test/show.jl +++ b/test/show.jl @@ -1861,6 +1861,9 @@ end B = @view ones(2)[r] Base.showarg(io, B, false) @test String(take!(io)) == "view(::Vector{Float64}, $(repr(r)))" + + Base.showarg(io, reshape(UnitRange{Int64}(1,1)), false) + @test String(take!(io)) == "reshape(::UnitRange{Int64})" end @testset "Methods" begin From cc4122caea994427177d3b8ad2b18585cb2d96e9 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sun, 22 Dec 2024 21:02:59 +0100 Subject: [PATCH 099/342] Switch debug registry mapping to `CodeInstance` (#56878) Currently our debugging code maps from pointers to `MethodInstance`. However, I think it makes more sense to map to `CodeInstance` instead, since that's what we're actually compiling and as we're starting to make more use of external owners and custom specializations, we'll want to be able to annotate that in backtraces. This only adjusts the internal data structures - any actual printing changes for those sorts of use cases will have to come separately. --- base/errorshow.jl | 12 +++---- base/stacktraces.jl | 71 +++++++++++++++++++++++++++++++----------- src/debug-registry.h | 8 ++--- src/debuginfo.cpp | 33 +++++++++----------- src/julia_internal.h | 2 +- src/stackwalk.c | 2 +- test/opaque_closure.jl | 9 ++++-- test/stacktraces.jl | 7 +++-- 8 files changed, 88 insertions(+), 56 deletions(-) diff --git a/base/errorshow.jl b/base/errorshow.jl index 70ac8105feb21..d4b9b3666fbb7 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -915,9 +915,9 @@ function _collapse_repeated_frames(trace) [3] g(x::Int64) <-- useless @ Main ./REPL[1]:1 =# - if frame.linfo isa MethodInstance && last_frame.linfo isa MethodInstance && - frame.linfo.def isa Method && last_frame.linfo.def isa Method - m, last_m = frame.linfo.def::Method, last_frame.linfo.def::Method + m, last_m = StackTraces.frame_method_or_module(frame), + StackTraces.frame_method_or_module(last_frame) + if m isa Method && last_m isa Method params, last_params = Base.unwrap_unionall(m.sig).parameters, Base.unwrap_unionall(last_m.sig).parameters if last_m.nkw != 0 pos_sig_params = last_params[(last_m.nkw+2):end] @@ -944,7 +944,6 @@ function _collapse_repeated_frames(trace) return trace[kept_frames] end - function process_backtrace(t::Vector, limit::Int=typemax(Int); skipC = true) n = 0 last_frame = StackTraces.UNKNOWN @@ -965,9 +964,8 @@ function process_backtrace(t::Vector, limit::Int=typemax(Int); skipC = true) if (lkup.from_c && skipC) continue end - code = lkup.linfo - if code isa MethodInstance - def = code.def + if lkup.linfo isa Union{MethodInstance, CodeInstance} + def = StackTraces.frame_method_or_module(lkup) if def isa Method && def.name !== :kwcall && def.sig <: Tuple{typeof(Core.kwcall),NamedTuple,Any,Vararg} # hide kwcall() methods, which are probably internal keyword sorter methods # (we print the internal method instead, after demangling diff --git a/base/stacktraces.jl b/base/stacktraces.jl index e16757541cfc9..01e8a3cf62e72 100644 --- a/base/stacktraces.jl +++ b/base/stacktraces.jl @@ -7,7 +7,7 @@ module StackTraces import Base: hash, ==, show -import Core: CodeInfo, MethodInstance +import Core: CodeInfo, MethodInstance, CodeInstance using Base.IRShow: normalize_method_name, append_scopes!, LineInfoNode export StackTrace, StackFrame, stacktrace @@ -21,9 +21,9 @@ Stack information representing execution context, with the following fields: The name of the function containing the execution context. -- `linfo::Union{Method, Core.MethodInstance, Core.CodeInfo, Nothing}` +- `linfo::Union{Method, Core.MethodInstance, Core.CodeInstance, Core.CodeInfo, Nothing}` - The Method, MethodInstance, or CodeInfo containing the execution context (if it could be found), \ + The Method, MethodInstance, CodeInstance, or CodeInfo containing the execution context (if it could be found), \ or nothing (for example, if the inlining was a result of macro expansion). - `file::Symbol` @@ -54,9 +54,9 @@ struct StackFrame # this type should be kept platform-agnostic so that profiles file::Symbol "the line number in the file containing the execution context" line::Int - "the MethodInstance or CodeInfo containing the execution context (if it could be found), \ + "the CodeInstance or CodeInfo containing the execution context (if it could be found), \ or nothing (for example, if the inlining was a result of macro expansion)." - linfo::Union{MethodInstance, Method, CodeInfo, Nothing} + linfo::Union{Core.MethodInstance, Core.CodeInstance, Method, CodeInfo, Nothing} "true if the code is from C" from_c::Bool "true if the code is from an inlined frame" @@ -137,16 +137,26 @@ function lookup(ip::Base.InterpreterIP) line = meth.line codeinfo = meth.source else + func = top_level_scope_sym + file = empty_sym + line = Int32(0) if code isa Core.CodeInstance codeinfo = code.inferred::CodeInfo + def = code.def + if isa(def, Core.ABIOverride) + def = def.def + end + if isa(def, MethodInstance) && isa(def.def, Method) + meth = def.def + func = meth.name + file = meth.file + line = meth.line + end else codeinfo = code::CodeInfo end - func = top_level_scope_sym - file = empty_sym - line = Int32(0) end - def = (code isa MethodInstance ? code : StackTraces) # Module just used as a token for top-level code + def = (code isa CodeInfo ? StackTraces : code) # Module just used as a token for top-level code pc::Int = max(ip.stmt + 1, 0) # n.b. ip.stmt is 0-indexed scopes = LineInfoNode[] append_scopes!(scopes, pc, codeinfo.debuginfo, def) @@ -157,7 +167,7 @@ function lookup(ip::Base.InterpreterIP) scopes = map(scopes) do lno if inlined def = lno.method - def isa Union{Method,MethodInstance} || (def = nothing) + def isa Union{Method,Core.CodeInstance,MethodInstance} || (def = nothing) else def = codeinfo end @@ -227,6 +237,23 @@ end is_top_level_frame(f::StackFrame) = f.linfo isa CodeInfo || (f.linfo === nothing && f.func === top_level_scope_sym) +function frame_method_or_module(lkup::StackFrame) + code = lkup.linfo + code isa Method && return code + code isa Module && return code + mi = frame_mi(lkup) + mi isa MethodInstance || return nothing + return mi.def +end + +function frame_mi(lkup::StackFrame) + code = lkup.linfo + code isa Core.CodeInstance && (code = code.def) + code isa Core.ABIOverride && (code = code.def) + code isa MethodInstance || return nothing + return code +end + function show_spec_linfo(io::IO, frame::StackFrame) linfo = frame.linfo if linfo === nothing @@ -241,16 +268,18 @@ function show_spec_linfo(io::IO, frame::StackFrame) print(io, "top-level scope") elseif linfo isa Module Base.print_within_stacktrace(io, Base.demangle_function_name(string(frame.func)), bold=true) - elseif linfo isa MethodInstance - def = linfo.def - if def isa Module - Base.show_mi(io, linfo, #=from_stackframe=#true) + else + if linfo isa Union{MethodInstance, CodeInstance} + def = frame_method_or_module(frame) + if def isa Module + Base.show_mi(io, linfo, #=from_stackframe=#true) + else + show_spec_sig(io, def, frame_mi(frame).specTypes) + end else - show_spec_sig(io, def, linfo.specTypes) + m = linfo::Method + show_spec_sig(io, m, m.sig) end - else - m = linfo::Method - show_spec_sig(io, m, m.sig) end end @@ -302,6 +331,12 @@ end function Base.parentmodule(frame::StackFrame) linfo = frame.linfo + if linfo isa CodeInstance + linfo = linfo.def + if isa(linfo, Core.ABIOverride) + linfo = linfo.def + end + end if linfo isa MethodInstance def = linfo.def if def isa Module diff --git a/src/debug-registry.h b/src/debug-registry.h index 4d0b7a44f19e5..72189c60d3d40 100644 --- a/src/debug-registry.h +++ b/src/debug-registry.h @@ -14,7 +14,7 @@ typedef struct { int64_t slide; } objfileentry_t; -// Central registry for resolving function addresses to `jl_method_instance_t`s and +// Central registry for resolving function addresses to `jl_code_instance_t`s and // originating `ObjectFile`s (for the DWARF debug info). // // A global singleton instance is notified by the JIT whenever a new object is emitted, @@ -82,7 +82,7 @@ class JITDebugInfoRegistry struct image_info_t { uint64_t base; jl_image_fptrs_t fptrs; - jl_method_instance_t **fvars_linfo; + jl_code_instance_t **fvars_cinst; size_t fvars_n; }; @@ -124,7 +124,7 @@ class JITDebugInfoRegistry typedef rev_map objfilemap_t; objectmap_t objectmap{}; - rev_map> linfomap{}; + rev_map> cimap{}; // Maintain a mapping of unrealized function names -> linfo objects // so that when we see it get emitted, we can add a link back to the linfo @@ -145,7 +145,7 @@ class JITDebugInfoRegistry libc_frames_t libc_frames{}; void add_code_in_flight(llvm::StringRef name, jl_code_instance_t *codeinst, const llvm::DataLayout &DL) JL_NOTSAFEPOINT; - jl_method_instance_t *lookupLinfo(size_t pointer) JL_NOTSAFEPOINT; + jl_code_instance_t *lookupCodeInstance(size_t pointer) JL_NOTSAFEPOINT; void registerJITObject(const llvm::object::ObjectFile &Object, std::function getLoadAddress) JL_NOTSAFEPOINT; objectmap_t& getObjectMap() JL_NOTSAFEPOINT; diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index ce8406bf91490..c16fb559a6516 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -94,12 +94,12 @@ void JITDebugInfoRegistry::add_code_in_flight(StringRef name, jl_code_instance_t (**codeinst_in_flight)[mangle(name, DL)] = codeinst; } -jl_method_instance_t *JITDebugInfoRegistry::lookupLinfo(size_t pointer) +jl_code_instance_t *JITDebugInfoRegistry::lookupCodeInstance(size_t pointer) { jl_lock_profile(); - auto region = linfomap.lower_bound(pointer); - jl_method_instance_t *linfo = NULL; - if (region != linfomap.end() && pointer < region->first + region->second.first) + auto region = cimap.lower_bound(pointer); + jl_code_instance_t *linfo = NULL; + if (region != cimap.end() && pointer < region->first + region->second.first) linfo = region->second.second; jl_unlock_profile(); return linfo; @@ -371,14 +371,9 @@ void JITDebugInfoRegistry::registerJITObject(const object::ObjectFile &Object, codeinst_in_flight.erase(codeinst_it); } } - jl_method_instance_t *mi = NULL; - if (codeinst) { - JL_GC_PROMISE_ROOTED(codeinst); - mi = jl_get_ci_mi(codeinst); - } jl_profile_atomic([&]() JL_NOTSAFEPOINT { - if (mi) - linfomap[Addr] = std::make_pair(Size, mi); + if (codeinst) + cimap[Addr] = std::make_pair(Size, codeinst); hassection = true; objectmap.insert(std::pair{SectionLoadAddr, SectionInfo{ ObjectCopy, @@ -506,7 +501,7 @@ static int lookup_pointer( std::size_t semi_pos = func_name.find(';'); if (semi_pos != std::string::npos) { func_name = func_name.substr(0, semi_pos); - frame->linfo = NULL; // Looked up on Julia side + frame->ci = NULL; // Looked up on Julia side } } } @@ -692,9 +687,9 @@ openDebugInfo(StringRef debuginfopath, const debug_link_info &info) JL_NOTSAFEPO } extern "C" JL_DLLEXPORT_CODEGEN void jl_register_fptrs_impl(uint64_t image_base, const jl_image_fptrs_t *fptrs, - jl_method_instance_t **linfos, size_t n) + jl_code_instance_t **cinfos, size_t n) { - getJITDebugRegistry().add_image_info({(uintptr_t) image_base, *fptrs, linfos, n}); + getJITDebugRegistry().add_image_info({(uintptr_t) image_base, *fptrs, cinfos, n}); } template @@ -1177,13 +1172,13 @@ static int jl_getDylibFunctionInfo(jl_frame_t **frames, size_t pointer, int skip if (saddr == image.fptrs.clone_ptrs[i]) { uint32_t idx = image.fptrs.clone_idxs[i] & jl_sysimg_val_mask; if (idx < image.fvars_n) // items after this were cloned but not referenced directly by a method (such as our ccall PLT thunks) - frame0->linfo = image.fvars_linfo[idx]; + frame0->ci = image.fvars_cinst[idx]; break; } } for (size_t i = 0; i < image.fvars_n; i++) { if (saddr == image.fptrs.ptrs[i]) { - frame0->linfo = image.fvars_linfo[i]; + frame0->ci = image.fvars_cinst[i]; break; } } @@ -1255,16 +1250,16 @@ extern "C" JL_DLLEXPORT_CODEGEN int jl_getFunctionInfo_impl(jl_frame_t **frames_ int64_t slide; uint64_t symsize; if (jl_DI_for_fptr(pointer, &symsize, &slide, &Section, &context)) { - frames[0].linfo = getJITDebugRegistry().lookupLinfo(pointer); + frames[0].ci = getJITDebugRegistry().lookupCodeInstance(pointer); int nf = lookup_pointer(Section, context, frames_out, pointer, slide, true, noInline); return nf; } return jl_getDylibFunctionInfo(frames_out, pointer, skipC, noInline); } -extern "C" jl_method_instance_t *jl_gdblookuplinfo(void *p) JL_NOTSAFEPOINT +extern "C" jl_code_instance_t *jl_gdblookupci(void *p) JL_NOTSAFEPOINT { - return getJITDebugRegistry().lookupLinfo((size_t)p); + return getJITDebugRegistry().lookupCodeInstance((size_t)p); } #if defined(_OS_DARWIN_) && defined(LLVM_SHLIB) diff --git a/src/julia_internal.h b/src/julia_internal.h index e452ff315d527..f0debd31e2fec 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -1349,7 +1349,7 @@ typedef struct { char *func_name; char *file_name; int line; - jl_method_instance_t *linfo; + jl_code_instance_t *ci; int fromC; int inlined; } jl_frame_t; diff --git a/src/stackwalk.c b/src/stackwalk.c index d6fca2c909f23..28adef030395e 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -624,7 +624,7 @@ JL_DLLEXPORT jl_value_t *jl_lookup_code_address(void *ip, int skipC) jl_svecset(r, 1, jl_empty_sym); free(frame.file_name); jl_svecset(r, 2, jl_box_long(frame.line)); - jl_svecset(r, 3, frame.linfo != NULL ? (jl_value_t*)frame.linfo : jl_nothing); + jl_svecset(r, 3, frame.ci != NULL ? (jl_value_t*)frame.ci : jl_nothing); jl_svecset(r, 4, jl_box_bool(frame.fromC)); jl_svecset(r, 5, jl_box_bool(frame.inlined)); } diff --git a/test/opaque_closure.jl b/test/opaque_closure.jl index 79c456de127bd..6c988b068a668 100644 --- a/test/opaque_closure.jl +++ b/test/opaque_closure.jl @@ -347,9 +347,12 @@ let (bt, did_gc) = make_oc_and_collect_bt() GC.gc(true); GC.gc(true); GC.gc(true); @test did_gc[] @test any(stacktrace(bt)) do frame - isa(frame.linfo, Core.MethodInstance) || return false - isa(frame.linfo.def, Method) || return false - return frame.linfo.def.is_for_opaque_closure + li = frame.linfo + isa(li, Core.CodeInstance) && (li = li.def) + isa(li, Core.ABIOverride) && (li = li.def) + isa(li, Core.MethodInstance) || return false + isa(li.def, Method) || return false + return li.def.is_for_opaque_closure end end diff --git a/test/stacktraces.jl b/test/stacktraces.jl index 12da6d571013e..ca553c2a2e801 100644 --- a/test/stacktraces.jl +++ b/test/stacktraces.jl @@ -92,9 +92,10 @@ can_inline = Bool(Base.JLOptions().can_inline) for (frame, func, inlined) in zip(trace, [g,h,f], (can_inline, can_inline, false)) @test frame.func === typeof(func).name.mt.name # broken until #50082 can be addressed - @test frame.linfo.def.module === which(func, (Any,)).module broken=inlined - @test frame.linfo.def === which(func, (Any,)) broken=inlined - @test frame.linfo.specTypes === Tuple{typeof(func), Int} broken=inlined + mi = isa(frame.linfo, Core.CodeInstance) ? frame.linfo.def : frame.linfo + @test mi.def.module === which(func, (Any,)).module broken=inlined + @test mi.def === which(func, (Any,)) broken=inlined + @test mi.specTypes === Tuple{typeof(func), Int} broken=inlined # line @test frame.file === Symbol(@__FILE__) @test !frame.from_c From 34c30dcf46afc0564b58f9a116b2017c026af61d Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Sun, 22 Dec 2024 17:17:01 -0500 Subject: [PATCH 100/342] binaryplatforms.jl: Remove duplicated riscv64 entry (#56888) --- base/binaryplatforms.jl | 3 --- 1 file changed, 3 deletions(-) diff --git a/base/binaryplatforms.jl b/base/binaryplatforms.jl index a372137edeb98..598b618f0d1ed 100644 --- a/base/binaryplatforms.jl +++ b/base/binaryplatforms.jl @@ -631,9 +631,6 @@ const arch_march_isa_mapping = let "a64fx" => get_set("aarch64", "a64fx"), "apple_m1" => get_set("aarch64", "apple_m1"), ], - "riscv64" => [ - "riscv64" => get_set("riscv64", "riscv64") - ], "powerpc64le" => [ "power8" => get_set("powerpc64le", "power8"), ], From ccfeb938caa7c244cb63e1d6f24400180fb9ea78 Mon Sep 17 00:00:00 2001 From: abhro <5664668+abhro@users.noreply.github.com> Date: Sun, 22 Dec 2024 19:32:40 -0500 Subject: [PATCH 101/342] Minor documentation updates (#56883) - Array/Vector/Matrix output showing - Syntax highlighting for fenced code block examples --------- Co-authored-by: Chengyu Han Co-authored-by: Lilith Orion Hafner --- base/asyncmap.jl | 12 +++---- base/docs/basedocs.jl | 32 +++++++++---------- base/essentials.jl | 4 +-- base/file.jl | 18 +++++------ base/genericmemory.jl | 2 +- base/multidimensional.jl | 6 ++-- base/show.jl | 2 +- base/stream.jl | 4 +-- doc/src/base/sort.md | 12 +++---- doc/src/manual/arrays.md | 16 +++++----- doc/src/manual/calling-c-and-fortran-code.md | 8 ++--- doc/src/manual/distributed-computing.md | 32 +++++++++---------- doc/src/manual/documentation.md | 2 +- doc/src/manual/functions.md | 4 +-- doc/src/manual/networking-and-streams.md | 10 +++--- stdlib/REPL/docs/src/index.md | 8 ++--- .../REPL/src/TerminalMenus/MultiSelectMenu.jl | 4 +-- stdlib/REPL/src/TerminalMenus/RadioMenu.jl | 8 ++--- stdlib/Random/src/Random.jl | 4 +-- stdlib/Sockets/src/addrinfo.jl | 6 ++-- 20 files changed, 97 insertions(+), 97 deletions(-) diff --git a/base/asyncmap.jl b/base/asyncmap.jl index 02e515d2e0c6c..1914ddc645f31 100644 --- a/base/asyncmap.jl +++ b/base/asyncmap.jl @@ -28,11 +28,11 @@ The following examples highlight execution in different tasks by returning the `objectid` of the tasks in which the mapping function is executed. First, with `ntasks` undefined, each element is processed in a different task. -``` +```julia-repl julia> tskoid() = objectid(current_task()); julia> asyncmap(x->tskoid(), 1:5) -5-element Array{UInt64,1}: +5-element Vector{UInt64}: 0x6e15e66c75c75853 0x440f8819a1baa682 0x9fb3eeadd0c83985 @@ -44,9 +44,9 @@ julia> length(unique(asyncmap(x->tskoid(), 1:5))) ``` With `ntasks=2` all elements are processed in 2 tasks. -``` +```julia-repl julia> asyncmap(x->tskoid(), 1:5; ntasks=2) -5-element Array{UInt64,1}: +5-element Vector{UInt64}: 0x027ab1680df7ae94 0xa23d2f80cd7cf157 0x027ab1680df7ae94 @@ -60,12 +60,12 @@ julia> length(unique(asyncmap(x->tskoid(), 1:5; ntasks=2))) With `batch_size` defined, the mapping function needs to be changed to accept an array of argument tuples and return an array of results. `map` is used in the modified mapping function to achieve this. -``` +```julia-repl julia> batch_func(input) = map(x->string("args_tuple: ", x, ", element_val: ", x[1], ", task: ", tskoid()), input) batch_func (generic function with 1 method) julia> asyncmap(batch_func, 1:5; ntasks=2, batch_size=2) -5-element Array{String,1}: +5-element Vector{String}: "args_tuple: (1,), element_val: 1, task: 9118321258196414413" "args_tuple: (2,), element_val: 2, task: 4904288162898683522" "args_tuple: (3,), element_val: 3, task: 9118321258196414413" diff --git a/base/docs/basedocs.jl b/base/docs/basedocs.jl index cef5e12a9e0d8..16175010a20fa 100644 --- a/base/docs/basedocs.jl +++ b/base/docs/basedocs.jl @@ -406,11 +406,11 @@ Assigning `a` to `b` does not create a copy of `b`; instead use [`copy`](@ref) o ```jldoctest julia> b = [1]; a = b; b[1] = 2; a -1-element Array{Int64, 1}: +1-element Vector{Int64}: 2 julia> b = [1]; a = copy(b); b[1] = 2; a -1-element Array{Int64, 1}: +1-element Vector{Int64}: 1 ``` @@ -420,7 +420,7 @@ julia> function f!(x); x[:] .+= 1; end f! (generic function with 1 method) julia> a = [1]; f!(a); a -1-element Array{Int64, 1}: +1-element Vector{Int64}: 2 ``` @@ -439,7 +439,7 @@ julia> a, b Assignment can operate on multiple variables in series, and will return the value of the right-hand-most expression: ```jldoctest julia> a = [1]; b = [2]; c = [3]; a = b = c -1-element Array{Int64, 1}: +1-element Vector{Int64}: 3 julia> b[1] = 2; a, b, c @@ -449,11 +449,11 @@ julia> b[1] = 2; a, b, c Assignment at out-of-bounds indices does not grow a collection. If the collection is a [`Vector`](@ref) it can instead be grown with [`push!`](@ref) or [`append!`](@ref). ```jldoctest julia> a = [1, 1]; a[3] = 2 -ERROR: BoundsError: attempt to access 2-element Array{Int64, 1} at index [3] +ERROR: BoundsError: attempt to access 2-element Vector{Int64} at index [3] [...] julia> push!(a, 2, 3) -4-element Array{Int64, 1}: +4-element Vector{Int64}: 1 1 2 @@ -467,7 +467,7 @@ ERROR: DimensionMismatch: tried to assign 0 elements to 1 destinations [...] julia> filter!(x -> x > 1, a) # in-place & thus more efficient than a = a[a .> 1] -2-element Array{Int64, 1}: +2-element Vector{Int64}: 2 3 @@ -490,14 +490,14 @@ assignment expression is converted into a single loop. julia> A = zeros(4, 4); B = [1, 2, 3, 4]; julia> A .= B -4×4 Array{Float64, 2}: +4×4 Matrix{Float64}: 1.0 1.0 1.0 1.0 2.0 2.0 2.0 2.0 3.0 3.0 3.0 3.0 4.0 4.0 4.0 4.0 julia> A -4×4 Array{Float64, 2}: +4×4 Matrix{Float64}: 1.0 1.0 1.0 1.0 2.0 2.0 2.0 2.0 3.0 3.0 3.0 3.0 @@ -1018,12 +1018,12 @@ collection or the last index of a dimension of an array. # Examples ```jldoctest julia> A = [1 2; 3 4] -2×2 Array{Int64, 2}: +2×2 Matrix{Int64}: 1 2 3 4 julia> A[end, :] -2-element Array{Int64, 1}: +2-element Vector{Int64}: 3 4 ``` @@ -1429,12 +1429,12 @@ collection or the first index of a dimension of an array. For example, # Examples ```jldoctest julia> A = [1 2; 3 4] -2×2 Array{Int64,2}: +2×2 Matrix{Int64}: 1 2 3 4 julia> A[begin, :] -2-element Array{Int64,1}: +2-element Matrix{Int64}: 1 2 ``` @@ -2826,7 +2826,7 @@ Construct an uninitialized [`Vector{T}`](@ref) of length `n`. # Examples ```julia-repl julia> Vector{Float64}(undef, 3) -3-element Array{Float64, 1}: +3-element Vector{Float64}: 6.90966e-310 6.90966e-310 6.90966e-310 @@ -2876,7 +2876,7 @@ Construct an uninitialized [`Matrix{T}`](@ref) of size `m`×`n`. # Examples ```julia-repl julia> Matrix{Float64}(undef, 2, 3) -2×3 Array{Float64, 2}: +2×3 Matrix{Float64}: 2.36365e-314 2.28473e-314 5.0e-324 2.26704e-314 2.26711e-314 NaN @@ -3014,7 +3014,7 @@ an alias for `UndefInitializer()`. # Examples ```julia-repl julia> Array{Float64, 1}(UndefInitializer(), 3) -3-element Array{Float64, 1}: +3-element Vector{Float64}: 2.2752528595e-314 2.202942107e-314 2.275252907e-314 diff --git a/base/essentials.jl b/base/essentials.jl index 3574116261968..fa5cf79192f56 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -93,7 +93,7 @@ f(y) = [x for x in y] # Examples -```julia +```julia-repl julia> f(A::AbstractArray) = g(A) f (generic function with 1 method) @@ -1270,7 +1270,7 @@ The `@world` macro is primarily used in the printing of bindings that are no lon available in the current world. ## Example -``` +```julia-repl julia> struct Foo; a::Int; end Foo diff --git a/base/file.jl b/base/file.jl index c69a598f42623..66e8114aba4ba 100644 --- a/base/file.jl +++ b/base/file.jl @@ -128,7 +128,7 @@ julia> pwd() "/home/JuliaUser" julia> cd(readdir, "/home/JuliaUser/Projects/julia") -34-element Array{String,1}: +34-element Vector{String}: ".circleci" ".freebsdci.sh" ".git" @@ -211,17 +211,17 @@ julia> mkpath("my/test/dir") # creates three directories "my/test/dir" julia> readdir() -1-element Array{String,1}: +1-element Vector{String}: "my" julia> cd("my") julia> readdir() -1-element Array{String,1}: +1-element Vector{String}: "test" julia> readdir("test") -1-element Array{String,1}: +1-element Vector{String}: "dir" julia> mkpath("intermediate_dir/actually_a_directory.txt") # creates two directories @@ -943,7 +943,7 @@ See also: [`walkdir`](@ref). julia> cd("/home/JuliaUser/dev/julia") julia> readdir() -30-element Array{String,1}: +30-element Vector{String}: ".appveyor.yml" ".git" ".gitattributes" @@ -953,7 +953,7 @@ julia> readdir() "usr-staging" julia> readdir(join=true) -30-element Array{String,1}: +30-element Vector{String}: "/home/JuliaUser/dev/julia/.appveyor.yml" "/home/JuliaUser/dev/julia/.git" "/home/JuliaUser/dev/julia/.gitattributes" @@ -963,7 +963,7 @@ julia> readdir(join=true) "/home/JuliaUser/dev/julia/usr-staging" julia> readdir("base") -145-element Array{String,1}: +145-element Vector{String}: ".gitignore" "Base.jl" "Enums.jl" @@ -973,7 +973,7 @@ julia> readdir("base") "weakkeydict.jl" julia> readdir("base", join=true) -145-element Array{String,1}: +145-element Vector{String}: "base/.gitignore" "base/Base.jl" "base/Enums.jl" @@ -983,7 +983,7 @@ julia> readdir("base", join=true) "base/weakkeydict.jl" julia> readdir(abspath("base"), join=true) -145-element Array{String,1}: +145-element Vector{String}: "/home/JuliaUser/dev/julia/base/.gitignore" "/home/JuliaUser/dev/julia/base/Base.jl" "/home/JuliaUser/dev/julia/base/Enums.jl" diff --git a/base/genericmemory.jl b/base/genericmemory.jl index fbf60255935a3..9d4614135050b 100644 --- a/base/genericmemory.jl +++ b/base/genericmemory.jl @@ -10,7 +10,7 @@ Fixed-size [`DenseVector{T}`](@ref DenseVector). `kind` can currently be either `:not_atomic` or `:atomic`. For details on what `:atomic` implies, see [`AtomicMemory`](@ref) `addrspace` can currently only be set to `Core.CPU`. It is designed to permit extension by other systems such as GPUs, which might define values such as: -``` +```julia module CUDA const Generic = bitcast(Core.AddrSpace{CUDA}, 0) const Global = bitcast(Core.AddrSpace{CUDA}, 1) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index c82f1c1ba75d7..ba08f0679590b 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -1313,16 +1313,16 @@ See also: [`circshift`](@ref). # Examples ```julia-repl julia> src = reshape(Vector(1:16), (4,4)) -4×4 Array{Int64,2}: +4×4 Matrix{Int64}: 1 5 9 13 2 6 10 14 3 7 11 15 4 8 12 16 -julia> dest = OffsetArray{Int}(undef, (0:3,2:5)) +julia> dest = OffsetArray{Int}(undef, (0:3,2:5)); julia> circcopy!(dest, src) -OffsetArrays.OffsetArray{Int64,2,Array{Int64,2}} with indices 0:3×2:5: +4×4 OffsetArray(::Matrix{Int64}, 0:3, 2:5) with eltype Int64 with indices 0:3×2:5: 8 12 16 4 5 9 13 1 6 10 14 2 diff --git a/base/show.jl b/base/show.jl index 5b121fdac5e80..381c0e7d1480a 100644 --- a/base/show.jl +++ b/base/show.jl @@ -3150,7 +3150,7 @@ Print to a stream `io`, or return a string `str`, giving a brief description of a value. By default returns `string(typeof(x))`, e.g. [`Int64`](@ref). For arrays, returns a string of size and type info, -e.g. `10-element Array{Int64,1}`. +e.g. `10-element Vector{Int64}` or `9×4×5 Array{Float64, 3}`. # Examples ```jldoctest diff --git a/base/stream.jl b/base/stream.jl index 488acd41d2a9e..e81f65685df72 100644 --- a/base/stream.jl +++ b/base/stream.jl @@ -76,7 +76,7 @@ function getproperty(stream::LibuvStream, name::Symbol) end # IO -# +- GenericIOBuffer{T<:AbstractArray{UInt8,1}} (not exported) +# +- GenericIOBuffer{T<:AbstractVector{UInt8}} (not exported) # +- AbstractPipe (not exported) # . +- Pipe # . +- Process (not exported) @@ -89,7 +89,7 @@ end # . +- TTY (not exported) # . +- UDPSocket # . +- BufferStream (FIXME: 2.0) -# +- IOBuffer = Base.GenericIOBuffer{Array{UInt8,1}} +# +- IOBuffer = Base.GenericIOBuffer{Vector{UInt8}} # +- IOStream # IOServer diff --git a/doc/src/base/sort.md b/doc/src/base/sort.md index b9d333ef2a939..cef080c5f8995 100644 --- a/doc/src/base/sort.md +++ b/doc/src/base/sort.md @@ -41,7 +41,7 @@ indices that puts the array into sorted order: ```julia-repl julia> v = randn(5) -5-element Array{Float64,1}: +5-element Vector{Float64}: 0.297288 0.382396 -0.597634 @@ -49,7 +49,7 @@ julia> v = randn(5) -0.839027 julia> p = sortperm(v) -5-element Array{Int64,1}: +5-element Vector{Int64}: 5 3 4 @@ -57,7 +57,7 @@ julia> p = sortperm(v) 2 julia> v[p] -5-element Array{Float64,1}: +5-element Vector{Float64}: -0.839027 -0.597634 -0.0104452 @@ -69,7 +69,7 @@ Arrays can be sorted according to an arbitrary transformation of their values: ```julia-repl julia> sort(v, by=abs) -5-element Array{Float64,1}: +5-element Vector{Float64}: -0.0104452 0.297288 0.382396 @@ -81,7 +81,7 @@ Or in reverse order by a transformation: ```julia-repl julia> sort(v, by=abs, rev=true) -5-element Array{Float64,1}: +5-element Vector{Float64}: -0.839027 -0.597634 0.382396 @@ -93,7 +93,7 @@ If needed, the sorting algorithm can be chosen: ```julia-repl julia> sort(v, alg=InsertionSort) -5-element Array{Float64,1}: +5-element Vector{Float64}: -0.839027 -0.597634 -0.0104452 diff --git a/doc/src/manual/arrays.md b/doc/src/manual/arrays.md index 8a33d31a23cf8..02d71fcd9939e 100644 --- a/doc/src/manual/arrays.md +++ b/doc/src/manual/arrays.md @@ -355,7 +355,7 @@ julia> Int8[[1 2] [3 4]] Comprehensions provide a general and powerful way to construct arrays. Comprehension syntax is similar to set construction notation in mathematics: -``` +```julia A = [ F(x, y, ...) for x=rx, y=ry, ... ] ``` @@ -366,11 +366,11 @@ The result is an N-d dense array with dimensions that are the concatenation of t of the variable ranges `rx`, `ry`, etc. and each `F(x,y,...)` evaluation returns a scalar. The following example computes a weighted average of the current element and its left and right -neighbor along a 1-d grid. : +neighbor along a 1-d grid: ```julia-repl julia> x = rand(8) -8-element Array{Float64,1}: +8-element Vector{Float64}: 0.843025 0.869052 0.365105 @@ -381,7 +381,7 @@ julia> x = rand(8) 0.809411 julia> [ 0.25*x[i-1] + 0.5*x[i] + 0.25*x[i+1] for i=2:length(x)-1 ] -6-element Array{Float64,1}: +6-element Vector{Float64}: 0.736559 0.57468 0.685417 @@ -1040,7 +1040,7 @@ be to replicate the vector to the size of the matrix: julia> a = rand(2, 1); A = rand(2, 3); julia> repeat(a, 1, 3) + A -2×3 Array{Float64,2}: +2×3 Matrix{Float64}: 1.20813 1.82068 1.25387 1.56851 1.86401 1.67846 ``` @@ -1051,16 +1051,16 @@ without using extra memory, and applies the given function elementwise: ```julia-repl julia> broadcast(+, a, A) -2×3 Array{Float64,2}: +2×3 Matrix{Float64}: 1.20813 1.82068 1.25387 1.56851 1.86401 1.67846 julia> b = rand(1,2) -1×2 Array{Float64,2}: +1×2 Matrix{Float64}: 0.867535 0.00457906 julia> broadcast(+, a, b) -2×2 Array{Float64,2}: +2×2 Matrix{Float64}: 1.71056 0.847604 1.73659 0.873631 ``` diff --git a/doc/src/manual/calling-c-and-fortran-code.md b/doc/src/manual/calling-c-and-fortran-code.md index f675ab5eb16e8..d198c796a2e0b 100644 --- a/doc/src/manual/calling-c-and-fortran-code.md +++ b/doc/src/manual/calling-c-and-fortran-code.md @@ -27,9 +27,9 @@ commonly passed in registers when using C or Julia calling conventions. The syntax for [`@ccall`](@ref) to generate a call to the library function is: ```julia - @ccall library.function_name(argvalue1::argtype1, ...)::returntype - @ccall function_name(argvalue1::argtype1, ...)::returntype - @ccall $function_pointer(argvalue1::argtype1, ...)::returntype +@ccall library.function_name(argvalue1::argtype1, ...)::returntype +@ccall function_name(argvalue1::argtype1, ...)::returntype +@ccall $function_pointer(argvalue1::argtype1, ...)::returntype ``` where `library` is a string constant or literal (but see [Non-constant Function @@ -825,7 +825,7 @@ Instead define a [`Base.cconvert`](@ref) method and pass the variables directly automatically arranges that all of its arguments will be preserved from garbage collection until the call returns. If a C API will store a reference to memory allocated by Julia, after the `@ccall` returns, you must ensure that the object remains visible to the garbage collector. The suggested -way to do this is to make a global variable of type `Array{Ref,1}` to hold these values until +way to do this is to make a global variable of type `Vector{Ref}` to hold these values until the C library notifies you that it is finished with them. Whenever you have created a pointer to Julia data, you must ensure the original data exists until diff --git a/doc/src/manual/distributed-computing.md b/doc/src/manual/distributed-computing.md index f60dfb7004ada..873a94ffb2181 100644 --- a/doc/src/manual/distributed-computing.md +++ b/doc/src/manual/distributed-computing.md @@ -48,7 +48,7 @@ Generally it makes sense for `n` to equal the number of CPU threads (logical cor argument implicitly loads module [`Distributed`](@ref man-distributed). -```julia +```julia-repl $ julia -p 2 julia> r = remotecall(rand, 2, 2, 2) @@ -58,7 +58,7 @@ julia> s = @spawnat 2 1 .+ fetch(r) Future(2, 1, 5, nothing) julia> fetch(s) -2×2 Array{Float64,2}: +2×2 Matrix{Float64}: 1.18526 1.50912 1.16296 1.60607 ``` @@ -106,7 +106,7 @@ julia> s = @spawnat :any 1 .+ fetch(r) Future(3, 1, 5, nothing) julia> fetch(s) -2×2 Array{Float64,2}: +2×2 Matrix{Float64}: 1.38854 1.9098 1.20939 1.57158 ``` @@ -153,7 +153,7 @@ julia> function rand2(dims...) end julia> rand2(2,2) -2×2 Array{Float64,2}: +2×2 Matrix{Float64}: 0.153756 0.368514 1.15119 0.918912 @@ -262,7 +262,7 @@ as a programmatic means of adding, removing and querying the processes in a clus julia> using Distributed julia> addprocs(2) -2-element Array{Int64,1}: +2-element Vector{Int64}: 2 3 ``` @@ -734,7 +734,7 @@ serialization/deserialization of data. Consequently, the call refers to the same as passed - no copies are created. This behavior is highlighted below: ```julia-repl -julia> using Distributed; +julia> using Distributed julia> rc = RemoteChannel(()->Channel(3)); # RemoteChannel created on local node @@ -748,7 +748,7 @@ julia> for i in 1:3 julia> result = [take!(rc) for _ in 1:3]; julia> println(result); -Array{Int64,1}[[3], [3], [3]] +[[3], [3], [3]] julia> println("Num Unique objects : ", length(unique(map(objectid, result)))); Num Unique objects : 1 @@ -767,7 +767,7 @@ julia> for i in 1:3 julia> result = [take!(rc) for _ in 1:3]; julia> println(result); -Array{Int64,1}[[1], [2], [3]] +[[1], [2], [3]] julia> println("Num Unique objects : ", length(unique(map(objectid, result)))); Num Unique objects : 3 @@ -855,7 +855,7 @@ Here's a brief example: julia> using Distributed julia> addprocs(3) -3-element Array{Int64,1}: +3-element Vector{Int64}: 2 3 4 @@ -863,7 +863,7 @@ julia> addprocs(3) julia> @everywhere using SharedArrays julia> S = SharedArray{Int,2}((3,4), init = S -> S[localindices(S)] = repeat([myid()], length(localindices(S)))) -3×4 SharedArray{Int64,2}: +3×4 SharedMatrix{Int64}: 2 2 3 4 2 3 3 4 2 3 4 4 @@ -872,7 +872,7 @@ julia> S[3,2] = 7 7 julia> S -3×4 SharedArray{Int64,2}: +3×4 SharedMatrix{Int64}: 2 2 3 4 2 3 3 4 2 7 4 4 @@ -884,7 +884,7 @@ you wish: ```julia-repl julia> S = SharedArray{Int,2}((3,4), init = S -> S[indexpids(S):length(procs(S)):length(S)] = repeat([myid()], length( indexpids(S):length(procs(S)):length(S)))) -3×4 SharedArray{Int64,2}: +3×4 SharedMatrix{Int64}: 2 2 2 2 3 3 3 3 4 4 4 4 @@ -1371,7 +1371,7 @@ julia> all(C .≈ 4*π) true julia> typeof(C) -Array{Float64,1} +Vector{Float64} (alias for Array{Float64, 1}) julia> dB = distribute(B); @@ -1383,7 +1383,7 @@ julia> all(dC .≈ 4*π) true julia> typeof(dC) -DistributedArrays.DArray{Float64,1,Array{Float64,1}} +DistributedArrays.DArray{Float64,1,Vector{Float64}} julia> cuB = CuArray(B); @@ -1419,7 +1419,7 @@ function declaration, let's see if it works with the aforementioned datatypes: julia> M = [2. 1; 1 1]; julia> v = rand(2) -2-element Array{Float64,1}: +2-element Vector{Float64}: 0.40395 0.445877 @@ -1442,7 +1442,7 @@ julia> dv = distribute(v); julia> dC = power_method(dM, dv); julia> typeof(dC) -Tuple{DistributedArrays.DArray{Float64,1,Array{Float64,1}},Float64} +Tuple{DistributedArrays.DArray{Float64,1,Vector{Float64}},Float64} ``` To end this short exposure to external packages, we can consider `MPI.jl`, a Julia wrapper diff --git a/doc/src/manual/documentation.md b/doc/src/manual/documentation.md index d41249abe6af8..a11d41d441b73 100644 --- a/doc/src/manual/documentation.md +++ b/doc/src/manual/documentation.md @@ -142,7 +142,7 @@ As in the example above, we recommend following some simple conventions when wri # Examples ```jldoctest julia> a = [1 2; 3 4] - 2×2 Array{Int64,2}: + 2×2 Matrix{Int64}: 1 2 3 4 ``` diff --git a/doc/src/manual/functions.md b/doc/src/manual/functions.md index be81fe529ef7d..0fcfdeb80d7b9 100644 --- a/doc/src/manual/functions.md +++ b/doc/src/manual/functions.md @@ -616,9 +616,9 @@ julia> foo(A(3, 4)) For anonymous functions, destructuring a single argument requires an extra comma: -``` +```julia-repl julia> map(((x, y),) -> x + y, [(1, 2), (3, 4)]) -2-element Array{Int64,1}: +2-element Vector{Int64}: 3 7 ``` diff --git a/doc/src/manual/networking-and-streams.md b/doc/src/manual/networking-and-streams.md index 35ba7fdf16601..3ef41754c1e07 100644 --- a/doc/src/manual/networking-and-streams.md +++ b/doc/src/manual/networking-and-streams.md @@ -31,7 +31,7 @@ For example, to read a simple byte array, we could do: ```julia-repl julia> x = zeros(UInt8, 4) -4-element Array{UInt8,1}: +4-element Vector{UInt8}: 0x00 0x00 0x00 @@ -39,7 +39,7 @@ julia> x = zeros(UInt8, 4) julia> read!(stdin, x) abcd -4-element Array{UInt8,1}: +4-element Vector{UInt8}: 0x61 0x62 0x63 @@ -52,7 +52,7 @@ example, we could have written the above as: ```julia-repl julia> read(stdin, 4) abcd -4-element Array{UInt8,1}: +4-element Vector{UInt8}: 0x61 0x62 0x63 @@ -151,7 +151,7 @@ julia> f = open("hello.txt") IOStream() julia> readlines(f) -1-element Array{String,1}: +1-element Vector{String}: "Hello, World!" ``` @@ -367,7 +367,7 @@ julia> task = Threads.@spawn open("foo.txt", "w") do io julia> wait(task) julia> readlines("foo.txt") -1-element Array{String,1}: +1-element Vector{String}: "Hello, World!" ``` diff --git a/stdlib/REPL/docs/src/index.md b/stdlib/REPL/docs/src/index.md index 6250fc84dc6b2..eabd7e729280e 100644 --- a/stdlib/REPL/docs/src/index.md +++ b/stdlib/REPL/docs/src/index.md @@ -68,7 +68,7 @@ It's possible, as an experimental feature, to specify the attributes used by the ```julia-repl julia> rand(2, 2) -2×2 Array{Float64,2}: +2×2 Matrix{Float64}: 0.8833 0.329197 0.719708 0.59114 @@ -78,7 +78,7 @@ julia> show(IOContext(stdout, :compact => false), "text/plain", rand(2, 2)) julia> Base.active_repl.options.iocontext[:compact] = false; julia> rand(2, 2) -2×2 Array{Float64,2}: +2×2 Matrix{Float64}: 0.2083967319174056 0.13330606013126012 0.6244375177790158 0.9777957560761545 ``` @@ -368,13 +368,13 @@ julia> π julia> e\_1[TAB] = [1,0] julia> e₁ = [1,0] -2-element Array{Int64,1}: +2-element Vector{Int64}: 1 0 julia> e\^1[TAB] = [1 0] julia> e¹ = [1 0] -1×2 Array{Int64,2}: +1×2 Matrix{Int64}: 1 0 julia> \sqrt[TAB]2 # √ is equivalent to the sqrt function diff --git a/stdlib/REPL/src/TerminalMenus/MultiSelectMenu.jl b/stdlib/REPL/src/TerminalMenus/MultiSelectMenu.jl index 5c3ecf3808c49..fd660fc0f7824 100644 --- a/stdlib/REPL/src/TerminalMenus/MultiSelectMenu.jl +++ b/stdlib/REPL/src/TerminalMenus/MultiSelectMenu.jl @@ -38,7 +38,7 @@ end """ - MultiSelectMenu(options::Array{String,1}; pagesize::Int=10, selected=[], kwargs...) + MultiSelectMenu(options::Vector{String}; pagesize::Int=10, selected=[], kwargs...) Create a MultiSelectMenu object. Use `request(menu::MultiSelectMenu)` to get user input. It returns a `Set` containing the indices of options that @@ -46,7 +46,7 @@ were selected by the user. # Arguments - - `options::Array{String, 1}`: Options to be displayed + - `options::Vector{String}`: Options to be displayed - `pagesize::Int=10`: The number of options to be displayed at one time, the menu will scroll if length(options) > pagesize - `selected=[]`: pre-selected items. `i ∈ selected` means that `options[i]` is preselected. diff --git a/stdlib/REPL/src/TerminalMenus/RadioMenu.jl b/stdlib/REPL/src/TerminalMenus/RadioMenu.jl index 32a6373b719d7..8e35e37f7f973 100644 --- a/stdlib/REPL/src/TerminalMenus/RadioMenu.jl +++ b/stdlib/REPL/src/TerminalMenus/RadioMenu.jl @@ -31,9 +31,9 @@ end """ - RadioMenu(options::Array{String,1}; pagesize::Int=10, - keybindings::Vector{Char}=Char[], - kwargs...) + RadioMenu(options::Vector{String}; pagesize::Int=10, + keybindings::Vector{Char}=Char[], + kwargs...) Create a RadioMenu object. Use `request(menu::RadioMenu)` to get user input. `request()` returns an `Int` which is the index of the option selected by the @@ -41,7 +41,7 @@ user. # Arguments - - `options::Array{String, 1}`: Options to be displayed + - `options::Vector{String}`: Options to be displayed - `pagesize::Int=10`: The number of options to be displayed at one time, the menu will scroll if length(options) > pagesize - `keybindings::Vector{Char}=Char[]`: Shortcuts to pick corresponding entry from `options` diff --git a/stdlib/Random/src/Random.jl b/stdlib/Random/src/Random.jl index 26116d3bf4c81..2d75f49480a7b 100644 --- a/stdlib/Random/src/Random.jl +++ b/stdlib/Random/src/Random.jl @@ -355,7 +355,7 @@ See also [`randn`](@ref) for normally distributed numbers, and [`rand!`](@ref) a # Examples ```julia-repl julia> rand(Int, 2) -2-element Array{Int64,1}: +2-element Vector{Int64}: 1339893410598768192 1575814717733606317 @@ -368,7 +368,7 @@ julia> rand((2, 3)) 3 julia> rand(Float64, (2, 3)) -2×3 Array{Float64,2}: +2×3 Matrix{Float64}: 0.999717 0.0143835 0.540787 0.696556 0.783855 0.938235 ``` diff --git a/stdlib/Sockets/src/addrinfo.jl b/stdlib/Sockets/src/addrinfo.jl index 93194b85d4e8c..f5599b8623a0b 100644 --- a/stdlib/Sockets/src/addrinfo.jl +++ b/stdlib/Sockets/src/addrinfo.jl @@ -58,7 +58,7 @@ Uses the operating system's underlying `getaddrinfo` implementation, which may d # Examples ```julia-repl julia> getalladdrinfo("google.com") -2-element Array{IPAddr,1}: +2-element Vector{IPAddr}: ip"172.217.6.174" ip"2607:f8b0:4000:804::200e" ``` @@ -307,7 +307,7 @@ The `loopback` keyword argument dictates whether loopback addresses (e.g. `ip"12 # Examples ```julia-repl julia> getipaddrs() -5-element Array{IPAddr,1}: +5-element Vector{IPAddr}: ip"198.51.100.17" ip"203.0.113.2" ip"2001:db8:8:4:445e:5fff:fe5d:5500" @@ -315,7 +315,7 @@ julia> getipaddrs() ip"fe80::445e:5fff:fe5d:5500" julia> getipaddrs(IPv6) -3-element Array{IPv6,1}: +3-element Vector{IPv6}: ip"2001:db8:8:4:445e:5fff:fe5d:5500" ip"2001:db8:8:4:c164:402e:7e3c:3668" ip"fe80::445e:5fff:fe5d:5500" From dde5028a11662fca831dd676505264566aec84ab Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Mon, 23 Dec 2024 12:52:54 +0530 Subject: [PATCH 102/342] Remove `similar` specialization with `Integer`s (#56881) This method seems unnecessary, as the method on line 830 does the same thing. Having this method in `Base` requires packages to disambiguate against this by adding redundant methods. --- base/abstractarray.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 6102a0a8a00fa..6d222e7e26281 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -828,7 +828,6 @@ similar(a::AbstractArray, ::Type{T}, dims::DimOrInd...) where {T} = similar(a, # define this method to convert supported axes to Ints, with the expectation that an offset array # package will define a method with dims::Tuple{Union{Integer, UnitRange}, Vararg{Union{Integer, UnitRange}}} similar(a::AbstractArray, ::Type{T}, dims::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T} = similar(a, T, to_shape(dims)) -similar(a::AbstractArray, ::Type{T}, dims::Tuple{Integer, Vararg{Integer}}) where {T} = similar(a, T, to_shape(dims)) # similar creates an Array by default similar(a::AbstractArray, ::Type{T}, dims::Dims{N}) where {T,N} = Array{T,N}(undef, dims) From 8fac39b71ca1c2a423ae1c7fc768722aff9005ee Mon Sep 17 00:00:00 2001 From: Oscar Smith Date: Mon, 23 Dec 2024 17:11:01 -0500 Subject: [PATCH 103/342] simplify and slightly improve memorynew inference (#56857) while investigating some missed optimizations in https://github.com/JuliaLang/julia/pull/56847, @gbaraldi and I realized that `copy(::Array)` was using `jl_genericmemory_copy_slice` rather than the `memmove`/`jl_genericmemory_copyto` that `copyto!` lowers to. This version lets us use the faster LLVM based Memory initialization, and the memove can theoretically be further optimized by LLVM (e.g. not copying elements that get over-written without ever being read). ``` julia> @btime copy($[1,2,3]) 15.521 ns (2 allocations: 80 bytes) # before 12.116 ns (2 allocations: 80 bytes) #after julia> m = Memory{Int}(undef, 3); julia> m.=[1,2,3]; julia> @btime copy($m) 11.013 ns (1 allocation: 48 bytes) #before 9.042 ns (1 allocation: 48 bytes) #after ``` We also optimize the `memorynew` type inference to make it so that getting the length of a memory with known length will propagate that length information (which is important for cases like `similar`/`copy` etc). --- Compiler/src/tfuncs.jl | 20 +++++++------------- base/array.jl | 9 +++++---- base/genericmemory.jl | 9 ++++++++- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/Compiler/src/tfuncs.jl b/Compiler/src/tfuncs.jl index 906bc9521adf9..e51d43e5b2fe1 100644 --- a/Compiler/src/tfuncs.jl +++ b/Compiler/src/tfuncs.jl @@ -2017,9 +2017,12 @@ function tuple_tfunc(𝕃::AbstractLattice, argtypes::Vector{Any}) return anyinfo ? PartialStruct(𝕃, typ, argtypes) : typ end -@nospecs function memorynew_tfunc(𝕃::AbstractLattice, memtype, m) - hasintersect(widenconst(m), Int) || return Bottom - return tmeet(𝕃, instanceof_tfunc(memtype, true)[1], GenericMemory) +@nospecs function memorynew_tfunc(𝕃::AbstractLattice, memtype, memlen) + hasintersect(widenconst(memlen), Int) || return Bottom + memt = tmeet(𝕃, instanceof_tfunc(memtype, true)[1], GenericMemory) + memt == Union{} && return memt + # PartialStruct so that loads of Const `length` get inferred + return PartialStruct(𝕃, memt, Any[memlen, Ptr{Nothing}]) end add_tfunc(Core.memorynew, 2, 2, memorynew_tfunc, 10) @@ -3125,16 +3128,7 @@ add_tfunc(Core.get_binding_type, 2, 2, @nospecs((𝕃::AbstractLattice, args...) const FOREIGNCALL_ARG_START = 6 -function foreigncall_effects(@specialize(abstract_eval), e::Expr) - args = e.args - name = args[1] - isa(name, QuoteNode) && (name = name.value) - if name === :jl_alloc_genericmemory - nothrow = new_genericmemory_nothrow(abstract_eval, args) - return Effects(EFFECTS_TOTAL; consistent=CONSISTENT_IF_NOTRETURNED, nothrow) - elseif name === :jl_genericmemory_copy_slice - return Effects(EFFECTS_TOTAL; consistent=CONSISTENT_IF_NOTRETURNED, nothrow=false) - end +function foreigncall_effects(@nospecialize(abstract_eval), e::Expr) # `:foreigncall` can potentially perform all sorts of operations, including calling # overlay methods, but the `:foreigncall` itself is not dispatched, and there is no # concern that the method calls that potentially occur within the `:foreigncall` will diff --git a/base/array.jl b/base/array.jl index 4c3dde73d52ba..aafcfc182124b 100644 --- a/base/array.jl +++ b/base/array.jl @@ -346,12 +346,13 @@ See also [`copy!`](@ref Base.copy!), [`copyto!`](@ref), [`deepcopy`](@ref). """ copy -@eval function copy(a::Array{T}) where {T} - # `jl_genericmemory_copy_slice` only throws when the size exceeds the max allocation - # size, but since we're copying an existing array, we're guaranteed that this will not happen. +@eval function copy(a::Array) + # `copy` only throws when the size exceeds the max allocation size, + # but since we're copying an existing array, we're guaranteed that this will not happen. @_nothrow_meta ref = a.ref - newmem = ccall(:jl_genericmemory_copy_slice, Ref{Memory{T}}, (Any, Ptr{Cvoid}, Int), ref.mem, ref.ptr_or_offset, length(a)) + newmem = typeof(ref.mem)(undef, length(a)) + @inbounds unsafe_copyto!(memoryref(newmem), ref, length(a)) return $(Expr(:new, :(typeof(a)), :(memoryref(newmem)), :(a.size))) end diff --git a/base/genericmemory.jl b/base/genericmemory.jl index 9d4614135050b..2a33336c0aad6 100644 --- a/base/genericmemory.jl +++ b/base/genericmemory.jl @@ -144,6 +144,7 @@ function unsafe_copyto!(dest::Memory{T}, doffs, src::Memory{T}, soffs, n) where{ return dest end +#fallback method when types don't match function unsafe_copyto!(dest::Memory, doffs, src::Memory, soffs, n) @_terminates_locally_meta n == 0 && return dest @@ -171,7 +172,13 @@ function unsafe_copyto!(dest::Memory, doffs, src::Memory, soffs, n) return dest end -copy(a::T) where {T<:Memory} = ccall(:jl_genericmemory_copy, Ref{T}, (Any,), a) +function copy(a::T) where {T<:Memory} + # `copy` only throws when the size exceeds the max allocation size, + # but since we're copying an existing array, we're guaranteed that this will not happen. + @_nothrow_meta + newmem = T(undef, length(a)) + @inbounds unsafe_copyto!(newmem, 1, a, 1, length(a)) +end copyto!(dest::Memory, src::Memory) = copyto!(dest, 1, src, 1, length(src)) function copyto!(dest::Memory, doffs::Integer, src::Memory, soffs::Integer, n::Integer) From 64d37f533b80851f2f5a3aee43374638420a98ec Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Tue, 24 Dec 2024 08:49:50 +0530 Subject: [PATCH 104/342] Update the OffsetArrays test helper (#56892) This updates the test helper to match v1.15.0 of `OffsetArrays.jl`. The current version was copied over from v1.11.2, which was released on May 20, 2022, so this bump fetches the intermediate updates to the package. The main changes are updates to `unsafe_wrap` and `reshape`. In the latter, several redundant methods are now removed, whereas, in the former, methods are added to wrap a `Ptr` in an `OffsetArray` (https://github.com/JuliaArrays/OffsetArrays.jl/issues/275#issue-1222585268). A third major change is that an `OffsetArray` now shares its parent's `eltype` and `ndims` in the struct definition, whereas previously this was ensured through the constructor. Other miscellaneous changes are included, such as performance-related ones. --- test/testhelpers/OffsetArrays.jl | 115 +++++++++++++++++++------------ 1 file changed, 72 insertions(+), 43 deletions(-) diff --git a/test/testhelpers/OffsetArrays.jl b/test/testhelpers/OffsetArrays.jl index e895372a34974..5acaa88064245 100644 --- a/test/testhelpers/OffsetArrays.jl +++ b/test/testhelpers/OffsetArrays.jl @@ -5,7 +5,7 @@ # This test file is designed to exercise support for generic indexing, # even though offset arrays aren't implemented in Base. -# OffsetArrays v1.11.2 +# OffsetArrays v1.15.0 # No compat patch and docstrings module OffsetArrays @@ -73,10 +73,15 @@ end IdOffsetRange(r::IdOffsetRange) = r # Constructor to make `show` round-trippable +# try to preserve typeof(values) if the indices are known to be 1-based +_subtractindexoffset(values, indices::Union{Base.OneTo, IdentityUnitRange{<:Base.OneTo}}, offset) = values +_subtractindexoffset(values, indices, offset) = _subtractoffset(values, offset) function IdOffsetRange(; values::AbstractUnitRange{<:Integer}, indices::AbstractUnitRange{<:Integer}) length(values) == length(indices) || throw(ArgumentError("values and indices must have the same length")) + values_nooffset = no_offset_view(values) offset = first(indices) - 1 - return IdOffsetRange(values .- offset, offset) + values_minus_offset = _subtractindexoffset(values_nooffset, indices, offset) + return IdOffsetRange(values_minus_offset, offset) end # Conversions to an AbstractUnitRange{Int} (and to an OrdinalRange{Int,Int} on Julia v"1.6") are necessary @@ -110,12 +115,19 @@ offset_coerce(::Type{I}, r::AbstractUnitRange) where I<:AbstractUnitRange = @inline Base.unsafe_indices(r::IdOffsetRange) = (Base.axes1(r),) @inline Base.length(r::IdOffsetRange) = length(r.parent) @inline Base.isempty(r::IdOffsetRange) = isempty(r.parent) +#= We specialize on reduced_indices to work around cases where the parent axis type doesn't +support reduced_index, but the axes do support reduced_indices +The difference is that reduced_index expects the axis type to remain unchanged, +which may not always be possible, eg. for statically sized axes +See https://github.com/JuliaArrays/OffsetArrays.jl/issues/204 +=# +function Base.reduced_indices(inds::Tuple{IdOffsetRange, Vararg{IdOffsetRange}}, d::Int) + parents_reduced = Base.reduced_indices(map(parent, inds), d) + ntuple(i -> IdOffsetRange(parents_reduced[i], inds[i].offset), Val(length(inds))) +end Base.reduced_index(i::IdOffsetRange) = typeof(i)(first(i):first(i)) # Workaround for #92 on Julia < 1.4 Base.reduced_index(i::IdentityUnitRange{<:IdOffsetRange}) = typeof(i)(first(i):first(i)) -for f in [:firstindex, :lastindex] - @eval @inline Base.$f(r::IdOffsetRange) = $f(r.parent) + r.offset -end for f in [:first, :last] # coerce the type to deal with values that get promoted on addition (eg. Bool) @eval @inline Base.$f(r::IdOffsetRange) = eltype(r)($f(r.parent) + r.offset) @@ -142,7 +154,7 @@ end @inline function Base.getindex(r::IdOffsetRange, i::Integer) i isa Bool && throw(ArgumentError("invalid index: $i of type Bool")) @boundscheck checkbounds(r, i) - @inbounds eltype(r)(r.parent[oftype(r.offset, i) - r.offset] + r.offset) + @inbounds eltype(r)(r.parent[i - r.offset] + r.offset) end # Logical indexing following https://github.com/JuliaLang/julia/pull/31829 @@ -186,18 +198,20 @@ for R in [:IIUR, :IdOffsetRange] end # offset-preserve broadcasting -Broadcast.broadcasted(::Base.Broadcast.DefaultArrayStyle{1}, ::typeof(-), r::IdOffsetRange{T}, x::Integer) where T = - IdOffsetRange{T}(r.parent .- x, r.offset) -Broadcast.broadcasted(::Base.Broadcast.DefaultArrayStyle{1}, ::typeof(+), r::IdOffsetRange{T}, x::Integer) where T = - IdOffsetRange{T}(r.parent .+ x, r.offset) -Broadcast.broadcasted(::Base.Broadcast.DefaultArrayStyle{1}, ::typeof(+), x::Integer, r::IdOffsetRange{T}) where T = - IdOffsetRange{T}(x .+ r.parent, r.offset) +Broadcast.broadcasted(::Base.Broadcast.DefaultArrayStyle{1}, ::typeof(-), r::IdOffsetRange, x::Integer) = + IdOffsetRange(r.parent .- x, r.offset) +Broadcast.broadcasted(::Base.Broadcast.DefaultArrayStyle{1}, ::typeof(+), r::IdOffsetRange, x::Integer) = + IdOffsetRange(r.parent .+ x, r.offset) +Broadcast.broadcasted(::Base.Broadcast.DefaultArrayStyle{1}, ::typeof(+), x::Integer, r::IdOffsetRange) = + IdOffsetRange(x .+ r.parent, r.offset) +Broadcast.broadcasted(::Base.Broadcast.DefaultArrayStyle{1}, ::typeof(big), r::IdOffsetRange) = + IdOffsetRange(big.(r.parent), r.offset) Base.show(io::IO, r::IdOffsetRange) = print(io, IdOffsetRange, "(values=",first(r), ':', last(r),", indices=",first(eachindex(r)),':',last(eachindex(r)), ")") # Optimizations @inline Base.checkindex(::Type{Bool}, inds::IdOffsetRange, i::Real) = Base.checkindex(Bool, inds.parent, i - inds.offset) -Base._firstslice(r::IdOffsetRange) = IdOffsetRange(Base._firstslice(r.parent), r.offset) +Base._firstslice(i::IdOffsetRange) = IdOffsetRange(Base._firstslice(i.parent), i.offset) ######################################################################################################## # origin.jl @@ -309,12 +323,12 @@ _popreshape(A::AbstractArray, ax, inds) = A # Technically we know the length of CartesianIndices but we need to convert it first, so here we # don't put it in OffsetAxisKnownLength. -const OffsetAxisKnownLength = Union{Integer,AbstractUnitRange} -const OffsetAxis = Union{OffsetAxisKnownLength,Colon} -const ArrayInitializer = Union{UndefInitializer,Missing,Nothing} +const OffsetAxisKnownLength = Union{Integer, AbstractUnitRange} +const OffsetAxis = Union{OffsetAxisKnownLength, Colon} +const ArrayInitializer = Union{UndefInitializer, Missing, Nothing} ## OffsetArray -struct OffsetArray{T,N,AA<:AbstractArray} <: AbstractArray{T,N} +struct OffsetArray{T,N,AA<:AbstractArray{T,N}} <: AbstractArray{T,N} parent::AA offsets::NTuple{N,Int} @inline function OffsetArray{T, N, AA}(parent::AA, offsets::NTuple{N, Int}; checkoverflow = true) where {T, N, AA<:AbstractArray{T,N}} @@ -482,6 +496,10 @@ Base.parent(A::OffsetArray) = A.parent # Base.Broadcast.BroadcastStyle(::Type{<:OffsetArray{<:Any, <:Any, AA}}) where AA = Base.Broadcast.BroadcastStyle(AA) @inline Base.size(A::OffsetArray) = size(parent(A)) +# specializing length isn't necessary, as length(A) = prod(size(A)), +# but specializing length enables constant-propagation for statically sized arrays +# see https://github.com/JuliaArrays/OffsetArrays.jl/pull/304 +@inline Base.length(A::OffsetArray) = length(parent(A)) @inline Base.axes(A::OffsetArray) = map(IdOffsetRange, axes(parent(A)), A.offsets) @inline Base.axes(A::OffsetArray, d) = d <= ndims(A) ? IdOffsetRange(axes(parent(A), d), A.offsets[d]) : IdOffsetRange(axes(parent(A), d)) @@ -528,7 +546,9 @@ _similar_axes_or_length(A, T, ax::I, ::I) where {I} = similar(A, T, map(_indexle _similar_axes_or_length(AT, ax::I, ::I) where {I} = similar(AT, map(_indexlength, ax)) # reshape accepts a single colon -Base.reshape(A::AbstractArray, inds::OffsetAxis...) = reshape(A, inds) +# this method is limited to AbstractUnitRange{<:Integer} to avoid method overwritten errors if Base defines the same, +# see https://github.com/JuliaLang/julia/pull/56850 +Base.reshape(A::AbstractArray, inds::Union{Integer, Colon, AbstractUnitRange{<:Integer}}...) = reshape(A, inds) function Base.reshape(A::AbstractArray, inds::Tuple{Vararg{OffsetAxis}}) AR = reshape(no_offset_view(A), map(_indexlength, inds)) O = OffsetArray(AR, map(_offset, axes(AR), inds)) @@ -553,21 +573,9 @@ _reshape2(A, inds) = reshape(A, inds) _reshape2(A::OffsetArray, inds) = reshape(parent(A), inds) _reshape_nov(A, inds) = _reshape(no_offset_view(A), inds) -Base.reshape(A::OffsetArray, inds::Tuple{OffsetAxis,Vararg{OffsetAxis}}) = - OffsetArray(_reshape(parent(A), inds), map(_toaxis, inds)) # And for non-offset axes, we can just return a reshape of the parent directly -Base.reshape(A::OffsetArray, inds::Tuple{Union{Integer,Base.OneTo},Vararg{Union{Integer,Base.OneTo}}}) = _reshape_nov(A, inds) Base.reshape(A::OffsetArray, inds::Tuple{Integer,Vararg{Integer}}) = _reshape_nov(A, inds) -Base.reshape(A::OffsetArray, inds::Tuple{Union{Colon, Integer}, Vararg{Union{Colon, Integer}}}) = _reshape_nov(A, inds) Base.reshape(A::OffsetArray, inds::Dims) = _reshape_nov(A, inds) -Base.reshape(A::OffsetVector, ::Colon) = A -Base.reshape(A::OffsetVector, ::Tuple{Colon}) = A -Base.reshape(A::OffsetArray, inds::Union{Int,Colon}...) = reshape(A, inds) -Base.reshape(A::OffsetArray, inds::Tuple{Vararg{Union{Int,Colon}}}) = _reshape_nov(A, inds) -# The following two additional methods for Colon are added to resolve method ambiguities to -# Base: https://github.com/JuliaLang/julia/pull/45387#issuecomment-1132859663 -Base.reshape(A::OffsetArray, inds::Colon) = _reshape_nov(A, inds) -Base.reshape(A::OffsetArray, inds::Tuple{Colon}) = _reshape_nov(A, inds) # permutedims in Base does not preserve axes, and can not be fixed in a non-breaking way # This is a stopgap solution @@ -583,7 +591,7 @@ Base.fill!(A::OffsetArray, x) = parent_call(Ap -> fill!(Ap, x), A) # Δi = i - first(r) # i′ = first(r.parent) + Δi # and one obtains the result below. -parentindex(r::IdOffsetRange, i) = oftype(r.offset, i) - r.offset +parentindex(r::IdOffsetRange, i) = i - r.offset @propagate_inbounds Base.getindex(A::OffsetArray{<:Any,0}) = A.parent[] @@ -632,7 +640,7 @@ Base.copy(A::OffsetArray) = parent_call(copy, A) Base.strides(A::OffsetArray) = strides(parent(A)) Base.elsize(::Type{OffsetArray{T,N,A}}) where {T,N,A} = Base.elsize(A) -Base.cconvert(::Type{Ptr{T}}, A::OffsetArray{T}) where {T} = Base.cconvert(Ptr{T}, parent(A)) +Base.cconvert(P::Type{Ptr{T}}, A::OffsetArray{T}) where {T} = Base.cconvert(P, parent(A)) # For fast broadcasting: ref https://discourse.julialang.org/t/why-is-there-a-performance-hit-on-broadcasting-with-offsetarrays/32194 Base.dataids(A::OffsetArray) = Base.dataids(parent(A)) @@ -732,15 +740,6 @@ if eltype(IIUR) === Int Base.map(::Type{T}, r::IdentityUnitRange) where {T<:Real} = _indexedby(map(T, UnitRange(r)), axes(r)) end -# mapreduce is faster with an IdOffsetRange than with an OffsetUnitRange -# We therefore convert OffsetUnitRanges to IdOffsetRanges with the same values and axes -function Base.mapreduce(f, op, A1::OffsetUnitRange{<:Integer}, As::OffsetUnitRange{<:Integer}...; kw...) - As = (A1, As...) - ofs = map(A -> first(axes(A,1)) - 1, As) - AIds = map((A, of) -> IdOffsetRange(_subtractoffset(parent(A), of), of), As, ofs) - mapreduce(f, op, AIds...; kw...) -end - # Optimize certain reductions that treat an OffsetVector as a list for f in [:minimum, :maximum, :extrema, :sum] @eval Base.$f(r::OffsetRange) = $f(parent(r)) @@ -762,7 +761,8 @@ Base.append!(A::OffsetVector, items) = (append!(A.parent, items); A) Base.empty!(A::OffsetVector) = (empty!(A.parent); A) # These functions keep the summary compact -function Base.inds2string(inds::Tuple{Vararg{Union{IdOffsetRange, IdentityUnitRange{<:IdOffsetRange}}}}) +const OffsetIndices = Union{IdOffsetRange, IdentityUnitRange{<:IdOffsetRange}} +function Base.inds2string(inds::Tuple{OffsetIndices, Vararg{OffsetIndices}}) Base.inds2string(map(UnitRange, inds)) end Base.showindices(io::IO, ind1::IdOffsetRange, inds::IdOffsetRange...) = Base.showindices(io, map(UnitRange, (ind1, inds...))...) @@ -786,7 +786,33 @@ function Base.replace_in_print_matrix(A::OffsetArray{<:Any,1}, i::Integer, j::In Base.replace_in_print_matrix(parent(A), ip, j, s) end +# Actual unsafe_wrap implementation +@inline function _unsafe_wrap(pointer::Ptr{T}, inds::NTuple{N, OffsetAxisKnownLength}; own = false, kw...) where {T,N} + _checkindices(N, inds, "indices") + AA = Base.unsafe_wrap(Array, pointer, map(_indexlength, inds); own=own) + OffsetArray{T, N, typeof(AA)}(AA, map(_indexoffset, inds); kw...) +end +const OffsetArrayUnion{T,N} = Union{Type{OffsetArray}, Type{OffsetArray{T}}, Type{OffsetArray{T,N}}, Type{OffsetArray{T1, N} where T1}} where {T,N} + +@inline function Base.unsafe_wrap(::OffsetArrayUnion{T,N}, pointer::Ptr{T}, inds::NTuple{N, OffsetAxisKnownLength}; kw...) where {T,N} + _unsafe_wrap(pointer, inds; kw...) +end +# Avoid ambiguity +@inline function Base.unsafe_wrap(::OffsetArrayUnion{T,N}, pointer::Ptr{T}, inds::NTuple{N, <:Integer}; kw...) where {T,N} + _unsafe_wrap(pointer, inds; kw...) +end +@inline function Base.unsafe_wrap(::OffsetArrayUnion{T,N}, pointer::Ptr{T}, inds::Vararg{OffsetAxisKnownLength,N}; kw...) where {T,N} + _unsafe_wrap(pointer, inds; kw...) +end +# Avoid ambiguity +@inline function Base.unsafe_wrap(::OffsetArrayUnion{T,N}, pointer::Ptr{T}, inds::Vararg{Integer,N}; kw...) where {T,N} + _unsafe_wrap(pointer, inds; kw...) +end + no_offset_view(A::OffsetArray) = no_offset_view(parent(A)) +no_offset_view(a::Base.Slice{<:Base.OneTo}) = a +no_offset_view(a::Base.Slice) = Base.Slice(UnitRange(a)) +no_offset_view(S::SubArray) = view(parent(S), map(no_offset_view, parentindices(S))...) no_offset_view(a::Array) = a no_offset_view(i::Number) = i no_offset_view(A::AbstractArray) = _no_offset_view(axes(A), A) @@ -802,9 +828,12 @@ _no_offset_view(::Any, A::AbstractUnitRange) = UnitRange(A) # These two helpers are deliberately not exported; their meaning can be very different in # other scenarios and will be very likely to cause name conflicts if exported. ##### + +_halfroundInt(v, r::RoundingMode) = div(v, 2, r) + function center(A::AbstractArray, r::RoundingMode=RoundDown) map(axes(A)) do inds - round(Int, (length(inds)-1)/2, r) + first(inds) + _halfroundInt(length(inds)-1, r) + first(inds) end end From cab11bbd2d5452f523ef277bfee2affec4e3c9f5 Mon Sep 17 00:00:00 2001 From: NegaScout <42321060+NegaScout@users.noreply.github.com> Date: Tue, 24 Dec 2024 14:50:19 +0100 Subject: [PATCH 105/342] fix: Base.GMP.MPZ.invert yielding return code instead of return value (#56894) There is a bug in `Base.GMP.MPZ.invert` it returned GMP return code, instead of the actual value. This commit fixes it. Before: ``` julia> Base.GMP.MPZ.invert(big"3", big"7") 1 ``` After: ``` julia> Base.GMP.MPZ.invert(big"3", big"7") 5 ``` --- base/gmp.jl | 2 +- test/gmp.jl | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/base/gmp.jl b/base/gmp.jl index df0d9fee49348..d5db71b0630d6 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -174,8 +174,8 @@ end invert!(x::BigInt, a::BigInt, b::BigInt) = ccall((:__gmpz_invert, libgmp), Cint, (mpz_t, mpz_t, mpz_t), x, a, b) -invert(a::BigInt, b::BigInt) = invert!(BigInt(), a, b) invert!(x::BigInt, b::BigInt) = invert!(x, x, b) +invert(a::BigInt, b::BigInt) = (ret=BigInt(); invert!(ret, a, b); ret) for op in (:add_ui, :sub_ui, :mul_ui, :mul_2exp, :fdiv_q_2exp, :pow_ui, :bin_ui) op! = Symbol(op, :!) diff --git a/test/gmp.jl b/test/gmp.jl index 13413abe55f9d..9ca327e63493b 100644 --- a/test/gmp.jl +++ b/test/gmp.jl @@ -468,6 +468,34 @@ end end end +@testset "modular invert" begin + # test invert is correct and does not mutate + a = BigInt(3) + b = BigInt(7) + i = BigInt(5) + @test Base.GMP.MPZ.invert(a, b) == i + @test a == BigInt(3) + @test b == BigInt(7) + + # test in place invert does mutate first argument + a = BigInt(3) + b = BigInt(7) + i = BigInt(5) + i_inplace = BigInt(3) + Base.GMP.MPZ.invert!(i_inplace, b) + @test i_inplace == i + + # test in place invert does mutate only first argument + a = BigInt(3) + b = BigInt(7) + i = BigInt(5) + i_inplace = BigInt(0) + Base.GMP.MPZ.invert!(i_inplace, a, b) + @test i_inplace == i + @test a == BigInt(3) + @test b == BigInt(7) +end + @testset "math ops returning BigFloat" begin # operations that when applied to Int64 give Float64, should give BigFloat @test typeof(exp(a)) == BigFloat From e3f90c4062af3a40ee548203242744424f2029fa Mon Sep 17 00:00:00 2001 From: Simeon David Schaub Date: Wed, 25 Dec 2024 23:26:15 +0100 Subject: [PATCH 106/342] fix precompilation error printing if `CI` is set (#56905) Co-authored-by: Ian Butterworth --- base/precompilation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/precompilation.jl b/base/precompilation.jl index f61169c6ca16d..c493690bab64e 100644 --- a/base/precompilation.jl +++ b/base/precompilation.jl @@ -1098,7 +1098,7 @@ function _precompilepkgs(pkgs::Vector{String}, direct = strict ? "" : "direct " err_msg = "The following $n_direct_errs $(direct)dependenc$(pluralde) failed to precompile:\n$(String(take!(err_str)))" if internal_call # aka. auto-precompilation - if isinteractive() && !get(ENV, "CI", false) + if isinteractive() plural1 = length(failed_deps) == 1 ? "y" : "ies" println(io, " ", color_string("$(length(failed_deps))", Base.error_color()), " dependenc$(plural1) errored.") println(io, " For a report of the errors see `julia> err`. To retry use `pkg> precompile`") From 8788497dc215088227af37b9a7065e00ca959859 Mon Sep 17 00:00:00 2001 From: Lilith Orion Hafner Date: Fri, 27 Dec 2024 15:38:22 -0600 Subject: [PATCH 107/342] Add #53664, public&export error to news (#56911) Suggested by @simeonschaub [here](https://github.com/JuliaLang/julia/pull/53664#issuecomment-2562408676) --- NEWS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS.md b/NEWS.md index 3c893566c7219..15d5e90c9c949 100644 --- a/NEWS.md +++ b/NEWS.md @@ -46,6 +46,9 @@ Language changes behavior. Infinite loops that actually do things (e.g. have side effects or sleep) were never and are still not undefined behavior. ([#52999]) + - It is now an error to mark a symbol as both `public` and `export`ed. + ([#53664]) + Compiler/Runtime improvements ----------------------------- From b4e4ba7bc4f4c3569c10d7c94da6d12dfcd5630e Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Sat, 28 Dec 2024 13:16:14 +0900 Subject: [PATCH 108/342] restrict `optimize_until` argument type correctly (#56912) The object types that `optimize_until` can accept are restricted by `matchpass`, so this restriction should also be reflected in functions like `typeinf_ircode` too. --- Compiler/src/optimize.jl | 2 +- Compiler/src/typeinfer.jl | 12 ++++++------ base/reflection.jl | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Compiler/src/optimize.jl b/Compiler/src/optimize.jl index bc3fc4f9705c4..12b2f3c9a269f 100644 --- a/Compiler/src/optimize.jl +++ b/Compiler/src/optimize.jl @@ -1025,7 +1025,7 @@ function run_passes_ipo_safe( optimize_until = nothing, # run all passes by default ) __stage__ = 0 # used by @pass - # NOTE: The pass name MUST be unique for `optimize_until::AbstractString` to work + # NOTE: The pass name MUST be unique for `optimize_until::String` to work @pass "convert" ir = convert_to_ircode(ci, sv) @pass "slot2reg" ir = slot2reg(ir, ci, sv) # TODO: Domsorting can produce an updated domtree - no need to recompute here diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index f7cd574abbcef..eba520a03ada1 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -977,23 +977,23 @@ end """ typeinf_ircode(interp::AbstractInterpreter, match::MethodMatch, - optimize_until::Union{Integer,AbstractString,Nothing}) -> (ir::Union{IRCode,Nothing}, returntype::Type) + optimize_until::Union{Int,String,Nothing}) -> (ir::Union{IRCode,Nothing}, returntype::Type) typeinf_ircode(interp::AbstractInterpreter, method::Method, atype, sparams::SimpleVector, - optimize_until::Union{Integer,AbstractString,Nothing}) -> (ir::Union{IRCode,Nothing}, returntype::Type) + optimize_until::Union{Int,String,Nothing}) -> (ir::Union{IRCode,Nothing}, returntype::Type) typeinf_ircode(interp::AbstractInterpreter, mi::MethodInstance, - optimize_until::Union{Integer,AbstractString,Nothing}) -> (ir::Union{IRCode,Nothing}, returntype::Type) + optimize_until::Union{Int,String,Nothing}) -> (ir::Union{IRCode,Nothing}, returntype::Type) Infer a `method` and return an `IRCode` with inferred `returntype` on success. """ typeinf_ircode(interp::AbstractInterpreter, match::MethodMatch, - optimize_until::Union{Integer,AbstractString,Nothing}) = + optimize_until::Union{Int,String,Nothing}) = typeinf_ircode(interp, specialize_method(match), optimize_until) typeinf_ircode(interp::AbstractInterpreter, method::Method, @nospecialize(atype), sparams::SimpleVector, - optimize_until::Union{Integer,AbstractString,Nothing}) = + optimize_until::Union{Int,String,Nothing}) = typeinf_ircode(interp, specialize_method(method, atype, sparams), optimize_until) function typeinf_ircode(interp::AbstractInterpreter, mi::MethodInstance, - optimize_until::Union{Integer,AbstractString,Nothing}) + optimize_until::Union{Int,String,Nothing}) frame = typeinf_frame(interp, mi, false) if frame === nothing return nothing, Any diff --git a/base/reflection.jl b/base/reflection.jl index be344648f8f52..f7952ac7a78d7 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -463,7 +463,7 @@ internals. when looking up methods, use current world age if not specified. - `interp::Core.Compiler.AbstractInterpreter = Core.Compiler.NativeInterpreter(world)`: optional, controls the abstract interpreter to use, use the native interpreter if not specified. -- `optimize_until::Union{Integer,AbstractString,Nothing} = nothing`: optional, +- `optimize_until::Union{Int,String,Nothing} = nothing`: optional, controls the optimization passes to run. If it is a string, it specifies the name of the pass up to which the optimizer is run. If it is an integer, it specifies the number of passes to run. @@ -507,7 +507,7 @@ function code_ircode_by_type( @nospecialize(tt::Type); world::UInt=get_world_counter(), interp=nothing, - optimize_until::Union{Integer,AbstractString,Nothing}=nothing, + optimize_until::Union{Int,String,Nothing}=nothing, ) passed_interp = interp interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp From 5198c062a2f9d6f308465bb464d3974965f95a97 Mon Sep 17 00:00:00 2001 From: Neven Sajko <4944410+nsajko@users.noreply.github.com> Date: Sun, 29 Dec 2024 07:57:48 +0100 Subject: [PATCH 109/342] doc: manual: give the Performance Tips a table of contents (#56917) The page is quite long, and now it also has a more intricate structure than before, IMO it deserves a TOC. --- doc/src/manual/performance-tips.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/src/manual/performance-tips.md b/doc/src/manual/performance-tips.md index 1166164241c60..d506ac9946ba6 100644 --- a/doc/src/manual/performance-tips.md +++ b/doc/src/manual/performance-tips.md @@ -3,6 +3,13 @@ In the following sections, we briefly go through a few techniques that can help make your Julia code run as fast as possible. +## [Table of contents](@id man-performance-tips-toc) + +```@contents +Pages = ["performance-tips.md"] +Depth = 3 +``` + ## General advice ### Performance critical code should be inside a function From 4b2f4d9d2eb85c2e585f2fdc4fdadc313b00bebd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Guedes?= Date: Sun, 29 Dec 2024 21:03:01 -0300 Subject: [PATCH 110/342] ReentrantLock: wakeup a single task on unlock and add a short spin (#56814) I propose a change in the implementation of the `ReentrantLock` to improve its overall throughput for short critical sections and fix the quadratic wake-up behavior where each unlock schedules **all** waiting tasks on the lock's wait queue. This implementation follows the same principles of the `Mutex` in the [parking_lot](https://github.com/Amanieu/parking_lot/tree/master) Rust crate which is based on the Webkit [WTF::ParkingLot](https://webkit.org/blog/6161/locking-in-webkit/) class. Only the basic working principle is implemented here, further improvements such as eventual fairness will be proposed separately. The gist of the change is that we add one extra state to the lock, essentially going from: ``` 0x0 => The lock is not locked 0x1 => The lock is locked by exactly one task. No other task is waiting for it. 0x2 => The lock is locked and some other task tried to lock but failed (conflict) ``` To: ``` # PARKED_BIT | LOCKED_BIT | Description # 0 | 0 | The lock is not locked, nor is anyone waiting for it. # -----------+------------+------------------------------------------------------------------ # 0 | 1 | The lock is locked by exactly one task. No other task is # | | waiting for it. # -----------+------------+------------------------------------------------------------------ # 1 | 0 | The lock is not locked. One or more tasks are parked. # -----------+------------+------------------------------------------------------------------ # 1 | 1 | The lock is locked by exactly one task. One or more tasks are # | | parked waiting for the lock to become available. # | | In this state, PARKED_BIT is only ever cleared when the cond_wait lock # | | is held (i.e. on unlock). This ensures that # | | we never end up in a situation where there are parked tasks but # | | PARKED_BIT is not set (which would result in those tasks # | | potentially never getting woken up). ``` In the current implementation we must schedule all tasks to cause a conflict (state 0x2) because on unlock we only notify any task if the lock is in the conflict state. This behavior means that with high contention and a short critical section the tasks will be effectively spinning in the scheduler queue. With the extra state the proposed implementation has enough information to know if there are other tasks to be notified or not, which means we can always notify one task at a time while preserving the optimized path of not notifying if there are no tasks waiting. To improve throughput for short critical sections we also introduce a bounded amount of spinning before attempting to park. ### Results Not spinning on the scheduler queue greatly reduces the CPU utilization of the following example: ```julia function example() lock = ReentrantLock() @sync begin for i in 1:10000 Threads.@spawn begin @lock lock begin sleep(0.001) end end end end end @time example() ``` Current: ``` 28.890623 seconds (101.65 k allocations: 7.646 MiB, 0.25% compilation time) ``` ![image](https://github.com/user-attachments/assets/dbd6ce57-c760-4f5a-b68a-27df6a97a46e) Proposed: ``` 22.806669 seconds (101.65 k allocations: 7.814 MiB, 0.35% compilation time) ``` ![image](https://github.com/user-attachments/assets/b0254180-658d-4493-86d3-dea4c500b5ac) In a micro-benchmark where 8 threads contend for a single lock with a very short critical section we see a ~2x improvement. Current: ``` 8-element Vector{Int64}: 6258688 5373952 6651904 6389760 6586368 3899392 5177344 5505024 Total iterations: 45842432 ``` Proposed: ``` 8-element Vector{Int64}: 12320768 12976128 10354688 12845056 7503872 13598720 13860864 11993088 Total iterations: 95453184 ``` ~~In the uncontended scenario the extra bookkeeping causes a 10% throughput reduction:~~ EDIT: I reverted _trylock to the simple case to recover the uncontended throughput and now both implementations are on the same ballpark (without hurting the above numbers). In the uncontended scenario: Current: ``` Total iterations: 236748800 ``` Proposed: ``` Total iterations: 237699072 ``` Closes #56182 --- base/lock.jl | 126 +++++++++++++++++++++++++++++++++++++++--------- test/threads.jl | 3 +- 2 files changed, 106 insertions(+), 23 deletions(-) diff --git a/base/lock.jl b/base/lock.jl index a44cd4c0d63cf..59e554c01c24a 100644 --- a/base/lock.jl +++ b/base/lock.jl @@ -9,6 +9,14 @@ Get the currently running [`Task`](@ref). """ current_task() = ccall(:jl_get_current_task, Ref{Task}, ()) +# This bit is set in the `havelock` of a `ReentrantLock` when that lock is locked by some task. +const LOCKED_BIT = 0b01 +# This bit is set in the `havelock` of a `ReentrantLock` just before parking a task. A task is being +# parked if it wants to lock the lock, but it is currently being held by some other task. +const PARKED_BIT = 0b10 + +const MAX_SPIN_ITERS = 40 + # Advisory reentrant lock """ ReentrantLock() @@ -43,7 +51,28 @@ mutable struct ReentrantLock <: AbstractLock # offset32 = 20, offset64 = 24 reentrancy_cnt::UInt32 # offset32 = 24, offset64 = 28 - @atomic havelock::UInt8 # 0x0 = none, 0x1 = lock, 0x2 = conflict + # + # This atomic integer holds the current state of the lock instance. Only the two lowest bits + # are used. See `LOCKED_BIT` and `PARKED_BIT` for the bitmask for these bits. + # + # # State table: + # + # PARKED_BIT | LOCKED_BIT | Description + # 0 | 0 | The lock is not locked, nor is anyone waiting for it. + # -----------+------------+------------------------------------------------------------------ + # 0 | 1 | The lock is locked by exactly one task. No other task is + # | | waiting for it. + # -----------+------------+------------------------------------------------------------------ + # 1 | 0 | The lock is not locked. One or more tasks are parked. + # -----------+------------+------------------------------------------------------------------ + # 1 | 1 | The lock is locked by exactly one task. One or more tasks are + # | | parked waiting for the lock to become available. + # | | In this state, PARKED_BIT is only ever cleared when the cond_wait lock + # | | is held (i.e. on unlock). This ensures that + # | | we never end up in a situation where there are parked tasks but + # | | PARKED_BIT is not set (which would result in those tasks + # | | potentially never getting woken up). + @atomic havelock::UInt8 # offset32 = 28, offset64 = 32 cond_wait::ThreadSynchronizer # 2 words # offset32 = 36, offset64 = 48 @@ -112,7 +141,7 @@ function islocked end # `ReentrantLock`. function islocked(rl::ReentrantLock) - return (@atomic :monotonic rl.havelock) != 0 + return (@atomic :monotonic rl.havelock) & LOCKED_BIT != 0 end """ @@ -136,7 +165,6 @@ function trylock end @inline function trylock(rl::ReentrantLock) ct = current_task() if rl.locked_by === ct - #@assert rl.havelock !== 0x00 rl.reentrancy_cnt += 0x0000_0001 return true end @@ -144,9 +172,8 @@ function trylock end end @noinline function _trylock(rl::ReentrantLock, ct::Task) GC.disable_finalizers() - if (@atomicreplace :acquire rl.havelock 0x00 => 0x01).success - #@assert rl.locked_by === nothing - #@assert rl.reentrancy_cnt === 0 + state = (@atomic :monotonic rl.havelock) & PARKED_BIT + if (@atomicreplace :acquire rl.havelock state => (state | LOCKED_BIT)).success rl.reentrancy_cnt = 0x0000_0001 @atomic :release rl.locked_by = ct return true @@ -168,23 +195,69 @@ Each `lock` must be matched by an [`unlock`](@ref). trylock(rl) || (@noinline function slowlock(rl::ReentrantLock) Threads.lock_profiling() && Threads.inc_lock_conflict_count() c = rl.cond_wait - lock(c.lock) - try - while true - if (@atomicreplace rl.havelock 0x01 => 0x02).old == 0x00 # :sequentially_consistent ? # now either 0x00 or 0x02 - # it was unlocked, so try to lock it ourself - _trylock(rl, current_task()) && break - else # it was locked, so now wait for the release to notify us - wait(c) + ct = current_task() + iteration = 1 + while true + state = @atomic :monotonic rl.havelock + # Grab the lock if it isn't locked, even if there is a queue on it + if state & LOCKED_BIT == 0 + GC.disable_finalizers() + result = (@atomicreplace :acquire :monotonic rl.havelock state => (state | LOCKED_BIT)) + if result.success + rl.reentrancy_cnt = 0x0000_0001 + @atomic :release rl.locked_by = ct + return end + GC.enable_finalizers() + continue end - finally - unlock(c.lock) + + if state & PARKED_BIT == 0 + # If there is no queue, try spinning a few times + if iteration <= MAX_SPIN_ITERS + Base.yield() + iteration += 1 + continue + end + + # If still not locked, try setting the parked bit + @atomicreplace :monotonic :monotonic rl.havelock state => (state | PARKED_BIT) + end + + # lock the `cond_wait` + lock(c.lock) + + # Last check before we wait to make sure `unlock` did not win the race + # to the `cond_wait` lock and cleared the parked bit + state = @atomic :acquire rl.havelock + if state != LOCKED_BIT | PARKED_BIT + unlock(c.lock) + continue + end + + # It was locked, so now wait for the unlock to notify us + wait_no_relock(c) + + # Loop back and try locking again + iteration = 1 end end)(rl) return end +function wait_no_relock(c::GenericCondition) + ct = current_task() + _wait2(c, ct) + token = unlockall(c.lock) + try + return wait() + catch + ct.queue === nothing || list_deletefirst!(ct.queue, ct) + rethrow() + end +end + + """ unlock(lock) @@ -201,18 +274,27 @@ internal counter and return immediately. rl.reentrancy_cnt = n if n == 0x0000_00000 @atomic :monotonic rl.locked_by = nothing - if (@atomicswap :release rl.havelock = 0x00) == 0x02 + result = (@atomicreplace :release :monotonic rl.havelock LOCKED_BIT => 0x00) + if result.success + return true + else (@noinline function notifywaiters(rl) cond_wait = rl.cond_wait lock(cond_wait) - try - notify(cond_wait) - finally - unlock(cond_wait) + + notify(cond_wait, all=false) + if !isempty(cond_wait.waitq) + @atomic :release rl.havelock = PARKED_BIT + else + # We may have won the race to the `cond_wait` lock as a task was about to park + # but we unlock anyway as any parking task will retry + @atomic :release rl.havelock = 0x00 end + + unlock(cond_wait) end)(rl) + return true end - return true end return false end)(rl) && GC.enable_finalizers() diff --git a/test/threads.jl b/test/threads.jl index 4d928ca05da16..179279dbab4e6 100644 --- a/test/threads.jl +++ b/test/threads.jl @@ -16,7 +16,8 @@ let lk = ReentrantLock() t2 = @async (notify(c2); trylock(lk)) wait(c1) wait(c2) - @test t1.queue === lk.cond_wait.waitq + # wait for the task to park in the queue (it may be spinning) + @test timedwait(() -> t1.queue === lk.cond_wait.waitq, 1.0) == :ok @test t2.queue !== lk.cond_wait.waitq @test istaskdone(t2) @test !fetch(t2) From d12bcfca4fae7785ca0fe3a8cfffdde0c6eeab87 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Mon, 30 Dec 2024 11:24:48 -0500 Subject: [PATCH 111/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?Pkg=20stdlib=20from=20e7c37f342=20to=20c7e611bc8=20(#56918)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Pkg-c7e611bc89826bc462c4b2a308f1a71dbb617145.tar.gz/md5 | 1 + .../Pkg-c7e611bc89826bc462c4b2a308f1a71dbb617145.tar.gz/sha512 | 1 + .../Pkg-e7c37f34293ab12051258828884755ea116b77df.tar.gz/md5 | 1 - .../Pkg-e7c37f34293ab12051258828884755ea116b77df.tar.gz/sha512 | 1 - stdlib/Pkg.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/Pkg-c7e611bc89826bc462c4b2a308f1a71dbb617145.tar.gz/md5 create mode 100644 deps/checksums/Pkg-c7e611bc89826bc462c4b2a308f1a71dbb617145.tar.gz/sha512 delete mode 100644 deps/checksums/Pkg-e7c37f34293ab12051258828884755ea116b77df.tar.gz/md5 delete mode 100644 deps/checksums/Pkg-e7c37f34293ab12051258828884755ea116b77df.tar.gz/sha512 diff --git a/deps/checksums/Pkg-c7e611bc89826bc462c4b2a308f1a71dbb617145.tar.gz/md5 b/deps/checksums/Pkg-c7e611bc89826bc462c4b2a308f1a71dbb617145.tar.gz/md5 new file mode 100644 index 0000000000000..ac906597fde45 --- /dev/null +++ b/deps/checksums/Pkg-c7e611bc89826bc462c4b2a308f1a71dbb617145.tar.gz/md5 @@ -0,0 +1 @@ +7e3e14d5f6f5851f91a487cbef962ddc diff --git a/deps/checksums/Pkg-c7e611bc89826bc462c4b2a308f1a71dbb617145.tar.gz/sha512 b/deps/checksums/Pkg-c7e611bc89826bc462c4b2a308f1a71dbb617145.tar.gz/sha512 new file mode 100644 index 0000000000000..b5e016fae36a7 --- /dev/null +++ b/deps/checksums/Pkg-c7e611bc89826bc462c4b2a308f1a71dbb617145.tar.gz/sha512 @@ -0,0 +1 @@ +2c492da39ecb43ff1c2ebac877a2de8b152564b4cac7ac1e3bdea006a80305168f7cd2d2d289073fc4db67b0686d6cc707b1f7ba04dacaef353bef9a4cbea61a diff --git a/deps/checksums/Pkg-e7c37f34293ab12051258828884755ea116b77df.tar.gz/md5 b/deps/checksums/Pkg-e7c37f34293ab12051258828884755ea116b77df.tar.gz/md5 deleted file mode 100644 index 6627dc3683c65..0000000000000 --- a/deps/checksums/Pkg-e7c37f34293ab12051258828884755ea116b77df.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -7024326f0c033e3da419ed217754fbed diff --git a/deps/checksums/Pkg-e7c37f34293ab12051258828884755ea116b77df.tar.gz/sha512 b/deps/checksums/Pkg-e7c37f34293ab12051258828884755ea116b77df.tar.gz/sha512 deleted file mode 100644 index cfc9d5f30f0e8..0000000000000 --- a/deps/checksums/Pkg-e7c37f34293ab12051258828884755ea116b77df.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -bef19838be850f027fb3dedadce0efa762cd64797809030210ec95830f538ced1b2aede3bd2ca5f32d489e2dc517b7c8e38307adcba194db417ce792437cfb56 diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 50105c42c642c..5102be7bdce46 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = master -PKG_SHA1 = e7c37f34293ab12051258828884755ea116b77df +PKG_SHA1 = c7e611bc89826bc462c4b2a308f1a71dbb617145 PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 From a6520678f2036ddb4a6f668af83a3a378e8d0121 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Mon, 30 Dec 2024 15:51:41 -0500 Subject: [PATCH 112/342] Don't report only-inferred methods as recompiles (#56914) --- src/gf.c | 12 +++++++++++- test/cmdlineargs.jl | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/gf.c b/src/gf.c index d220ad057176a..52741094c0533 100644 --- a/src/gf.c +++ b/src/gf.c @@ -2863,7 +2863,17 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t // Everything from here on is considered (user facing) compile time uint64_t start = jl_typeinf_timing_begin(); - int is_recompile = jl_atomic_load_relaxed(&mi->cache) != NULL; + + // Is a recompile if there is cached code, and it was compiled (not only inferred) before + int is_recompile = 0; + jl_code_instance_t *codeinst_old = jl_atomic_load_relaxed(&mi->cache); + while (codeinst_old != NULL) { + if (jl_atomic_load_relaxed(&codeinst_old->invoke) != NULL) { + is_recompile = 1; + break; + } + codeinst_old = jl_atomic_load_relaxed(&codeinst_old->next); + } // This codeinst hasn't been previously inferred do that now // jl_type_infer will internally do a cache lookup and jl_engine_reserve call diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index 5df174694049d..74f953250cd37 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -818,6 +818,26 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no` @test occursin(" ms =# precompile(Tuple{typeof(Main.foo), Int", _stderr) end + # Base.@trace_compile (local version of the 2 above args) + let + io = IOBuffer() + v = writereadpipeline( + """ + f(x::Int) = 1 + applyf(container) = f(container[1]) + Base.@trace_compile @eval applyf([100]) + Base.@trace_compile @eval applyf(Any[100]) + f(::Bool) = 2 + Base.@trace_compile @eval applyf([true]) + Base.@trace_compile @eval applyf(Any[true]) + """, + `$exename -i`, + stderr=io) + _stderr = String(take!(io)) + @test length(findall(r"precompile\(", _stderr)) == 5 + @test length(findall(r" # recompile", _stderr)) == 1 + end + # --trace-dispatch let io = IOBuffer() From 27ebbf01ccc44d78694516ff6daf55af65b7439b Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Mon, 30 Dec 2024 15:52:23 -0500 Subject: [PATCH 113/342] precompilepkgs: respect loaded dependencies when precompiling for load (#56901) --- base/loading.jl | 4 ++-- base/precompilation.jl | 24 ++++++++++++++---------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/base/loading.jl b/base/loading.jl index 8ed43e4539c20..024c4ceb356fd 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -1828,7 +1828,7 @@ function compilecache_path(pkg::PkgId; path = nothing isnothing(sourcepath) && error("Cannot locate source for $(repr("text/plain", pkg))") for path_to_try in cachepaths - staledeps = stale_cachefile(sourcepath, path_to_try, ignore_loaded = true, requested_flags=flags) + staledeps = stale_cachefile(sourcepath, path_to_try; ignore_loaded, requested_flags=flags) if staledeps === true continue end @@ -2649,7 +2649,7 @@ function __require_prelocked(pkg::PkgId, env) parallel_precompile_attempted = true unlock(require_lock) try - Precompilation.precompilepkgs([pkg.name]; _from_loading=true) + Precompilation.precompilepkgs([pkg.name]; _from_loading=true, ignore_loaded=false) finally lock(require_lock) end diff --git a/base/precompilation.jl b/base/precompilation.jl index c493690bab64e..c7dcd0af64caa 100644 --- a/base/precompilation.jl +++ b/base/precompilation.jl @@ -418,11 +418,12 @@ function precompilepkgs(pkgs::Vector{String}=String[]; io::IO=stderr, # asking for timing disables fancy mode, as timing is shown in non-fancy mode fancyprint::Bool = can_fancyprint(io) && !timing, - manifest::Bool=false,) + manifest::Bool=false, + ignore_loaded::Bool=true) # monomorphize this to avoid latency problems _precompilepkgs(pkgs, internal_call, strict, warn_loaded, timing, _from_loading, configs isa Vector{Config} ? configs : [configs], - IOContext{IO}(io), fancyprint, manifest) + IOContext{IO}(io), fancyprint, manifest, ignore_loaded) end function _precompilepkgs(pkgs::Vector{String}, @@ -434,7 +435,8 @@ function _precompilepkgs(pkgs::Vector{String}, configs::Vector{Config}, io::IOContext{IO}, fancyprint::Bool, - manifest::Bool) + manifest::Bool, + ignore_loaded::Bool) requested_pkgs = copy(pkgs) # for understanding user intent time_start = time_ns() @@ -918,7 +920,7 @@ function _precompilepkgs(pkgs::Vector{String}, wait(was_processed[(dep,config)]) end circular = pkg in circular_deps - is_stale = !Base.isprecompiled(pkg; ignore_loaded=true, stale_cache, cachepath_cache, cachepaths, sourcepath, flags=cacheflags) + is_stale = !Base.isprecompiled(pkg; ignore_loaded, stale_cache, cachepath_cache, cachepaths, sourcepath, flags=cacheflags) if !circular && is_stale Base.acquire(parallel_limiter) is_project_dep = pkg in project_deps @@ -944,10 +946,10 @@ function _precompilepkgs(pkgs::Vector{String}, try # allows processes to wait if another process is precompiling a given package to # a functionally identical package cache (except for preferences, which may differ) - t = @elapsed ret = precompile_pkgs_maybe_cachefile_lock(io, print_lock, fancyprint, pkg_config, pkgspidlocked, hascolor, parallel_limiter) do + t = @elapsed ret = precompile_pkgs_maybe_cachefile_lock(io, print_lock, fancyprint, pkg_config, pkgspidlocked, hascolor, parallel_limiter, ignore_loaded) do Base.with_logger(Base.NullLogger()) do - # The false here means we ignore loaded modules, so precompile for a fresh session - keep_loaded_modules = false + # whether to respect already loaded dependency versions + keep_loaded_modules = !ignore_loaded # for extensions, any extension in our direct dependencies is one we have a right to load # for packages, we may load any extension (all possible triggers are accounted for above) loadable_exts = haskey(ext_to_parent, pkg) ? filter((dep)->haskey(ext_to_parent, dep), direct_deps[pkg]) : nothing @@ -1037,9 +1039,11 @@ function _precompilepkgs(pkgs::Vector{String}, plural1 = length(configs) > 1 ? "dependency configurations" : n_loaded == 1 ? "dependency" : "dependencies" plural2 = n_loaded == 1 ? "a different version is" : "different versions are" plural3 = n_loaded == 1 ? "" : "s" + plural4 = n_loaded == 1 ? "this package" : "these packages" print(iostr, "\n ", color_string(string(n_loaded), Base.warn_color()), - " $(plural1) precompiled but $(plural2) currently loaded. Restart julia to access the new version$(plural3)" + " $(plural1) precompiled but $(plural2) currently loaded. Restart julia to access the new version$(plural3). \ + Otherwise, loading dependents of $(plural4) may trigger further precompilation to work with the unexpected version$(plural3)." ) end if !isempty(precomperr_deps) @@ -1130,7 +1134,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) +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) if !(isdefined(Base, :mkpidlock_hook) && isdefined(Base, :trymkpidlock_hook) && Base.isdefined(Base, :parse_pidfile_hook)) return f() end @@ -1158,7 +1162,7 @@ function precompile_pkgs_maybe_cachefile_lock(f, io::IO, print_lock::ReentrantLo # wait until the lock is available @invokelatest Base.mkpidlock_hook(() -> begin # double-check in case the other process crashed or the lock expired - if Base.isprecompiled(pkg; ignore_loaded=true, flags=cacheflags) # don't use caches for this as the env state will have changed + if Base.isprecompiled(pkg; ignore_loaded, flags=cacheflags) # don't use caches for this as the env state will have changed return nothing # returning nothing indicates a process waited for another else delete!(pkgspidlocked, pkg_config) From 90dee4d1090abbd28608a33a1a638639e6b31720 Mon Sep 17 00:00:00 2001 From: Arno Strouwen Date: Mon, 30 Dec 2024 22:57:23 +0100 Subject: [PATCH 114/342] Add julia-repl in destructuring docs (#56866) From 16230c01bf9fb40634225fd432aa5cadb55a58a2 Mon Sep 17 00:00:00 2001 From: Neven Sajko <4944410+nsajko@users.noreply.github.com> Date: Tue, 31 Dec 2024 05:48:23 +0100 Subject: [PATCH 115/342] doc: manual: Command-line Interface: tiny Markdown code formatting fix (#56919) --- doc/src/manual/command-line-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/manual/command-line-interface.md b/doc/src/manual/command-line-interface.md index 3477f61164c50..14dd60d89b384 100644 --- a/doc/src/manual/command-line-interface.md +++ b/doc/src/manual/command-line-interface.md @@ -216,7 +216,7 @@ The following is a complete list of command-line switches available when launchi |`--output-asm ` |Generate an assembly file (.s)| |`--output-incremental={yes\|no*}` |Generate an incremental output file (rather than complete)| |`--trace-compile={stderr\|name}` |Print precompile statements for methods compiled during execution or save to stderr or a path. Methods that were recompiled are printed in yellow or with a trailing comment if color is not supported| -|`--trace-compile-timing` |If --trace-compile is enabled show how long each took to compile in ms| +|`--trace-compile-timing` |If `--trace-compile` is enabled show how long each took to compile in ms| |`--trace-dispatch={stderr\|name}` |Print precompile statements for methods dispatched during execution or save to stderr or a path.| |`--image-codegen` |Force generate code in imaging mode| |`--permalloc-pkgimg={yes\|no*}` |Copy the data section of package images into memory| From d604057050dd9642fcf7fa0dd03f96f22923c4f9 Mon Sep 17 00:00:00 2001 From: James Wrigley Date: Tue, 31 Dec 2024 15:30:47 +0100 Subject: [PATCH 116/342] Make threadpoolsize(), threadpooltids(), and ngcthreads() public (#55701) --- base/threadingconstructs.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/threadingconstructs.jl b/base/threadingconstructs.jl index 07ff814af1570..3d86e203ef72e 100644 --- a/base/threadingconstructs.jl +++ b/base/threadingconstructs.jl @@ -3,7 +3,7 @@ export threadid, nthreads, @threads, @spawn, threadpool, nthreadpools -public Condition +public Condition, threadpoolsize, ngcthreads """ Threads.threadid([t::Task]) -> Int From 6136893eeed0c3559263a5aa465b630d2c7dc821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= <765740+giordano@users.noreply.github.com> Date: Tue, 31 Dec 2024 18:34:05 +0100 Subject: [PATCH 117/342] [Test] Print RNG of a failed testset and add option to set it (#56260) Also, add a keyword option to `@testset` to let users override the seed used there, to make testsets more replicable. To give you a taster of what this PR enables: ``` julia> using Random, Test julia> @testset begin @test rand() == 0 end; test set: Test Failed at REPL[2]:2 Expression: rand() == 0 Evaluated: 0.559472630416976 == 0 Stacktrace: [1] top-level scope @ REPL[2]:2 [2] macro expansion @ ~/repo/julia/usr/share/julia/stdlib/v1.12/Test/src/Test.jl:1713 [inlined] [3] macro expansion @ REPL[2]:2 [inlined] [4] macro expansion @ ~/repo/julia/usr/share/julia/stdlib/v1.12/Test/src/Test.jl:679 [inlined] Test Summary: | Fail Total Time test set | 1 1 0.9s ERROR: Some tests did not pass: 0 passed, 1 failed, 0 errored, 0 broken. Random seed for this testset: Xoshiro(0x2e026445595ed28e, 0x07bb81ac4c54926d, 0x83d7d70843e8bad6, 0xdbef927d150af80b, 0xdbf91ddf2534f850) julia> @testset rng=Xoshiro(0x2e026445595ed28e, 0x07bb81ac4c54926d, 0x83d7d70843e8bad6, 0xdbef927d150af80b, 0xdbf91ddf2534f850) begin @test rand() == 0.559472630416976 end; Test Summary: | Pass Total Time test set | 1 1 0.0s ``` This also works with nested testsets, and testsets on for loops: ``` julia> @testset rng=Xoshiro(0xc380f460355639ee, 0xb39bc754b7d63bbf, 0x1551dbcfb5ed5668, 0x71ab5a18fec21a25, 0x649d0c1be1ca5436) "Outer" begin @test rand() == 0.0004120194925605336 @testset rng=Xoshiro(0xee97f5b53f7cdc49, 0x480ac387b0527d3d, 0x614b416502a9e0f5, 0x5250cb36e4a4ceb1, 0xed6615c59e475fa0) "Inner: $(i)" for i in 1:10 @test rand() == 0.39321938407066637 end end; Test Summary: | Pass Total Time Outer | 11 11 0.0s ``` Being able to see what was the seed inside a testset and being able to set it afterwards should make replicating test failures which only depend on the state of the RNG much easier to debug. --- NEWS.md | 9 +++++ stdlib/Test/src/Test.jl | 64 +++++++++++++++++++++++++++++------- stdlib/Test/test/runtests.jl | 31 +++++++++++++---- 3 files changed, 86 insertions(+), 18 deletions(-) diff --git a/NEWS.md b/NEWS.md index 15d5e90c9c949..e6d12f1822da4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -183,6 +183,15 @@ Standard library changes #### Test +* A failing `DefaultTestSet` now prints to screen the random number generator (RNG) of the failed test, to help reproducing a stochastic failure which only depends on the state of the RNG. + It is also possible seed a test set by passing the `rng` keyword argument to `@testset`: + ```julia + using Test, Random + @testset rng=Xoshiro(0x2e026445595ed28e, 0x07bb81ac4c54926d, 0x83d7d70843e8bad6, 0xdbef927d150af80b, 0xdbf91ddf2534f850) begin + @test rand() == 0.559472630416976 + end + ``` + #### Dates #### Statistics diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index 3a60527a26e11..79fdb89399d42 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -1071,8 +1071,9 @@ mutable struct DefaultTestSet <: AbstractTestSet time_end::Union{Float64,Nothing} failfast::Bool file::Union{String,Nothing} + rng::Union{Nothing,AbstractRNG} end -function DefaultTestSet(desc::AbstractString; verbose::Bool = false, showtiming::Bool = true, failfast::Union{Nothing,Bool} = nothing, source = nothing) +function DefaultTestSet(desc::AbstractString; verbose::Bool = false, showtiming::Bool = true, failfast::Union{Nothing,Bool} = nothing, source = nothing, rng = nothing) if isnothing(failfast) # pass failfast state into child testsets parent_ts = get_testset() @@ -1082,7 +1083,7 @@ function DefaultTestSet(desc::AbstractString; verbose::Bool = false, showtiming: failfast = false end end - return DefaultTestSet(String(desc)::String, [], 0, false, verbose, showtiming, time(), nothing, failfast, extract_file(source)) + return DefaultTestSet(String(desc)::String, [], 0, false, verbose, showtiming, time(), nothing, failfast, extract_file(source), rng) end extract_file(source::LineNumberNode) = extract_file(source.file) extract_file(file::Symbol) = string(file) @@ -1219,6 +1220,13 @@ function print_test_results(ts::AbstractTestSet, depth_pad=0) println() # Recursively print a summary at every level print_counts(ts, depth_pad, align, pass_width, fail_width, error_width, broken_width, total_width, duration_width, timing) + # Print the RNG of the outer testset if there are failures + if total != total_pass + total_broken + rng = get_rng(ts) + if !isnothing(rng) + println("RNG of the outermost testset: ", rng) + end + end end @@ -1290,6 +1298,24 @@ function filter_errors(ts::DefaultTestSet) efs end +""" + Test.get_rng(ts::AbstractTestSet) -> Union{Nothing,AbstractRNG} + +Return the global random number generator (RNG) associated to the input testset `ts`. +If no RNG is associated to it, return `nothing`. +""" +get_rng(::AbstractTestSet) = nothing +get_rng(ts::DefaultTestSet) = ts.rng +""" + Test.set_rng!(ts::AbstractTestSet, rng::AbstractRNG) -> AbstractRNG + +Set the global random number generator (RNG) associated to the input testset `ts` to `rng`. +If no RNG is associated to it, do nothing. +In any case, always return the input `rng`. +""" +set_rng!(::AbstractTestSet, rng::AbstractRNG) = rng +set_rng!(ts::DefaultTestSet, rng::AbstractRNG) = ts.rng = rng + """ TestCounts @@ -1494,14 +1520,17 @@ along with a summary of the test results. Any custom testset type (subtype of `AbstractTestSet`) can be given and it will also be used for any nested `@testset` invocations. The given options are only applied to the test set where they are given. The default test set type -accepts three boolean options: -- `verbose`: if `true`, the result summary of the nested testsets is shown even +accepts the following options: +- `verbose::Bool`: if `true`, the result summary of the nested testsets is shown even when they all pass (the default is `false`). -- `showtiming`: if `true`, the duration of each displayed testset is shown +- `showtiming::Bool`: if `true`, the duration of each displayed testset is shown (the default is `true`). -- `failfast`: if `true`, any test failure or error will cause the testset and any +- `failfast::Bool`: if `true`, any test failure or error will cause the testset and any child testsets to return immediately (the default is `false`). This can also be set globally via the env var `JULIA_TEST_FAILFAST`. +- `rng::Random.AbstractRNG`: use the given random number generator (RNG) as the global one + for the testset. `rng` must be `copy!`-able. This option can be useful to locally + reproduce stochastic test failures which only depend on the state of the global RNG. !!! compat "Julia 1.8" `@testset test_func()` requires at least Julia 1.8. @@ -1509,6 +1538,9 @@ accepts three boolean options: !!! compat "Julia 1.9" `failfast` requires at least Julia 1.9. +!!! compat "Julia 1.12" + The `rng` option requires at least Julia 1.12. + The description string accepts interpolation from the loop indices. If no description is provided, one is constructed based on the variables. If a function call is provided, its name will be used. @@ -1521,13 +1553,19 @@ method, which by default will return a list of the testset objects used in each iteration. Before the execution of the body of a `@testset`, there is an implicit -call to `Random.seed!(seed)` where `seed` is the current seed of the global RNG. +call to `copy!(Random.default_rng(), rng)` where `rng` is the RNG of the current task, or +the value of the RNG passed via the `rng` option. Moreover, after the execution of the body, the state of the global RNG is restored to what it was before the `@testset`. This is meant to ease reproducibility in case of failure, and to allow seamless re-arrangements of `@testset`s regardless of their side-effect on the global RNG state. +!!! note "RNG of nested testsets" + Unless changed with the `rng` option, the same RNG is set at the beginning of all + nested testsets. The RNG printed to screen when a testset has failures is the global RNG of + the outermost testset even if inner testsets have different RNGs manually set by the user. + ## Examples ```jldoctest; filter = r"trigonometric identities | 4 4 [0-9\\.]+s" julia> @testset "trigonometric identities" begin @@ -1717,9 +1755,11 @@ function testset_beginend_call(args, tests, source) # by wrapping the body in a function local default_rng_orig = copy(default_rng()) local tls_seed_orig = copy(Random.get_tls_seed()) + local tls_seed = isnothing(get_rng(ts)) ? set_rng!(ts, tls_seed_orig) : get_rng(ts) try # default RNG is reset to its state from last `seed!()` to ease reproduce a failed test - copy!(Random.default_rng(), tls_seed_orig) + copy!(Random.default_rng(), tls_seed) + copy!(Random.get_tls_seed(), Random.default_rng()) let $(esc(tests)) end @@ -1800,10 +1840,10 @@ function testset_forloop(args, testloop, source) finish_errored = true push!(arr, finish(ts)) finish_errored = false - copy!(default_rng(), tls_seed_orig) + copy!(default_rng(), tls_seed) end ts = if ($testsettype === $DefaultTestSet) && $(isa(source, LineNumberNode)) - $(testsettype)($desc; source=$(QuoteNode(source.file)), $options...) + $(testsettype)($desc; source=$(QuoteNode(source.file)), $options..., rng=tls_seed) else $(testsettype)($desc; $options...) end @@ -1825,10 +1865,12 @@ function testset_forloop(args, testloop, source) local arr = Vector{Any}() local first_iteration = true local ts + local rng_option = get($(options), :rng, nothing) local finish_errored = false local default_rng_orig = copy(default_rng()) local tls_seed_orig = copy(Random.get_tls_seed()) - copy!(Random.default_rng(), tls_seed_orig) + local tls_seed = isnothing(rng_option) ? copy(Random.get_tls_seed()) : rng_option + copy!(Random.default_rng(), tls_seed) try let $(Expr(:for, Expr(:block, [esc(v) for v in loopvars]...), blk)) diff --git a/stdlib/Test/test/runtests.jl b/stdlib/Test/test/runtests.jl index 0c08f78ef356f..995d2c983437c 100644 --- a/stdlib/Test/test/runtests.jl +++ b/stdlib/Test/test/runtests.jl @@ -1712,13 +1712,13 @@ end # this tests both the `TestCounts` parts as well as the fallback `x`s expected = r""" - Test Summary: | Pass Fail Error Broken Total Time - outer | 3 1 1 1 6 \s*\d*.\ds - a | 1 1 \s*\d*.\ds - custom | 1 1 1 1 4 \s*?s - no-record | x x x x ? \s*?s - b | 1 1 \s*\d*.\ds - ERROR: Some tests did not pass: 3 passed, 1 failed, 1 errored, 1 broken. + Test Summary: \| Pass Fail Error Broken Total Time + outer \| 3 1 1 1 6 \s*\d*.\ds + a \| 1 1 \s*\d*.\ds + custom \| 1 1 1 1 4 \s*\?s + no-record \| x x x x \? \s*\?s + b \| 1 1 \s*\d*.\ds + RNG of the outermost testset: .* """ cmd = `$(Base.julia_cmd()) --startup-file=no --color=no $f` @@ -1753,3 +1753,20 @@ module M54082 end @test only(result) isa Test.Fail end end + +@testset "Set RNG of testset" begin + rng1 = Xoshiro(0x2e026445595ed28e, 0x07bb81ac4c54926d, 0x83d7d70843e8bad6, 0xdbef927d150af80b, 0xdbf91ddf2534f850) + rng2 = Xoshiro(0xc380f460355639ee, 0xb39bc754b7d63bbf, 0x1551dbcfb5ed5668, 0x71ab5a18fec21a25, 0x649d0c1be1ca5436) + rng3 = Xoshiro(0xee97f5b53f7cdc49, 0x480ac387b0527d3d, 0x614b416502a9e0f5, 0x5250cb36e4a4ceb1, 0xed6615c59e475fa0) + + @testset rng=rng1 begin + @test rand() == rand(rng1) + end + + @testset rng=rng2 "Outer" begin + @test rand() == rand(rng2) + @testset rng=rng3 "Inner: $(i)" for i in 1:10 + @test rand() == rand(rng3) + end + end +end From 8e9c59f062173bbbb51341fcb6e84a41956cc4cc Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Tue, 31 Dec 2024 23:17:26 -0500 Subject: [PATCH 118/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?Pkg=20stdlib=20from=20c7e611bc8=20to=20739a64a0b=20(#56927)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Pkg-739a64a0b1d4a8d79c703e99c73bd0433b32ebfa.tar.gz/md5 | 1 + .../Pkg-739a64a0b1d4a8d79c703e99c73bd0433b32ebfa.tar.gz/sha512 | 1 + .../Pkg-c7e611bc89826bc462c4b2a308f1a71dbb617145.tar.gz/md5 | 1 - .../Pkg-c7e611bc89826bc462c4b2a308f1a71dbb617145.tar.gz/sha512 | 1 - stdlib/Pkg.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/Pkg-739a64a0b1d4a8d79c703e99c73bd0433b32ebfa.tar.gz/md5 create mode 100644 deps/checksums/Pkg-739a64a0b1d4a8d79c703e99c73bd0433b32ebfa.tar.gz/sha512 delete mode 100644 deps/checksums/Pkg-c7e611bc89826bc462c4b2a308f1a71dbb617145.tar.gz/md5 delete mode 100644 deps/checksums/Pkg-c7e611bc89826bc462c4b2a308f1a71dbb617145.tar.gz/sha512 diff --git a/deps/checksums/Pkg-739a64a0b1d4a8d79c703e99c73bd0433b32ebfa.tar.gz/md5 b/deps/checksums/Pkg-739a64a0b1d4a8d79c703e99c73bd0433b32ebfa.tar.gz/md5 new file mode 100644 index 0000000000000..ca4ab8cc00ab2 --- /dev/null +++ b/deps/checksums/Pkg-739a64a0b1d4a8d79c703e99c73bd0433b32ebfa.tar.gz/md5 @@ -0,0 +1 @@ +e647741a0c769fc636712d78f262536d diff --git a/deps/checksums/Pkg-739a64a0b1d4a8d79c703e99c73bd0433b32ebfa.tar.gz/sha512 b/deps/checksums/Pkg-739a64a0b1d4a8d79c703e99c73bd0433b32ebfa.tar.gz/sha512 new file mode 100644 index 0000000000000..dbfe7f0f4b9a6 --- /dev/null +++ b/deps/checksums/Pkg-739a64a0b1d4a8d79c703e99c73bd0433b32ebfa.tar.gz/sha512 @@ -0,0 +1 @@ +5e98a337fed1558e2704c478e6f62c6f775e5d4c665c3c2ae5089bd334df52ba8badc982fcea35904927b8bcbad427de868f709da95babca78aee6091ea53d32 diff --git a/deps/checksums/Pkg-c7e611bc89826bc462c4b2a308f1a71dbb617145.tar.gz/md5 b/deps/checksums/Pkg-c7e611bc89826bc462c4b2a308f1a71dbb617145.tar.gz/md5 deleted file mode 100644 index ac906597fde45..0000000000000 --- a/deps/checksums/Pkg-c7e611bc89826bc462c4b2a308f1a71dbb617145.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -7e3e14d5f6f5851f91a487cbef962ddc diff --git a/deps/checksums/Pkg-c7e611bc89826bc462c4b2a308f1a71dbb617145.tar.gz/sha512 b/deps/checksums/Pkg-c7e611bc89826bc462c4b2a308f1a71dbb617145.tar.gz/sha512 deleted file mode 100644 index b5e016fae36a7..0000000000000 --- a/deps/checksums/Pkg-c7e611bc89826bc462c4b2a308f1a71dbb617145.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -2c492da39ecb43ff1c2ebac877a2de8b152564b4cac7ac1e3bdea006a80305168f7cd2d2d289073fc4db67b0686d6cc707b1f7ba04dacaef353bef9a4cbea61a diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 5102be7bdce46..982ac2e313b43 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = master -PKG_SHA1 = c7e611bc89826bc462c4b2a308f1a71dbb617145 +PKG_SHA1 = 739a64a0b1d4a8d79c703e99c73bd0433b32ebfa PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 From 9a231690964dc30101ce6024a85d52cbebed17db Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Wed, 1 Jan 2025 19:49:35 -0500 Subject: [PATCH 119/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?Pkg=20stdlib=20from=20739a64a0b=20to=208d3cf02e5=20(#56930)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Pkg-739a64a0b1d4a8d79c703e99c73bd0433b32ebfa.tar.gz/md5 | 1 - .../Pkg-739a64a0b1d4a8d79c703e99c73bd0433b32ebfa.tar.gz/sha512 | 1 - .../Pkg-8d3cf02e5e35913c89440c3b5c6678c1a806e975.tar.gz/md5 | 1 + .../Pkg-8d3cf02e5e35913c89440c3b5c6678c1a806e975.tar.gz/sha512 | 1 + stdlib/Pkg.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/Pkg-739a64a0b1d4a8d79c703e99c73bd0433b32ebfa.tar.gz/md5 delete mode 100644 deps/checksums/Pkg-739a64a0b1d4a8d79c703e99c73bd0433b32ebfa.tar.gz/sha512 create mode 100644 deps/checksums/Pkg-8d3cf02e5e35913c89440c3b5c6678c1a806e975.tar.gz/md5 create mode 100644 deps/checksums/Pkg-8d3cf02e5e35913c89440c3b5c6678c1a806e975.tar.gz/sha512 diff --git a/deps/checksums/Pkg-739a64a0b1d4a8d79c703e99c73bd0433b32ebfa.tar.gz/md5 b/deps/checksums/Pkg-739a64a0b1d4a8d79c703e99c73bd0433b32ebfa.tar.gz/md5 deleted file mode 100644 index ca4ab8cc00ab2..0000000000000 --- a/deps/checksums/Pkg-739a64a0b1d4a8d79c703e99c73bd0433b32ebfa.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -e647741a0c769fc636712d78f262536d diff --git a/deps/checksums/Pkg-739a64a0b1d4a8d79c703e99c73bd0433b32ebfa.tar.gz/sha512 b/deps/checksums/Pkg-739a64a0b1d4a8d79c703e99c73bd0433b32ebfa.tar.gz/sha512 deleted file mode 100644 index dbfe7f0f4b9a6..0000000000000 --- a/deps/checksums/Pkg-739a64a0b1d4a8d79c703e99c73bd0433b32ebfa.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -5e98a337fed1558e2704c478e6f62c6f775e5d4c665c3c2ae5089bd334df52ba8badc982fcea35904927b8bcbad427de868f709da95babca78aee6091ea53d32 diff --git a/deps/checksums/Pkg-8d3cf02e5e35913c89440c3b5c6678c1a806e975.tar.gz/md5 b/deps/checksums/Pkg-8d3cf02e5e35913c89440c3b5c6678c1a806e975.tar.gz/md5 new file mode 100644 index 0000000000000..0ec07e44a059d --- /dev/null +++ b/deps/checksums/Pkg-8d3cf02e5e35913c89440c3b5c6678c1a806e975.tar.gz/md5 @@ -0,0 +1 @@ +30eed5409ab2f5e7791cac9f6583ccad diff --git a/deps/checksums/Pkg-8d3cf02e5e35913c89440c3b5c6678c1a806e975.tar.gz/sha512 b/deps/checksums/Pkg-8d3cf02e5e35913c89440c3b5c6678c1a806e975.tar.gz/sha512 new file mode 100644 index 0000000000000..37415fcac993c --- /dev/null +++ b/deps/checksums/Pkg-8d3cf02e5e35913c89440c3b5c6678c1a806e975.tar.gz/sha512 @@ -0,0 +1 @@ +bb995ff7bc047121e79162da8775cbf21a2874427af53ea46ccf9db2a01d5d3e864262d232e2988f41248e6b45a266a64467ada7e6a88f2306135ac4f1bb794f diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 982ac2e313b43..568a15dae1cc0 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = master -PKG_SHA1 = 739a64a0b1d4a8d79c703e99c73bd0433b32ebfa +PKG_SHA1 = 8d3cf02e5e35913c89440c3b5c6678c1a806e975 PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 From 51c27665e1f14b638ae948c02bd20c3828da46d5 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Thu, 2 Jan 2025 02:07:10 -0500 Subject: [PATCH 120/342] doc: summary of output functions: cross-ref println and printstyled (#55860) Slight tweak to #54547 to add cross-referenes to `println` and `printstyled`. Co-authored-by: Dilum Aluthge --- doc/src/manual/types.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/manual/types.md b/doc/src/manual/types.md index 0b1d380c2c601..f13e2e6865d0f 100644 --- a/doc/src/manual/types.md +++ b/doc/src/manual/types.md @@ -1595,7 +1595,7 @@ Most new types should only need to define `show` methods, if anything. * [`display(x)`](@ref) tells the current environment to display `x` in whatever way it thinks best. (This might even be a graphical display in something like a Jupyter or Pluto notebook.) By default (e.g. in scripts or in the text REPL), it calls `show(io, "text/plain", x)`, or equivalently `show(io, MIME"text/plain"(), x)`, for an appropriate `io` stream. (In the REPL, `io` is an [`IOContext`](@ref) wrapper around [`stdout`](@ref).) The REPL uses `display` to output the result of an evaluated expression. * The 3-argument [`show(io, ::MIME"text/plain", x)`](@ref) method performs verbose pretty-printing of `x`. By default (if no 3-argument method is defined for `typeof(x)`), it calls the 2-argument `show(io, x)`. It is called by the 2-argument `repr("text/plain", x)`. Other 3-argument `show` methods can be defined for additional MIME types as discussed above, to enable richer display of `x` in some interactive environments. * The 2-argument [`show(io, x)`](@ref) is the default simple text representation of `x`. It is called by the 1-argument [`repr(x)`](@ref), and is typically the format you might employ to input `x` into Julia. The 1-argument `show(x)` calls `show(stdout, x)`. -* [`print(io, x)`](@ref) by default calls `show(io, x)`, but a few types have a distinct `print` format — most notably, when `x` is a string, `print` outputs the raw text whereas `show` outputs an escaped string enclosed in quotation marks. The 1-argument `print(x)` calls `print(stdout, x)`. `print` is also called by [`string(x)`](@ref). +* [`print(io, x)`](@ref) by default calls `show(io, x)`, but a few types have a distinct `print` format — most notably, when `x` is a string, `print` outputs the raw text whereas `show` outputs an escaped string enclosed in quotation marks. The 1-argument `print(x)` calls `print(stdout, x)`. `print` is also called by [`string(x)`](@ref). See also [`println`](@ref) (to append a newline) and [`printstyled`](@ref) (to add colors etc.), both of which call `print`. * [`write(io, x)`](@ref), if it is defined (it generally has *no* default definition for new types), writes a "raw" binary representation of `x` to `io`, e.g. an `x::Int32` will be written as 4 bytes. It is also helpful to be familiar with the metadata that can be attached to an `io` stream by an [`IOContext`](@ref) wrapper. For example, the REPL sets the `:limit => true` flag from `display` for an evaluated expression, in order to limit the output to fit in the terminal; you can query this flag with `get(io, :limit, false)`. And when displaying an object contained within, for example, a multi-column matrix, the `:compact => true` flag could be set, which you can query with `get(io, :compact, false)`. From 4f1842f10d09711f888f2a3ba93bc09c685fe8dc Mon Sep 17 00:00:00 2001 From: matthias314 <56549971+matthias314@users.noreply.github.com> Date: Thu, 2 Jan 2025 04:53:57 -0500 Subject: [PATCH 121/342] Make `Markdown.parse` public and add a docstring (#56818) --- stdlib/Markdown/docs/src/index.md | 1 + stdlib/Markdown/src/Common/block.jl | 2 +- stdlib/Markdown/src/GitHub/GitHub.jl | 2 +- stdlib/Markdown/src/Markdown.jl | 13 +++++++++++++ stdlib/Markdown/src/parse/parse.jl | 15 +++++++++------ 5 files changed, 25 insertions(+), 8 deletions(-) diff --git a/stdlib/Markdown/docs/src/index.md b/stdlib/Markdown/docs/src/index.md index ad620c22eae5d..926e3921d339d 100644 --- a/stdlib/Markdown/docs/src/index.md +++ b/stdlib/Markdown/docs/src/index.md @@ -420,6 +420,7 @@ custom flavour of Markdown can be used, but this should generally be unnecessary Markdown.MD Markdown.@md_str Markdown.@doc_str +Markdown.parse Markdown.html Markdown.latex ``` diff --git a/stdlib/Markdown/src/Common/block.jl b/stdlib/Markdown/src/Common/block.jl index 1b5cc1a752bcb..247c894769f15 100644 --- a/stdlib/Markdown/src/Common/block.jl +++ b/stdlib/Markdown/src/Common/block.jl @@ -21,7 +21,7 @@ function paragraph(stream::IO, md::MD) char == '\r' && !eof(stream) && peek(stream, Char) == '\n' && read(stream, Char) if prev_char == '\\' write(buffer, '\n') - elseif blankline(stream) || parse(stream, md, breaking = true) + elseif blankline(stream) || _parse(stream, md, breaking = true) break else write(buffer, ' ') diff --git a/stdlib/Markdown/src/GitHub/GitHub.jl b/stdlib/Markdown/src/GitHub/GitHub.jl index 61807d267511d..676ae4a137779 100644 --- a/stdlib/Markdown/src/GitHub/GitHub.jl +++ b/stdlib/Markdown/src/GitHub/GitHub.jl @@ -44,7 +44,7 @@ function github_paragraph(stream::IO, md::MD) for char in readeach(stream, Char) if char == '\n' eof(stream) && break - if blankline(stream) || parse(stream, md, breaking = true) + if blankline(stream) || _parse(stream, md, breaking = true) break else write(buffer, '\n') diff --git a/stdlib/Markdown/src/Markdown.jl b/stdlib/Markdown/src/Markdown.jl index 0d45d9e534df2..8d79cc93d6171 100644 --- a/stdlib/Markdown/src/Markdown.jl +++ b/stdlib/Markdown/src/Markdown.jl @@ -35,6 +35,8 @@ include("render/terminal/render.jl") export @md_str, @doc_str +public MD, parse + const MARKDOWN_FACES = [ :markdown_header => Face(weight=:bold), :markdown_h1 => Face(height=1.25, inherit=:markdown_header), @@ -57,7 +59,16 @@ const MARKDOWN_FACES = [ __init__() = foreach(addface!, MARKDOWN_FACES) parse(markdown::String; flavor = julia) = parse(IOBuffer(markdown), flavor = flavor) + +""" + Markdown.parse(markdown::AbstractString) -> MD + +Parse `markdown` as Julia-flavored Markdown text and return the corresponding `MD` object. + +See also [`@md_str`](@ref). +""" parse(markdown::AbstractString; flavor = julia) = parse(String(markdown), flavor = flavor) + parse_file(file::AbstractString; flavor = julia) = parse(read(file, String), flavor = flavor) function mdexpr(s, flavor = :julia) @@ -74,6 +85,8 @@ end Parse the given string as Markdown text and return a corresponding [`MD`](@ref) object. +See also [`Markdown.parse`](@ref Markdown.parse(::AbstractString)). + # Examples ```jldoctest julia> s = md"# Hello, world!" diff --git a/stdlib/Markdown/src/parse/parse.jl b/stdlib/Markdown/src/parse/parse.jl index 389099b2984f6..dee1e781bfbef 100644 --- a/stdlib/Markdown/src/parse/parse.jl +++ b/stdlib/Markdown/src/parse/parse.jl @@ -15,8 +15,6 @@ mutable struct MD new(content, meta) end -public MD - MD(xs...) = MD(vcat(xs...)) function MD(cfg::Config, xs...) @@ -85,7 +83,7 @@ parseinline(s, md::MD) = parseinline(s, md, config(md)) # Block parsing -function parse(stream::IO, block::MD, config::Config; breaking = false) +function _parse(stream::IO, block::MD, config::Config; breaking = false) skipblank(stream) eof(stream) && return false for parser in (breaking ? config.breaking : [config.breaking; config.regular]) @@ -94,12 +92,17 @@ function parse(stream::IO, block::MD, config::Config; breaking = false) return false end -parse(stream::IO, block::MD; breaking = false) = - parse(stream, block, config(block), breaking = breaking) +_parse(stream::IO, block::MD; breaking = false) = + _parse(stream, block, config(block), breaking = breaking) + +""" + parse(stream::IO) -> MD +Parse the content of `stream` as Julia-flavored Markdown text and return the corresponding `MD` object. +""" function parse(stream::IO; flavor = julia) isa(flavor, Symbol) && (flavor = flavors[flavor]) markdown = MD(flavor) - while parse(stream, markdown, flavor) end + while _parse(stream, markdown, flavor) end return markdown end From 27b44cf9304b86fbb01b3697d5cfab11e0eee0c2 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Thu, 2 Jan 2025 07:30:08 -0500 Subject: [PATCH 122/342] precompilepkgs: color the "is currently loaded" text to make meaning clearer (#56926) --- base/precompilation.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/base/precompilation.jl b/base/precompilation.jl index c7dcd0af64caa..820cf260df71f 100644 --- a/base/precompilation.jl +++ b/base/precompilation.jl @@ -1042,7 +1042,9 @@ function _precompilepkgs(pkgs::Vector{String}, plural4 = n_loaded == 1 ? "this package" : "these packages" print(iostr, "\n ", color_string(string(n_loaded), Base.warn_color()), - " $(plural1) precompiled but $(plural2) currently loaded. Restart julia to access the new version$(plural3). \ + " $(plural1) precompiled but ", + color_string("$(plural2) currently loaded", Base.warn_color()), + ". Restart julia to access the new version$(plural3). \ Otherwise, loading dependents of $(plural4) may trigger further precompilation to work with the unexpected version$(plural3)." ) end From a393c6f18324f5d4cfab14108c991b31976358c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20=C3=96qvist?= Date: Thu, 2 Jan 2025 15:12:40 +0100 Subject: [PATCH 123/342] Remove unused variable from `endswith` (#56934) This is a trivial code cleanup suggestion. The `cub` variable was unused in `endswith(::Union{String, SubString{String}}, ::Union{String, SubString{String}})`. I ran the tests with `make test`, there were some failures but they did not appear to be related to the change. --- base/strings/util.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/base/strings/util.jl b/base/strings/util.jl index 1b73fbbbab5cf..87c2abab5344c 100644 --- a/base/strings/util.jl +++ b/base/strings/util.jl @@ -100,7 +100,6 @@ Base.startswith(io::IO, prefix::AbstractString) = startswith(io, String(prefix)) function endswith(a::Union{String, SubString{String}}, b::Union{String, SubString{String}}) - cub = ncodeunits(b) astart = ncodeunits(a) - ncodeunits(b) + 1 if astart < 1 false From 0741f9b99587e90333b736999110fba3d1bc6cac Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Thu, 2 Jan 2025 09:30:50 -0500 Subject: [PATCH 124/342] deps: support Unicode 16 via utf8proc 2.10.0 (#56925) Similar to #51799, support [Unicode 16](https://www.unicode.org/versions/Unicode16.0.0/) by bumping utf8proc to 2.10.0 (thanks to https://github.com/JuliaStrings/utf8proc/pull/277 by @eschnett). This allows us to use [7 exciting new emoji characters](https://www.unicode.org/emoji/charts-16.0/emoji-released.html) as identifiers, including "face with bags under eyes" ![image](https://github.com/user-attachments/assets/4959b7ca-100e-4efc-af58-b03184ae2dca) `"\U1fae9"` (but still no superscript "q"). Closes #56035. --- NEWS.md | 1 + deps/checksums/utf8proc | 4 ++-- deps/utf8proc.version | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index e6d12f1822da4..8f02045a213d6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -22,6 +22,7 @@ New language features The available metrics are: - actual running time for the task (`Base.Experimental.task_running_time_ns`), and - wall-time for the task (`Base.Experimental.task_wall_time_ns`). +- Support for Unicode 16 ([#56925]). Language changes ---------------- diff --git a/deps/checksums/utf8proc b/deps/checksums/utf8proc index 543c1805afbd8..2055d3323b7e1 100644 --- a/deps/checksums/utf8proc +++ b/deps/checksums/utf8proc @@ -1,2 +1,2 @@ -utf8proc-34db3f7954e9298e89f42641ac78e0450f80a70d.tar.gz/md5/e70e4fd2c914b4d4c0e3f0e2ca6c96d4 -utf8proc-34db3f7954e9298e89f42641ac78e0450f80a70d.tar.gz/sha512/0037f144e1150abd1b330d8a0c3a46c8352903acc9f4c8aad6bddd1370b19cc34551f8def58752cdff4eaace3efe54180bc11439a0e35c5ccad2fec4678c017e +utf8proc-a1b99daa2a3393884220264c927a48ba1251a9c6.tar.gz/md5/2c404870fdc19982ec5313ee78e478d7 +utf8proc-a1b99daa2a3393884220264c927a48ba1251a9c6.tar.gz/sha512/a6652f5840439fe051d973d9467ca9805dcea8d0ac75a2d35e3f8041c513d6ccd5d205a3873f28d7cb5e33ce6471165850164997f188ca359111963b3aac9a16 diff --git a/deps/utf8proc.version b/deps/utf8proc.version index a026ca858cfd3..c880d6561ce09 100644 --- a/deps/utf8proc.version +++ b/deps/utf8proc.version @@ -1,2 +1,2 @@ -UTF8PROC_BRANCH=v2.9.0 -UTF8PROC_SHA1=34db3f7954e9298e89f42641ac78e0450f80a70d +UTF8PROC_BRANCH=v2.10.0 +UTF8PROC_SHA1=a1b99daa2a3393884220264c927a48ba1251a9c6 From 5c88b72ebc9979a1b856eefda25b9bc11fefaae1 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 20 Dec 2024 20:24:09 +0000 Subject: [PATCH 125/342] teach jitlayers to use equivalent edges Sometimes an edge (especially from precompile file, but sometimes from inference) will specify a CodeInstance that does not need to be compiled for its ABI and simply needs to be cloned to point to the existing copy of it. --- src/gf.c | 6 +--- src/jitlayers.cpp | 79 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 71 insertions(+), 14 deletions(-) diff --git a/src/gf.c b/src/gf.c index 52741094c0533..dcf1823f57746 100644 --- a/src/gf.c +++ b/src/gf.c @@ -344,7 +344,7 @@ jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_a jl_code_instance_t *jl_type_infer(jl_method_instance_t *mi, size_t world, uint8_t source_mode) { if (jl_typeinf_func == NULL) - return NULL; + return jl_method_inferred_with_abi(mi, world); jl_task_t *ct = jl_current_task; if (ct->reentrant_timing & 0b1000) { // We must avoid attempting to re-enter inference here @@ -2857,9 +2857,6 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t } // Ok, compilation is enabled. We'll need to try to compile something (probably). - // Try to find a codeinst we have already inferred (e.g. while we were compiling - // something else). - codeinst = jl_method_inferred_with_abi(mi, world); // Everything from here on is considered (user facing) compile time uint64_t start = jl_typeinf_timing_begin(); @@ -2875,7 +2872,6 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t codeinst_old = jl_atomic_load_relaxed(&codeinst_old->next); } - // This codeinst hasn't been previously inferred do that now // jl_type_infer will internally do a cache lookup and jl_engine_reserve call // to synchronize this across threads if (!codeinst) { diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index bdb8298df41a6..139a5631d63c0 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -301,6 +301,29 @@ static void finish_params(Module *M, jl_codegen_params_t ¶ms) JL_NOTSAFEPOIN } } +// look for something with an egal ABI that is already in the JIT +static jl_code_instance_t *jl_method_compiled_egal(jl_code_instance_t *ci JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT +{ + jl_method_instance_t *mi = ci->def; + jl_value_t *owner = ci->owner; + jl_value_t *rettype = ci->rettype; + size_t min_world = jl_atomic_load_relaxed(&ci->min_world); + size_t max_world = jl_atomic_load_relaxed(&ci->max_world); + jl_code_instance_t *codeinst = jl_atomic_load_relaxed(&mi->cache); + while (codeinst) { + if (codeinst != ci && + jl_atomic_load_relaxed(&codeinst->inferred) != NULL && + jl_atomic_load_relaxed(&codeinst->invoke) != NULL && + jl_atomic_load_relaxed(&codeinst->min_world) <= min_world && + jl_atomic_load_relaxed(&codeinst->max_world) >= max_world && + jl_egal(codeinst->owner, owner) && + jl_egal(codeinst->rettype, rettype)) { + return codeinst; + } + codeinst = jl_atomic_load_relaxed(&codeinst->next); + } + return codeinst; +} static int jl_analyze_workqueue(jl_code_instance_t *callee, jl_codegen_params_t ¶ms, bool forceall=false) JL_NOTSAFEPOINT_LEAVE JL_NOTSAFEPOINT_ENTER { @@ -309,6 +332,7 @@ static int jl_analyze_workqueue(jl_code_instance_t *callee, jl_codegen_params_t std::swap(params.workqueue, edges); for (auto &it : edges) { jl_code_instance_t *codeinst = it.first; + JL_GC_PROMISE_ROOTED(codeinst); auto &proto = it.second; // try to emit code for this item from the workqueue StringRef invokeName = ""; @@ -321,7 +345,7 @@ static int jl_analyze_workqueue(jl_code_instance_t *callee, jl_codegen_params_t // But it must be consistent with the following invokenames lookup, which is protected by the engine_lock uint8_t specsigflags; void *fptr; - void jl_read_codeinst_invoke(jl_code_instance_t *ci, uint8_t *specsigflags, jl_callptr_t *invoke, void **specptr, int waitcompile) JL_NOTSAFEPOINT; // not a safepoint (or deadlock) in this file due to 0 parameter + void jl_read_codeinst_invoke(jl_code_instance_t *ci, uint8_t *specsigflags, jl_callptr_t *invoke, void **specptr, int waitcompile) JL_NOTSAFEPOINT; // declare it is not a safepoint (or deadlock) in this file due to 0 parameter jl_read_codeinst_invoke(codeinst, &specsigflags, &invoke, &fptr, 0); //if (specsig ? specsigflags & 0b1 : invoke == jl_fptr_args_addr) if (invoke == jl_fptr_args_addr) { @@ -349,6 +373,40 @@ static int jl_analyze_workqueue(jl_code_instance_t *callee, jl_codegen_params_t force = true; } } + if (preal_decl.empty()) { + // there may be an equivalent method already compiled (or at least registered with the JIT to compile), in which case we should be using that instead + jl_code_instance_t *compiled_ci = jl_method_compiled_egal(codeinst); + if (compiled_ci) { + codeinst = compiled_ci; + uint8_t specsigflags; + void *fptr; + jl_read_codeinst_invoke(codeinst, &specsigflags, &invoke, &fptr, 0); + //if (specsig ? specsigflags & 0b1 : invoke == jl_fptr_args_addr) + if (invoke == jl_fptr_args_addr) { + preal_decl = jl_ExecutionEngine->getFunctionAtAddress((uintptr_t)fptr, invoke, codeinst); + } + else if (specsigflags & 0b1) { + preal_decl = jl_ExecutionEngine->getFunctionAtAddress((uintptr_t)fptr, invoke, codeinst); + preal_specsig = true; + } + if (preal_decl.empty()) { + auto it = invokenames.find(codeinst); + if (it != invokenames.end()) { + auto &decls = it->second; + invokeName = decls.functionObject; + if (decls.functionObject == "jl_fptr_args") { + preal_decl = decls.specFunctionObject; + isedge = true; + } + else if (decls.functionObject != "jl_fptr_sparam" && decls.functionObject != "jl_f_opaque_closure_call") { + preal_decl = decls.specFunctionObject; + preal_specsig = true; + isedge = true; + } + } + } + } + } if (!preal_decl.empty() || force) { // if we have a prototype emitted, compare it to what we emitted earlier Module *mod = proto.decl->getParent(); @@ -733,14 +791,17 @@ static void recursive_compile_graph( while (!workqueue.empty()) { auto this_code = workqueue.pop_back_val(); if (Seen.insert(this_code).second) { - if (this_code != codeinst) { - JL_GC_PROMISE_ROOTED(this_code); // rooted transitively from following edges from original argument - jl_emit_codeinst_to_jit(this_code, nullptr); // contains safepoints - } - jl_unique_gcsafe_lock lock(engine_lock); - auto edges = complete_graph.find(this_code); - if (edges != complete_graph.end()) { - workqueue.append(edges->second); + jl_code_instance_t *compiled_ci = jl_method_compiled_egal(codeinst); + if (!compiled_ci) { + if (this_code != codeinst) { + JL_GC_PROMISE_ROOTED(this_code); // rooted transitively from following edges from original argument + jl_emit_codeinst_to_jit(this_code, nullptr); // contains safepoints + } + jl_unique_gcsafe_lock lock(engine_lock); + auto edges = complete_graph.find(this_code); + if (edges != complete_graph.end()) { + workqueue.append(edges->second); + } } } } From b6fbd8123af1f68fb8aa5f06551bd28b0fd1ee3a Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 18 Dec 2024 18:52:48 +0000 Subject: [PATCH 126/342] opaque_closure: fix data-race mistakes with reading fields by using standard helper function --- src/gf.c | 1 + src/opaque_closure.c | 28 +++++++++++++++------------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/gf.c b/src/gf.c index dcf1823f57746..8086d75329bef 100644 --- a/src/gf.c +++ b/src/gf.c @@ -2722,6 +2722,7 @@ void jl_read_codeinst_invoke(jl_code_instance_t *ci, uint8_t *specsigflags, jl_c initial_invoke = jl_atomic_load_acquire(&ci->invoke); // happens-before for subsequent read of fptr } void *fptr = jl_atomic_load_relaxed(&ci->specptr.fptr); + // TODO: if fptr is NULL, it may mean we read this too fast, and should have spun and waited for jl_compile_codeinst to finish if (initial_invoke == NULL || fptr == NULL) { *invoke = initial_invoke; *specptr = NULL; diff --git a/src/opaque_closure.c b/src/opaque_closure.c index e3334c037f5a9..8a9dcac30a4f8 100644 --- a/src/opaque_closure.c +++ b/src/opaque_closure.c @@ -67,12 +67,14 @@ static jl_opaque_closure_t *new_opaque_closure(jl_tupletype_t *argt, jl_value_t ci = jl_compile_method_internal(mi, world); } - jl_fptr_args_t invoke = (jl_fptr_args_t)jl_interpret_opaque_closure; + jl_fptr_args_t callptr = (jl_fptr_args_t)jl_interpret_opaque_closure; void *specptr = NULL; if (ci) { - invoke = (jl_fptr_args_t)jl_atomic_load_relaxed(&ci->invoke); - specptr = jl_atomic_load_relaxed(&ci->specptr.fptr); + uint8_t specsigflags; + jl_callptr_t invoke; + jl_read_codeinst_invoke(ci, &specsigflags, &invoke, &specptr, 1); + callptr = (jl_fptr_args_t)invoke; // codegen puts the object (or a jl_fptr_interpret_call token )here for us, even though it was the wrong type to put here selected_rt = ci->rettype; // If we're not allowed to generate a specsig with this, rt, fall @@ -82,7 +84,7 @@ static jl_opaque_closure_t *new_opaque_closure(jl_tupletype_t *argt, jl_value_t // TODO: It would be better to try to get a specialization with the // correct rt check here (or we could codegen a wrapper). specptr = NULL; // this will force codegen of the unspecialized version - invoke = (jl_fptr_args_t)jl_interpret_opaque_closure; + callptr = (jl_fptr_args_t)jl_interpret_opaque_closure; jl_value_t *ts[2] = {rt_lb, (jl_value_t*)ci->rettype}; selected_rt = jl_type_union(ts, 2); } @@ -90,18 +92,18 @@ static jl_opaque_closure_t *new_opaque_closure(jl_tupletype_t *argt, jl_value_t // TODO: It would be better to try to get a specialization with the // correct rt check here (or we could codegen a wrapper). specptr = NULL; // this will force codegen of the unspecialized version - invoke = (jl_fptr_args_t)jl_interpret_opaque_closure; + callptr = (jl_fptr_args_t)jl_interpret_opaque_closure; selected_rt = jl_type_intersection(rt_ub, selected_rt); } - if (invoke == (jl_fptr_args_t) jl_fptr_interpret_call) { - invoke = (jl_fptr_args_t)jl_interpret_opaque_closure; + if (callptr == (jl_fptr_args_t)jl_fptr_interpret_call) { + callptr = (jl_fptr_args_t)jl_interpret_opaque_closure; } - else if (invoke == (jl_fptr_args_t)jl_fptr_args && specptr) { - invoke = (jl_fptr_args_t)specptr; + else if (callptr == (jl_fptr_args_t)jl_fptr_args && specptr != NULL) { + callptr = (jl_fptr_args_t)specptr; } - else if (invoke == (jl_fptr_args_t)jl_fptr_const_return) { - invoke = jl_isa(ci->rettype_const, selected_rt) ? + else if (callptr == (jl_fptr_args_t)jl_fptr_const_return) { + callptr = jl_isa(ci->rettype_const, selected_rt) ? (jl_fptr_args_t)jl_fptr_const_opaque_closure : (jl_fptr_args_t)jl_fptr_const_opaque_closure_typeerror; captures = ci->rettype_const; @@ -117,14 +119,14 @@ static jl_opaque_closure_t *new_opaque_closure(jl_tupletype_t *argt, jl_value_t // OC wrapper methods are not world dependent and have no edges or other info ci = jl_get_method_inferred(mi_generic, selected_rt, 1, ~(size_t)0, NULL, NULL); if (!jl_atomic_load_acquire(&ci->invoke)) - jl_compile_codeinst(ci); // confusing this actually calls jl_emit_oc_wrapper and never actually compiles ci (which would be impossible) + jl_compile_codeinst(ci); // confusing this actually calls jl_emit_oc_wrapper and never actually compiles ci (which would be impossible since it cannot have source) specptr = jl_atomic_load_relaxed(&ci->specptr.fptr); } jl_opaque_closure_t *oc = (jl_opaque_closure_t*)jl_gc_alloc(ct->ptls, sizeof(jl_opaque_closure_t), oc_type); oc->source = source; oc->captures = captures; oc->world = world; - oc->invoke = invoke; + oc->invoke = callptr; oc->specptr = specptr; JL_GC_POP(); From 835c8ac9aacdbb806695230aed875b4508bbf319 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 18 Dec 2024 20:39:34 +0000 Subject: [PATCH 127/342] opaque_closure: fix world-age mistake in fallback path This was failing the h_world_age test sometimes. --- src/codegen.cpp | 13 ++++++++++++- src/gf.c | 12 ++++++++++++ src/julia.h | 1 + 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 5bf7c74deedcb..ceaba9507e4c7 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -996,6 +996,15 @@ static const auto jlinvoke_func = new JuliaFunction<>{ {AttributeSet(), Attributes(C, {Attribute::ReadOnly, Attribute::NoCapture})}); }, }; +static const auto jlinvokeoc_func = new JuliaFunction<>{ + XSTR(jl_invoke_oc), + get_func2_sig, + [](LLVMContext &C) { return AttributeList::get(C, + AttributeSet(), + Attributes(C, {Attribute::NonNull}), + {AttributeSet(), + Attributes(C, {Attribute::ReadOnly, Attribute::NoCapture})}); }, +}; static const auto jlopaque_closure_call_func = new JuliaFunction<>{ XSTR(jl_f_opaque_closure_call), get_func_sig, @@ -7288,7 +7297,9 @@ Function *emit_tojlinvoke(jl_code_instance_t *codeinst, StringRef theFptrName, M theFarg = literal_pointer_val(ctx, (jl_value_t*)codeinst); } else { - theFunc = prepare_call(jlinvoke_func); + jl_method_instance_t *mi = codeinst->def; + bool is_opaque_closure = jl_is_method(mi->def.value) && mi->def.method->is_for_opaque_closure; + theFunc = prepare_call(is_opaque_closure ? jlinvokeoc_func : jlinvoke_func); theFarg = literal_pointer_val(ctx, (jl_value_t*)jl_get_ci_mi(codeinst)); } theFarg = track_pjlvalue(ctx, theFarg); diff --git a/src/gf.c b/src/gf.c index 8086d75329bef..3a308ca6154fc 100644 --- a/src/gf.c +++ b/src/gf.c @@ -3373,6 +3373,18 @@ JL_DLLEXPORT jl_value_t *jl_invoke(jl_value_t *F, jl_value_t **args, uint32_t na return _jl_invoke(F, args, nargs, mfunc, world); } +JL_DLLEXPORT jl_value_t *jl_invoke_oc(jl_value_t *F, jl_value_t **args, uint32_t nargs, jl_method_instance_t *mfunc) +{ + jl_opaque_closure_t *oc = (jl_opaque_closure_t*)F; + jl_task_t *ct = jl_current_task; + size_t last_age = ct->world_age; + size_t world = oc->world; + ct->world_age = world; + jl_value_t *ret = _jl_invoke(F, args, nargs, mfunc, world); + ct->world_age = last_age; + return ret; +} + STATIC_INLINE int sig_match_fast(jl_value_t *arg1t, jl_value_t **args, jl_value_t **sig, size_t n) { // NOTE: This function is a huge performance hot spot!! diff --git a/src/julia.h b/src/julia.h index a71f9db030274..9b8d090fe37cb 100644 --- a/src/julia.h +++ b/src/julia.h @@ -2237,6 +2237,7 @@ STATIC_INLINE int jl_vinfo_usedundef(uint8_t vi) JL_DLLEXPORT jl_value_t *jl_apply_generic(jl_value_t *F, jl_value_t **args, uint32_t nargs); JL_DLLEXPORT jl_value_t *jl_invoke(jl_value_t *F, jl_value_t **args, uint32_t nargs, jl_method_instance_t *meth); +JL_DLLEXPORT jl_value_t *jl_invoke_oc(jl_value_t *F, jl_value_t **args, uint32_t nargs, jl_method_instance_t *meth); JL_DLLEXPORT int32_t jl_invoke_api(jl_code_instance_t *linfo); STATIC_INLINE jl_value_t *jl_apply(jl_value_t **args, uint32_t nargs) From 59d74d46f8aeb4c826f2b2c65f36978589cdfafb Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 11 Dec 2024 16:33:46 +0000 Subject: [PATCH 128/342] inference,codegen: connect source directly to jit This avoids unnecessary compression when running (not generating code). While generating code, we continue the legacy behavior of storing compressed code, since restarting from a ji without that is quite slow. Eventually, we should also remove that code also once we have generated the object file from it. This replaces the defective SOURCE_MODE_FORCE_SOURCE option with a new `typeinf_ext_toplevel` batch-mode interface for compilation which returns all required source code. Only two options remain now: SOURCE_MODE_NOT_REQUIRED : Require only that the IPO information (e.g. rettype and friends) is present. SOURCE_MODE_FORCE_ABI : Require that the IPO information is present (for ABI computation) and that the returned CodeInstance can be invoked on the host target (preferably after inference, called directly, but perfectly acceptable for Base.Compiler to instead force the runtime to use a stub there or call into it with the interpreter instead by having failed to provide any code). This replaces the awkward `jl_create_native` interface (which is now just a shim for calling the new batch-mode `typeinf_ext_toplevel`) with a simpler `jl_emit_native` API, which does not do any inference or other callbacks, but simply is a batch-mode call to `jl_emit_codeinfo` and the work to build the external wrapper around them for linkage. --- Compiler/src/bootstrap.jl | 19 +- Compiler/src/tfuncs.jl | 18 +- Compiler/src/typeinfer.jl | 245 ++++++++++++++++---------- Compiler/src/types.jl | 13 +- Compiler/src/utilities.jl | 3 + Compiler/test/abioverride.jl | 30 ++-- base/reflection.jl | 8 - src/aotcompile.cpp | 332 +++++++++++++++-------------------- src/ccall.cpp | 8 +- src/codegen-stubs.c | 20 ++- src/codegen.cpp | 81 +-------- src/gf.c | 60 ++++++- src/jitlayers.cpp | 46 +++-- src/jitlayers.h | 8 +- src/jl_exported_funcs.inc | 3 +- src/julia.h | 1 + src/julia_internal.h | 17 +- src/precompile_utils.c | 16 +- src/toplevel.c | 16 +- test/precompile.jl | 59 +++---- 20 files changed, 501 insertions(+), 502 deletions(-) diff --git a/Compiler/src/bootstrap.jl b/Compiler/src/bootstrap.jl index 475c53e317152..ea7510df313c7 100644 --- a/Compiler/src/bootstrap.jl +++ b/Compiler/src/bootstrap.jl @@ -16,9 +16,9 @@ function activate_codegen!() end function bootstrap!() + global bootstrapping_compiler = true let time() = ccall(:jl_clock_now, Float64, ()) println("Compiling the compiler. This may take several minutes ...") - interp = NativeInterpreter() ssa_inlining_pass!_tt = Tuple{typeof(ssa_inlining_pass!), IRCode, InliningState{NativeInterpreter}, Bool} optimize_tt = Tuple{typeof(optimize), NativeInterpreter, OptimizationState{NativeInterpreter}, InferenceResult} @@ -45,13 +45,15 @@ function bootstrap!() end end starttime = time() + methods = Any[] + world = get_world_counter() for f in fs if isa(f, DataType) && f.name === typename(Tuple) tt = f else tt = Tuple{typeof(f), Vararg{Any}} end - matches = _methods_by_ftype(tt, 10, get_world_counter())::Vector + matches = _methods_by_ftype(tt, 10, world)::Vector if isempty(matches) println(stderr, "WARNING: no matching method found for `", tt, "`") else @@ -62,14 +64,25 @@ function bootstrap!() for i = 1:length(params) params[i] = unwraptv(params[i]) end - typeinf_type(interp, m.method, Tuple{params...}, m.sparams) + mi = specialize_method(m.method, Tuple{params...}, m.sparams) + #isa_compileable_sig(mi) || println(stderr, "WARNING: inferring `", mi, "` which isn't expected to be called.") + push!(methods, mi) end end end + codeinfos = typeinf_ext_toplevel(methods, [world], false) + for i = 1:2:length(codeinfos) + ci = codeinfos[i]::CodeInstance + src = codeinfos[i + 1]::CodeInfo + isa_compileable_sig(ci.def) || continue # println(stderr, "WARNING: compiling `", ci.def, "` which isn't expected to be called.") + ccall(:jl_add_codeinst_to_jit, Cvoid, (Any, Any), ci, src) + end endtime = time() println("Base.Compiler ──── ", sub_float(endtime,starttime), " seconds") end activate_codegen!() + global bootstrapping_compiler = false + nothing end function activate!(; reflection=true, codegen=false) diff --git a/Compiler/src/tfuncs.jl b/Compiler/src/tfuncs.jl index e51d43e5b2fe1..f0c793a4ae3b7 100644 --- a/Compiler/src/tfuncs.jl +++ b/Compiler/src/tfuncs.jl @@ -42,11 +42,10 @@ macro nospecs(ex) push!(names, arg) end @assert isexpr(body, :block) - if !isempty(names) - lin = first(body.args)::LineNumberNode - nospec = Expr(:macrocall, Symbol("@nospecialize"), lin, names...) - insert!(body.args, 2, nospec) - end + isempty(names) && throw(ArgumentError("no arguments for @nospec")) + lin = first(body.args)::LineNumberNode + nospec = Expr(:macrocall, GlobalRef(@__MODULE__, :var"@nospecialize"), lin, names...) + insert!(body.args, 2, nospec) return esc(ex) end @@ -2115,7 +2114,7 @@ add_tfunc(memoryrefoffset, 1, 1, memoryrefoffset_tfunc, 5) return true end -@nospecs function memoryref_elemtype(@nospecialize mem) +@nospecs function memoryref_elemtype(mem) m = widenconst(mem) if !has_free_typevars(m) && m <: GenericMemoryRef m0 = m @@ -2131,7 +2130,7 @@ end return Any end -@nospecs function _memoryref_elemtype(@nospecialize mem) +@nospecs function _memoryref_elemtype(mem) m = widenconst(mem) if !has_free_typevars(m) && m <: GenericMemoryRef m0 = m @@ -2166,7 +2165,7 @@ end end # whether getindex for the elements can potentially throw UndefRef -function array_type_undefable(@nospecialize(arytype)) +@nospecs function array_type_undefable(arytype) arytype = unwrap_unionall(arytype) if isa(arytype, Union) return array_type_undefable(arytype.a) || array_type_undefable(arytype.b) @@ -2247,7 +2246,7 @@ end return boundscheck ⊑ Bool && memtype ⊑ GenericMemoryRef && order ⊑ Symbol end -@nospecs function memorynew_nothrow(argtypes::Vector{Any}) +function memorynew_nothrow(argtypes::Vector{Any}) if !(argtypes[1] isa Const && argtypes[2] isa Const) return false end @@ -2263,6 +2262,7 @@ end overflows = checked_smul_int(len, elsz)[2] return !overflows end + # Query whether the given builtin is guaranteed not to throw given the `argtypes`. # `argtypes` can be assumed not to contain varargs. function _builtin_nothrow(𝕃::AbstractLattice, @nospecialize(f::Builtin), argtypes::Vector{Any}, diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index eba520a03ada1..45df4707e4caa 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -92,8 +92,7 @@ If set to `true`, record per-method-instance timings within type inference in th __set_measure_typeinf(onoff::Bool) = __measure_typeinf__[] = onoff const __measure_typeinf__ = RefValue{Bool}(false) -function finish!(interp::AbstractInterpreter, caller::InferenceState; - can_discard_trees::Bool=may_discard_trees(interp)) +function finish!(interp::AbstractInterpreter, caller::InferenceState) result = caller.result opt = result.src if opt isa OptimizationState @@ -120,20 +119,28 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState; store_backedges(ci, edges) end inferred_result = nothing + uncompressed = inferred_result relocatability = 0x1 const_flag = is_result_constabi_eligible(result) - if !can_discard_trees || (is_cached(caller) && !const_flag) + discard_src = caller.cache_mode === CACHE_MODE_NULL || const_flag + if !discard_src inferred_result = transform_result_for_cache(interp, result) # TODO: do we want to augment edges here with any :invoke targets that we got from inlining (such that we didn't have a direct edge to it already)? - relocatability = 0x0 if inferred_result isa CodeInfo + if may_compress(interp) + nslots = length(inferred_result.slotflags) + resize!(inferred_result.slottypes::Vector{Any}, nslots) + resize!(inferred_result.slotnames, nslots) + end di = inferred_result.debuginfo uncompressed = inferred_result - inferred_result = maybe_compress_codeinfo(interp, result.linfo, inferred_result, can_discard_trees) - result.is_src_volatile |= uncompressed !== inferred_result + inferred_result = maybe_compress_codeinfo(interp, result.linfo, inferred_result) + result.is_src_volatile = false elseif ci.owner === nothing # The global cache can only handle objects that codegen understands inferred_result = nothing + else + relocatability = 0x0 end if isa(inferred_result, String) t = @_gc_preserve_begin inferred_result @@ -141,7 +148,7 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState; @_gc_preserve_end t end end - # n.b. relocatability = isa(inferred_result, String) && inferred_result[end] + # n.b. relocatability = !isa(inferred_result, String) || inferred_result[end] if !@isdefined di di = DebugInfo(result.linfo) end @@ -149,6 +156,19 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState; ci, inferred_result, const_flag, first(result.valid_worlds), last(result.valid_worlds), encode_effects(result.ipo_effects), result.analysis_results, relocatability, di, edges) engine_reject(interp, ci) + if !discard_src && isdefined(interp, :codegen) && uncompressed isa CodeInfo + # record that the caller could use this result to generate code when required, if desired, to avoid repeating n^2 work + interp.codegen[ci] = uncompressed + if bootstrapping_compiler && inferred_result == nothing + # This is necessary to get decent bootstrapping performance + # when compiling the compiler to inject everything eagerly + # where codegen can start finding and using it right away + mi = result.linfo + if mi.def isa Method && isa_compileable_sig(mi) + ccall(:jl_add_codeinst_to_jit, Cvoid, (Any, Any), ci, uncompressed) + end + end + end end return nothing end @@ -223,19 +243,13 @@ end transform_result_for_cache(::AbstractInterpreter, result::InferenceResult) = result.src -function maybe_compress_codeinfo(interp::AbstractInterpreter, mi::MethodInstance, ci::CodeInfo, - can_discard_trees::Bool=may_discard_trees(interp)) +function maybe_compress_codeinfo(interp::AbstractInterpreter, mi::MethodInstance, ci::CodeInfo) def = mi.def isa(def, Method) || return ci # don't compress toplevel code - cache_the_tree = true - if can_discard_trees - cache_the_tree = is_inlineable(ci) || isa_compileable_sig(mi.specTypes, mi.sparam_vals, def) - end + can_discard_trees = may_discard_trees(interp) + cache_the_tree = !can_discard_trees || is_inlineable(ci) if cache_the_tree if may_compress(interp) - nslots = length(ci.slotflags) - resize!(ci.slottypes::Vector{Any}, nslots) - resize!(ci.slotnames, nslots) return ccall(:jl_compress_ir, String, (Any, Any), def, ci) else return ci @@ -476,7 +490,7 @@ function finishinfer!(me::InferenceState, interp::AbstractInterpreter) rettype_const = nothing const_flags = 0x0 end - relocatability = 0x0 + relocatability = 0x1 di = nothing edges = empty_edges # `edges` will be updated within `finish!` ci = result.ci @@ -484,10 +498,10 @@ function finishinfer!(me::InferenceState, interp::AbstractInterpreter) ci, widenconst(result_type), widenconst(result.exc_result), rettype_const, const_flags, first(result.valid_worlds), last(result.valid_worlds), encode_effects(result.ipo_effects), result.analysis_results, di, edges) - if is_cached(me) + if is_cached(me) # CACHE_MODE_GLOBAL cached_result = cache_result!(me.interp, result, ci) if !cached_result - me.cache_mode = CACHE_MODE_NULL + me.cache_mode = CACHE_MODE_VOLATILE end end end @@ -705,7 +719,7 @@ function resolve_call_cycle!(interp::AbstractInterpreter, mi::MethodInstance, pa for frameid = reverse(1:length(frames)) frame = frames[frameid] isa(frame, InferenceState) || break - uncached |= !is_cached(frame) # ensure we never add an uncached frame to a cycle + uncached |= !is_cached(frame) # ensure we never add a (globally) uncached frame to a cycle if is_same_frame(interp, mi, frame) if uncached # our attempt to speculate into a constant call lead to an undesired self-cycle @@ -796,6 +810,7 @@ function typeinf_edge(interp::AbstractInterpreter, method::Method, @nospecialize cache_mode = CACHE_MODE_GLOBAL # cache edge targets globally by default force_inline = is_stmt_inline(get_curr_ssaflag(caller)) edge_ci = nothing + # check cache with SOURCE_MODE_NOT_REQUIRED source_mode let codeinst = get(code_cache(interp), mi, nothing) if codeinst isa CodeInstance # return existing rettype if the code is already inferred inferred = @atomic :monotonic codeinst.inferred @@ -945,21 +960,6 @@ function codeinfo_for_const(interp::AbstractInterpreter, mi::MethodInstance, @no return tree end -""" - codeinstance_for_const_with_code(interp::AbstractInterpreter, code::CodeInstance) - -Given a constabi `CodeInstance`, create another (uncached) CodeInstance that contains the dummy code created -by [`codeinfo_for_const`](@ref) for use in reflection functions that require this. See [`codeinfo_for_const`](@ref) for -more details. -""" -function codeinstance_for_const_with_code(interp::AbstractInterpreter, code::CodeInstance) - src = codeinfo_for_const(interp, code.def, code.rettype_const) - return CodeInstance(code.def, cache_owner(interp), code.rettype, code.exctype, code.rettype_const, src, - Int32(0x3), code.min_world, code.max_world, - code.ipo_purity_bits, code.analysis_results, - code.relocatability, src.debuginfo, src.edges) -end - result_is_constabi(interp::AbstractInterpreter, result::InferenceResult) = may_discard_trees(interp) && is_result_constabi_eligible(result) @@ -1051,44 +1051,35 @@ it has constabi) or one that can be made so by compiling its `->inferred` field. N.B.: The `->inferred` field is volatile and the compiler may delete it. -In such a case, it will first set the `invoke` field to a method that -will block the thread until compilation is completed. """ const SOURCE_MODE_ABI = 0x1 -""" - SOURCE_MODE_FORCE_SOURCE - -Indicates that inference must always produce source in the `->inferred` field. -This may mean that inference will need to re-do inference (if the `->inferred` -field was previously deleted by the JIT) or may need to synthesize source for -other kinds of CodeInstances. - -N.B.: The same caching considerations as SOURCE_MODE_ABI apply. -""" -const SOURCE_MODE_FORCE_SOURCE = 0x2 - -function ci_has_source(code::CodeInstance) - inf = @atomic :monotonic code.inferred - return code.owner === nothing ? (isa(inf, CodeInfo) || isa(inf, String)) : inf !== nothing -end - """ ci_has_abi(code::CodeInstance) Determine whether this CodeInstance is something that could be invoked if we gave it -to the runtime system (either because it already has an ->invoke ptr, or because it -has source that could be compiled). +to the runtime system (either because it already has an ->invoke ptr, or +because it has source that could be compiled). Note that this information may +be stale by the time the user see it, so the user will need to perform their +own checks if they actually need the abi from it. """ function ci_has_abi(code::CodeInstance) - ci_has_source(code) && return true - return code.invoke !== C_NULL + (@atomic :acquire code.invoke) !== C_NULL && return true + inf = @atomic :monotonic code.inferred + if code.owner === nothing ? (isa(inf, CodeInfo) || isa(inf, String)) : inf !== nothing + # interp.codegen[code] = maybe_uncompress(code, inf) # TODO: the correct way to ensure this information doesn't become stale would be to push it into the stable codegen cache + return true + end + return false +end + +function ci_has_invoke(code::CodeInstance) + return (@atomic :monotonic code.invoke) !== C_NULL end function ci_meets_requirement(code::CodeInstance, source_mode::UInt8) source_mode == SOURCE_MODE_NOT_REQUIRED && return true source_mode == SOURCE_MODE_ABI && return ci_has_abi(code) - source_mode == SOURCE_MODE_FORCE_SOURCE && return ci_has_source(code) return false end @@ -1098,11 +1089,6 @@ function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance, source_mod let code = get(code_cache(interp), mi, nothing) if code isa CodeInstance # see if this code already exists in the cache - if source_mode == SOURCE_MODE_FORCE_SOURCE && use_const_api(code) - code = codeinstance_for_const_with_code(interp, code) - ccall(:jl_typeinf_timing_end, Cvoid, (UInt64,), start_time) - return code - end if ci_meets_requirement(code, source_mode) ccall(:jl_typeinf_timing_end, Cvoid, (UInt64,), start_time) return code @@ -1124,12 +1110,6 @@ function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance, source_mod let code = get(code_cache(interp), mi, nothing) if code isa CodeInstance # see if this code already exists in the cache - if source_mode == SOURCE_MODE_FORCE_SOURCE && use_const_api(code) - engine_reject(interp, ci) - code = codeinstance_for_const_with_code(interp, code) - ccall(:jl_typeinf_timing_end, Cvoid, (UInt64,), start_time) - return code - end if ci_meets_requirement(code, source_mode) engine_reject(interp, ci) ccall(:jl_typeinf_timing_end, Cvoid, (UInt64,), start_time) @@ -1148,26 +1128,15 @@ function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance, source_mod ccall(:jl_typeinf_timing_end, Cvoid, (UInt64,), start_time) ci = result.ci # reload from result in case it changed - if source_mode == SOURCE_MODE_ABI && frame.cache_mode != CACHE_MODE_GLOBAL - # XXX: jl_type_infer somewhat ambiguously assumes this must be cached, while jl_ci_cache_lookup sort of ambiguously re-caches it + @assert frame.cache_mode != CACHE_MODE_NULL + @assert is_result_constabi_eligible(result) || (!isdefined(interp, :codegen) || haskey(interp.codegen, ci)) + @assert is_result_constabi_eligible(result) == use_const_api(ci) + @assert isdefined(ci, :inferred) "interpreter did not fulfill our expectations" + if !is_cached(frame) && source_mode == SOURCE_MODE_ABI + # XXX: jl_type_infer somewhat ambiguously assumes this must be cached # XXX: this should be using the CI from the cache, if possible instead: haskey(cache, mi) && (ci = cache[mi]) - @assert isdefined(ci, :inferred) "interpreter did not fulfill its requirements" code_cache(interp)[mi] = ci end - if source_mode == SOURCE_MODE_FORCE_SOURCE && use_const_api(ci) - # If the caller cares about the code and this is constabi, still use our synthesis function - # anyway, because we will have not finished inferring the code inside the CodeInstance once - # we realized it was constabi, but we want reflection to pretend that we did. - # XXX: the one user of this does not actually want this behavior, but it is required by the flag definition currently - ci = codeinstance_for_const_with_code(interp, ci) - @assert ci_meets_requirement(ci, source_mode) - return ci - end - if !ci_meets_requirement(ci, source_mode) - can_discard_trees = false - finish!(interp, frame; can_discard_trees) # redo finish! with the correct can_discard_trees parameter value - @assert ci_meets_requirement(ci, source_mode) - end return ci end @@ -1212,10 +1181,104 @@ function typeinf_type(interp::AbstractInterpreter, mi::MethodInstance) return widenconst(ignorelimited(result.result)) end -# This is a bridge for the C code calling `jl_typeinf_func()` -typeinf_ext_toplevel(mi::MethodInstance, world::UInt, source_mode::UInt8) = typeinf_ext_toplevel(NativeInterpreter(world), mi, source_mode) -function typeinf_ext_toplevel(interp::AbstractInterpreter, mi::MethodInstance, source_mode::UInt8) - return typeinf_ext(interp, mi, source_mode) +# collect a list of all code that is needed along with CodeInstance to codegen it fully +function collectinvokes!(wq::Vector{CodeInstance}, ci::CodeInfo) + src = ci.code + for i = 1:length(src) + stmt = src[i] + isexpr(stmt, :(=)) && (stmt = stmt.args[2]) + if isexpr(stmt, :invoke) || isexpr(stmt, :invoke_modify) + edge = stmt.args[1] + edge isa CodeInstance && isdefined(edge, :inferred) && push!(wq, edge) + end + # TODO: handle other StmtInfo like @cfunction and OpaqueClosure? + end +end + +# This is a bridge for the C code calling `jl_typeinf_func()` on a single Method match +function typeinf_ext_toplevel(mi::MethodInstance, world::UInt, source_mode::UInt8) + interp = NativeInterpreter(world) + ci = typeinf_ext(interp, mi, source_mode) + if source_mode == SOURCE_MODE_ABI && ci isa CodeInstance && !ci_has_invoke(ci) + inspected = IdSet{CodeInstance}() + tocompile = Vector{CodeInstance}() + push!(tocompile, ci) + while !isempty(tocompile) + # ci_has_real_invoke(ci) && return ci # optimization: cease looping if ci happens to get compiled (not just jl_fptr_wait_for_compiled, but fully jl_is_compiled_codeinst) + callee = pop!(tocompile) + ci_has_invoke(callee) && continue + callee in inspected && continue + src = get(interp.codegen, callee, nothing) + if !isa(src, CodeInfo) + src = @atomic :monotonic callee.inferred + if isa(src, String) + src = _uncompressed_ir(callee, src) + end + if !isa(src, CodeInfo) + newcallee = typeinf_ext(interp, callee.def, source_mode) + if newcallee isa CodeInstance + callee === ci && (ci = newcallee) # ci stopped meeting the requirements after typeinf_ext last checked, try again with newcallee + push!(tocompile, newcallee) + #else + # println("warning: could not get source code for ", callee.def) + end + continue + end + end + push!(inspected, callee) + collectinvokes!(tocompile, src) + ccall(:jl_add_codeinst_to_jit, Cvoid, (Any, Any), callee, src) + end + end + return ci +end + +# This is a bridge for the C code calling `jl_typeinf_func()` on set of Method matches +function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim::Bool) + inspected = IdSet{CodeInstance}() + tocompile = Vector{CodeInstance}() + codeinfos = [] + # first compute the ABIs of everything + for this_world in reverse(sort!(worlds)) + interp = NativeInterpreter(this_world) + for i = 1:length(methods) + # each item in this list is either a MethodInstance indicating something + # to compile, or an svec(rettype, sig) describing a C-callable alias to create. + item = methods[i] + if item isa MethodInstance + # if this method is generally visible to the current compilation world, + # and this is either the primary world, or not applicable in the primary world + # then we want to compile and emit this + if item.def.primary_world <= this_world <= item.def.deleted_world + ci = typeinf_ext(interp, item, SOURCE_MODE_NOT_REQUIRED) + ci isa CodeInstance && !use_const_api(ci) && push!(tocompile, ci) + end + elseif item isa SimpleVector + push!(codeinfos, item[1]::Type) + push!(codeinfos, item[2]::Type) + end + end + while !isempty(tocompile) + callee = pop!(tocompile) + callee in inspected && continue + push!(inspected, callee) + # now make sure everything has source code, if desired + # TODO: typeinf_code could return something with different edges/ages (needing an update to callee), which we don't handle here + if use_const_api(callee) + src = codeinfo_for_const(interp, callee.def, code.rettype_const) + elseif haskey(interp.codegen, callee) + src = interp.codegen[callee] + else + src = typeinf_code(interp, callee.def, true) + end + if src isa CodeInfo + collectinvokes!(tocompile, src) + push!(codeinfos, callee) + push!(codeinfos, src) + end + end + end + return codeinfos end function return_type(@nospecialize(f), t::DataType) # this method has a special tfunc diff --git a/Compiler/src/types.jl b/Compiler/src/types.jl index 5669ec3175c9e..6ffb5402682f3 100644 --- a/Compiler/src/types.jl +++ b/Compiler/src/types.jl @@ -366,6 +366,7 @@ struct NativeInterpreter <: AbstractInterpreter # Cache of inference results for this particular interpreter inf_cache::Vector{InferenceResult} + codegen::IdDict{CodeInstance,CodeInfo} # Parameters for inference and optimization inf_params::InferenceParams @@ -386,16 +387,8 @@ function NativeInterpreter(world::UInt = get_world_counter(); @assert world <= curr_max_world method_table = CachedMethodTable(InternalMethodTable(world)) inf_cache = Vector{InferenceResult}() # Initially empty cache - return NativeInterpreter(world, method_table, inf_cache, inf_params, opt_params) -end - -function NativeInterpreter(interp::NativeInterpreter; - world::UInt = interp.world, - method_table::CachedMethodTable{InternalMethodTable} = interp.method_table, - inf_cache::Vector{InferenceResult} = interp.inf_cache, - inf_params::InferenceParams = interp.inf_params, - opt_params::OptimizationParams = interp.opt_params) - return NativeInterpreter(world, method_table, inf_cache, inf_params, opt_params) + codegen = IdDict{CodeInstance,CodeInfo}() + return NativeInterpreter(world, method_table, inf_cache, codegen, inf_params, opt_params) end # Quickly and easily satisfy the AbstractInterpreter API contract diff --git a/Compiler/src/utilities.jl b/Compiler/src/utilities.jl index 196722f8bca33..c322d1062cea1 100644 --- a/Compiler/src/utilities.jl +++ b/Compiler/src/utilities.jl @@ -149,6 +149,9 @@ end isa_compileable_sig(@nospecialize(atype), sparams::SimpleVector, method::Method) = !iszero(ccall(:jl_isa_compileable_sig, Int32, (Any, Any, Any), atype, sparams, method)) +isa_compileable_sig(m::MethodInstance) = (def = m.def; !isa(def, Method) || isa_compileable_sig(m.specTypes, m.sparam_vals, def)) +isa_compileable_sig(m::ABIOverride) = false + has_typevar(@nospecialize(t), v::TypeVar) = ccall(:jl_has_typevar, Cint, (Any, Any), t, v) != 0 """ diff --git a/Compiler/test/abioverride.jl b/Compiler/test/abioverride.jl index d35fa8876cf1c..e257074852099 100644 --- a/Compiler/test/abioverride.jl +++ b/Compiler/test/abioverride.jl @@ -12,19 +12,23 @@ struct SecondArgConstOverride arg2::Int end -world = Base.tls_world_age() -mi = Base.specialize_method(only(Base._methods_by_ftype(Tuple{typeof(myplus), Int, Int}, -1, world))) -interp = Compiler.NativeInterpreter(world) -ci = Compiler.typeinf_ext(interp, mi, Compiler.SOURCE_MODE_FORCE_SOURCE) - function is_known_call(@nospecialize(x), @nospecialize(func), src::Core.CodeInfo) isexpr(x, :call) || return false ft = Compiler.argextype(x.args[1], src, Compiler.VarState[]) return Compiler.singleton_type(ft) === func end + # Construct a CodeInstance with an ABI override -new_ci = let new_source = copy(Base.uncompressed_ir(ci)) +let world = Base.tls_world_age() + # Get some inferred source code to give to the compiler + # Do not look at a CodeInstance here, since those fields are only valid to + # use while attached to a cache, and are thus invalid to make copies of + # (since you'd have to have made the copy to insert into the cache before + # making the original CodeInstance to copy from, which is obviously + # rather temporally-challenged) + new_source = only(code_typed(myplus, (Int, Int)))[1] + mi = new_source.parent ## Sanity check @assert length(new_source.code) == 2 add = new_source.code[1] @@ -37,15 +41,19 @@ new_ci = let new_source = copy(Base.uncompressed_ir(ci)) resize!(new_source.slotnames, 2) resize!(new_source.slotflags, 2) - # Construct the CodeInstance - new_ci = Core.CodeInstance(Core.ABIOverride(Tuple{typeof(myplus), Int}, mi), - SecondArgConstOverride(1), ci.rettype, ci.exctype, nothing, new_source, - Int32(0), ci.min_world, ci.max_world, ci.ipo_purity_bits, nothing, ci.relocatability, ci.debuginfo, ci.edges) + # Construct the CodeInstance from the modified CodeInfo data + global new_ci = Core.CodeInstance(Core.ABIOverride(Tuple{typeof(myplus), Int}, mi), + #=owner=#SecondArgConstOverride(1), new_source.rettype, Any#=new_source.exctype is missing=#, + #=inferred_const=#nothing, #=code=#nothing, #=const_flags=#Int32(0), + new_source.min_world, new_source.max_world, #=new_source.ipo_purity_bits is missing=#UInt32(0), + #=analysis_results=#nothing, #=not relocatable?=#UInt8(0), new_source.debuginfo, new_source.edges) # Poke the CI into the global cache + # This isn't necessary, but does conveniently give it the mandatory permanent GC-root before calling `invoke` ccall(:jl_mi_cache_insert, Cvoid, (Any, Any), mi, new_ci) - new_ci + # Poke the source code into the JIT for it + ccall(:jl_add_codeinst_to_jit, Cvoid, (Any, Any), new_ci, new_source) end @test contains(repr(new_ci), "ABI Overridden") diff --git a/base/reflection.jl b/base/reflection.jl index f7952ac7a78d7..f9c5dd9765533 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -132,14 +132,6 @@ uncompressed_ir(m::Method) = isdefined(m, :source) ? _uncompressed_ir(m) : isdefined(m, :generator) ? error("Method is @generated; try `code_lowered` instead.") : error("Code for this Method is not available.") -function uncompressed_ir(ci::CodeInstance) - inferred = ci.inferred - isa(inferred, CodeInfo) && return inferred - isa(inferred, String) && return _uncompressed_ir(ci, inferred) - inferred === nothing && error("Inferred code was deleted.") - error(string("Unknown inferred code type ", typeof(inferred))) -end - # for backwards compat const uncompressed_ast = uncompressed_ir const _uncompressed_ast = _uncompressed_ir diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index b238c44c52676..0600106c41aa6 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -52,7 +52,6 @@ using namespace llvm; #define DEBUG_TYPE "julia_aotcompile" -STATISTIC(CICacheLookups, "Number of codeinst cache lookups"); STATISTIC(CreateNativeCalls, "Number of jl_create_native calls made"); STATISTIC(CreateNativeMethods, "Number of methods compiled for jl_create_native"); STATISTIC(CreateNativeMax, "Max number of methods compiled at once for jl_create_native"); @@ -307,37 +306,6 @@ static void makeSafeName(GlobalObject &G) G.setName(StringRef(SafeName.data(), SafeName.size())); } -static jl_code_instance_t *jl_ci_cache_lookup(jl_method_instance_t *mi, size_t world, jl_codeinstance_lookup_t lookup) -{ - ++CICacheLookups; - jl_value_t *ci = lookup(mi, world, world); - JL_GC_PROMISE_ROOTED(ci); - jl_code_instance_t *codeinst = NULL; - if (ci != jl_nothing && jl_atomic_load_relaxed(&((jl_code_instance_t *)ci)->inferred) != jl_nothing) { - codeinst = (jl_code_instance_t*)ci; - } - else { - if (lookup != jl_rettype_inferred_addr) { - // XXX: This will corrupt and leak a lot of memory which may be very bad - jl_error("Refusing to automatically run type inference with custom cache lookup."); - } - else { - // XXX: SOURCE_MODE_ABI is wrong here (not sufficient) - codeinst = jl_type_infer(mi, world, SOURCE_MODE_ABI); - /* Even if this codeinst is ordinarily not cacheable, we need to force - * it into the cache here, since it was explicitly requested and is - * otherwise not reachable from anywhere in the system image. - */ - if (codeinst && !jl_mi_cache_has_ci(mi, codeinst)) { - JL_GC_PUSH1(&codeinst); - jl_mi_cache_insert(mi, codeinst); - JL_GC_POP(); - } - } - } - return codeinst; -} - namespace { // file-local namespace class egal_set { public: @@ -432,7 +400,7 @@ static void aot_optimize_roots(jl_codegen_params_t ¶ms, egal_set &method_roo } } -static void compile_workqueue(jl_codegen_params_t ¶ms, egal_set &method_roots, CompilationPolicy policy, jl_compiled_functions_t &compiled_functions) +static void resolve_workqueue(jl_codegen_params_t ¶ms, egal_set &method_roots, jl_compiled_functions_t &compiled_functions) { decltype(params.workqueue) workqueue; std::swap(params.workqueue, workqueue); @@ -449,24 +417,6 @@ static void compile_workqueue(jl_codegen_params_t ¶ms, egal_set &method_root bool preal_specsig = false; { auto it = compiled_functions.find(codeinst); - if (it == compiled_functions.end()) { - // Reinfer the function. The JIT came along and removed the inferred - // method body. See #34993 - if ((policy != CompilationPolicy::Default || params.params->trim) && - jl_atomic_load_relaxed(&codeinst->inferred) == jl_nothing) { - // XXX: SOURCE_MODE_FORCE_SOURCE is wrong here (neither sufficient nor necessary) - codeinst = jl_type_infer(jl_get_ci_mi(codeinst), jl_atomic_load_relaxed(&codeinst->max_world), SOURCE_MODE_FORCE_SOURCE); - } - if (codeinst) { - orc::ThreadSafeModule result_m = - jl_create_ts_module(name_from_method_instance(jl_get_ci_mi(codeinst)), - params.tsctx, params.DL, params.TargetTriple); - auto decls = jl_emit_codeinst(result_m, codeinst, NULL, params); - record_method_roots(method_roots, jl_get_ci_mi(codeinst)); - if (result_m) - it = compiled_functions.insert(std::make_pair(codeinst, std::make_pair(std::move(result_m), std::move(decls)))).first; - } - } if (it != compiled_functions.end()) { auto &decls = it->second.second; invokeName = decls.functionObject; @@ -478,6 +428,12 @@ static void compile_workqueue(jl_codegen_params_t ¶ms, egal_set &method_root preal_specsig = true; } } + else if (params.params->trim) { + jl_safe_printf("warning: no code provided for function"); + jl_(codeinst->def); + if (params.params->trim) + abort(); + } } // patch up the prototype we emitted earlier Module *mod = proto.decl->getParent(); @@ -485,7 +441,7 @@ static void compile_workqueue(jl_codegen_params_t ¶ms, egal_set &method_root Function *pinvoke = nullptr; if (preal_decl.empty()) { if (invokeName.empty() && params.params->trim) { - errs() << "Bailed out to invoke when compiling:"; + jl_safe_printf("warning: bailed out to invoke when compiling:"); jl_(codeinst->def); abort(); } @@ -543,31 +499,109 @@ static void compile_workqueue(jl_codegen_params_t ¶ms, egal_set &method_root JL_GC_POP(); } + // takes the running content that has collected in the shadow module and dump it to disk -// this builds the object file portion of the sysimage files for fast startup, and can +// this builds the object file portion of the sysimage files for fast startup +// `_external_linkage` create linkages between pkgimages. +extern "C" JL_DLLEXPORT_CODEGEN +void *jl_create_native_impl(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvmmod, int _trim, int _external_linkage, size_t world) +{ + JL_TIMING(INFERENCE, INFERENCE); + auto ct = jl_current_task; + bool timed = (ct->reentrant_timing & 1) == 0; + if (timed) + ct->reentrant_timing |= 1; + uint64_t compiler_start_time = 0; + uint8_t measure_compile_time_enabled = jl_atomic_load_relaxed(&jl_measure_compile_time_enabled); + if (measure_compile_time_enabled) + compiler_start_time = jl_hrtime(); + + jl_cgparams_t cgparams = jl_default_cgparams; + cgparams.trim = _trim ? 1 : 0; + size_t compile_for[] = { jl_typeinf_world, world }; + int compiler_world = 1; + if (_trim || compile_for[0] == 0) + compiler_world = 0; + jl_value_t **fargs; + JL_GC_PUSHARGS(fargs, 4); + jl_array_t *codeinfos = NULL; + if (jl_typeinf_func) { + fargs[0] = (jl_value_t*)jl_typeinf_func; + fargs[1] = (jl_value_t*)methods; +#ifdef _P64 + jl_value_t *jl_array_ulong_type = jl_array_uint64_type; +#else + jl_value_t *jl_array_ulong_type = jl_array_uint32_type; +#endif + jl_array_t *worlds = jl_alloc_array_1d(jl_array_ulong_type, 1 + compiler_world); + fargs[2] = (jl_value_t*)worlds; + jl_array_data(worlds, size_t)[0] = jl_typeinf_world; + jl_array_data(worlds, size_t)[compiler_world] = world; // might overwrite previous + fargs[3] = _trim ? jl_true : jl_false; + size_t last_age = ct->world_age; + ct->world_age = jl_typeinf_world; + codeinfos = (jl_array_t*)jl_apply(fargs, 4); + ct->world_age = last_age; + JL_TYPECHK(create_native, array_any, (jl_value_t*)codeinfos); + } + else { + // we could put a very simple generator here, but there is no reason to do that right now + jl_error("inference not available for generating compiled output"); + } + fargs[0] = (jl_value_t*)codeinfos; + void *data = jl_emit_native(codeinfos, llvmmod, &cgparams, _external_linkage); + + // move everything inside, now that we've merged everything + // (before adding the exported headers) + ((jl_native_code_desc_t*)data)->M.withModuleDo([&](Module &M) { + auto TT = Triple(M.getTargetTriple()); + Function *juliapersonality_func = nullptr; + if (TT.isOSWindows() && TT.getArch() == Triple::x86_64) { + // setting the function personality enables stack unwinding and catching exceptions + // so make sure everything has something set + Type *T_int32 = Type::getInt32Ty(M.getContext()); + juliapersonality_func = Function::Create(FunctionType::get(T_int32, true), + Function::ExternalLinkage, "__julia_personality", M); + juliapersonality_func->setDLLStorageClass(GlobalValue::DLLImportStorageClass); + } + for (GlobalObject &G : M.global_objects()) { + if (!G.isDeclaration()) { + G.setLinkage(GlobalValue::InternalLinkage); + G.setDSOLocal(true); + makeSafeName(G); + if (Function *F = dyn_cast(&G)) { + if (juliapersonality_func) { + // Add unwind exception personalities to functions to handle async exceptions + F->setPersonalityFn(juliapersonality_func); + } + } + } + } + }); + + JL_GC_POP(); + if (timed) { + if (measure_compile_time_enabled) { + auto end = jl_hrtime(); + jl_atomic_fetch_add_relaxed(&jl_cumulative_compile_time, end - compiler_start_time); + } + ct->reentrant_timing &= ~1ull; + } + return data; +} + // also be used be extern consumers like GPUCompiler.jl to obtain a module containing // all reachable & inferrrable functions. -// The `policy` flag switches between the default mode `0` and the extern mode `1` used by GPUCompiler. -// `_imaging_mode` controls if raw pointers can be embedded (e.g. the code will be loaded into the same session). -// `_external_linkage` create linkages between pkgimages. extern "C" JL_DLLEXPORT_CODEGEN -void *jl_create_native_impl(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvmmod, const jl_cgparams_t *cgparams, int _policy, int _imaging_mode, int _external_linkage, size_t _world, jl_codeinstance_lookup_t lookup) +void *jl_emit_native_impl(jl_array_t *codeinfos, LLVMOrcThreadSafeModuleRef llvmmod, const jl_cgparams_t *cgparams, int _external_linkage) { JL_TIMING(NATIVE_AOT, NATIVE_Create); ++CreateNativeCalls; - CreateNativeMax.updateMax(jl_array_nrows(methods)); + CreateNativeMax.updateMax(jl_array_nrows(codeinfos)); if (cgparams == NULL) cgparams = &jl_default_cgparams; - if (lookup == NULL) - lookup = &jl_rettype_inferred_native; jl_native_code_desc_t *data = new jl_native_code_desc_t; - CompilationPolicy policy = (CompilationPolicy) _policy; - bool imaging = imaging_default() || _imaging_mode == 1; jl_method_instance_t *mi = NULL; - auto ct = jl_current_task; - bool timed = (ct->reentrant_timing & 1) == 0; - if (timed) - ct->reentrant_timing |= 1; orc::ThreadSafeContext ctx; orc::ThreadSafeModule backing; if (!llvmmod) { @@ -577,13 +611,7 @@ void *jl_create_native_impl(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvm orc::ThreadSafeModule &clone = llvmmod ? *unwrap(llvmmod) : backing; auto ctxt = clone.getContext(); - uint64_t compiler_start_time = 0; - uint8_t measure_compile_time_enabled = jl_atomic_load_relaxed(&jl_measure_compile_time_enabled); - if (measure_compile_time_enabled) - compiler_start_time = jl_hrtime(); - // compile all methods for the current world and type-inference world - auto target_info = clone.withModuleDo([&](Module &M) { return std::make_pair(M.getDataLayout(), Triple(M.getTargetTriple())); }); @@ -592,84 +620,57 @@ void *jl_create_native_impl(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvm if (!llvmmod) params.getContext().setDiscardValueNames(true); params.params = cgparams; - params.imaging_mode = imaging; + assert(params.imaging_mode); // `_imaging_mode` controls if broken features like code-coverage are disabled params.external_linkage = _external_linkage; params.temporary_roots = jl_alloc_array_1d(jl_array_any_type, 0); JL_GC_PUSH3(¶ms.temporary_roots, &method_roots.list, &method_roots.keyset); - size_t compile_for[] = { jl_typeinf_world, _world }; - int worlds = 0; - if (jl_options.trim != JL_TRIM_NO) - worlds = 1; jl_compiled_functions_t compiled_functions; - for (; worlds < 2; worlds++) { - JL_TIMING(NATIVE_AOT, NATIVE_Codegen); - size_t this_world = compile_for[worlds]; - if (!this_world) - continue; - // Don't emit methods for the typeinf_world with extern policy - if (policy != CompilationPolicy::Default && this_world == jl_typeinf_world) - continue; - size_t i, l; - for (i = 0, l = jl_array_nrows(methods); i < l; i++) { - // each item in this list is either a MethodInstance indicating something - // to compile, or an svec(rettype, sig) describing a C-callable alias to create. - jl_value_t *item = jl_array_ptr_ref(methods, i); - if (jl_is_simplevector(item)) { - if (worlds == 1) - jl_compile_extern_c(wrap(&clone), ¶ms, NULL, jl_svecref(item, 0), jl_svecref(item, 1)); - continue; - } - mi = (jl_method_instance_t*)item; - // if this method is generally visible to the current compilation world, - // and this is either the primary world, or not applicable in the primary world - // then we want to compile and emit this - if (jl_atomic_load_relaxed(&mi->def.method->primary_world) <= this_world && this_world <= jl_atomic_load_relaxed(&mi->def.method->deleted_world)) { - // find and prepare the source code to compile - jl_code_instance_t *codeinst = jl_ci_cache_lookup(mi, this_world, lookup); - JL_GC_PROMISE_ROOTED(codeinst); - if (jl_options.trim != JL_TRIM_NO && !codeinst) { - // If we're building a small image, we need to compile everything - // to ensure that we have all the information we need. - jl_safe_printf("Codegen decided not to compile code root"); - jl_(mi); - abort(); - } - if (codeinst && !compiled_functions.count(codeinst) && !data->jl_fvar_map.count(codeinst)) { - // now add it to our compilation results - // Const returns do not do codegen, but juliac inspects codegen results so make a dummy fvar entry to represent it - if (jl_options.trim != JL_TRIM_NO && jl_atomic_load_relaxed(&codeinst->invoke) == jl_fptr_const_return_addr) { - data->jl_fvar_map[codeinst] = std::make_tuple((uint32_t)-3, (uint32_t)-3); - } - else { - orc::ThreadSafeModule result_m = jl_create_ts_module(name_from_method_instance(jl_get_ci_mi(codeinst)), - params.tsctx, clone.getModuleUnlocked()->getDataLayout(), - Triple(clone.getModuleUnlocked()->getTargetTriple())); - jl_llvm_functions_t decls = jl_emit_codeinst(result_m, codeinst, NULL, params); - JL_GC_PROMISE_ROOTED(codeinst->def); // analyzer seems confused - record_method_roots(method_roots, jl_get_ci_mi(codeinst)); - if (result_m) - compiled_functions[codeinst] = {std::move(result_m), std::move(decls)}; - else if (jl_options.trim != JL_TRIM_NO) { - // if we're building a small image, we need to compile everything - // to ensure that we have all the information we need. - jl_safe_printf("codegen failed to compile code root"); - jl_(mi); - abort(); - } - } + size_t i, l; + for (i = 0, l = jl_array_nrows(codeinfos); i < l; i++) { + // each item in this list is either a CodeInstance followed by a CodeInfo indicating something + // to compile, or a rettype followed by a sig describing a C-callable alias to create. + jl_value_t *item = jl_array_ptr_ref(codeinfos, i); + if (jl_is_code_instance(item)) { + // now add it to our compilation results + jl_code_instance_t *codeinst = (jl_code_instance_t*)item; + jl_code_info_t *src = (jl_code_info_t*)jl_array_ptr_ref(codeinfos, ++i); + assert(jl_is_code_info(src)); + if (compiled_functions.count(codeinst)) + continue; // skip any duplicates that accidentally made there way in here (or make this an error?) + if (_external_linkage) { + uint8_t specsigflags; + jl_callptr_t invoke; + void *fptr; + jl_read_codeinst_invoke(codeinst, &specsigflags, &invoke, &fptr, 0); + if (invoke != NULL && (specsigflags & 0b100)) { + // this codeinst is already available externally + // TODO: for performance, avoid generating the src code when we know it would reach here anyways + continue; } } - else if (this_world != jl_typeinf_world) { - /* - jl_safe_printf("Codegen could not find requested codeinstance to be compiled\n"); + orc::ThreadSafeModule result_m = jl_create_ts_module(name_from_method_instance(jl_get_ci_mi(codeinst)), + params.tsctx, clone.getModuleUnlocked()->getDataLayout(), + Triple(clone.getModuleUnlocked()->getTargetTriple())); + jl_llvm_functions_t decls = jl_emit_codeinst(result_m, codeinst, src, params); + record_method_roots(method_roots, jl_get_ci_mi(codeinst)); + if (result_m) + compiled_functions[codeinst] = {std::move(result_m), std::move(decls)}; + else if (params.params->trim) { + // if we're building a small image, we need to compile everything + // to ensure that we have all the information we need. + jl_safe_printf("codegen failed to compile code root"); jl_(mi); abort(); - */ } } + else { + jl_value_t *sig = jl_array_ptr_ref(codeinfos, ++i); + assert(jl_is_type(item) && jl_is_type(sig)); + jl_compile_extern_c(wrap(&clone), ¶ms, NULL, item, sig); + } } - // finally, make sure all referenced methods also get compiled or fixed up - compile_workqueue(params, method_roots, policy, compiled_functions); + // finally, make sure all referenced methods get fixed up, particularly if the user declined to compile them + resolve_workqueue(params, method_roots, compiled_functions); aot_optimize_roots(params, method_roots, compiled_functions); params.temporary_roots = nullptr; JL_GC_POP(); @@ -712,7 +713,6 @@ void *jl_create_native_impl(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvm // clones the contents of the module `m` to the shadow_output collector // while examining and recording what kind of function pointer we have { - JL_TIMING(NATIVE_AOT, NATIVE_Merge); Linker L(*clone.getModuleUnlocked()); for (auto &def : compiled_functions) { jl_merge_module(clone, std::move(std::get<0>(def.second))); @@ -762,45 +762,7 @@ void *jl_create_native_impl(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvm } CreateNativeGlobals += gvars.size(); - //Safe b/c context is locked by params - auto TT = Triple(clone.getModuleUnlocked()->getTargetTriple()); - Function *juliapersonality_func = nullptr; - if (TT.isOSWindows() && TT.getArch() == Triple::x86_64) { - // setting the function personality enables stack unwinding and catching exceptions - // so make sure everything has something set - Type *T_int32 = Type::getInt32Ty(clone.getModuleUnlocked()->getContext()); - juliapersonality_func = Function::Create(FunctionType::get(T_int32, true), - Function::ExternalLinkage, "__julia_personality", clone.getModuleUnlocked()); - juliapersonality_func->setDLLStorageClass(GlobalValue::DLLImportStorageClass); - } - - // move everything inside, now that we've merged everything - // (before adding the exported headers) - if (policy == CompilationPolicy::Default) { - //Safe b/c context is locked by params - for (GlobalObject &G : clone.getModuleUnlocked()->global_objects()) { - if (!G.isDeclaration()) { - G.setLinkage(GlobalValue::InternalLinkage); - G.setDSOLocal(true); - makeSafeName(G); - if (Function *F = dyn_cast(&G)) { - if (TT.isOSWindows() && TT.getArch() == Triple::x86_64) { - // Add unwind exception personalities to functions to handle async exceptions - F->setPersonalityFn(juliapersonality_func); - } - } - } - } - } - data->M = std::move(clone); - if (timed) { - if (measure_compile_time_enabled) { - auto end = jl_hrtime(); - jl_atomic_fetch_add_relaxed(&jl_cumulative_compile_time, end - compiler_start_time); - } - ct->reentrant_timing &= ~1ull; - } return (void*)data; } @@ -1954,8 +1916,7 @@ void jl_dump_native_impl(void *native_code, sysimg_outputs = compile(sysimgM, "sysimg", 1, [](Module &) {}); } - bool imaging_mode = imaging_default() || jl_options.outputo; - + const bool imaging_mode = true; unsigned threads = 1; unsigned nfvars = 0; unsigned ngvars = 0; @@ -2062,8 +2023,7 @@ void jl_dump_native_impl(void *native_code, data_outputs = compile(*dataM, "text", threads, [data](Module &) { delete data; }); } - if (params->emit_metadata) - { + if (params->emit_metadata) { JL_TIMING(NATIVE_AOT, NATIVE_Metadata); LLVMContext Context; Context.setDiscardValueNames(true); @@ -2258,13 +2218,7 @@ void jl_get_llvmf_defn_impl(jl_llvmf_dump_t* dump, jl_method_instance_t *mi, jl_ }); jl_codegen_params_t output(ctx, std::move(target_info.first), std::move(target_info.second)); output.params = ¶ms; - output.imaging_mode = imaging_default(); - // This would be nice, but currently it causes some assembly regressions that make printed output - // differ very significantly from the actual non-imaging mode code. - // // Force imaging mode for names of pointers - // output.imaging = true; - // This would also be nice, but it seems to cause OOMs on the windows32 builder - // To get correct names in the IR this needs to be at least 2 + output.imaging_mode = jl_options.image_codegen; output.temporary_roots = jl_alloc_array_1d(jl_array_any_type, 0); JL_GC_PUSH1(&output.temporary_roots); auto decls = jl_emit_code(m, mi, src, NULL, output); diff --git a/src/ccall.cpp b/src/ccall.cpp index 3937570896f82..1b635ca40840f 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -697,14 +697,12 @@ static jl_cgval_t emit_cglobal(jl_codectx_t &ctx, jl_value_t **args, size_t narg } else if (sym.fptr != NULL) { res = ConstantInt::get(lrt, (uint64_t)sym.fptr); - if (ctx.emission_context.imaging_mode) - jl_printf(JL_STDERR,"WARNING: literal address used in cglobal for %s; code cannot be statically compiled\n", sym.f_name); } else if (sym.f_name != NULL) { if (sym.lib_expr) { res = runtime_sym_lookup(ctx, getPointerTy(ctx.builder.getContext()), NULL, sym.lib_expr, sym.f_name, ctx.f); } - else /*if (ctx.emission_context.imaging) */{ + else { res = runtime_sym_lookup(ctx, getPointerTy(ctx.builder.getContext()), sym.f_lib, NULL, sym.f_name, ctx.f); } } else { @@ -2134,8 +2132,6 @@ jl_cgval_t function_sig_t::emit_a_ccall( Type *funcptype = functype->getPointerTo(0); llvmf = literal_static_pointer_val((void*)(uintptr_t)symarg.fptr, funcptype); setName(ctx.emission_context, llvmf, "ccall_fptr"); - if (ctx.emission_context.imaging_mode) - jl_printf(JL_STDERR,"WARNING: literal address used in ccall for %s; code cannot be statically compiled\n", symarg.f_name); } else if (!ctx.params->use_jlplt) { if ((symarg.f_lib && !((symarg.f_lib == JL_EXE_LIBNAME) || @@ -2152,7 +2148,7 @@ jl_cgval_t function_sig_t::emit_a_ccall( ++DeferredCCallLookups; llvmf = runtime_sym_lookup(ctx, funcptype, NULL, symarg.lib_expr, symarg.f_name, ctx.f); } - else /*if (ctx.emission_context.imaging) */{ + else { ++DeferredCCallLookups; // vararg requires musttail, // but musttail is incompatible with noreturn. diff --git a/src/codegen-stubs.c b/src/codegen-stubs.c index fe50af3f8e84d..5e243ddda28c9 100644 --- a/src/codegen-stubs.c +++ b/src/codegen-stubs.c @@ -46,11 +46,26 @@ JL_DLLEXPORT void jl_generate_fptr_for_unspecialized_fallback(jl_code_instance_t JL_DLLEXPORT int jl_compile_codeinst_fallback(jl_code_instance_t *unspec) { - // Do nothing. The caller will notice that we failed to provide a an ->invoke and trigger + // Do nothing. The caller will notice that we failed to provide an ->invoke and trigger // appropriate fallbacks. return 0; } +JL_DLLEXPORT void jl_emit_codeinst_to_jit_fallback(jl_code_instance_t *codeinst, jl_code_info_t *src) +{ + jl_value_t *inferred = jl_atomic_load_relaxed(&codeinst->inferred); + if (jl_is_code_info(inferred)) + return; + if (jl_is_svec(src->edges)) { + jl_atomic_store_release(&codeinst->inferred, (jl_value_t*)src->edges); + jl_gc_wb(codeinst, src->edges); + } + jl_atomic_store_release(&codeinst->debuginfo, src->debuginfo); + jl_gc_wb(codeinst, src->debuginfo); + jl_atomic_store_release(&codeinst->inferred, (jl_value_t*)src); + jl_gc_wb(codeinst, src); +} + JL_DLLEXPORT uint32_t jl_get_LLVM_VERSION_fallback(void) { return 0; @@ -70,7 +85,8 @@ JL_DLLEXPORT size_t jl_jit_total_bytes_fallback(void) return 0; } -JL_DLLEXPORT void *jl_create_native_fallback(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvmmod, const jl_cgparams_t *cgparams, int _policy, int _imaging_mode, int _external_linkage, size_t _world, jl_codeinstance_lookup_t lookup) UNAVAILABLE +JL_DLLEXPORT void *jl_create_native_fallback(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvmmod, int _trim, int _external_linkage, size_t _world) UNAVAILABLE +JL_DLLEXPORT void *jl_emit_native_fallback(jl_array_t *codeinfos, LLVMOrcThreadSafeModuleRef llvmmod, const jl_cgparams_t *cgparams, int _external_linkage) UNAVAILABLE JL_DLLEXPORT void jl_dump_compiles_fallback(void *s) { diff --git a/src/codegen.cpp b/src/codegen.cpp index ceaba9507e4c7..04253b67d6b6d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6771,7 +6771,7 @@ static void emit_latestworld(jl_codectx_t &ctx) (void)store_world; } -// `expr` is not clobbered in JL_TRY +// `expr` is not actually clobbered in JL_TRY JL_GCC_IGNORE_START("-Wclobbered") static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaidx_0based) { @@ -7297,10 +7297,10 @@ Function *emit_tojlinvoke(jl_code_instance_t *codeinst, StringRef theFptrName, M theFarg = literal_pointer_val(ctx, (jl_value_t*)codeinst); } else { - jl_method_instance_t *mi = codeinst->def; + jl_method_instance_t *mi = jl_get_ci_mi(codeinst); bool is_opaque_closure = jl_is_method(mi->def.value) && mi->def.method->is_for_opaque_closure; theFunc = prepare_call(is_opaque_closure ? jlinvokeoc_func : jlinvoke_func); - theFarg = literal_pointer_val(ctx, (jl_value_t*)jl_get_ci_mi(codeinst)); + theFarg = literal_pointer_val(ctx, (jl_value_t*)mi); } theFarg = track_pjlvalue(ctx, theFarg); auto args = f->arg_begin(); @@ -7466,7 +7466,7 @@ static Function *gen_cfun_wrapper( jl_code_instance_t *codeinst = NULL; if (lam) { - // TODO: this isn't ideal to be unconditionally calling type inference (and compile) from here + // TODO: this isn't ideal to be unconditionally calling type inference from here codeinst = jl_type_infer(lam, world, SOURCE_MODE_NOT_REQUIRED); astrt = codeinst->rettype; if (astrt != (jl_value_t*)jl_bottom_type && @@ -9975,9 +9975,6 @@ static jl_llvm_functions_t // --- entry point --- -void jl_add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL); - -JL_GCC_IGNORE_START("-Wclobbered") jl_llvm_functions_t jl_emit_code( orc::ThreadSafeModule &m, jl_method_instance_t *li, @@ -10023,15 +10020,6 @@ jl_llvm_functions_t jl_emit_code( return decls; } -static int effects_foldable(uint32_t effects) -{ - // N.B.: This needs to be kept in sync with Core.Compiler.is_foldable(effects, true) - return ((effects & 0x7) == 0) && // is_consistent(effects) - (((effects >> 10) & 0x03) == 0) && // is_noub(effects) - (((effects >> 3) & 0x03) == 0) && // is_effect_free(effects) - ((effects >> 6) & 0x01); // is_terminates(effects) -} - static jl_llvm_functions_t jl_emit_oc_wrapper(orc::ThreadSafeModule &m, jl_codegen_params_t ¶ms, jl_method_instance_t *mi, jl_value_t *rettype) { jl_llvm_functions_t declarations; @@ -10082,67 +10070,8 @@ jl_llvm_functions_t jl_emit_codeinst( return jl_llvm_functions_t(); // failed } } - assert(jl_egal((jl_value_t*)jl_atomic_load_relaxed(&codeinst->debuginfo), (jl_value_t*)src->debuginfo) && "trying to generate code for a codeinst for an incompatible src"); + //assert(jl_egal((jl_value_t*)jl_atomic_load_relaxed(&codeinst->debuginfo), (jl_value_t*)src->debuginfo) && "trying to generate code for a codeinst for an incompatible src"); jl_llvm_functions_t decls = jl_emit_code(m, jl_get_ci_mi(codeinst), src, get_ci_abi(codeinst), params); - - const std::string &specf = decls.specFunctionObject; - const std::string &f = decls.functionObject; - if (params.cache && !f.empty()) { - // Prepare debug info to receive this function - // record that this function name came from this linfo, - // so we can build a reverse mapping for debug-info. - bool toplevel = !jl_is_method(jl_get_ci_mi(codeinst)->def.method); - if (!toplevel) { - //Safe b/c params holds context lock - const DataLayout &DL = m.getModuleUnlocked()->getDataLayout(); - // but don't remember toplevel thunks because - // they may not be rooted in the gc for the life of the program, - // and the runtime doesn't notify us when the code becomes unreachable :( - if (!specf.empty()) - jl_add_code_in_flight(specf, codeinst, DL); - if (!f.empty() && f != "jl_fptr_args" && f != "jl_fptr_sparam") - jl_add_code_in_flight(f, codeinst, DL); - } - - jl_value_t *inferred = jl_atomic_load_relaxed(&codeinst->inferred); - // don't change inferred state - if (inferred) { - jl_method_t *def = jl_get_ci_mi(codeinst)->def.method; - if (// keep code when keeping everything - !(JL_DELETE_NON_INLINEABLE) || - // aggressively keep code when debugging level >= 2 - // note that this uses the global jl_options.debug_level, not the local emission_ctx.debug_info_level - jl_options.debug_level > 1) { - // update the stored code - if (inferred != (jl_value_t*)src) { - // TODO: it is somewhat unclear what it means to be mutating this - if (jl_is_method(def)) { - src = (jl_code_info_t*)jl_compress_ir(def, src); - assert(jl_is_string(src)); - codeinst->relocatability = jl_string_data(src)[jl_string_len(src)-1]; - } - jl_atomic_store_release(&codeinst->inferred, (jl_value_t*)src); - jl_gc_wb(codeinst, src); - } - } - // delete non-inlineable code, since it won't be needed again - // because we already emitted LLVM code from it and the native - // Julia-level optimization will never need to see it - else if (jl_is_method(def) && // don't delete toplevel code - def->source != NULL && // don't delete code from optimized opaque closures that can't be reconstructed - inferred != jl_nothing && // and there is something to delete (test this before calling jl_ir_inlining_cost) - ((!effects_foldable(jl_atomic_load_relaxed(&codeinst->ipo_purity_bits)) && // don't delete code we may want for irinterp - (jl_ir_inlining_cost(inferred) == UINT16_MAX) && // don't delete inlineable code - !jl_generating_output()) || // don't delete code when generating a precompile file, trading memory in the short term for avoiding likely duplicating inference work for aotcompile - jl_atomic_load_relaxed(&codeinst->invoke) == jl_fptr_const_return_addr)) { // unless it is constant (although this shouldn't have had code in the first place) - // Never end up in a situation where the codeinst has no invoke, but also no source, so we never fall - // through the cracks of SOURCE_MODE_ABI. - jl_callptr_t expected = NULL; - jl_atomic_cmpswap_relaxed(&codeinst->invoke, &expected, jl_fptr_wait_for_compiled_addr); - jl_atomic_store_release(&codeinst->inferred, jl_nothing); - } - } - } JL_GC_POP(); return decls; } diff --git a/src/gf.c b/src/gf.c index 3a308ca6154fc..390ba72143f5d 100644 --- a/src/gf.c +++ b/src/gf.c @@ -343,8 +343,12 @@ jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_a // if inference doesn't occur (or can't finish), returns NULL instead jl_code_instance_t *jl_type_infer(jl_method_instance_t *mi, size_t world, uint8_t source_mode) { - if (jl_typeinf_func == NULL) - return jl_method_inferred_with_abi(mi, world); + if (jl_typeinf_func == NULL) { + if (source_mode == SOURCE_MODE_ABI) + return jl_method_inferred_with_abi(mi, world); + else + return NULL; + } jl_task_t *ct = jl_current_task; if (ct->reentrant_timing & 0b1000) { // We must avoid attempting to re-enter inference here @@ -366,6 +370,10 @@ jl_code_instance_t *jl_type_infer(jl_method_instance_t *mi, size_t world, uint8_ fargs[1] = (jl_value_t*)mi; fargs[2] = jl_box_ulong(world); fargs[3] = jl_box_uint8(source_mode); + int last_errno = errno; +#ifdef _OS_WINDOWS_ + DWORD last_error = GetLastError(); +#endif jl_timing_show_method_instance(mi, JL_TIMING_DEFAULT_BLOCK); #ifdef TRACE_INFERENCE @@ -374,10 +382,6 @@ jl_code_instance_t *jl_type_infer(jl_method_instance_t *mi, size_t world, uint8_ jl_static_show_func_sig(JL_STDERR, (jl_value_t*)mi->specTypes); jl_printf(JL_STDERR, "\n"); } -#endif - int last_errno = errno; -#ifdef _OS_WINDOWS_ - DWORD last_error = GetLastError(); #endif int last_pure = ct->ptls->in_pure_callback; ct->ptls->in_pure_callback = 0; @@ -2745,6 +2749,25 @@ void jl_read_codeinst_invoke(jl_code_instance_t *ci, uint8_t *specsigflags, jl_c jl_method_instance_t *jl_normalize_to_compilable_mi(jl_method_instance_t *mi JL_PROPAGATES_ROOT); +JL_DLLEXPORT void jl_add_codeinst_to_jit(jl_code_instance_t *codeinst, jl_code_info_t *src) +{ + assert(jl_is_code_info(src)); + jl_emit_codeinst_to_jit(codeinst, src); + jl_method_instance_t *mi = jl_get_ci_mi(codeinst); + if (jl_generating_output() && jl_is_method(mi->def.method) && jl_atomic_load_relaxed(&codeinst->inferred) == jl_nothing) { + jl_value_t *compressed = jl_compress_ir(mi->def.method, src); + // These should already be compatible (and should be an assert), but make sure of it anyways + if (jl_is_svec(src->edges)) { + jl_atomic_store_release(&codeinst->edges, (jl_svec_t*)src->edges); + jl_gc_wb(codeinst, src->edges); + } + jl_atomic_store_release(&codeinst->debuginfo, src->debuginfo); + jl_gc_wb(codeinst, src->debuginfo); + jl_atomic_store_release(&codeinst->inferred, compressed); + jl_gc_wb(codeinst, compressed); + } +} + jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t world) { // quick check if we already have a compiled result @@ -2815,8 +2838,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t jl_method_instance_t *unspecmi = jl_atomic_load_relaxed(&def->unspecialized); if (unspecmi) { jl_code_instance_t *unspec = jl_atomic_load_relaxed(&unspecmi->cache); - jl_callptr_t unspec_invoke = NULL; - if (unspec && (unspec_invoke = jl_atomic_load_acquire(&unspec->invoke))) { + if (unspec && jl_atomic_load_acquire(&unspec->invoke) != NULL) { uint8_t specsigflags; jl_callptr_t invoke; void *fptr; @@ -2886,7 +2908,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t } if (codeinst) { - if (jl_atomic_load_acquire(&codeinst->invoke) != NULL) { + if (jl_is_compiled_codeinst(codeinst)) { jl_typeinf_timing_end(start, is_recompile); // Already compiled - e.g. constabi, or compiled by a different thread while we were waiting. return codeinst; @@ -2972,12 +2994,32 @@ jl_value_t *jl_fptr_wait_for_compiled(jl_value_t *f, jl_value_t **args, uint32_t { jl_callptr_t invoke = jl_atomic_load_acquire(&m->invoke); if (invoke == &jl_fptr_wait_for_compiled) { + int64_t last_alloc = jl_options.malloc_log ? jl_gc_diff_total_bytes() : 0; + int last_errno = errno; +#ifdef _OS_WINDOWS_ + DWORD last_error = GetLastError(); +#endif jl_compile_codeinst(m); +#ifdef _OS_WINDOWS_ + SetLastError(last_error); +#endif + errno = last_errno; + if (jl_options.malloc_log) + jl_gc_sync_total_bytes(last_alloc); // discard allocation count from compilation invoke = jl_atomic_load_acquire(&m->invoke); } return invoke(f, args, nargs, m); } +// test whether codeinst->invoke is usable already without further compilation needed +JL_DLLEXPORT int jl_is_compiled_codeinst(jl_code_instance_t *codeinst) +{ + jl_callptr_t invoke = jl_atomic_load_relaxed(&codeinst->invoke); + if (invoke == NULL || invoke == &jl_fptr_wait_for_compiled) + return 0; + return 1; +} + JL_DLLEXPORT const jl_callptr_t jl_fptr_args_addr = &jl_fptr_args; JL_DLLEXPORT const jl_callptr_t jl_fptr_const_return_addr = &jl_fptr_const_return; diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 139a5631d63c0..e2bf75d346613 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -272,7 +272,7 @@ static void finish_params(Module *M, jl_codegen_params_t ¶ms) JL_NOTSAFEPOIN // the fiction that we don't know what loads from the global will return. Thus, we // need to emit a separate module for the globals before any functions are compiled, // to ensure that the globals are defined when they are compiled. - if (params.imaging_mode) { + if (jl_options.image_codegen) { if (!params.global_targets.empty()) { void **globalslots = new void*[params.global_targets.size()]; void **slot = globalslots; @@ -304,7 +304,8 @@ static void finish_params(Module *M, jl_codegen_params_t ¶ms) JL_NOTSAFEPOIN // look for something with an egal ABI that is already in the JIT static jl_code_instance_t *jl_method_compiled_egal(jl_code_instance_t *ci JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT { - jl_method_instance_t *mi = ci->def; + jl_value_t *def = ci->def; + jl_method_instance_t *mi = jl_get_ci_mi(ci); jl_value_t *owner = ci->owner; jl_value_t *rettype = ci->rettype; size_t min_world = jl_atomic_load_relaxed(&ci->min_world); @@ -316,6 +317,7 @@ static jl_code_instance_t *jl_method_compiled_egal(jl_code_instance_t *ci JL_PRO jl_atomic_load_relaxed(&codeinst->invoke) != NULL && jl_atomic_load_relaxed(&codeinst->min_world) <= min_world && jl_atomic_load_relaxed(&codeinst->max_world) >= max_world && + jl_egal(codeinst->def, def) && jl_egal(codeinst->owner, owner) && jl_egal(codeinst->rettype, rettype)) { return codeinst; @@ -503,15 +505,6 @@ static int jl_analyze_workqueue(jl_code_instance_t *callee, jl_codegen_params_t return params.workqueue.size(); } -// test whether codeinst->invoke is usable already without further compilation needed -static bool jl_is_compiled_codeinst(jl_code_instance_t *codeinst) JL_NOTSAFEPOINT -{ - auto invoke = jl_atomic_load_relaxed(&codeinst->invoke); - if (invoke == nullptr || invoke == jl_fptr_wait_for_compiled_addr) - return false; - return true; -} - // move codeinst (and deps) from incompletemodules to emitted modules // and populate compileready from complete_graph static void prepare_compile(jl_code_instance_t *codeinst) JL_NOTSAFEPOINT_LEAVE JL_NOTSAFEPOINT_ENTER @@ -732,10 +725,15 @@ static void jl_compile_codeinst_now(jl_code_instance_t *codeinst) } } -static void jl_emit_codeinst_to_jit( +void jl_add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL); + +extern "C" JL_DLLEXPORT_CODEGEN +void jl_emit_codeinst_to_jit_impl( jl_code_instance_t *codeinst, jl_code_info_t *src) { + if (jl_is_compiled_codeinst(codeinst)) + return; { // lock scope jl_unique_gcsafe_lock lock(engine_lock); if (invokenames.count(codeinst) || jl_is_compiled_codeinst(codeinst)) @@ -746,7 +744,7 @@ static void jl_emit_codeinst_to_jit( jl_codegen_params_t params(std::make_unique(), jl_ExecutionEngine->getDataLayout(), jl_ExecutionEngine->getTargetTriple()); // Locks the context params.getContext().setDiscardValueNames(true); params.cache = true; - params.imaging_mode = imaging_default(); + params.imaging_mode = 0; orc::ThreadSafeModule result_m = jl_create_ts_module(name_from_method_instance(jl_get_ci_mi(codeinst)), params.tsctx, params.DL, params.TargetTriple); params.temporary_roots = jl_alloc_array_1d(jl_array_any_type, 0); @@ -765,6 +763,24 @@ static void jl_emit_codeinst_to_jit( jl_unique_gcsafe_lock lock(engine_lock); if (invokenames.count(codeinst) || jl_is_compiled_codeinst(codeinst)) return; // destroy everything + const std::string &specf = decls.specFunctionObject; + const std::string &f = decls.functionObject; + assert(!f.empty()); + // Prepare debug info to receive this function + // record that this function name came from this linfo, + // so we can build a reverse mapping for debug-info. + bool toplevel = !jl_is_method(jl_get_ci_mi(codeinst)->def.method); + if (!toplevel) { + // don't remember toplevel thunks because + // they may not be rooted in the gc for the life of the program, + // and the runtime doesn't notify us when the code becomes unreachable :( + if (!specf.empty()) + jl_add_code_in_flight(specf, codeinst, params.DL); + if (f != "jl_fptr_args" && f != "jl_fptr_sparam") + jl_add_code_in_flight(f, codeinst, params.DL); + } + jl_callptr_t expected = NULL; + jl_atomic_cmpswap_relaxed(&codeinst->invoke, &expected, jl_fptr_wait_for_compiled_addr); invokenames[codeinst] = std::move(decls); complete_emit(codeinst); params.tsctx_lock = params.tsctx.getLock(); // re-acquire lock @@ -853,7 +869,7 @@ int jl_compile_extern_c_impl(LLVMOrcThreadSafeModuleRef llvmmod, void *p, void * jl_codegen_params_t params(into->getContext(), DL, TargetTriple); if (pparams == NULL) { params.cache = p == NULL; - params.imaging_mode = imaging_default(); + params.imaging_mode = 0; params.tsctx.getContext()->setDiscardValueNames(true); pparams = ¶ms; } @@ -1425,7 +1441,7 @@ namespace { #endif #endif uint32_t target_flags = 0; - auto target = jl_get_llvm_target(imaging_default(), target_flags); + auto target = jl_get_llvm_target(jl_generating_output(), target_flags); auto &TheCPU = target.first; SmallVector targetFeatures(target.second.begin(), target.second.end()); std::string errorstr; diff --git a/src/jitlayers.h b/src/jitlayers.h index 342cb516debd7..b41f2e38bc470 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -68,8 +68,6 @@ using namespace llvm; -extern "C" jl_cgparams_t jl_default_cgparams; - DEFINE_SIMPLE_CONVERSION_FUNCTIONS(orc::ThreadSafeContext, LLVMOrcThreadSafeContextRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(orc::ThreadSafeModule, LLVMOrcThreadSafeModuleRef) @@ -78,10 +76,6 @@ void jl_merge_module(orc::ThreadSafeModule &dest, orc::ThreadSafeModule src) JL_ GlobalVariable *jl_emit_RTLD_DEFAULT_var(Module *M) JL_NOTSAFEPOINT; DataLayout jl_create_datalayout(TargetMachine &TM) JL_NOTSAFEPOINT; -static inline bool imaging_default() JL_NOTSAFEPOINT { - return jl_options.image_codegen || (jl_generating_output() && (!jl_options.incremental || jl_options.use_pkgimages)); -} - struct OptimizationOptions { bool lower_intrinsics; bool dump_native; @@ -265,7 +259,7 @@ struct jl_codegen_params_t { tsctx_lock(tsctx.getLock()), DL(std::move(DL)), TargetTriple(std::move(triple)), - imaging_mode(imaging_default()) + imaging_mode(1) { // LLVM's RISC-V back-end currently does not support the Swift calling convention if (TargetTriple.isRISCV()) diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index 71a78b1c20fc7..cb48cf6f9962c 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -240,7 +240,6 @@ XX(jl_has_typevar_from_unionall) \ XX(jl_hrtime) \ XX(jl_idtable_rehash) \ - XX(jl_infer_thunk) \ XX(jl_init) \ XX(jl_init_options) \ XX(jl_init_restored_module) \ @@ -517,6 +516,7 @@ #define JL_CODEGEN_EXPORTED_FUNCS(YY) \ YY(jl_dump_function_ir) \ YY(jl_dump_method_asm) \ + YY(jl_emit_codeinst_to_jit) \ YY(jl_extern_c) \ YY(jl_get_llvmf_defn) \ YY(jl_get_llvm_function) \ @@ -542,6 +542,7 @@ YY(jl_dump_emitted_mi_name) \ YY(jl_dump_llvm_opt) \ YY(jl_dump_fptr_asm) \ + YY(jl_emit_native) \ YY(jl_get_function_id) \ YY(jl_type_to_llvm) \ YY(jl_getUnwindInfo) \ diff --git a/src/julia.h b/src/julia.h index 9b8d090fe37cb..5cafc9bfa5232 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1580,6 +1580,7 @@ static inline int jl_field_isconst(jl_datatype_t *st, int i) JL_NOTSAFEPOINT #define jl_is_addrspacecore(v) jl_typetagis(v,jl_addrspacecore_type) #define jl_is_abioverride(v) jl_typetagis(v,jl_abioverride_type) #define jl_genericmemory_isbitsunion(a) (((jl_datatype_t*)jl_typetagof(a))->layout->flags.arrayelem_isunion) +#define jl_is_array_any(v) jl_typetagis(v,jl_array_any_type) JL_DLLEXPORT int jl_subtype(jl_value_t *a, jl_value_t *b); diff --git a/src/julia_internal.h b/src/julia_internal.h index f0debd31e2fec..7e91e23b9087d 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -400,7 +400,7 @@ extern arraylist_t eytzinger_image_tree; extern arraylist_t eytzinger_idxs; extern JL_DLLEXPORT size_t jl_page_size; -extern jl_function_t *jl_typeinf_func JL_GLOBALLY_ROOTED; +extern JL_DLLEXPORT jl_function_t *jl_typeinf_func JL_GLOBALLY_ROOTED; extern JL_DLLEXPORT size_t jl_typeinf_world; extern _Atomic(jl_typemap_entry_t*) call_cache[N_CALL_CACHE] JL_GLOBALLY_ROOTED; @@ -667,7 +667,6 @@ typedef union { // Also defined in typeinfer.jl - See documentation there. #define SOURCE_MODE_NOT_REQUIRED 0x0 #define SOURCE_MODE_ABI 0x1 -#define SOURCE_MODE_FORCE_SOURCE 0x2 JL_DLLEXPORT jl_code_instance_t *jl_engine_reserve(jl_method_instance_t *m, jl_value_t *owner); JL_DLLEXPORT void jl_engine_fulfill(jl_code_instance_t *ci, jl_code_info_t *src); @@ -683,6 +682,7 @@ JL_DLLEXPORT jl_code_instance_t *jl_get_method_inferred( JL_DLLEXPORT jl_method_instance_t *jl_get_unspecialized(jl_method_t *def JL_PROPAGATES_ROOT); JL_DLLEXPORT void jl_read_codeinst_invoke(jl_code_instance_t *ci, uint8_t *specsigflags, jl_callptr_t *invoke, void **specptr, int waitcompile); JL_DLLEXPORT jl_method_instance_t *jl_method_match_to_mi(jl_method_match_t *match, size_t world, size_t min_valid, size_t max_valid, int mt_cache); +JL_DLLEXPORT void jl_add_codeinst_to_jit(jl_code_instance_t *codeinst, jl_code_info_t *src); JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst_uninit(jl_method_instance_t *mi, jl_value_t *owner); JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst( @@ -695,9 +695,11 @@ JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst( STATIC_INLINE jl_method_instance_t *jl_get_ci_mi(jl_code_instance_t *ci JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT { - if (jl_is_abioverride(ci->def)) - return ((jl_abi_override_t*)ci->def)->def; - return (jl_method_instance_t*)ci->def; + jl_value_t *def = ci->def; + if (jl_is_abioverride(def)) + return ((jl_abi_override_t*)def)->def; + assert(jl_is_method_instance(def)); + return (jl_method_instance_t*)def; } JL_DLLEXPORT const char *jl_debuginfo_file(jl_debuginfo_t *debuginfo) JL_NOTSAFEPOINT; @@ -705,6 +707,7 @@ JL_DLLEXPORT const char *jl_debuginfo_file1(jl_debuginfo_t *debuginfo) JL_NOTSAF JL_DLLEXPORT jl_module_t *jl_debuginfo_module1(jl_value_t *debuginfo_def) JL_NOTSAFEPOINT; JL_DLLEXPORT const char *jl_debuginfo_name(jl_value_t *func) JL_NOTSAFEPOINT; +JL_DLLEXPORT int jl_is_compiled_codeinst(jl_code_instance_t *codeinst) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_compile_method_instance(jl_method_instance_t *mi, jl_tupletype_t *types, size_t world); JL_DLLEXPORT void jl_compile_method_sig(jl_method_t *m, jl_value_t *types, jl_svec_t *sparams, size_t world); JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types); @@ -1944,6 +1947,7 @@ JL_DLLEXPORT uint32_t jl_crc32c(uint32_t crc, const char *buf, size_t len); JL_DLLIMPORT void jl_generate_fptr_for_unspecialized(jl_code_instance_t *unspec); JL_DLLIMPORT int jl_compile_codeinst(jl_code_instance_t *unspec); JL_DLLIMPORT int jl_compile_extern_c(LLVMOrcThreadSafeModuleRef llvmmod, void *params, void *sysimg, jl_value_t *declrt, jl_value_t *sigt); +JL_DLLIMPORT void jl_emit_codeinst_to_jit(jl_code_instance_t *codeinst, jl_code_info_t *src); typedef struct { LLVMOrcThreadSafeModuleRef TSM; @@ -1958,7 +1962,8 @@ JL_DLLIMPORT jl_value_t *jl_dump_function_ir(jl_llvmf_dump_t *dump, char strip_i JL_DLLIMPORT jl_value_t *jl_dump_function_asm(jl_llvmf_dump_t *dump, char emit_mc, const char* asm_variant, const char *debuginfo, char binary, char raw); typedef jl_value_t *(*jl_codeinstance_lookup_t)(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t min_world, size_t max_world); -JL_DLLIMPORT void *jl_create_native(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvmmod, const jl_cgparams_t *cgparams, int policy, int imaging_mode, int cache, size_t world, jl_codeinstance_lookup_t lookup); +JL_DLLIMPORT void *jl_create_native(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvmmod, int trim, int cache, size_t world); +JL_DLLIMPORT void *jl_emit_native(jl_array_t *codeinfos, LLVMOrcThreadSafeModuleRef llvmmod, const jl_cgparams_t *cgparams, int _external_linkage); 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); diff --git a/src/precompile_utils.c b/src/precompile_utils.c index f2777455c4ed1..8906b3eb586d3 100644 --- a/src/precompile_utils.c +++ b/src/precompile_utils.c @@ -203,8 +203,8 @@ static int precompile_enq_specialization_(jl_method_instance_t *mi, void *closur else if (jl_atomic_load_relaxed(&codeinst->invoke) != jl_fptr_const_return) { jl_value_t *inferred = jl_atomic_load_relaxed(&codeinst->inferred); if (inferred && - inferred != jl_nothing && - (jl_options.compile_enabled != JL_OPTIONS_COMPILE_ALL && jl_ir_inlining_cost(inferred) == UINT16_MAX)) { + (jl_options.compile_enabled == JL_OPTIONS_COMPILE_ALL || inferred == jl_nothing || + ((jl_is_string(inferred) || jl_is_code_info(inferred)) && jl_ir_inlining_cost(inferred) == UINT16_MAX))) { do_compile = 1; } else if (jl_atomic_load_relaxed(&codeinst->invoke) != NULL || jl_atomic_load_relaxed(&codeinst->precompile)) { @@ -275,9 +275,7 @@ static void *jl_precompile_(jl_array_t *m, int external_linkage) jl_array_ptr_1d_push(m2, item); } } - void *native_code = jl_create_native(m2, NULL, NULL, 0, 1, external_linkage, - jl_atomic_load_acquire(&jl_world_counter), - NULL); + void *native_code = jl_create_native(m2, NULL, 0, external_linkage, jl_atomic_load_acquire(&jl_world_counter)); JL_GC_POP(); return native_code; } @@ -372,8 +370,7 @@ static void *jl_precompile_trimmed(size_t world) jl_value_t *ccallable = NULL; JL_GC_PUSH2(&m, &ccallable); jl_method_instance_t *mi; - while (1) - { + while (1) { mi = (jl_method_instance_t*)arraylist_pop(jl_entrypoint_mis); if (mi == NULL) break; @@ -385,10 +382,7 @@ static void *jl_precompile_trimmed(size_t world) jl_array_ptr_1d_push(m, ccallable); } - jl_cgparams_t params = jl_default_cgparams; - params.trim = jl_options.trim; - void *native_code = jl_create_native(m, NULL, ¶ms, 0, /* imaging */ 1, 0, - world, NULL); + void *native_code = jl_create_native(m, NULL, jl_options.trim, 0, world); JL_GC_POP(); return native_code; } diff --git a/src/toplevel.c b/src/toplevel.c index 44b503d4e1463..11e1f9ad521a1 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -1054,7 +1054,7 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val size_t world = jl_atomic_load_acquire(&jl_world_counter); ct->world_age = world; if (!has_defs && jl_get_module_infer(m) != 0) { - (void)jl_type_infer(mfunc, world, SOURCE_MODE_NOT_REQUIRED); + (void)jl_type_infer(mfunc, world, SOURCE_MODE_ABI); } result = jl_invoke(/*func*/NULL, /*args*/NULL, /*nargs*/0, mfunc); ct->world_age = last_age; @@ -1138,20 +1138,6 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_in(jl_module_t *m, jl_value_t *ex) return v; } -JL_DLLEXPORT jl_value_t *jl_infer_thunk(jl_code_info_t *thk, jl_module_t *m) -{ - jl_method_instance_t *li = jl_method_instance_for_thunk(thk, m); - JL_GC_PUSH1(&li); - jl_resolve_globals_in_ir((jl_array_t*)thk->code, m, NULL, 0); - jl_task_t *ct = jl_current_task; - jl_code_instance_t *ci = jl_type_infer(li, ct->world_age, SOURCE_MODE_NOT_REQUIRED); - JL_GC_POP(); - if (ci) - return ci->rettype; - return (jl_value_t*)jl_any_type; -} - - //------------------------------------------------------------------------------ // Code loading: combined parse+eval for include() diff --git a/test/precompile.jl b/test/precompile.jl index d9bbf524609c9..2d4a4d310b4e0 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -750,10 +750,9 @@ precompile_test_harness("code caching") do dir struct X end struct X2 end @noinline function f(d) - @noinline - d[X()] = nothing + @noinline d[X()] = nothing end - @noinline fpush(dest) = push!(dest, X()) + @noinline fpush(dest) = @noinline push!(dest, X()) function callboth() f(Dict{X,Any}()) fpush(X[]) @@ -797,18 +796,6 @@ precompile_test_harness("code caching") do dir end end @test hasspec - # Test that compilation adds to method roots with appropriate provenance - m = which(setindex!, (Dict{M.X,Any}, Any, M.X)) - @test Memory{M.X} ∈ m.roots - # Check that roots added outside of incremental builds get attributed to a moduleid of 0 - Base.invokelatest() do - Dict{M.X2,Any}()[M.X2()] = nothing - end - @test Memory{M.X2} ∈ m.roots - groups = group_roots(m) - @test Memory{M.X} ∈ groups[Mid] # attributed to M - @test Memory{M.X2} ∈ groups[0] # activate module is not known - @test !isempty(groups[Bid]) # Check that internal methods and their roots are accounted appropriately minternal = which(M.getelsize, (Vector,)) mi = minternal.specializations::Core.MethodInstance @@ -832,12 +819,12 @@ precompile_test_harness("code caching") do dir """ module $Cache_module2 struct Y end - @noinline f(dest) = push!(dest, Y()) + @noinline f(dest) = @noinline push!(dest, Y()) callf() = f(Y[]) callf() using $(Cache_module) struct Z end - @noinline g(dest) = push!(dest, Z()) + @noinline g(dest) = @noinline push!(dest, Z()) callg() = g(Z[]) callg() end @@ -1146,22 +1133,22 @@ precompile_test_harness("invoke") do dir call_getlast(x) = getlast(x) - # force precompilation + # force precompilation, force call so that inlining heuristics don't affect the result begin Base.Experimental.@force_compile - callf(3) - callg(3) - callh(3) - callq(3) - callqi(3) - callfnc(3) - callgnc(3) - callhnc(3) - callqnc(3) - callqnci(3) - internal(3) - internalnc(3) - call_getlast([1,2,3]) + @noinline callf(3) + @noinline callg(3) + @noinline callh(3) + @noinline callq(3) + @noinline callqi(3) + @noinline callfnc(3) + @noinline callgnc(3) + @noinline callhnc(3) + @noinline callqnc(3) + @noinline callqnci(3) + @noinline internal(3) + @noinline internalnc(3) + @noinline call_getlast([1,2,3]) end # Now that we've precompiled, invalidate with a new method that overrides the `invoke` dispatch @@ -1194,9 +1181,15 @@ precompile_test_harness("invoke") do dir for func in (M.f, M.g, M.internal, M.fnc, M.gnc, M.internalnc) m = get_method_for_type(func, Real) mi = m.specializations::Core.MethodInstance - @test length(mi.backedges) == 2 + @test length(mi.backedges) == 2 || length(mi.backedges) == 4 # internalnc might have a constprop edge @test mi.backedges[1] === Tuple{typeof(func), Real} @test isa(mi.backedges[2], Core.CodeInstance) + if length(mi.backedges) == 4 + @test mi.backedges[3] === Tuple{typeof(func), Real} + @test isa(mi.backedges[4], Core.CodeInstance) + @test mi.backedges[2] !== mi.backedges[4] + @test mi.backedges[2].def === mi.backedges[4].def + end @test mi.cache.max_world == typemax(mi.cache.max_world) end for func in (M.q, M.qnc) @@ -1215,7 +1208,7 @@ precompile_test_harness("invoke") do dir m = only(methods(M.callq)) @test nvalid(m.specializations::Core.MethodInstance) == 0 m = only(methods(M.callqnc)) - @test nvalid(m.specializations::Core.MethodInstance) == 0 + @test nvalid(m.specializations::Core.MethodInstance) == 1 m = only(methods(M.callqi)) @test (m.specializations::Core.MethodInstance).specTypes == Tuple{typeof(M.callqi), Int} m = only(methods(M.callqnci)) From 987682318bc1bad53620904ecbc71d131fce31e5 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sat, 21 Dec 2024 03:09:51 +0000 Subject: [PATCH 129/342] delete unused code, so the jit no longer uses the inferred field at all --- src/codegen.cpp | 20 ++++--------- src/gf.c | 70 +++++++++++++++++++++++++++++++++----------- src/jitlayers.cpp | 68 +++++++++++------------------------------- src/julia_internal.h | 3 +- src/opaque_closure.c | 6 ++-- 5 files changed, 80 insertions(+), 87 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 04253b67d6b6d..540ee5ec74c4c 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -10050,29 +10050,19 @@ jl_llvm_functions_t jl_emit_codeinst( { JL_TIMING(CODEGEN, CODEGEN_Codeinst); jl_timing_show_method_instance(jl_get_ci_mi(codeinst), JL_TIMING_DEFAULT_BLOCK); - JL_GC_PUSH1(&src); if (!src) { - src = (jl_code_info_t*)jl_atomic_load_relaxed(&codeinst->inferred); jl_method_instance_t *mi = jl_get_ci_mi(codeinst); - jl_method_t *def = mi->def.method; - // Check if this is the generic method for opaque closure wrappers - - // if so, this must compile specptr such that it holds the specptr -> invoke wrapper + // Assert that this this is the generic method for opaque closure wrappers: + // this signals to instead compile specptr such that it holds the specptr -> invoke wrapper // to satisfy the dispatching implementation requirements of jl_f_opaque_closure_call - if (def == jl_opaque_closure_method) { - JL_GC_POP(); + if (mi->def.method == jl_opaque_closure_method) { return jl_emit_oc_wrapper(m, params, mi, codeinst->rettype); } - if (src && (jl_value_t*)src != jl_nothing && jl_is_method(def)) - src = jl_uncompress_ir(def, codeinst, (jl_value_t*)src); - if (!src || !jl_is_code_info(src)) { - JL_GC_POP(); - m = orc::ThreadSafeModule(); - return jl_llvm_functions_t(); // failed - } + m = orc::ThreadSafeModule(); + return jl_llvm_functions_t(); // user error } //assert(jl_egal((jl_value_t*)jl_atomic_load_relaxed(&codeinst->debuginfo), (jl_value_t*)src->debuginfo) && "trying to generate code for a codeinst for an incompatible src"); jl_llvm_functions_t decls = jl_emit_code(m, jl_get_ci_mi(codeinst), src, get_ci_abi(codeinst), params); - JL_GC_POP(); return decls; } diff --git a/src/gf.c b/src/gf.c index 390ba72143f5d..48cb8003072ca 100644 --- a/src/gf.c +++ b/src/gf.c @@ -337,6 +337,59 @@ jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_a return dt; } +// only relevant for bootstrapping. otherwise fairly broken. +static int emit_codeinst_and_edges(jl_code_instance_t *codeinst) +{ + jl_value_t *code = jl_atomic_load_relaxed(&codeinst->inferred); + if (code) { + if (jl_atomic_load_relaxed(&codeinst->invoke) != NULL) + return 1; + if (code != jl_nothing) { + JL_GC_PUSH1(&code); + jl_method_instance_t *mi = jl_get_ci_mi(codeinst); + jl_method_t *def = mi->def.method; + if (jl_is_string(code) && jl_is_method(def)) + code = (jl_value_t*)jl_uncompress_ir(def, codeinst, (jl_value_t*)code); + if (jl_is_code_info(code)) { + jl_emit_codeinst_to_jit(codeinst, (jl_code_info_t*)code); + if (0) { + // next emit all the invoke edges too (if this seems profitable) + jl_array_t *src = ((jl_code_info_t*)code)->code; + for (size_t i = 0; i < jl_array_dim0(src); i++) { + jl_value_t *stmt = jl_array_ptr_ref(src, i); + if (jl_is_expr(stmt) && ((jl_expr_t*)stmt)->head == jl_assign_sym) + stmt = jl_exprarg(stmt, 1); + if (jl_is_expr(stmt) && ((jl_expr_t*)stmt)->head == jl_invoke_sym) { + jl_value_t *invoke = jl_exprarg(stmt, 0); + if (jl_is_code_instance(invoke)) + emit_codeinst_and_edges((jl_code_instance_t*)invoke); + } + } + } + JL_GC_POP(); + return 1; + } + JL_GC_POP(); + } + } + return 0; +} + +// Opportunistic SOURCE_MODE_ABI cache lookup, only for bootstrapping. +static jl_code_instance_t *jl_method_inferred_with_abi(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t world) +{ + jl_code_instance_t *codeinst = jl_atomic_load_relaxed(&mi->cache); + for (; codeinst; codeinst = jl_atomic_load_relaxed(&codeinst->next)) { + if (codeinst->owner != jl_nothing) + continue; + if (jl_atomic_load_relaxed(&codeinst->min_world) <= world && world <= jl_atomic_load_relaxed(&codeinst->max_world)) { + if (emit_codeinst_and_edges(codeinst)) + return codeinst; + } + } + return NULL; +} + // 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 @@ -2571,23 +2624,6 @@ jl_code_instance_t *jl_method_compiled(jl_method_instance_t *mi, size_t world) return NULL; } -// Opportunistic SOURCE_MODE_ABI cache lookup. -jl_code_instance_t *jl_method_inferred_with_abi(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t world) -{ - jl_code_instance_t *codeinst = jl_atomic_load_relaxed(&mi->cache); - for (; codeinst; codeinst = jl_atomic_load_relaxed(&codeinst->next)) { - if (codeinst->owner != jl_nothing) - continue; - - if (jl_atomic_load_relaxed(&codeinst->min_world) <= world && world <= jl_atomic_load_relaxed(&codeinst->max_world)) { - jl_value_t *code = jl_atomic_load_relaxed(&codeinst->inferred); - if (code && (code != jl_nothing || (jl_atomic_load_relaxed(&codeinst->invoke) != NULL))) - return codeinst; - } - } - return NULL; -} - jl_mutex_t precomp_statement_out_lock; _Atomic(uint8_t) jl_force_trace_compile_timing_enabled = 0; diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index e2bf75d346613..21d865891e45c 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -795,47 +795,6 @@ void jl_emit_codeinst_to_jit_impl( emittedmodules[codeinst] = std::move(result_m); } -static void recursive_compile_graph( - jl_code_instance_t *codeinst, - jl_code_info_t *src) -{ - jl_emit_codeinst_to_jit(codeinst, src); - DenseSet Seen; - SmallVector workqueue; - workqueue.push_back(codeinst); - // if any edges were incomplete, try to complete them now - while (!workqueue.empty()) { - auto this_code = workqueue.pop_back_val(); - if (Seen.insert(this_code).second) { - jl_code_instance_t *compiled_ci = jl_method_compiled_egal(codeinst); - if (!compiled_ci) { - if (this_code != codeinst) { - JL_GC_PROMISE_ROOTED(this_code); // rooted transitively from following edges from original argument - jl_emit_codeinst_to_jit(this_code, nullptr); // contains safepoints - } - jl_unique_gcsafe_lock lock(engine_lock); - auto edges = complete_graph.find(this_code); - if (edges != complete_graph.end()) { - workqueue.append(edges->second); - } - } - } - } -} - -// this generates llvm code for the lambda info -// and adds the result to the jitlayers -// (and the shadow module), -// and generates code for it -static void _jl_compile_codeinst( - jl_code_instance_t *codeinst, - jl_code_info_t *src) -{ - recursive_compile_graph(codeinst, src); - jl_compile_codeinst_now(codeinst); - assert(jl_is_compiled_codeinst(codeinst)); -} - const char *jl_generate_ccallable(Module *llvmmod, void *sysimg_handle, jl_value_t *declrt, jl_value_t *sigt, jl_codegen_params_t ¶ms); @@ -859,7 +818,6 @@ int jl_compile_extern_c_impl(LLVMOrcThreadSafeModuleRef llvmmod, void *p, void * orc::ThreadSafeModule backing; bool success = true; const char *name = ""; - SmallVector dependencies; if (into == NULL) { ctx = pparams ? pparams->tsctx : jl_ExecutionEngine->makeContext(); backing = jl_create_ts_module("cextern", ctx, DL, TargetTriple); @@ -887,11 +845,16 @@ int jl_compile_extern_c_impl(LLVMOrcThreadSafeModuleRef llvmmod, void *p, void * } params.tsctx_lock = params.tsctx.getLock(); // re-acquire lock if (success && params.cache) { - for (auto &it : params.workqueue) { + size_t newest_world = jl_atomic_load_acquire(&jl_world_counter); + for (auto &it : params.workqueue) { // really just zero or one, and just the ABI not the rest of the metadata jl_code_instance_t *codeinst = it.first; JL_GC_PROMISE_ROOTED(codeinst); - dependencies.push_back(codeinst); - recursive_compile_graph(codeinst, nullptr); + jl_code_instance_t *newest_ci = jl_type_infer(jl_get_ci_mi(codeinst), newest_world, SOURCE_MODE_ABI); + if (newest_ci) { + if (jl_egal(codeinst->rettype, newest_ci->rettype)) + it.first = codeinst; + jl_compile_codeinst_now(newest_ci); + } } jl_analyze_workqueue(nullptr, params, true); assert(params.workqueue.empty()); @@ -904,8 +867,6 @@ int jl_compile_extern_c_impl(LLVMOrcThreadSafeModuleRef llvmmod, void *p, void * { // lock scope jl_unique_gcsafe_lock lock(extern_c_lock); if (!jl_ExecutionEngine->getGlobalValueAddress(name)) { - for (auto dep : dependencies) - jl_compile_codeinst_now(dep); { auto Lock = backing.getContext().getLock(); jl_ExecutionEngine->optimizeDLSyms(*backing.getModuleUnlocked()); // safepoint @@ -976,7 +937,7 @@ int jl_compile_codeinst_impl(jl_code_instance_t *ci) if (!jl_is_compiled_codeinst(ci)) { ++SpecFPtrCount; uint64_t start = jl_typeinf_timing_begin(); - _jl_compile_codeinst(ci, NULL); + jl_compile_codeinst_now(ci); jl_typeinf_timing_end(start, 0); newly_compiled = 1; } @@ -1007,8 +968,7 @@ void jl_generate_fptr_for_unspecialized_impl(jl_code_instance_t *unspec) } else { jl_method_instance_t *mi = jl_get_ci_mi(unspec); - jl_code_instance_t *uninferred = jl_cached_uninferred( - jl_atomic_load_relaxed(&mi->cache), 1); + jl_code_instance_t *uninferred = jl_cached_uninferred(jl_atomic_load_relaxed(&mi->cache), 1); assert(uninferred); src = (jl_code_info_t*)jl_atomic_load_relaxed(&uninferred->inferred); assert(src); @@ -1019,10 +979,16 @@ void jl_generate_fptr_for_unspecialized_impl(jl_code_instance_t *unspec) if (!jl_is_compiled_codeinst(unspec)) { assert(jl_is_code_info(src)); ++UnspecFPtrCount; + jl_svec_t *edges = (jl_svec_t*)src->edges; + if (jl_is_svec(edges)) { + jl_atomic_store_release(&unspec->edges, edges); // n.b. this assumes the field was always empty svec(), which is not entirely true + jl_gc_wb(unspec, edges); + } jl_debuginfo_t *debuginfo = src->debuginfo; jl_atomic_store_release(&unspec->debuginfo, debuginfo); // n.b. this assumes the field was previously NULL, which is not entirely true jl_gc_wb(unspec, debuginfo); - _jl_compile_codeinst(unspec, src); + jl_emit_codeinst_to_jit(unspec, src); + jl_compile_codeinst_now(unspec); } JL_UNLOCK(&jitlock); // Might GC } diff --git a/src/julia_internal.h b/src/julia_internal.h index 7e91e23b9087d..00103e9b00a48 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -673,7 +673,7 @@ JL_DLLEXPORT void jl_engine_fulfill(jl_code_instance_t *ci, jl_code_info_t *src) void jl_engine_sweep(jl_ptls_t *gc_all_tls_states) JL_NOTSAFEPOINT; int jl_engine_hasreserved(jl_method_instance_t *m, jl_value_t *owner) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_code_instance_t *jl_type_infer(jl_method_instance_t *li, size_t world, uint8_t source_mode); +JL_DLLEXPORT jl_code_instance_t *jl_type_infer(jl_method_instance_t *li JL_PROPAGATES_ROOT, size_t world, uint8_t source_mode); JL_DLLEXPORT jl_code_info_t *jl_gdbcodetyped1(jl_method_instance_t *mi, size_t world); JL_DLLEXPORT jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *meth JL_PROPAGATES_ROOT, size_t world); JL_DLLEXPORT jl_code_instance_t *jl_get_method_inferred( @@ -1210,7 +1210,6 @@ jl_method_instance_t *jl_get_specialized(jl_method_t *m, jl_value_t *types, jl_s JL_DLLEXPORT jl_value_t *jl_rettype_inferred(jl_value_t *owner, jl_method_instance_t *li JL_PROPAGATES_ROOT, size_t min_world, size_t max_world); JL_DLLEXPORT jl_value_t *jl_rettype_inferred_native(jl_method_instance_t *mi, size_t min_world, size_t max_world) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_code_instance_t *jl_method_compiled(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t world) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_code_instance_t *jl_method_inferred_with_abi(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t world) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_methtable_lookup(jl_methtable_t *mt JL_PROPAGATES_ROOT, jl_value_t *type, size_t world); JL_DLLEXPORT jl_method_instance_t *jl_specializations_get_linfo( jl_method_t *m JL_PROPAGATES_ROOT, jl_value_t *type, jl_svec_t *sparams); diff --git a/src/opaque_closure.c b/src/opaque_closure.c index 8a9dcac30a4f8..2d11d763be662 100644 --- a/src/opaque_closure.c +++ b/src/opaque_closure.c @@ -118,8 +118,10 @@ static jl_opaque_closure_t *new_opaque_closure(jl_tupletype_t *argt, jl_value_t // OC wrapper methods are not world dependent and have no edges or other info ci = jl_get_method_inferred(mi_generic, selected_rt, 1, ~(size_t)0, NULL, NULL); - if (!jl_atomic_load_acquire(&ci->invoke)) - jl_compile_codeinst(ci); // confusing this actually calls jl_emit_oc_wrapper and never actually compiles ci (which would be impossible since it cannot have source) + if (!jl_atomic_load_acquire(&ci->invoke)) { + jl_emit_codeinst_to_jit(ci, NULL); // confusing this actually calls jl_emit_oc_wrapper and never actually compiles ci (which would be impossible since it cannot have source) + jl_compile_codeinst(ci); + } specptr = jl_atomic_load_relaxed(&ci->specptr.fptr); } jl_opaque_closure_t *oc = (jl_opaque_closure_t*)jl_gc_alloc(ct->ptls, sizeof(jl_opaque_closure_t), oc_type); From 1e2758e753cf1b1f710492cdb558550b9982266f Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Fri, 3 Jan 2025 14:20:00 -0300 Subject: [PATCH 130/342] Make sure we don't promise alignments that are larger than the heap alignment to LLVM (#56938) Fixes https://github.com/JuliaLang/julia/issues/56937 --------- Co-authored-by: Oscar Smith --- Compiler/test/codegen.jl | 5 +++++ src/codegen.cpp | 2 ++ src/datatype.c | 2 ++ 3 files changed, 9 insertions(+) diff --git a/Compiler/test/codegen.jl b/Compiler/test/codegen.jl index 9ba268fe95be8..9b92f560c64fc 100644 --- a/Compiler/test/codegen.jl +++ b/Compiler/test/codegen.jl @@ -1036,3 +1036,8 @@ f56739(a) where {T} = a @test f56739(1) == 1 g56739(x) = @noinline f56739(x) @test g56739(1) == 1 + +struct Vec56937 x::NTuple{8, VecElement{Int}} end + +x56937 = Ref(Vec56937(ntuple(_->VecElement(1),8))) +@test x56937[].x[1] == VecElement{Int}(1) # shouldn't crash diff --git a/src/codegen.cpp b/src/codegen.cpp index 540ee5ec74c4c..1ca45a98b0620 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8927,6 +8927,8 @@ static jl_llvm_functions_t Type *RT = Arg->getParamStructRetType(); TypeSize sz = DL.getTypeAllocSize(RT); Align al = DL.getPrefTypeAlign(RT); + if (al > MAX_ALIGN) + al = Align(MAX_ALIGN); param.addAttribute(Attribute::NonNull); // The `dereferenceable` below does not imply `nonnull` for non addrspace(0) pointers. param.addDereferenceableAttr(sz); diff --git a/src/datatype.c b/src/datatype.c index c78b00fdd2245..fd25cca503676 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -769,6 +769,8 @@ void jl_compute_field_offsets(jl_datatype_t *st) if (al > alignm) alignm = al; } + if (alignm > MAX_ALIGN) + alignm = MAX_ALIGN; // We cannot guarantee alignments over 16 bytes because that's what our heap is aligned as if (LLT_ALIGN(sz, alignm) > sz) { haspadding = 1; sz = LLT_ALIGN(sz, alignm); From e757769cb5e14781012aba8c22763bcb79d19710 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Sat, 4 Jan 2025 09:18:29 -0500 Subject: [PATCH 131/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?NetworkOptions=20stdlib=20from=208eec5cb=20to=20c090626=20(#569?= =?UTF-8?q?49)?= 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: master Old commit: 8eec5cb New commit: c090626 Julia version: 1.12.0-DEV NetworkOptions version: 1.3.0(Does not match) Bump invoked by: @giordano Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaLang/NetworkOptions.jl/compare/8eec5cb0acec4591e6db3c017f7499426cd8e352...c090626d3feee6d6a5c476346d22d6147c9c6d2d ``` $ git log --oneline 8eec5cb..c090626 c090626 Enable OpenSSL certificates (#36) ``` --- .../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-8eec5cb0acec4591e6db3c017f7499426cd8e352.tar.gz/md5 delete mode 100644 deps/checksums/NetworkOptions-8eec5cb0acec4591e6db3c017f7499426cd8e352.tar.gz/sha512 create mode 100644 deps/checksums/NetworkOptions-c090626d3feee6d6a5c476346d22d6147c9c6d2d.tar.gz/md5 create mode 100644 deps/checksums/NetworkOptions-c090626d3feee6d6a5c476346d22d6147c9c6d2d.tar.gz/sha512 diff --git a/deps/checksums/NetworkOptions-8eec5cb0acec4591e6db3c017f7499426cd8e352.tar.gz/md5 b/deps/checksums/NetworkOptions-8eec5cb0acec4591e6db3c017f7499426cd8e352.tar.gz/md5 deleted file mode 100644 index 7f391aac1e64d..0000000000000 --- a/deps/checksums/NetworkOptions-8eec5cb0acec4591e6db3c017f7499426cd8e352.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -d2ccb9b91b0700bfb5ac7c01a03b4322 diff --git a/deps/checksums/NetworkOptions-8eec5cb0acec4591e6db3c017f7499426cd8e352.tar.gz/sha512 b/deps/checksums/NetworkOptions-8eec5cb0acec4591e6db3c017f7499426cd8e352.tar.gz/sha512 deleted file mode 100644 index b7db226225d75..0000000000000 --- a/deps/checksums/NetworkOptions-8eec5cb0acec4591e6db3c017f7499426cd8e352.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -051223ab45dce692c0bbea0755cc0057bb3322a40659c092007799932a10cc23e80ee6b88fa0d86f28af5e7fe5a455cc9fb8267c76af0cd2b425cf2718629e91 diff --git a/deps/checksums/NetworkOptions-c090626d3feee6d6a5c476346d22d6147c9c6d2d.tar.gz/md5 b/deps/checksums/NetworkOptions-c090626d3feee6d6a5c476346d22d6147c9c6d2d.tar.gz/md5 new file mode 100644 index 0000000000000..87111ac121562 --- /dev/null +++ b/deps/checksums/NetworkOptions-c090626d3feee6d6a5c476346d22d6147c9c6d2d.tar.gz/md5 @@ -0,0 +1 @@ +b851cab503506c37af6e4c861d81b8ce diff --git a/deps/checksums/NetworkOptions-c090626d3feee6d6a5c476346d22d6147c9c6d2d.tar.gz/sha512 b/deps/checksums/NetworkOptions-c090626d3feee6d6a5c476346d22d6147c9c6d2d.tar.gz/sha512 new file mode 100644 index 0000000000000..79f9e269ff599 --- /dev/null +++ b/deps/checksums/NetworkOptions-c090626d3feee6d6a5c476346d22d6147c9c6d2d.tar.gz/sha512 @@ -0,0 +1 @@ +4cba5c531e5e7205bb6d7f0179da8b29ca7c4dcf42f27de5f70be7674efc1fa92ea22e134e6584743e2905edbd754838d8a02f6ba7811c7a5b99ab9db3bde596 diff --git a/stdlib/NetworkOptions.version b/stdlib/NetworkOptions.version index 221b9b934f1a1..69b56e03ed89e 100644 --- a/stdlib/NetworkOptions.version +++ b/stdlib/NetworkOptions.version @@ -1,4 +1,4 @@ NETWORKOPTIONS_BRANCH = master -NETWORKOPTIONS_SHA1 = 8eec5cb0acec4591e6db3c017f7499426cd8e352 +NETWORKOPTIONS_SHA1 = c090626d3feee6d6a5c476346d22d6147c9c6d2d NETWORKOPTIONS_GIT_URL := https://github.com/JuliaLang/NetworkOptions.jl.git NETWORKOPTIONS_TAR_URL = https://api.github.com/repos/JuliaLang/NetworkOptions.jl/tarball/$1 From eee709e8330a508d11729308dc3605fee89db143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= <765740+giordano@users.noreply.github.com> Date: Sat, 4 Jan 2025 16:03:47 +0100 Subject: [PATCH 132/342] [build] Fix value of `CMAKE_C{,XX}_ARG` when `CC_ARG` doesn't have args (#56920) The problem was that `cut` by default prints the entire line if the delimiter doesn't appear, unless the option `-s` is used, which means that if `CC_ARG` contains only `gcc` then `CMAKE_CC_ARG` also contains `gcc` instead of being empty. Before the PR: ```console $ make -C deps/ print-CC_ARG print-CMAKE_CC_ARG print-CMAKE_COMMON USECCACHE=1 make: Entering directory '/home/mose/repo/julia/deps' CC_ARG=gcc CMAKE_CC_ARG=gcc CMAKE_COMMON=-DCMAKE_INSTALL_PREFIX:PATH=/home/mose/repo/julia/usr -DCMAKE_PREFIX_PATH=/home/mose/repo/julia/usr -DLIB_INSTALL_DIR=/home/mose/repo/julia/usr/lib -DCMAKE_INSTALL_LIBDIR=/home/mose/repo/julia/usr/lib -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER="$(which gcc)" -DCMAKE_C_COMPILER_ARG1="gcc " -DCMAKE_CXX_COMPILER="$(which g++)" -DCMAKE_CXX_COMPILER_ARG1="g++ " -DCMAKE_LINKER="$(which ld)" -DCMAKE_AR="$(which ar)" -DCMAKE_RANLIB="$(which ranlib)" make: Leaving directory '/home/mose/repo/julia/deps' ``` After the PR ```console $ make -C deps/ print-CC_ARG print-CMAKE_CC_ARG print-CMAKE_COMMON USECCACHE=1 make: Entering directory '/home/mose/repo/julia/deps' CC_ARG=gcc CMAKE_CC_ARG= CMAKE_COMMON=-DCMAKE_INSTALL_PREFIX:PATH=/home/mose/repo/julia/usr -DCMAKE_PREFIX_PATH=/home/mose/repo/julia/usr -DLIB_INSTALL_DIR=/home/mose/repo/julia/usr/lib -DCMAKE_INSTALL_LIBDIR=/home/mose/repo/julia/usr/lib -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER="$(which gcc)" -DCMAKE_CXX_COMPILER="$(which g++)" -DCMAKE_LINKER="$(which ld)" -DCMAKE_AR="$(which ar)" -DCMAKE_RANLIB="$(which ranlib)" make: Leaving directory '/home/mose/repo/julia/deps' ``` as intended. --- deps/tools/common.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deps/tools/common.mk b/deps/tools/common.mk index 3cefc253cec3d..01b57316f9d1a 100644 --- a/deps/tools/common.mk +++ b/deps/tools/common.mk @@ -36,8 +36,8 @@ CMAKE_COMMON += -DCMAKE_C_COMPILER_LAUNCHER=ccache CMAKE_COMMON += -DCMAKE_CXX_COMPILER_LAUNCHER=ccache CMAKE_CC := "$$(which $(shell echo $(CC_ARG) | cut -d' ' -f1))" CMAKE_CXX := "$$(which $(shell echo $(CXX_ARG) | cut -d' ' -f1))" -CMAKE_CC_ARG := $(shell echo $(CC_ARG) | cut -d' ' -f2-) -CMAKE_CXX_ARG := $(shell echo $(CXX_ARG) | cut -d' ' -f2-) +CMAKE_CC_ARG := $(shell echo $(CC_ARG) | cut -s -d' ' -f2-) +CMAKE_CXX_ARG := $(shell echo $(CXX_ARG) | cut -s -d' ' -f2-) else CMAKE_CC := "$$(which $(CC_BASE))" CMAKE_CXX := "$$(which $(CXX_BASE))" From 638dacc9c0c49e9662fa0009eadbd10ab7af1fed Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Sat, 4 Jan 2025 12:12:48 -0500 Subject: [PATCH 133/342] Switch from MbedTLS to OpenSSL (#56708) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on @fxcoudert's openssl branch and pull request at https://github.com/JuliaLang/julia/pull/53891. - diff re-applied to current Julia master (hence the new commit) - LibCURL, LibGit2, LibSSH2, OpenSSL updated to newest version - MbedTLS removed Fix #48799. --------- Co-authored-by: Zentrik Co-authored-by: Ian Butterworth Co-authored-by: Mosè Giordano <765740+giordano@users.noreply.github.com> Co-authored-by: Mosè Giordano --- Make.inc | 4 +- Makefile | 2 +- THIRDPARTY.md | 2 +- base/Makefile | 5 +- contrib/refresh_checksums.mk | 2 +- deps/Makefile | 12 +- deps/checksums/curl | 68 ++++++------ deps/checksums/libgit2 | 70 ++++++------ deps/checksums/libssh2 | 70 ++++++------ deps/checksums/mbedtls | 36 ------ deps/checksums/openssl | 36 ++++++ deps/curl.mk | 24 ++-- deps/curl.version | 5 +- deps/libgit2.mk | 6 +- deps/libgit2.version | 4 +- deps/libssh2.mk | 14 +-- deps/libssh2.version | 7 +- deps/mbedtls.mk | 97 ---------------- deps/openssl.mk | 102 +++++++++++++++++ deps/{mbedtls.version => openssl.version} | 5 +- deps/patches/curl-8.6.0-build.patch | 23 ---- deps/patches/curl-strdup.patch | 10 ++ deps/patches/libssh2-mbedtls-size_t.patch | 105 ------------------ deps/pcre.version | 1 + doc/Manifest.toml | 20 ++-- doc/src/devdocs/build/build.md | 4 +- julia.spdx.json | 16 +-- stdlib/LibCURL_jll/Project.toml | 4 +- stdlib/LibCURL_jll/src/LibCURL_jll.jl | 6 +- stdlib/LibGit2_jll/Project.toml | 4 +- stdlib/LibGit2_jll/src/LibGit2_jll.jl | 6 +- stdlib/LibGit2_jll/test/runtests.jl | 2 +- stdlib/LibSSH2_jll/Project.toml | 4 +- stdlib/LibSSH2_jll/src/LibSSH2_jll.jl | 6 +- stdlib/LibSSH2_jll/test/runtests.jl | 7 +- stdlib/Makefile | 2 +- stdlib/Manifest.toml | 22 ++-- stdlib/MbedTLS_jll/src/MbedTLS_jll.jl | 61 ---------- stdlib/MbedTLS_jll/test/runtests.jl | 10 -- .../{MbedTLS_jll => OpenSSL_jll}/Project.toml | 8 +- stdlib/OpenSSL_jll/src/OpenSSL_jll.jl | 58 ++++++++++ stdlib/OpenSSL_jll/test/runtests.jl | 10 ++ stdlib/Project.toml | 2 +- stdlib/stdlib.mk | 4 +- 44 files changed, 431 insertions(+), 535 deletions(-) delete mode 100644 deps/checksums/mbedtls create mode 100644 deps/checksums/openssl delete mode 100644 deps/mbedtls.mk create mode 100644 deps/openssl.mk rename deps/{mbedtls.version => openssl.version} (50%) delete mode 100644 deps/patches/curl-8.6.0-build.patch create mode 100644 deps/patches/curl-strdup.patch delete mode 100644 deps/patches/libssh2-mbedtls-size_t.patch delete mode 100644 stdlib/MbedTLS_jll/src/MbedTLS_jll.jl delete mode 100644 stdlib/MbedTLS_jll/test/runtests.jl rename stdlib/{MbedTLS_jll => OpenSSL_jll}/Project.toml (66%) create mode 100644 stdlib/OpenSSL_jll/src/OpenSSL_jll.jl create mode 100644 stdlib/OpenSSL_jll/test/runtests.jl diff --git a/Make.inc b/Make.inc index a60a95d21c3db..2f2ffcad754c4 100644 --- a/Make.inc +++ b/Make.inc @@ -51,7 +51,7 @@ USE_SYSTEM_MPFR:=0 USE_SYSTEM_LIBSUITESPARSE:=0 USE_SYSTEM_LIBUV:=0 USE_SYSTEM_UTF8PROC:=0 -USE_SYSTEM_MBEDTLS:=0 +USE_SYSTEM_OPENSSL:=0 USE_SYSTEM_LIBSSH2:=0 USE_SYSTEM_NGHTTP2:=0 USE_SYSTEM_CURL:=0 @@ -1355,7 +1355,7 @@ CSL_NEXT_GLIBCXX_VERSION=GLIBCXX_3\.4\.33|GLIBCXX_3\.5\.|GLIBCXX_4\. # Note: we explicitly _do not_ define `CSL` here, since it requires some more # advanced techniques to decide whether it should be installed from a BB source # or not. See `deps/csl.mk` for more detail. -BB_PROJECTS := BLASTRAMPOLINE OPENBLAS LLVM LIBSUITESPARSE OPENLIBM GMP MBEDTLS LIBSSH2 NGHTTP2 MPFR CURL LIBGIT2 PCRE LIBUV LIBUNWIND DSFMT OBJCONV ZLIB P7ZIP LLD LIBTRACYCLIENT BOLT +BB_PROJECTS := BLASTRAMPOLINE OPENBLAS LLVM LIBSUITESPARSE OPENLIBM GMP OPENSSL LIBSSH2 NGHTTP2 MPFR CURL LIBGIT2 PCRE LIBUV LIBUNWIND DSFMT OBJCONV ZLIB P7ZIP LLD LIBTRACYCLIENT BOLT define SET_BB_DEFAULT # First, check to see if BB is disabled on a global setting ifeq ($$(USE_BINARYBUILDER),0) diff --git a/Makefile b/Makefile index f0b1dfaa708e4..20d131ee8524c 100644 --- a/Makefile +++ b/Makefile @@ -228,7 +228,7 @@ JL_PRIVATE_LIBS-$(USE_SYSTEM_GMP) += libgmp libgmpxx JL_PRIVATE_LIBS-$(USE_SYSTEM_MPFR) += libmpfr JL_PRIVATE_LIBS-$(USE_SYSTEM_LIBSSH2) += libssh2 JL_PRIVATE_LIBS-$(USE_SYSTEM_NGHTTP2) += libnghttp2 -JL_PRIVATE_LIBS-$(USE_SYSTEM_MBEDTLS) += libmbedtls libmbedcrypto libmbedx509 +JL_PRIVATE_LIBS-$(USE_SYSTEM_OPENSSL) += libcrypto libssl JL_PRIVATE_LIBS-$(USE_SYSTEM_CURL) += libcurl JL_PRIVATE_LIBS-$(USE_SYSTEM_LIBGIT2) += libgit2 JL_PRIVATE_LIBS-$(USE_SYSTEM_LIBUV) += libuv diff --git a/THIRDPARTY.md b/THIRDPARTY.md index 3a74afec4a283..f3f59ca4ff3f7 100644 --- a/THIRDPARTY.md +++ b/THIRDPARTY.md @@ -36,7 +36,7 @@ Julia's `stdlib` uses the following external libraries, which have their own lic - [LIBGIT2](https://github.com/libgit2/libgit2/blob/development/COPYING) [GPL2+ with unlimited linking exception] - [CURL](https://curl.haxx.se/docs/copyright.html) [MIT/X derivative] - [LIBSSH2](https://github.com/libssh2/libssh2/blob/master/COPYING) [BSD-3] -- [MBEDTLS](https://github.com/ARMmbed/mbedtls/blob/development/LICENSE) [Apache 2.0] +- [OPENSSL](https://www.openssl.org/source/license.html) [Apache 2.0] - [MPFR](https://www.mpfr.org/mpfr-current/mpfr.html#Copying) [LGPL3+] - [OPENBLAS](https://raw.github.com/xianyi/OpenBLAS/master/LICENSE) [BSD-3] - [LAPACK](https://netlib.org/lapack/LICENSE.txt) [BSD-3] diff --git a/base/Makefile b/base/Makefile index febee53a9ddfc..09f79e5b98611 100644 --- a/base/Makefile +++ b/base/Makefile @@ -264,9 +264,8 @@ $(eval $(call symlink_system_library,LAPACK,$(LIBLAPACKNAME))) endif $(eval $(call symlink_system_library,GMP,libgmp)) $(eval $(call symlink_system_library,MPFR,libmpfr)) -$(eval $(call symlink_system_library,MBEDTLS,libmbedtls)) -$(eval $(call symlink_system_library,MBEDTLS,libmbedcrypto)) -$(eval $(call symlink_system_library,MBEDTLS,libmbedx509)) +$(eval $(call symlink_system_library,OPENSSL,libcrypto)) +$(eval $(call symlink_system_library,OPENSSL,libssl)) $(eval $(call symlink_system_library,LIBSSH2,libssh2)) $(eval $(call symlink_system_library,NGHTTP2,libnghttp2)) $(eval $(call symlink_system_library,CURL,libcurl)) diff --git a/contrib/refresh_checksums.mk b/contrib/refresh_checksums.mk index e7bf2fd7c2efc..21ef72c26a03d 100644 --- a/contrib/refresh_checksums.mk +++ b/contrib/refresh_checksums.mk @@ -24,7 +24,7 @@ CLANG_TRIPLETS=$(filter %-darwin %-freebsd,$(TRIPLETS)) NON_CLANG_TRIPLETS=$(filter-out %-darwin %-freebsd,$(TRIPLETS)) # These are the projects currently using BinaryBuilder; both GCC-expanded and non-GCC-expanded: -BB_PROJECTS=mbedtls libssh2 nghttp2 mpfr curl libgit2 pcre libuv unwind llvmunwind dsfmt objconv p7zip zlib libsuitesparse openlibm blastrampoline libtracyclient +BB_PROJECTS=openssl libssh2 nghttp2 mpfr curl libgit2 pcre libuv unwind llvmunwind dsfmt objconv p7zip zlib libsuitesparse openlibm blastrampoline libtracyclient BB_GCC_EXPANDED_PROJECTS=openblas csl BB_CXX_EXPANDED_PROJECTS=gmp llvm clang llvm-tools lld # These are non-BB source-only deps diff --git a/deps/Makefile b/deps/Makefile index b87a3e1e58609..d4ef52646cfdc 100644 --- a/deps/Makefile +++ b/deps/Makefile @@ -22,9 +22,9 @@ BUILDDIR := $(BUILDDIR)$(MAYBE_HOST) # additionally all targets should be listed in the getall target for easier off-line compilation # if you are adding a new target, it can help to copy an similar, existing target # -# autoconf configure-driven scripts: pcre unwind gmp mpfr patchelf libuv curl +# autoconf configure-driven scripts: pcre unwind gmp mpfr patchelf libuv curl openssl # custom Makefile rules: openlibm dsfmt libsuitesparse lapack blastrampoline openblas utf8proc objconv libwhich -# CMake libs: llvm llvmunwind libgit2 libssh2 mbedtls libtracyclient +# CMake libs: llvm llvmunwind libgit2 libssh2 libtracyclient # # downloadable via git: llvm-svn, libuv, libopenlibm, utf8proc, libgit2, libssh2, libtracyclient # @@ -119,8 +119,8 @@ ifeq ($(USE_SYSTEM_GMP), 0) DEP_LIBS += gmp endif -ifeq ($(USE_SYSTEM_MBEDTLS), 0) -DEP_LIBS += mbedtls +ifeq ($(USE_SYSTEM_OPENSSL), 0) +DEP_LIBS += openssl endif ifeq ($(USE_SYSTEM_LIBSSH2), 0) @@ -200,7 +200,7 @@ DEP_LIBS_STAGED := $(DEP_LIBS) # list all targets DEP_LIBS_STAGED_ALL := llvm llvm-tools clang llvmunwind unwind libuv pcre \ openlibm dsfmt blastrampoline openblas lapack gmp mpfr patchelf utf8proc \ - objconv mbedtls libssh2 nghttp2 curl libgit2 libwhich zlib p7zip csl \ + objconv openssl libssh2 nghttp2 curl libgit2 libwhich zlib p7zip csl \ sanitizers libsuitesparse lld libtracyclient ittapi nvtx JuliaSyntax \ terminfo DEP_LIBS_ALL := $(DEP_LIBS_STAGED_ALL) @@ -256,7 +256,7 @@ include $(SRCDIR)/unwind.mk include $(SRCDIR)/gmp.mk include $(SRCDIR)/mpfr.mk include $(SRCDIR)/patchelf.mk -include $(SRCDIR)/mbedtls.mk +include $(SRCDIR)/openssl.mk include $(SRCDIR)/libssh2.mk include $(SRCDIR)/nghttp2.mk include $(SRCDIR)/curl.mk diff --git a/deps/checksums/curl b/deps/checksums/curl index e6f7989db33d7..f96fe5f1a15e3 100644 --- a/deps/checksums/curl +++ b/deps/checksums/curl @@ -1,36 +1,36 @@ LibCURL-a65b64f6eabc932f63c2c0a4a5fb5d75f3e688d0.tar.gz/md5/e8c53aa3fb963c80921787d5d565eb2c LibCURL-a65b64f6eabc932f63c2c0a4a5fb5d75f3e688d0.tar.gz/sha512/8e442ea834299df9c02acb87226c121395ad8e550025ac5ee1103df09c6ff43817e9e48dd1bcbc92c80331ef3ddff531962430269115179acbec2bab2de5b011 -LibCURL.v8.6.0+0.aarch64-apple-darwin.tar.gz/md5/83854e8cdd078ec1fc5f92da2816e379 -LibCURL.v8.6.0+0.aarch64-apple-darwin.tar.gz/sha512/f3b3cc5804d9a7986ed9ea7c3186caa8dba0f4d6bbcb9b5d2070b4e6412234f2ed7908446dbe217323510c6d3b042540e18ec7839093c2c3c66f3195937a6a3b -LibCURL.v8.6.0+0.aarch64-linux-gnu.tar.gz/md5/880014fface52bddaa1a0240e0668dde -LibCURL.v8.6.0+0.aarch64-linux-gnu.tar.gz/sha512/a29b923e14425ad729484648ce15577e717a97acf6138e0ec3d35a8000aeef17f27ce01d1fdc1642c6eda72d8d8b46642d79844ef9a50f30a0148e29452565c1 -LibCURL.v8.6.0+0.aarch64-linux-musl.tar.gz/md5/b84fcb98f1305803d941f7a5accbfdb1 -LibCURL.v8.6.0+0.aarch64-linux-musl.tar.gz/sha512/0880dc91109aedd9b108f2e28a25bf7091ac976a6f94e65000f647802c57a01e8111d421b91a91244c3cfb56990155af2c47b3499997be2af8ab93d344b8331d -LibCURL.v8.6.0+0.armv6l-linux-gnueabihf.tar.gz/md5/24249f42db0bc99c2dde4cf61d61f11f -LibCURL.v8.6.0+0.armv6l-linux-gnueabihf.tar.gz/sha512/350443c86f7b6733fb6a28f8a2fe7a6c0e91462b9e4078fed3475059ec7e12fef5014e22d0d0babe44f172ace7258292de577a0ab90f90c65d825d74940c9c47 -LibCURL.v8.6.0+0.armv6l-linux-musleabihf.tar.gz/md5/375c01cef98204c4f63ac218b08c4c7b -LibCURL.v8.6.0+0.armv6l-linux-musleabihf.tar.gz/sha512/ed0981d458c6ddc9f380b90f1ec25cbaa6be910f0dab5d5485e4d1e9a33f8a918d210722a5e6685b4d3b917e0800194856f826164ee2e90b8a886ada7498a52b -LibCURL.v8.6.0+0.armv7l-linux-gnueabihf.tar.gz/md5/4c81aa99065cf797d6e09ce172dd2fa7 -LibCURL.v8.6.0+0.armv7l-linux-gnueabihf.tar.gz/sha512/08bbb1bc80411a5fd65699a0d721fc70a9bba1005194f2937accc2e98f7f803bac4a704c88aa1fc1d72e54e7c327a113963f8a4c52ebb1e5921778d1dd549143 -LibCURL.v8.6.0+0.armv7l-linux-musleabihf.tar.gz/md5/6865b2f2d93754b5206d618048c32b57 -LibCURL.v8.6.0+0.armv7l-linux-musleabihf.tar.gz/sha512/c1a5891f4c487d5f7cf91db7cd2d85394d9686cda01c89cddaf7afba09782aa9f00713592d72ed8a0dd20439884dd75c1e001a9ecb16dd8ce5f08f79c194c7c8 -LibCURL.v8.6.0+0.i686-linux-gnu.tar.gz/md5/3f35cc6a2dc7e9dba5e3b4aeaf130160 -LibCURL.v8.6.0+0.i686-linux-gnu.tar.gz/sha512/b34c5ba2fee272e6ca848c42335ffa0c4d0c06337608504a3a2cfeb111e228da3f82d91c0c4387c76fc347babbf50b368992b5b8d5fda1a60ed5c0ce5d9242db -LibCURL.v8.6.0+0.i686-linux-musl.tar.gz/md5/0072b83eaf91d9da4a8d25ef65fd8ca8 -LibCURL.v8.6.0+0.i686-linux-musl.tar.gz/sha512/029552e3dac29857726988352a01a3b57859bfe5e327e7b759bd9968ed5af5498fd27ab490810d2d3ef05b1003c1a950fd092d1dbce7732a911f7cb6e5714303 -LibCURL.v8.6.0+0.i686-w64-mingw32.tar.gz/md5/d58ef948bc9a04a8c934a88b7ab5599d -LibCURL.v8.6.0+0.i686-w64-mingw32.tar.gz/sha512/1e1742ea39f2fe1f13b0aff5907f96401276e3fc469a8f09f2bc31fffc72367a92856973db66eb9b05d20fd708764ad9429e385913f6236ce8067ec4e11dbb33 -LibCURL.v8.6.0+0.powerpc64le-linux-gnu.tar.gz/md5/60ec16b6dfd3e30eb0655cf177b026c7 -LibCURL.v8.6.0+0.powerpc64le-linux-gnu.tar.gz/sha512/f591897972c8b01edf64701885f636fc1d5c04cce8fc63577d06108e14e5480bad74306d6ee31515911bd8ba3db10d1f2c733a6149aceae32aa4b77e263087c3 -LibCURL.v8.6.0+0.x86_64-apple-darwin.tar.gz/md5/c6bc0d9cd0a9f9c35ed2aac058ae332f -LibCURL.v8.6.0+0.x86_64-apple-darwin.tar.gz/sha512/038f55bfb06dce877540ea7d50f5a0b8fdc070539c505774139a7c23df276a5fc75b5cecabecbc2826417e091028382d79298a51ed73c3d776249b4ff35f9f26 -LibCURL.v8.6.0+0.x86_64-linux-gnu.tar.gz/md5/18bf9d909dd5eebc0554d23bf4a4ee0f -LibCURL.v8.6.0+0.x86_64-linux-gnu.tar.gz/sha512/35e60faa1ee072003fdd5cd510295bc310aa99375aee6ef94eee3ee2d5e0b7844145866a74927c588c14131939c1d9865d6f5128ac4f6b93606a68042a94f39f -LibCURL.v8.6.0+0.x86_64-linux-musl.tar.gz/md5/213190e1d79c9c291ff460e1648a61d3 -LibCURL.v8.6.0+0.x86_64-linux-musl.tar.gz/sha512/4ea063982520400c02dcdf44ed3f018dec19607ad20762231316eb745cdb1cd054b18677fee1b5c5fb0bd55eb845121a2113704c5301be1d76edfc8a4a09d93f -LibCURL.v8.6.0+0.x86_64-unknown-freebsd.tar.gz/md5/30dda5aaeb7977eb3563c603af08cd6c -LibCURL.v8.6.0+0.x86_64-unknown-freebsd.tar.gz/sha512/edf603a6c013d3f6e01fc4fd6f12caf93ff99df9baf14bc73b610638a5b5ff90ec3118b112d9a39221294f5f419f3bf12232c16eaf91b07a68d92342a5c56912 -LibCURL.v8.6.0+0.x86_64-w64-mingw32.tar.gz/md5/9a2c980db329393f5274d42f87c2aec6 -LibCURL.v8.6.0+0.x86_64-w64-mingw32.tar.gz/sha512/6b926a87a3470796eb111e448c459a8ff1267533513f14d58f6e08cbebfb3e838c114827fcf39298bcefe8d76b8578bb4d3903c848bfafb0590022e6a49b2a00 -curl-8.6.0.tar.bz2/md5/4418e0d94f29d352afafdab445e37a3d -curl-8.6.0.tar.bz2/sha512/726fe7e21f8a2a925ab4ab6fe4e4ad099105f00656bfdc702beec12e1549ba2cb63d908d1d19f43b90feeb1d950ae5a6ac9a72a27447f5acf1907df396d1823c +LibCURL.v8.9.1+0.aarch64-apple-darwin.tar.gz/md5/8a1929a2dc1a6682ff9ff7f66cda25f4 +LibCURL.v8.9.1+0.aarch64-apple-darwin.tar.gz/sha512/e491542103f6e1a34caf96cfae7f31ba12588c50517ca2c974be907c664cd873b554009e538fd7db7d31ebe46d68330da3fcf14ffe9fcbbda73b6d1919ea966d +LibCURL.v8.9.1+0.aarch64-linux-gnu.tar.gz/md5/eb5f8fdb31189047527af3b98c6959b0 +LibCURL.v8.9.1+0.aarch64-linux-gnu.tar.gz/sha512/6fd5e489f63edec29efd20165b0888e86d0b53a19d352bebbdb0afc00a1f6478eec524143797307ab7a799cf924d2c76bd5ece9d9fd8fdc9346ba3c739a1fe83 +LibCURL.v8.9.1+0.aarch64-linux-musl.tar.gz/md5/6202ec4890ae02cf2a7999fe5e24d77c +LibCURL.v8.9.1+0.aarch64-linux-musl.tar.gz/sha512/caf00ed30075d000efc638586520dac2e22f8ba04924d42dbe27bc1bd715aa7b2dbede062de296fc080a33d0aead6099a870f38d017a69693097413056629b1b +LibCURL.v8.9.1+0.armv6l-linux-gnueabihf.tar.gz/md5/5bd474f4e09b4fe7658b2497861a580e +LibCURL.v8.9.1+0.armv6l-linux-gnueabihf.tar.gz/sha512/ff6b58cfff9a7433d9191766e3fe652f0b5b10fbc6da8fb03ca04ed44a46a36158fb7d8096932617011389fb5505844d5c4ef2c29bcf1c8da811287def4e91f9 +LibCURL.v8.9.1+0.armv6l-linux-musleabihf.tar.gz/md5/8f071c5389ba1df7d4d22683f068b6de +LibCURL.v8.9.1+0.armv6l-linux-musleabihf.tar.gz/sha512/b8be3a8df717d0921ec225ce87dd9cd4fc9e13fd1f39c4906d02f30dcae24971f1798b017f3af346c603030cfa80869c117cdb5dff8e7762ee2e72c4027ef7a1 +LibCURL.v8.9.1+0.armv7l-linux-gnueabihf.tar.gz/md5/120e51d99907522150d79c44812decfa +LibCURL.v8.9.1+0.armv7l-linux-gnueabihf.tar.gz/sha512/b512a75cb3185904661375760250132c58678f43002a9ba0608de60dcca6afc1e2eef567a9f42f2d3dfa0be1ff01cb15f68980adebada220728521b13367b77d +LibCURL.v8.9.1+0.armv7l-linux-musleabihf.tar.gz/md5/e8a59894ccb325fb424a3e5861c854f7 +LibCURL.v8.9.1+0.armv7l-linux-musleabihf.tar.gz/sha512/3bb4afef9b7be04f17a4e2e20e020bcfbf5fb4a36bc699a90337d76a108f75600fff49c877652956431946a948f42054497621593f1c6c593a537fe08ceda1c2 +LibCURL.v8.9.1+0.i686-linux-gnu.tar.gz/md5/1034cd95f6369cd994979c8653786639 +LibCURL.v8.9.1+0.i686-linux-gnu.tar.gz/sha512/5f7f755d17770dc8b995f2bbc817fda96db23da751439e5929526482b8f854f4ed73c6e930df0dd1657756f8951edd4f3c41be80f3b812a793678b6ededd855e +LibCURL.v8.9.1+0.i686-linux-musl.tar.gz/md5/ad4a4cf21d15b48ce27275af67079075 +LibCURL.v8.9.1+0.i686-linux-musl.tar.gz/sha512/9e5c6d0d91d966154e3ecd8cd71c9b31841debc036b847dec684dcf3189ca617cd0bca4b73cf9440e55133e36ebafb02730c598c133dc33a9e164ba43c689506 +LibCURL.v8.9.1+0.i686-w64-mingw32.tar.gz/md5/300a71d7ba8c858f9ed85d761dfeef32 +LibCURL.v8.9.1+0.i686-w64-mingw32.tar.gz/sha512/a916f60a7c8ed41a56686d1145be73dc0162349ce1d098dbd12441fcc97a3f0bd4c5750d3e58e4cfe7e9ba7e0d3817bf592bd99a946cd6b45b296636c3220766 +LibCURL.v8.9.1+0.powerpc64le-linux-gnu.tar.gz/md5/0657e472b888b089c448695d200346d0 +LibCURL.v8.9.1+0.powerpc64le-linux-gnu.tar.gz/sha512/a81f25260c4204a069a87463d9ef58169d9286125daaf23b4e2295fc8108ef536049fd07248ca3f1caa2aac3eb0b376d2c64281d0302dfea6f0a782dfb3988fd +LibCURL.v8.9.1+0.x86_64-apple-darwin.tar.gz/md5/3638b3365e97dd516d1eaa6f03892fe6 +LibCURL.v8.9.1+0.x86_64-apple-darwin.tar.gz/sha512/4e6c76fde045134c869dbaab52b28dc809541209077aa54d2e870b9aa29f3d43a8040f3194e06e519642348fc4de6aa49fcb04880a4707bae4e55206ac70f01b +LibCURL.v8.9.1+0.x86_64-linux-gnu.tar.gz/md5/e48dd6fe9078600bf6db0fdd6f986b76 +LibCURL.v8.9.1+0.x86_64-linux-gnu.tar.gz/sha512/e6c33bdac80c9463d6d067f77cf7f2f595258e5f292fd133b5f5782e678004bed925c8bcbba1c708f2f535a0db7a0527fce9acef5250469a958ee11dff533c8f +LibCURL.v8.9.1+0.x86_64-linux-musl.tar.gz/md5/2d219b4c0ba83dfce64b93c1e4d6ef24 +LibCURL.v8.9.1+0.x86_64-linux-musl.tar.gz/sha512/5fb8bb08d357ea3b7c9e417838bf37198ae673185c4f4564ecd1a06ce0e72c4c804909e8c6ffeafefb3460ad151308f662b3128ab5d4149f035de0fa9890506b +LibCURL.v8.9.1+0.x86_64-unknown-freebsd.tar.gz/md5/66e715f6934f360398e527f534f6f5c5 +LibCURL.v8.9.1+0.x86_64-unknown-freebsd.tar.gz/sha512/64334fb156c15b7aa56e4ef81b9d81f93be6ee4c7a61d921bb09cb9951eeb3309197ac89150bde0187e7cecd6e53626e91b7bba14f0daaa0ba472563541c9ff1 +LibCURL.v8.9.1+0.x86_64-w64-mingw32.tar.gz/md5/672ffcacf3e1bc72d7cf244af0cbc5a2 +LibCURL.v8.9.1+0.x86_64-w64-mingw32.tar.gz/sha512/ea265d172a242026cbf7e6b991904aa403a7f491a1c55f91b444776782ad0ca2fdf4882735d1ed04e90df8b38a754f4d0181ad8c17f5fbd75b40a6b908ebbd36 +curl-8.9.1.tar.bz2/md5/8feb255a16590f2465926d7627f86583 +curl-8.9.1.tar.bz2/sha512/27e4b36550b676c42d1a533ade5b2b35ac7ca95e1998bd05cc34b5dfa3bdc9c0539ec7000481230b6431baa549e64da1b46b39d6ba1f112e37458d7b35948c2e diff --git a/deps/checksums/libgit2 b/deps/checksums/libgit2 index 629a5f0601fcd..0a8d2a39ffc86 100644 --- a/deps/checksums/libgit2 +++ b/deps/checksums/libgit2 @@ -1,34 +1,36 @@ -LibGit2.v1.8.0+0.aarch64-apple-darwin.tar.gz/md5/c19f3a4f6567b7504f607fc6f328312f -LibGit2.v1.8.0+0.aarch64-apple-darwin.tar.gz/sha512/0a776ab3eb4593abe0f2198a7371cbcf653ac5cf71ab7af9d5520c2bbbbbc981cf07ba3afa70f1ef6ea56f81e2d4b33b1be1482f9e215e61178b3dd1149ecb80 -LibGit2.v1.8.0+0.aarch64-linux-gnu.tar.gz/md5/8137d530bea16d41a614983068c1909d -LibGit2.v1.8.0+0.aarch64-linux-gnu.tar.gz/sha512/bdcb6249acd8df887a8af7c084d409132694a39f5e9f90bd70bba0f3eba2bad3eab6958cce9f060b2a4392d99352ccda8be92000f24ed4498c85ba55e0cbf13f -LibGit2.v1.8.0+0.aarch64-linux-musl.tar.gz/md5/4b9508ea58d4b1bd99f8471bd7c9a839 -LibGit2.v1.8.0+0.aarch64-linux-musl.tar.gz/sha512/e0996627a3d3ab9b3b1d103bbdd3e1179ede5479816f6b1be54471f120f76fe0495d3c7587c382985173c0614b634903b58c67ac3badbead82b4d797cc5915d7 -LibGit2.v1.8.0+0.armv6l-linux-gnueabihf.tar.gz/md5/02d6fae1745562cf724190929383688e -LibGit2.v1.8.0+0.armv6l-linux-gnueabihf.tar.gz/sha512/11c14c5f395252143218a495c7dd2817c8f18f73320200a521f5ccd5f0c3c87403dee2c3b9e8166022fde1a67e83cbb83e6f222aac38b41efa43a6c0254548a9 -LibGit2.v1.8.0+0.armv6l-linux-musleabihf.tar.gz/md5/afa7b90751565b865f443b5a0a870d8b -LibGit2.v1.8.0+0.armv6l-linux-musleabihf.tar.gz/sha512/3594c223883a7da3bc0c78ae656fb15e47cc9dd196cf08f0abc0a1fb5f799842261e125440c07e92ba82896ad7427814bb43b63ba64d9b72ba38e9149132c26b -LibGit2.v1.8.0+0.armv7l-linux-gnueabihf.tar.gz/md5/ead27583a1cc5748c84d58a07fa6fc7e -LibGit2.v1.8.0+0.armv7l-linux-gnueabihf.tar.gz/sha512/c81c3582fda7b299aaed72de07e9d0bd06c0c231aed73bb980c12c89b2b7593b2fb7990421bc2e45173f3d107ab50660842289675efa31f24ff752f0ebc63875 -LibGit2.v1.8.0+0.armv7l-linux-musleabihf.tar.gz/md5/71e38f112e8629682cc383c510f1f13f -LibGit2.v1.8.0+0.armv7l-linux-musleabihf.tar.gz/sha512/0b4b2677bdfc4f8e2a5ef3b9adf8fa2c0c1e76bd240b2173c268835b59cda29cbffc4241319fe36dcd63d1507ecf0e0e843f48fca80e3fbe4d3df53601ad7dec -LibGit2.v1.8.0+0.i686-linux-gnu.tar.gz/md5/b54cdd02201c1481746ab81db6f39aac -LibGit2.v1.8.0+0.i686-linux-gnu.tar.gz/sha512/0496a607b0d6841fc0c87477274b61eb95afa24d48d2624f8aaf230028a24d0248336902b01a326010fdbc45d8d73eecedb14c82313e1b1a94b3b6a4296e2607 -LibGit2.v1.8.0+0.i686-linux-musl.tar.gz/md5/b8946f9c1b83a7c22b2a8ca6da05b23b -LibGit2.v1.8.0+0.i686-linux-musl.tar.gz/sha512/931ff27da4e35749a5c020af72b750dce0b1d672cd98c04ad5a340f4f33ddb61c4df6711c36c6601063262fb733d45a3bb24eb1141e9d2fd2e0ab7b9bfbf54c8 -LibGit2.v1.8.0+0.i686-w64-mingw32.tar.gz/md5/cb9db0b590efe0c60f6e2f9558de4e5b -LibGit2.v1.8.0+0.i686-w64-mingw32.tar.gz/sha512/b9f637ec10cd751dfb2156e154a68809af400cdecbf0d25910792937c63ea56e60b703c7b78e3038ab34b1100bb20df79dce6346f40f1d24e5188fefe9517ccc -LibGit2.v1.8.0+0.powerpc64le-linux-gnu.tar.gz/md5/4ac1fa6b1ca43d3f6e97d590d1d27127 -LibGit2.v1.8.0+0.powerpc64le-linux-gnu.tar.gz/sha512/5cc3b9b9d85068bb3c6711c63ccb2672be765888a114147f70cae0eebf96f5bde00a40f163202c20e18a4cf4af2488fd1c304060daa3dd35748b30ab5a1fdb1d -LibGit2.v1.8.0+0.x86_64-apple-darwin.tar.gz/md5/26c2d1dcf68bc7b9919dfd24eb2fabc7 -LibGit2.v1.8.0+0.x86_64-apple-darwin.tar.gz/sha512/9c3ba94c438682f321cb2130f71028587a4a21b960f94f8c3f633dbe007210ff1b7b5e0b0bc4972e818458843a47a9e8d50d88f1bd3fb03a8fe129fa66332a38 -LibGit2.v1.8.0+0.x86_64-linux-gnu.tar.gz/md5/8d48ad388cca20d6338095cf8a36c3c9 -LibGit2.v1.8.0+0.x86_64-linux-gnu.tar.gz/sha512/9ddf4dc7420a9129ff8c34eb07ee94d9213c1a1c22700521199032a773353ab2413fd70d002b273a06dd951558128cd5577b7e917de6575d379911831d737bed -LibGit2.v1.8.0+0.x86_64-linux-musl.tar.gz/md5/5d9fd50bdf38ec99311e9627f254b95d -LibGit2.v1.8.0+0.x86_64-linux-musl.tar.gz/sha512/eae36cc70cb414e15924c22c9b03a98949b89fd8ca429fbe23fa215253266ed4cd11530adb2feccc9a19299ebf2048f1f5929c1faffba463b593b6c3e1808bee -LibGit2.v1.8.0+0.x86_64-unknown-freebsd.tar.gz/md5/af9e9d4bbe0df291f07f41416809a6f2 -LibGit2.v1.8.0+0.x86_64-unknown-freebsd.tar.gz/sha512/859786f13ba1fb5cd448dd5f22ebdf3381f5290d4875d65840fb31567ccd012f283a1849a82f2b2f58c3d73eda4c748d3da07d84a99665e0f50aeb39c37a4fb2 -LibGit2.v1.8.0+0.x86_64-w64-mingw32.tar.gz/md5/b51e3e238d776d52e396dd749f895e4f -LibGit2.v1.8.0+0.x86_64-w64-mingw32.tar.gz/sha512/2581d4b1d6fd4d0f15b406f050bd8a2a41e13dc2a1699a9b956e56426778beb994e6552988bf50ddad682349209a8694eace9450dab0570434cdfbed9c9f0b24 -libgit2-d74d491481831ddcd23575d376e56d2197e95910.tar.gz/md5/2420def04a290dd7ad0e67f93789f106 -libgit2-d74d491481831ddcd23575d376e56d2197e95910.tar.gz/sha512/496c6640d2453c58b66bc53c6e4e9e84f48d89eb8f240aefc1eea7e2d19b6c601614764590f2d2ca9e51e7e1de8fcdd5bf67f27f32bab628eae40d26ed382048 +LibGit2.v1.8.4+0.aarch64-apple-darwin.tar.gz/md5/a2bca9483d0468b6836304068a8f8d99 +LibGit2.v1.8.4+0.aarch64-apple-darwin.tar.gz/sha512/bbc150e8c330f3cd666136334e15cfbd1017174193b3ece49b1c701aebd2774ef1b23e5e59ec8b05f23788db2ed8a3f103d7ff0fac364966eb5b5b2d814ffd22 +LibGit2.v1.8.4+0.aarch64-linux-gnu.tar.gz/md5/55f133dbf3a1e5ad37c69df3ea6b2274 +LibGit2.v1.8.4+0.aarch64-linux-gnu.tar.gz/sha512/c6f5a25f9b47be391f438867f076ed5b2539ddbb6542119b8225d52c7767705cda499940007b1f33801288426408a2d5ca3feb743e898b747fe0051df5ca7ad4 +LibGit2.v1.8.4+0.aarch64-linux-musl.tar.gz/md5/660b58d4e23b5f142731ccfcffff7b39 +LibGit2.v1.8.4+0.aarch64-linux-musl.tar.gz/sha512/e5d3add19efbbb59c7b79298b83d6342f70b2ad9415ead9460d9e78e117f2a98417a96f49ebfec62e2c18cf9519114e829c2d492e08c45b501aa25552ed97722 +LibGit2.v1.8.4+0.aarch64-unknown-freebsd.tar.gz/md5/67797f9177f007617b2e027673277453 +LibGit2.v1.8.4+0.aarch64-unknown-freebsd.tar.gz/sha512/1dff62cf24e842d978638ca0df9d67e0ed11250b6cb432880aad4603f292c456fcca10b6af304ed19954c22d24bcd8d3fe32e48c45bc2ea348d58eaa0ba6a1ad +LibGit2.v1.8.4+0.armv6l-linux-gnueabihf.tar.gz/md5/cc3264f393d133f9d34d796a1ddccac2 +LibGit2.v1.8.4+0.armv6l-linux-gnueabihf.tar.gz/sha512/8479dda021511747c6ef432eb9a092a54b2fe402e9010b5500faf01be3f2c4f6121fbb45849d6ba5e6a0f57318d6065956c58a5b5ea849e38b056d011ea0588d +LibGit2.v1.8.4+0.armv6l-linux-musleabihf.tar.gz/md5/4427150daaa544d04c0fa59b1b326831 +LibGit2.v1.8.4+0.armv6l-linux-musleabihf.tar.gz/sha512/b2a3cfd08022d012bb27e17bc4d67a0a1c09561420043a96111d029e582be0fdc619fe5227532ab7a902a5d43b5ef4ba1048d2c437c5bc9ac347d80535b60d9a +LibGit2.v1.8.4+0.armv7l-linux-gnueabihf.tar.gz/md5/f8afd5a5b5702dd0015829753244d223 +LibGit2.v1.8.4+0.armv7l-linux-gnueabihf.tar.gz/sha512/986f45f15b66109f372b41a2af2a6c4a7e03edb11ec4ad1cefba0c4cf16a6ddf3b490ba7d60e92a1f2eae91bc550f8d792f1ce66df64e0e2b3c66fbb6ff94cf7 +LibGit2.v1.8.4+0.armv7l-linux-musleabihf.tar.gz/md5/02534a7e25196d3cd504a6ef2993d051 +LibGit2.v1.8.4+0.armv7l-linux-musleabihf.tar.gz/sha512/31ba2fa0c71da0812fdadcf056bfd235379dc4d6960624a9b487bfcef2dd3b0ef3a618e7ed72850fd9e401cae0a143158c0ac48f6526c4845d80d2397eb08fb8 +LibGit2.v1.8.4+0.i686-linux-gnu.tar.gz/md5/0e73f9c928a69a552539f6aab5d44b0c +LibGit2.v1.8.4+0.i686-linux-gnu.tar.gz/sha512/6cca444bcfdef691cbd8ea249328a9f066a20ff23ac71f238a62d32bf40d236d4b4f6cb6d48862652b97791bd199bbf7f8851361ec2778c779a59168b0e08c01 +LibGit2.v1.8.4+0.i686-linux-musl.tar.gz/md5/a6cdca1ca0926ceb5827205005e80759 +LibGit2.v1.8.4+0.i686-linux-musl.tar.gz/sha512/37a456b7a31ca9a482976d3a7aab463dedaebf48aba1d16be5aceae2dbd9051679a0287776a93eabed70f6e9bb89ed4084564a88ed83e1d6a085ec6e32111be5 +LibGit2.v1.8.4+0.i686-w64-mingw32.tar.gz/md5/5ffb5489354195b163c55a6a83d059f0 +LibGit2.v1.8.4+0.i686-w64-mingw32.tar.gz/sha512/81423290e6122210102166b5878e6a101fde2dcdd16de2dea016a682d8aeb13a9db04230d0b6358bec3a8fb8db543b89c3b720c5cdf3418471e41db74bdff993 +LibGit2.v1.8.4+0.powerpc64le-linux-gnu.tar.gz/md5/d99482bb86f1347c83c2795ec10ed551 +LibGit2.v1.8.4+0.powerpc64le-linux-gnu.tar.gz/sha512/a52b1141c1562f7ff55e29e41f95791645f4cca437a8ae09842239a2c132b3b4479edf24abb907d4674b04ceffdc0003dd5d8314697a96b73580ae0cebb59ac1 +LibGit2.v1.8.4+0.x86_64-apple-darwin.tar.gz/md5/f385317d44621ba48d296ffe39d74250 +LibGit2.v1.8.4+0.x86_64-apple-darwin.tar.gz/sha512/25d6fd31a4207d0890b93aa30f98c430d349cfa3c4759e3a81254c39ec095162c916a6fdc6d91ca4b3df3892ac8836209d0927c3ca18b4dfbe5b067f5d79cae9 +LibGit2.v1.8.4+0.x86_64-linux-gnu.tar.gz/md5/9f881bf0428bfbeed1fce06fce156a3c +LibGit2.v1.8.4+0.x86_64-linux-gnu.tar.gz/sha512/ea6e90997ae1dd77cdf73b65995682d3b2563e40215b7316f2cc17982f8a35ac8f40d194d8d25c1a7334cb8443ec028516d05e64b841559b0c5dc15ce289e238 +LibGit2.v1.8.4+0.x86_64-linux-musl.tar.gz/md5/349b44527421615d99c08dca5299bbb6 +LibGit2.v1.8.4+0.x86_64-linux-musl.tar.gz/sha512/809c53ba91a3643ed534c49b1e3352ef8e6cf642dbcd45e21b7d2a2e4edb8235d2d35245c4e891362a2597c9b724cee93ec885c50259763e3d06f2d82cdbe3ee +LibGit2.v1.8.4+0.x86_64-unknown-freebsd.tar.gz/md5/01bb75c5eda895d47a55b9a231c0977e +LibGit2.v1.8.4+0.x86_64-unknown-freebsd.tar.gz/sha512/ba4ba6e681faf3d768d6a09d6ad0f82934fcbf635d42d4e92a9f0a2d545733757cebff759a720d79981eac8046f278c17b9ea982db3a0b7b774af686b790960b +LibGit2.v1.8.4+0.x86_64-w64-mingw32.tar.gz/md5/37f1e39363db20979948f9a1ebdf312f +LibGit2.v1.8.4+0.x86_64-w64-mingw32.tar.gz/sha512/d74108deed353ec26a56d020f533bdc35a881d640d621292e08ab259461f132e19afbdfee0e21915e6f54b7f0debc9cf4f5959d711104534e0ec85d3fe3a0ac1 +libgit2-3f4182d15eab74a302718f2de454ffadb1995626.tar.gz/md5/c502ae54871bd3afc0bd593a5cf05d68 +libgit2-3f4182d15eab74a302718f2de454ffadb1995626.tar.gz/sha512/7381abb66b42d8b667be12afa360a855627149d1f293a3091c05f02a528fdcc9e44fd7a5adebba8b30ee4ac1f4d1f029a2f0d0b49ada97a751159e0a61f8a54e diff --git a/deps/checksums/libssh2 b/deps/checksums/libssh2 index 697601a037132..fa05f325fa6a7 100644 --- a/deps/checksums/libssh2 +++ b/deps/checksums/libssh2 @@ -1,34 +1,36 @@ -LibSSH2.v1.11.0+1.aarch64-apple-darwin.tar.gz/md5/462442a50f5dd719d251f65e7170dbf6 -LibSSH2.v1.11.0+1.aarch64-apple-darwin.tar.gz/sha512/8f0d9916c1e1abb8ba2d4baef0f850f9f5aa8d24f5eeefd7c7d30697b15d33180b32588f50328f4999e1d4136a2951c4e3319c5a5dca6f34a84fba30ac90518f -LibSSH2.v1.11.0+1.aarch64-linux-gnu.tar.gz/md5/63d8a681bcce23e76650719cf3c6999b -LibSSH2.v1.11.0+1.aarch64-linux-gnu.tar.gz/sha512/9dc722d866d27f378481e4787a5bb932facc0c7b828e75e812c9c875ac10e7194d090d94e01a46bb2b3c5624e18d013f0226c5f574269df96f1de0ed16897571 -LibSSH2.v1.11.0+1.aarch64-linux-musl.tar.gz/md5/e85cfee900145726857d3609b541f7b5 -LibSSH2.v1.11.0+1.aarch64-linux-musl.tar.gz/sha512/ad42ddf4674f6359e61fb23ef6fb5942e716c6f0cd50378e93b8c3af799b9b21cc9cefc471d27e19bc31686c7aa469a5ed81918ea9926d5d432c3c5f70e83fcb -LibSSH2.v1.11.0+1.armv6l-linux-gnueabihf.tar.gz/md5/acb3b46ec386e9d41dd73cb3c9b60d1e -LibSSH2.v1.11.0+1.armv6l-linux-gnueabihf.tar.gz/sha512/bddc50ab698c280256d819cd7ea1a39a33366f2eb6004df6b66f6a45ce4b5bdb1525f724aee35f3b9796809f9e68db4a6dab01ab035c8a88bec291b59fd55854 -LibSSH2.v1.11.0+1.armv6l-linux-musleabihf.tar.gz/md5/d4efa89a3b4e1d3be80f6790e183ad07 -LibSSH2.v1.11.0+1.armv6l-linux-musleabihf.tar.gz/sha512/8da36af6514189b7bf3422ccbbbf69d271208e7d9b0af469cbbd476ddd3d62f2f9a0d25f38f22123a603e448c285936f0692a31d91d6d79dfc66baacb8af4522 -LibSSH2.v1.11.0+1.armv7l-linux-gnueabihf.tar.gz/md5/d4eeaf06f64997a4f46737798c15ccb0 -LibSSH2.v1.11.0+1.armv7l-linux-gnueabihf.tar.gz/sha512/4cb24ec2b13c9f56220a6cd3bb0ea1dda687a7ebbf062caa8fad9d17c903a2982f12340b93e82b42567e29b4326acda373f81c0ebb4f4d968a12ff7807f5d066 -LibSSH2.v1.11.0+1.armv7l-linux-musleabihf.tar.gz/md5/319db985d453fc32a69eaad85bdbeac4 -LibSSH2.v1.11.0+1.armv7l-linux-musleabihf.tar.gz/sha512/5f7f35e3cb1362ecda3236c1686a211409937e90fdb29dd9e4032d541b8fe45c28f24067cd012edef879d668d7b1040e887ea594eac03ffe5412d5f2c49cc294 -LibSSH2.v1.11.0+1.i686-linux-gnu.tar.gz/md5/e7cb7d9d6db13b46250da30969f8504d -LibSSH2.v1.11.0+1.i686-linux-gnu.tar.gz/sha512/fe8983aa012787361cadb5a78df8eec6ac5640a514c3fe4b4ab23d584b018ba4fa7d3514f0951d2b687cf56bf9ee17e247049d99a4e9360aec4ecbb636d2a6f1 -LibSSH2.v1.11.0+1.i686-linux-musl.tar.gz/md5/d7c5d3e8ecd86e216d97d4912457a66c -LibSSH2.v1.11.0+1.i686-linux-musl.tar.gz/sha512/4d64996d837cfec15b42ca7f850cda32ee3b3a8f93001d24f95ff6f8c94b76517e5dfc7e525e8335fc8788ecf7e196bdb7cc64c8c53f536c592afb337d98ee82 -LibSSH2.v1.11.0+1.i686-w64-mingw32.tar.gz/md5/9562e41b5dda94c23150668559e9b123 -LibSSH2.v1.11.0+1.i686-w64-mingw32.tar.gz/sha512/d13d022ec9eb82f8afa3954c730bd1840a8d1bb16cdbd07a89fff6ce07b1c0c2ba6a9e934b2585abf7dddcb0522e1ba0f38df4385447c66986d5fcb6dddc2d15 -LibSSH2.v1.11.0+1.powerpc64le-linux-gnu.tar.gz/md5/4e2463eb11a5dde8c3e0d3fab6c58169 -LibSSH2.v1.11.0+1.powerpc64le-linux-gnu.tar.gz/sha512/d8794571d051cf206da87a4f7f0f71c8b41be061691b08333df7678c4e40fb9abbe63812a5ff5243fabca9eb2e599d81a69520cd854afbddbc16b44678fbe1b7 -LibSSH2.v1.11.0+1.x86_64-apple-darwin.tar.gz/md5/5729492b3a91e0d8e3fcc459de784157 -LibSSH2.v1.11.0+1.x86_64-apple-darwin.tar.gz/sha512/8e49b2ff1c9b5ae499f14be238776d7da2b64231592f1d46a6f769f200681342ff157d76102fa7c16b2972c7fe603919f7d2ce7c8a30b46c98ecaf2ef809fe3c -LibSSH2.v1.11.0+1.x86_64-linux-gnu.tar.gz/md5/0f7f2214d453f562107fe22af5004e8a -LibSSH2.v1.11.0+1.x86_64-linux-gnu.tar.gz/sha512/bd510f25dc26c05362ff204adcc356521bfdacd665411a99e07071ea0c4638274a2e78f009644cdf5e472a1d81c80e353f4673071d90411e6122b55160140f3e -LibSSH2.v1.11.0+1.x86_64-linux-musl.tar.gz/md5/ee98538d67b8b091c4ddcf632e72e7d1 -LibSSH2.v1.11.0+1.x86_64-linux-musl.tar.gz/sha512/38cbb59ffa420e4299db848b6ae95098e8e3e6e1334e05369089d17b04fcd0787ad22ba69465611f3e335a1efab228990db776916f40a937b21b18ca511a4484 -LibSSH2.v1.11.0+1.x86_64-unknown-freebsd.tar.gz/md5/0abe5a971abe63c3db4353e7e9b181e9 -LibSSH2.v1.11.0+1.x86_64-unknown-freebsd.tar.gz/sha512/8e8199bc0634a8ec51460cb8628c3b33d765b7060ca79aac3e80a0b29d55de5562cdbb36945b4a9feab5392f7f16d2dc48684e43d54c62a9fdb1f07f36b71810 -LibSSH2.v1.11.0+1.x86_64-w64-mingw32.tar.gz/md5/d30fc8e9b74388a1c642cb15ed33dba3 -LibSSH2.v1.11.0+1.x86_64-w64-mingw32.tar.gz/sha512/e278b87d081fbbe15f88bafa8870f0f294cea3ff8c8c1fc9a6c10228da91717aa3caa268cdb10f78c8e55651a90243962f85101eeb4433f85c1dfacc1461d96d -libssh2-1c3f1b7da588f2652260285529ec3c1f1125eb4e.tar.gz/md5/7b52de6ff70e16aa78cd699fee3e997a -libssh2-1c3f1b7da588f2652260285529ec3c1f1125eb4e.tar.gz/sha512/7c99d33e60862e2d89bbcc4a09ffff3fbfb921ed674e0d3166a255c72a8e0622a9c6be64f0eb2f8c12ddd80da0307b05d761615b876194bd854aa2c62e26f4ad +LibSSH2.v1.11.3+0.aarch64-apple-darwin.tar.gz/md5/87ba86e78421d6195aa6a46129ff61d4 +LibSSH2.v1.11.3+0.aarch64-apple-darwin.tar.gz/sha512/2b7129be9e9518337f59857474882a6a3448f358c931c66ab9f9ec67506c68d2356df591bd45925154844ca0d6f6e1f071d4c54d62039c5078b468fcb356187b +LibSSH2.v1.11.3+0.aarch64-linux-gnu.tar.gz/md5/84c6eb68e7797038d0863513fa4e292f +LibSSH2.v1.11.3+0.aarch64-linux-gnu.tar.gz/sha512/3012beb35fdf94136907037e8f5261a5cc94d102f461172321d4ed8f328da3789d521513dd03cb344c6fcb73675cd1d3ede606bf9a904fb811d40c43fd09d8aa +LibSSH2.v1.11.3+0.aarch64-linux-musl.tar.gz/md5/5a49057201e779f3427b794b72bf07a2 +LibSSH2.v1.11.3+0.aarch64-linux-musl.tar.gz/sha512/62a812efb4ad7b24bfeeb3bb89756004215c09a1cc01e0530f14ce4b8546f1dcbbac18155ac2ce08311c1790d659b14674e3bb3549ff68d1209d52b5e5986fff +LibSSH2.v1.11.3+0.aarch64-unknown-freebsd.tar.gz/md5/a5129167b7be7ac8ba2c873e164afb1b +LibSSH2.v1.11.3+0.aarch64-unknown-freebsd.tar.gz/sha512/f8d9cc5098a3b401fbbe98a24efaca0ea46f533ecaf11dbfe8f7e7e3853363af19914de62bd1cb5a573e55e90d5c6074532ddc6d64723c9e235b277f438ce6ef +LibSSH2.v1.11.3+0.armv6l-linux-gnueabihf.tar.gz/md5/5c59c95612bf9aa172e5d487002db509 +LibSSH2.v1.11.3+0.armv6l-linux-gnueabihf.tar.gz/sha512/5ba41e49365c2018d55c92e4a23d806ca9ab960a448593b08380527da21eec03f76cab89c34befbc56f4104002aa189d5cae6f655797f1447f395b51a14d40e2 +LibSSH2.v1.11.3+0.armv6l-linux-musleabihf.tar.gz/md5/4bc27411f0eddf82a787d1ede17ce2c3 +LibSSH2.v1.11.3+0.armv6l-linux-musleabihf.tar.gz/sha512/d6024b6949ac6867c56c66defbb99300a5661e0c73da6c330165bceba78d64063986c8851601ca74554b27944d5b02e3f602b1e71781097bbb8b12effc0cbbdb +LibSSH2.v1.11.3+0.armv7l-linux-gnueabihf.tar.gz/md5/40e1a0d323969b96ab121eb5a3ecc874 +LibSSH2.v1.11.3+0.armv7l-linux-gnueabihf.tar.gz/sha512/67ce15a5b1c1fe0fd1096ed5d2d9f44d83983de11c1bc651f5914d70d387a99ee6bde31716031b758f48981e2a9383599f077f02d61a5c783ee6d09a7bf445db +LibSSH2.v1.11.3+0.armv7l-linux-musleabihf.tar.gz/md5/9453c52394b1b06bd36c43e461a3b48f +LibSSH2.v1.11.3+0.armv7l-linux-musleabihf.tar.gz/sha512/c62068ecb1b88dbd08a2474e0b93cd313bdc4e1407a22cd9164a73b2d897564f12a3c34f6fc492b264af579b00e9335a0fe1fa853fbe0fbb18d8335b77d409b2 +LibSSH2.v1.11.3+0.i686-linux-gnu.tar.gz/md5/992453b1c59033aefa8d98b89f491ff6 +LibSSH2.v1.11.3+0.i686-linux-gnu.tar.gz/sha512/ebf14565d614086c4401e1a997a3aacc83f8e499ed836c429f87c4f95f1c8409713fad47f1c34a2b1cd23f90de3daf14caafba3c82b15642018592213607c874 +LibSSH2.v1.11.3+0.i686-linux-musl.tar.gz/md5/e0cb0566c724c107f4f04619080d4c0c +LibSSH2.v1.11.3+0.i686-linux-musl.tar.gz/sha512/af7d08dba5bb06eaf7ce8aeb12b69701d3c2829996a1c8e68510c106402a1166ad060687987df49365c26d30e8d6511c66f2a50ec810a493d2c090931ccf05a5 +LibSSH2.v1.11.3+0.i686-w64-mingw32.tar.gz/md5/c5e8d3145deb56d6df008522a5d3ea6f +LibSSH2.v1.11.3+0.i686-w64-mingw32.tar.gz/sha512/47f3c36747d2e42a4c0669ef468d395078328235d30056b7d67d76bd737b5118c1bbc720aef455c4d9017e7b9350e8cc043ed28264ea8a9ecb6833ca517f82aa +LibSSH2.v1.11.3+0.powerpc64le-linux-gnu.tar.gz/md5/12eba4aec5e320a4d0cf09225bca3f7c +LibSSH2.v1.11.3+0.powerpc64le-linux-gnu.tar.gz/sha512/d6b8413d77d8af3d29b867692f6c02b63e793f5e8f17c4777756d247c8e602b3ab87380031aefa60f2c3ddae5a3c7a1f1c739439f149db34a32c79f32e08048b +LibSSH2.v1.11.3+0.x86_64-apple-darwin.tar.gz/md5/f6e7cd35e16290b198c80c61a0fca5e5 +LibSSH2.v1.11.3+0.x86_64-apple-darwin.tar.gz/sha512/2c83814ef6ae78ec94a43f2997151dd7195c0a0f9cf456fcd3f780268bd1cbdd7ea55182fc5a1f8e1413c26889e54fccb01964b0b91dd4b925ecaa16b7df8d07 +LibSSH2.v1.11.3+0.x86_64-linux-gnu.tar.gz/md5/95aa96befc9f9007e6a000a95c1b7572 +LibSSH2.v1.11.3+0.x86_64-linux-gnu.tar.gz/sha512/6058dca6d933afb7fe5fc3374937b4432f202a5dfe3ebcc2f91f65777230c18d76801c38071f84f8362527ee08656a97f79da234ab5481265a7ccf29e94c20c5 +LibSSH2.v1.11.3+0.x86_64-linux-musl.tar.gz/md5/88b69d889d602bc3df420535dba30f9e +LibSSH2.v1.11.3+0.x86_64-linux-musl.tar.gz/sha512/7335954124074e7df786989db86e86e3bcf41f503b8e3b27d6ac18032c8025bec26180bd2c537b23349bcf5673eb67245531479b939670e620faf5aa13c8c4ab +LibSSH2.v1.11.3+0.x86_64-unknown-freebsd.tar.gz/md5/6d5f6e9455c35c5f6655cb4d46797db0 +LibSSH2.v1.11.3+0.x86_64-unknown-freebsd.tar.gz/sha512/9515d11bb5686e29eb5a37bbcb7ab07574da0869c82e5b3f0cf282bbc56792af31e6174521d58133968b997caa6db75ac9b195024144fd2c95fd1bbf689ebbf6 +LibSSH2.v1.11.3+0.x86_64-w64-mingw32.tar.gz/md5/e66cdac0c2d5ce2d160e482d780ad0c3 +LibSSH2.v1.11.3+0.x86_64-w64-mingw32.tar.gz/sha512/2dabb1e8da5ea496898751d5517ca37178e1a44c78c26fe33f87487a0b4acf7185f686ce8d6ea0e65e38a8fd56e5ff09fd70becda402a942b5e459707eb2a44e +libssh2-a312b43325e3383c865a87bb1d26cb52e3292641.tar.gz/md5/06d5e2881ac023583c7fd6665d628a87 +libssh2-a312b43325e3383c865a87bb1d26cb52e3292641.tar.gz/sha512/5dee8cce91853eb8c9968d7453b1ad0c3cd1411901d288f1731b7c7e4adf380313f61c2a66eee0d3b89eba79e420e13269bb3738bcf2c59f0b88276aa785fa8c diff --git a/deps/checksums/mbedtls b/deps/checksums/mbedtls deleted file mode 100644 index e52066b6f4bac..0000000000000 --- a/deps/checksums/mbedtls +++ /dev/null @@ -1,36 +0,0 @@ -MbedTLS.v2.28.6+1.aarch64-apple-darwin.tar.gz/md5/c97705b08c6bf695fa7a11a42167df94 -MbedTLS.v2.28.6+1.aarch64-apple-darwin.tar.gz/sha512/91825c3a495045ca74ceb5a23e3d7e9387701e401911b147d905a49892b1a5a9f22662a4f16a7f4468c5a807f2980b66e3409ea1ff7e04c6fdac0b105472e200 -MbedTLS.v2.28.6+1.aarch64-linux-gnu.tar.gz/md5/8ebaaeefd75c805227229086c262d0e7 -MbedTLS.v2.28.6+1.aarch64-linux-gnu.tar.gz/sha512/89983c1f9f9d7b901619522afcd12c6bc1996757edeb9f3012954992f82f3b36ae50f49dcf7731623fca197946e4281eecffdc29a5819f04e7f6203afd4eb93a -MbedTLS.v2.28.6+1.aarch64-linux-musl.tar.gz/md5/b40b2ba247f4ff755e15daad13c5a255 -MbedTLS.v2.28.6+1.aarch64-linux-musl.tar.gz/sha512/4cb4f2213b631dda0caa8baafa8effc9c8592c72a6a5b826fce060cd81f8f77c188c9ddc76595b47078db3c35b3043d9bf0cb891d822a940df87982de56dec44 -MbedTLS.v2.28.6+1.aarch64-unknown-freebsd.tar.gz/md5/51774d7907dc1a72d7c6e1b6cff02347 -MbedTLS.v2.28.6+1.aarch64-unknown-freebsd.tar.gz/sha512/b85292a75d4ba6fc3996ed497f0951f0dc0a3846e1df83f36b7d3ed3fc30687efdc1742848f6fb5a06e204fa9eb66837c8fbef16e6329f50763086bafef14fb7 -MbedTLS.v2.28.6+1.armv6l-linux-gnueabihf.tar.gz/md5/c6dd1cb1aba1075c73c41719a03c5ab5 -MbedTLS.v2.28.6+1.armv6l-linux-gnueabihf.tar.gz/sha512/981a8925dd90418150625e9467cc791e4a9d5223e7df6ead113ec41a279a5dd7e8ebcecb5b87611ef451fc6483fd6eb5bf984cf528037ad742e68b4be94e5c07 -MbedTLS.v2.28.6+1.armv6l-linux-musleabihf.tar.gz/md5/c30ed777bd74d269656f7e9bc8163765 -MbedTLS.v2.28.6+1.armv6l-linux-musleabihf.tar.gz/sha512/f04014181082561195caa4d3b178480bb5cce7f459d76aca8cdaa2f615d105b24871656ce4cbf8d9ec33f0424de35a16f12d4964a1f0fab9a416e5d18a468c94 -MbedTLS.v2.28.6+1.armv7l-linux-gnueabihf.tar.gz/md5/256f8327773ea2d0d6b4649541c34e84 -MbedTLS.v2.28.6+1.armv7l-linux-gnueabihf.tar.gz/sha512/ab4c9e82752386a0fd642a709bc90b712d6aaff78309968f1fdbf1121a790a9c0227ddd8e79373359cea9c75b21e762f600abea42036609571ba999531b50852 -MbedTLS.v2.28.6+1.armv7l-linux-musleabihf.tar.gz/md5/249ada3e9a7ad4eba08270e575ae68ec -MbedTLS.v2.28.6+1.armv7l-linux-musleabihf.tar.gz/sha512/0682e65f4257c3d237ba8cfc643be4430341888ec4cd17c2dc3018350aa7ff176e834a69ebc9d240b383a7aed439b34e45c237310ad66043956700b782323793 -MbedTLS.v2.28.6+1.i686-linux-gnu.tar.gz/md5/d0a176d2843ac780884395c90971bf68 -MbedTLS.v2.28.6+1.i686-linux-gnu.tar.gz/sha512/c2f96f314d0e5d9bffe46dc7d0adceb038db81e8c9d9a3c0fb0a237849d0d568d249e2df6c275d27a74a9122d0a53b38e5d8521807669a9c82bd67befbea169c -MbedTLS.v2.28.6+1.i686-linux-musl.tar.gz/md5/9c7501c6b04df53f8d56cd59dd42ae4c -MbedTLS.v2.28.6+1.i686-linux-musl.tar.gz/sha512/6fd35f9c2e1c5822920bc1d9315dc68b10694ee5507cc512868615c3d35dc389fa67038b9ab79fa86ea7ff6bf5f6f1eed053fafcc519080559057dcaff813ec5 -MbedTLS.v2.28.6+1.i686-w64-mingw32.tar.gz/md5/1eef46b3c89a81973778817a8856673c -MbedTLS.v2.28.6+1.i686-w64-mingw32.tar.gz/sha512/f202595cf971825601d5e12263eef0dd101e9be971d15592a12187f1d170fafaab358f02db89458f495ddc8922f66fbd662123b0d6df527fffa514e9f410784a -MbedTLS.v2.28.6+1.powerpc64le-linux-gnu.tar.gz/md5/fec1779ff02d71d5e94b3f1455453fc0 -MbedTLS.v2.28.6+1.powerpc64le-linux-gnu.tar.gz/sha512/e97ae38c555f6b45e33c023c7e07c982d36501f6c2dc36121bb73f2fb08db3fa3ab7f4ab0d9ecb622d25bfe1816eab3a6190d2034a05a66b7425c36a637623e0 -MbedTLS.v2.28.6+1.x86_64-apple-darwin.tar.gz/md5/6d44a0c126affaedad544460da9415ab -MbedTLS.v2.28.6+1.x86_64-apple-darwin.tar.gz/sha512/bf074429f32f51d954bc0c242fb4455ec6ead0e8337a3e5ab9e5b0df47d8a195947a488169f743db63d70b245be80084cd0d78f2211b6cd4b9524010b2c893cc -MbedTLS.v2.28.6+1.x86_64-linux-gnu.tar.gz/md5/95641af7a92c8c83d82264dd2275692c -MbedTLS.v2.28.6+1.x86_64-linux-gnu.tar.gz/sha512/3606ecd5a566e643cc03959a3eac9a45cb4c644006ee5820b852dfc22d40b85d75f5c018c46776954d92001986ecb49238058ca3d99340f9a689875b690aa6e7 -MbedTLS.v2.28.6+1.x86_64-linux-musl.tar.gz/md5/aee58ac107ca0d9e1eb5d7de8146ec8d -MbedTLS.v2.28.6+1.x86_64-linux-musl.tar.gz/sha512/86219aa5ba3280da39e91beded7455160c1ebc274c3158b9f0703a2c034756a9a9e51e5354d22ce983fcd026157d81f471446e6ee2743cae2663384e3e796176 -MbedTLS.v2.28.6+1.x86_64-unknown-freebsd.tar.gz/md5/67857ac031b10fb6a0620b453477653b -MbedTLS.v2.28.6+1.x86_64-unknown-freebsd.tar.gz/sha512/118f3c662580c88d092610be08b60236939c7fd7feab4cd524c7c1e2e2e1b557bddbd603902b697142695889ea6c0a8087982020cd5e7267c9c7c82b49622460 -MbedTLS.v2.28.6+1.x86_64-w64-mingw32.tar.gz/md5/1ca2c982712620941c4b0d731251dfff -MbedTLS.v2.28.6+1.x86_64-w64-mingw32.tar.gz/sha512/cef70c00c79e421ce92424bbfda259b4e233d7be3489db1b8cbac7e926d9429be6c88fb806664db60210427748810ea08117066480e8e17c60cb61485b639669 -mbedtls-2.28.6.tar.gz/md5/768932cee6c42f7f4751362091ac56d4 -mbedtls-2.28.6.tar.gz/sha512/a5c876489bf89908f34626c879f68e8f962d84b50756df17b6b75dfb93e08fe163ed3f32bf70e89bce9080d15257a4cbd2679b743bf8f2e2d7a04606c5811c05 diff --git a/deps/checksums/openssl b/deps/checksums/openssl new file mode 100644 index 0000000000000..4d56641b34c80 --- /dev/null +++ b/deps/checksums/openssl @@ -0,0 +1,36 @@ +OpenSSL.v3.0.15+1.aarch64-apple-darwin.tar.gz/md5/8495727a34f178bc474c970855b88e8d +OpenSSL.v3.0.15+1.aarch64-apple-darwin.tar.gz/sha512/2beb6003e0431d56fd4161a7739d0ea2e2238181b2a064f552d5083b59e7724904e8a991e5d0ecaeb05e21d17b56ca44f321c71ac477db4ddaa05d792cb61c9b +OpenSSL.v3.0.15+1.aarch64-linux-gnu.tar.gz/md5/652845c276f3403e8374111fd6654aa0 +OpenSSL.v3.0.15+1.aarch64-linux-gnu.tar.gz/sha512/5d7a20836fffd253eaf574eb461eb10dcbb3fcf0d4f3d763539ef02a922af944e4ff29e8f20cec210ed798a48c742684ea713d511c58c784f33793e167a98469 +OpenSSL.v3.0.15+1.aarch64-linux-musl.tar.gz/md5/52397b6264c156815cdf9de5709533ef +OpenSSL.v3.0.15+1.aarch64-linux-musl.tar.gz/sha512/f1e8c0a3a7bac3c8b78d68fce551c29e5d537f7289f51c297e75c5c7bc3678747dc19ed579387021def041f02bf08d0e7938c5498b4493438efeb4685e01a191 +OpenSSL.v3.0.15+1.aarch64-unknown-freebsd.tar.gz/md5/bbdbea23761b13821d99f9eb4ba5d198 +OpenSSL.v3.0.15+1.aarch64-unknown-freebsd.tar.gz/sha512/a1c3985658eaf38a901bc7de1e782101ab41638d4641fea3115c5020b229d3f6fba3e3709c5568b3395986f396d82feb32b804d343dfd05c2fa1e6eefe120e96 +OpenSSL.v3.0.15+1.armv6l-linux-gnueabihf.tar.gz/md5/ceeb288e5c8da5831047dc4b1c2a983e +OpenSSL.v3.0.15+1.armv6l-linux-gnueabihf.tar.gz/sha512/961c4ec351b69aaf42082b462623afd7315b6606c2a5fb98142ca1bc6ce0494c388f5020474eff5081e850fd34aed8b3ef2f881304872255236fcae0b0b641e4 +OpenSSL.v3.0.15+1.armv6l-linux-musleabihf.tar.gz/md5/e75d83ecf3876a595cfe36cf81853489 +OpenSSL.v3.0.15+1.armv6l-linux-musleabihf.tar.gz/sha512/3e113a275233f434df685b114342f2a59634282a9b68606d4c16da51e5173cbed26498512b22f84017100a18415cc1bb2d269f1ba0d44941d51b8d05c73950cc +OpenSSL.v3.0.15+1.armv7l-linux-gnueabihf.tar.gz/md5/fbe3bf8921cf9b679b60ea12e2d19458 +OpenSSL.v3.0.15+1.armv7l-linux-gnueabihf.tar.gz/sha512/294c91308eede14b8db255ff1b47fe5dba3b6441318e38e284446f276355b93d97b88e6c78d9ed6bb6623623c47be5c65ce6b2fa5ce5ea087a8bfaeb94830627 +OpenSSL.v3.0.15+1.armv7l-linux-musleabihf.tar.gz/md5/ab35b5d4f79e349d558742c69c775d34 +OpenSSL.v3.0.15+1.armv7l-linux-musleabihf.tar.gz/sha512/6a5c85e36ed609ad33d0d2466fa1732a47072af37226052456172d7b049b9d943ad48d94b444600ed1f859a4c016226fc1952fda7381f3aaa6229bcd15c72f78 +OpenSSL.v3.0.15+1.i686-linux-gnu.tar.gz/md5/99e76e6c5d50fd0a4e6218bb807f1062 +OpenSSL.v3.0.15+1.i686-linux-gnu.tar.gz/sha512/30235842672e3b854d38ffd3ba1812a9e81b1f9fcf285ed12d07622d386a5355b79f2264be3d0e84d0bec0e57a9f3e1ac6de898463c43f6d2e3290854205cb30 +OpenSSL.v3.0.15+1.i686-linux-musl.tar.gz/md5/adb2ed9a8ef34294643f7762de1c7842 +OpenSSL.v3.0.15+1.i686-linux-musl.tar.gz/sha512/56d56eb89ea0dcadafbfc92a3bd2032b6c934d217882f56ba47086783b7a5134816f43d391a569963fa978ab708bf695af5abf03cac11c709930752882c761b7 +OpenSSL.v3.0.15+1.i686-w64-mingw32.tar.gz/md5/4596a947bb22aab728ba585d2727053a +OpenSSL.v3.0.15+1.i686-w64-mingw32.tar.gz/sha512/6a1479036c7ccb170daf42ed7d6054d2c7f3a4115dbb01fe34e518efdf0a60929eb89771d5f7fdcb3d055ebf05351cbc82397606d49ea4bde44c465cdb60274e +OpenSSL.v3.0.15+1.powerpc64le-linux-gnu.tar.gz/md5/f36402387dde259a64b0bed2a0d2a3c9 +OpenSSL.v3.0.15+1.powerpc64le-linux-gnu.tar.gz/sha512/3011eec16c1abcbf3c452a2d8e4e7c5a3c280981ea57374a938e3f8843f25022e9b0beaa6a87a1e5f7547ae4abd614221cc2a0a51495869fe99a03f6b3f46d8e +OpenSSL.v3.0.15+1.x86_64-apple-darwin.tar.gz/md5/f4c82b74f80a3cda4ae409e4623b6615 +OpenSSL.v3.0.15+1.x86_64-apple-darwin.tar.gz/sha512/d4a08a914533e603f06e584b8d7e69f4fca9671635fe24e1a896a362bfd388eea2397b9b66b82aecc0ba751e72dfcfbd8b46c5a148349f5aaeb9c37bc257ed37 +OpenSSL.v3.0.15+1.x86_64-linux-gnu.tar.gz/md5/9868c286c6275581a5891167540def7d +OpenSSL.v3.0.15+1.x86_64-linux-gnu.tar.gz/sha512/5631aa288e0e174bd05d520d90a29423c743576eb2385e97a58ed45361e94e59daa3b3193e81ce649bfed21d07fd508c135a38b486b34120afc3af1b4f92451d +OpenSSL.v3.0.15+1.x86_64-linux-musl.tar.gz/md5/e118f2b842a3a1be539208aff17281ec +OpenSSL.v3.0.15+1.x86_64-linux-musl.tar.gz/sha512/1c6fa866bebf5c0c6cc5ea8a423d2a522b186e7f2590146e464813be22d66de0a9bc797449508fa5508d296309348b8dd3a881c0099e6fb77b8d28ff270fab35 +OpenSSL.v3.0.15+1.x86_64-unknown-freebsd.tar.gz/md5/03830b4a8735a7e704df444e9a4353ab +OpenSSL.v3.0.15+1.x86_64-unknown-freebsd.tar.gz/sha512/bfc9e4ca160a9e3d4232117d819ea37f3997d4c433cfc85a4055ced60e8c65e7df6009d58f6b94f6f2aa1b436a8ee9f08dcf5a21faf7106bfdb50ca9a05322c6 +OpenSSL.v3.0.15+1.x86_64-w64-mingw32.tar.gz/md5/5b2c640cb72115f417cdd7ec82a8336f +OpenSSL.v3.0.15+1.x86_64-w64-mingw32.tar.gz/sha512/d2224dd37205c7781be93f1581a08c4008f4c35cb3f457f3b4455a00805c1a20be7f7e29188a55164364c42a926ffa12527af379d1bc8d11f4351b07d8a5928b +openssl-3.0.15.tar.gz/md5/08f458c00fff496a52ef931c481045cd +openssl-3.0.15.tar.gz/sha512/acd80f2f7924d90c1416946a5c61eff461926ad60f4821bb6b08845ea18f8452fd5e88a2c2c5bd0d7590a792cb8341a3f3be042fd0a5b6c9c1b84a497c347bbf diff --git a/deps/curl.mk b/deps/curl.mk index ae2830c3cd4f2..29745448692c6 100644 --- a/deps/curl.mk +++ b/deps/curl.mk @@ -35,31 +35,35 @@ checksum-curl: $(SRCCACHE)/curl-$(CURL_VER).tar.bz2 ## xref: https://github.com/JuliaPackaging/Yggdrasil/blob/master/L/LibCURL/common.jl # Disable....almost everything -CURL_CONFIGURE_FLAGS := $(CONFIGURE_COMMON) \ - --without-gnutls --without-libidn2 --without-librtmp \ - --without-libpsl --without-libgsasl --without-fish-functions-dir \ - --disable-ares --disable-manual --disable-ldap --disable-ldaps --disable-static \ - --without-gssapi --without-brotli +CURL_CONFIGURE_FLAGS := $(CONFIGURE_COMMON) \ + --without-gnutls \ + --without-libidn2 --without-librtmp \ + --without-nss --without-libpsl \ + --disable-ares --disable-manual \ + --disable-ldap --disable-ldaps --without-zsh-functions-dir \ + --disable-static --without-libgsasl \ + --without-brotli # A few things we actually enable -CURL_CONFIGURE_FLAGS += --enable-versioned-symbols \ - --with-libssh2=${build_prefix} --with-zlib=${build_prefix} --with-nghttp2=${build_prefix} +CURL_CONFIGURE_FLAGS += \ + --with-libssh2=${build_prefix} --with-zlib=${build_prefix} --with-nghttp2=${build_prefix} \ + --enable-versioned-symbols # We use different TLS libraries on different platforms. # On Windows, we use schannel # On MacOS, we use SecureTransport -# On Linux, we use mbedTLS +# On Linux, we use OpenSSL ifeq ($(OS), WINNT) CURL_TLS_CONFIGURE_FLAGS := --with-schannel else ifeq ($(OS), Darwin) CURL_TLS_CONFIGURE_FLAGS := --with-secure-transport else -CURL_TLS_CONFIGURE_FLAGS := --with-mbedtls=$(build_prefix) +CURL_TLS_CONFIGURE_FLAGS := --with-openssl endif CURL_CONFIGURE_FLAGS += $(CURL_TLS_CONFIGURE_FLAGS) $(SRCCACHE)/curl-$(CURL_VER)/curl-8.6.0-build.patch-applied: $(SRCCACHE)/curl-$(CURL_VER)/source-extracted cd $(dir $@) && \ - patch -p1 -f < $(SRCDIR)/patches/curl-8.6.0-build.patch + patch -p1 -f < $(SRCDIR)/patches/curl-strdup.patch echo 1 > $@ $(SRCCACHE)/curl-$(CURL_VER)/source-patched: $(SRCCACHE)/curl-$(CURL_VER)/curl-8.6.0-build.patch-applied diff --git a/deps/curl.version b/deps/curl.version index 5ecfcc2b642a1..ff360676b335a 100644 --- a/deps/curl.version +++ b/deps/curl.version @@ -3,4 +3,7 @@ CURL_JLL_NAME := LibCURL ## source build -CURL_VER := 8.6.0 +# curl version 8.10 and later seem to be broken, probably due to a bug +# on Julia. See +# . +CURL_VER := 8.9.1 diff --git a/deps/libgit2.mk b/deps/libgit2.mk index 022582d48c78e..8b17ae6d70424 100644 --- a/deps/libgit2.mk +++ b/deps/libgit2.mk @@ -9,8 +9,8 @@ ifeq ($(USE_SYSTEM_LIBSSH2), 0) $(BUILDDIR)/$(LIBGIT2_SRC_DIR)/build-configured: | $(build_prefix)/manifest/libssh2 endif -ifeq ($(USE_SYSTEM_MBEDTLS), 0) -$(BUILDDIR)/$(LIBGIT2_SRC_DIR)/build-configured: | $(build_prefix)/manifest/mbedtls +ifeq ($(USE_SYSTEM_OPENSSL), 0) +$(BUILDDIR)/$(LIBGIT2_SRC_DIR)/build-configured: | $(build_prefix)/manifest/openssl endif LIBGIT2_OPTS := $(CMAKE_COMMON) -DCMAKE_BUILD_TYPE=Release -DUSE_THREADS=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON -DBUILD_CLI=OFF @@ -39,7 +39,7 @@ LIBGIT2_OPTS += -DCMAKE_C_FLAGS="-I/usr/local/include" endif ifneq (,$(findstring $(OS),Linux FreeBSD OpenBSD)) -LIBGIT2_OPTS += -DUSE_HTTPS="mbedTLS" -DUSE_SHA1="CollisionDetection" -DCMAKE_INSTALL_RPATH="\$$ORIGIN" +LIBGIT2_OPTS += -DUSE_HTTPS="OpenSSL" -DUSE_SHA1="CollisionDetection" -DCMAKE_INSTALL_RPATH="\$$ORIGIN" endif # use the bundled distribution of libpcre. we should consider linking against the diff --git a/deps/libgit2.version b/deps/libgit2.version index ae475f0b3644f..9b908cff803e3 100644 --- a/deps/libgit2.version +++ b/deps/libgit2.version @@ -3,8 +3,8 @@ LIBGIT2_JLL_NAME := LibGit2 ## source build -LIBGIT2_BRANCH=v1.8.0 -LIBGIT2_SHA1=d74d491481831ddcd23575d376e56d2197e95910 +LIBGIT2_BRANCH=v1.8.4 +LIBGIT2_SHA1=3f4182d15eab74a302718f2de454ffadb1995626 ## Other deps # Specify the version of the Mozilla CA Certificate Store to obtain. diff --git a/deps/libssh2.mk b/deps/libssh2.mk index c293d8309d2bc..3f802db15be6d 100644 --- a/deps/libssh2.mk +++ b/deps/libssh2.mk @@ -4,8 +4,8 @@ LIBSSH2_GIT_URL := https://github.com/libssh2/libssh2.git LIBSSH2_TAR_URL = https://api.github.com/repos/libssh2/libssh2/tarball/$1 $(eval $(call git-external,libssh2,LIBSSH2,CMakeLists.txt,,$(SRCCACHE))) -ifeq ($(USE_SYSTEM_MBEDTLS), 0) -$(BUILDDIR)/$(LIBSSH2_SRC_DIR)/build-configured: | $(build_prefix)/manifest/mbedtls +ifeq ($(USE_SYSTEM_OPENSSL), 0) +$(BUILDDIR)/$(LIBSSH2_SRC_DIR)/build-configured: | $(build_prefix)/manifest/openssl endif LIBSSH2_OPTS := $(CMAKE_COMMON) -DBUILD_SHARED_LIBS=ON -DBUILD_EXAMPLES=OFF \ @@ -21,7 +21,7 @@ ifeq ($(BUILD_OS),WINNT) LIBSSH2_OPTS += -G"MSYS Makefiles" endif else -LIBSSH2_OPTS += -DCRYPTO_BACKEND=mbedTLS -DENABLE_ZLIB_COMPRESSION=OFF +LIBSSH2_OPTS += -DCRYPTO_BACKEND=OpenSSL -DENABLE_ZLIB_COMPRESSION=OFF endif ifneq (,$(findstring $(OS),Linux FreeBSD OpenBSD)) @@ -34,14 +34,6 @@ endif LIBSSH2_SRC_PATH := $(SRCCACHE)/$(LIBSSH2_SRC_DIR) -$(LIBSSH2_SRC_PATH)/libssh2-mbedtls-size_t.patch-applied: $(LIBSSH2_SRC_PATH)/source-extracted - cd $(LIBSSH2_SRC_PATH) && \ - patch -p1 -f < $(SRCDIR)/patches/libssh2-mbedtls-size_t.patch - echo 1 > $@ - -$(BUILDDIR)/$(LIBSSH2_SRC_DIR)/build-configured: \ - $(LIBSSH2_SRC_PATH)/libssh2-mbedtls-size_t.patch-applied - $(BUILDDIR)/$(LIBSSH2_SRC_DIR)/build-configured: $(LIBSSH2_SRC_PATH)/source-extracted mkdir -p $(dir $@) cd $(dir $@) && \ diff --git a/deps/libssh2.version b/deps/libssh2.version index 7fff90885f6a3..d6cc8a629c3bf 100644 --- a/deps/libssh2.version +++ b/deps/libssh2.version @@ -1,7 +1,8 @@ +# -*- makefile -*- ## jll artifact LIBSSH2_JLL_NAME := LibSSH2 ## source build -LIBSSH2_VER := 1.11.0 -LIBSSH2_BRANCH=libssh2-1.11.0 -LIBSSH2_SHA1=1c3f1b7da588f2652260285529ec3c1f1125eb4e +LIBSSH2_VER := 1.11.1 +LIBSSH2_BRANCH=libssh2-1.11.1 +LIBSSH2_SHA1=a312b43325e3383c865a87bb1d26cb52e3292641 diff --git a/deps/mbedtls.mk b/deps/mbedtls.mk deleted file mode 100644 index 39cf817d70658..0000000000000 --- a/deps/mbedtls.mk +++ /dev/null @@ -1,97 +0,0 @@ -## mbedtls -include $(SRCDIR)/mbedtls.version - -ifneq ($(USE_BINARYBUILDER_MBEDTLS), 1) -MBEDTLS_SRC = mbedtls-$(MBEDTLS_VER) -MBEDTLS_URL = https://github.com/Mbed-TLS/mbedtls/archive/v$(MBEDTLS_VER).tar.gz - -MBEDTLS_OPTS := $(CMAKE_COMMON) -DUSE_SHARED_MBEDTLS_LIBRARY=ON \ - -DUSE_STATIC_MBEDTLS_LIBRARY=OFF -DENABLE_PROGRAMS=OFF -DCMAKE_BUILD_TYPE=Release - -MBEDTLS_OPTS += -DENABLE_ZLIB_SUPPORT=OFF -DMBEDTLS_FATAL_WARNINGS=OFF -ifeq ($(BUILD_OS),WINNT) -MBEDTLS_OPTS += -G"MSYS Makefiles" -endif - -ifneq (,$(findstring $(OS),Linux FreeBSD OpenBSD)) -MBEDTLS_OPTS += -DCMAKE_INSTALL_RPATH="\$$ORIGIN" -endif - -$(SRCCACHE)/$(MBEDTLS_SRC).tar.gz: | $(SRCCACHE) - $(JLDOWNLOAD) $@ $(MBEDTLS_URL) - -$(SRCCACHE)/$(MBEDTLS_SRC)/source-extracted: $(SRCCACHE)/$(MBEDTLS_SRC).tar.gz - $(JLCHECKSUM) $< - mkdir -p $(dir $@) && \ - $(TAR) -C $(dir $@) --strip-components 1 -xf $< - # Force-enable MD4 - sed -i.org "s|//#define MBEDTLS_MD4_C|#define MBEDTLS_MD4_C|" $(SRCCACHE)/$(MBEDTLS_SRC)/include/mbedtls/config.h - touch -c $(SRCCACHE)/$(MBEDTLS_SRC)/CMakeLists.txt # old target - echo 1 > $@ - -checksum-mbedtls: $(SRCCACHE)/$(MBEDTLS_SRC).tar.gz - $(JLCHECKSUM) $< - -$(BUILDDIR)/$(MBEDTLS_SRC)/build-configured: $(SRCCACHE)/$(MBEDTLS_SRC)/source-extracted - mkdir -p $(dir $@) - cd $(dir $@) && \ - $(CMAKE) $(dir $<) $(MBEDTLS_OPTS) - echo 1 > $@ - -$(BUILDDIR)/$(MBEDTLS_SRC)/build-compiled: $(BUILDDIR)/$(MBEDTLS_SRC)/build-configured - $(MAKE) -C $(dir $<) - echo 1 > $@ - -$(BUILDDIR)/$(MBEDTLS_SRC)/build-checked: $(BUILDDIR)/$(MBEDTLS_SRC)/build-compiled -ifeq ($(OS),$(BUILD_OS)) - $(MAKE) -C $(dir $@) test -endif - echo 1 > $@ - -ifeq ($(OS),WINNT) -define MBEDTLS_INSTALL - mkdir -p $2/$$(build_shlibdir) - cp $1/library/libmbedcrypto.$$(SHLIB_EXT) $2/$$(build_shlibdir) - cp $1/library/libmbedx509.$$(SHLIB_EXT) $2/$$(build_shlibdir) - cp $1/library/libmbedtls.$$(SHLIB_EXT) $2/$$(build_shlibdir) -endef -else -define MBEDTLS_INSTALL - $(call MAKE_INSTALL,$1,$2,) -endef -endif -$(eval $(call staged-install, \ - mbedtls,$(MBEDTLS_SRC), \ - MBEDTLS_INSTALL,,, \ - $$(INSTALL_NAME_CMD)libmbedx509.$$(SHLIB_EXT) $$(build_shlibdir)/libmbedx509.$$(SHLIB_EXT) && \ - $$(INSTALL_NAME_CMD)libmbedtls.$$(SHLIB_EXT) $$(build_shlibdir)/libmbedtls.$$(SHLIB_EXT) && \ - $$(INSTALL_NAME_CHANGE_CMD) libmbedx509.1.dylib @rpath/libmbedx509.$$(SHLIB_EXT) $$(build_shlibdir)/libmbedtls.$$(SHLIB_EXT) && \ - $$(INSTALL_NAME_CHANGE_CMD) libmbedcrypto.7.dylib @rpath/libmbedcrypto.$$(SHLIB_EXT) $$(build_shlibdir)/libmbedtls.$$(SHLIB_EXT) && \ - $$(INSTALL_NAME_CHANGE_CMD) libmbedcrypto.7.dylib @rpath/libmbedcrypto.$$(SHLIB_EXT) $$(build_shlibdir)/libmbedx509.$$(SHLIB_EXT) && \ - $$(INSTALL_NAME_CMD)libmbedcrypto.$$(SHLIB_EXT) $$(build_shlibdir)/libmbedcrypto.$$(SHLIB_EXT))) - - -clean-mbedtls: - -rm -f $(BUILDDIR)/$(MBEDTLS_SRC)/build-configured \ - $(BUILDDIR)/$(MBEDTLS_SRC)/build-compiled - -$(MAKE) -C $(BUILDDIR)/$(MBEDTLS_SRC) clean - -distclean-mbedtls: - rm -rf $(SRCCACHE)/$(MBEDTLS_SRC).tar.gz \ - $(SRCCACHE)/$(MBEDTLS_SRC) \ - $(BUILDDIR)/$(MBEDTLS_SRC) - - -get-mbedtls: $(SRCCACHE)/$(MBEDTLS_SRC).tar.gz -extract-mbedtls: $(SRCCACHE)/$(MBEDTLS_SRC)/source-extracted -configure-mbedtls: $(BUILDDIR)/$(MBEDTLS_SRC)/build-configured -compile-mbedtls: $(BUILDDIR)/$(MBEDTLS_SRC)/build-compiled -# tests disabled since they are known to fail -fastcheck-mbedtls: #check-mbedtls -check-mbedtls: $(BUILDDIR)/$(MBEDTLS_SRC)/build-checked - -else # USE_BINARYBUILDER_MBEDTLS - -$(eval $(call bb-install,mbedtls,MBEDTLS,false)) - -endif diff --git a/deps/openssl.mk b/deps/openssl.mk new file mode 100644 index 0000000000000..0ced5737a49a2 --- /dev/null +++ b/deps/openssl.mk @@ -0,0 +1,102 @@ +## OpenSSL ## +include $(SRCDIR)/openssl.version + +ifneq ($(USE_BINARYBUILDER_OPENSSL),1) + +ifeq ($(OS),Darwin) +ifeq ($(APPLE_ARCH),arm64) +OPENSSL_TARGET := darwin64-arm64-cc +else +OPENSSL_TARGET := darwin64-x86_64-cc +endif +else ifeq ($(OS),WINNT) +ifeq ($(ARCH),x86_64) +OPENSSL_TARGET := mingw64 +else +OPENSSL_TARGET := mingw +endif +else ifeq ($(OS),FreeBSD) +ifeq ($(ARCH),aarch64) +OPENSSL_TARGET := BSD-aarch64 +else +OPENSSL_TARGET := BSD-x86_64 +endif +else ifeq ($(OS),Linux) +ifeq ($(ARCH),x86_64) +OPENSSL_TARGET := linux-x86_64 +else ifeq ($(ARCH),i686) +OPENSSL_TARGET := linux-x86 +else ifeq ($(ARCH),arm) +OPENSSL_TARGET := linux-armv4 +else ifeq ($(ARCH),aarch64) +OPENSSL_TARGET := linux-aarch64 +else ifeq ($(ARCH),ppc64le) +OPENSSL_TARGET := linux-ppc64le +else ifeq ($(ARCH),powerpc64le) +OPENSSL_TARGET := linux-ppc64le +endif +else +OPENSSL_TARGET := unknown +endif + +$(SRCCACHE)/openssl-$(OPENSSL_VER).tar.gz: | $(SRCCACHE) + $(JLDOWNLOAD) $@ https://www.openssl.org/source/$(notdir $@) + +$(SRCCACHE)/openssl-$(OPENSSL_VER)/source-extracted: $(SRCCACHE)/openssl-$(OPENSSL_VER).tar.gz + $(JLCHECKSUM) $< + cd $(dir $<) && $(TAR) -zxf $< + touch -c $(SRCCACHE)/openssl-$(OPENSSL_VER)/configure # old target + echo 1 > $@ + +checksum-openssl: $(SRCCACHE)/openssl-$(OPENSSL_VER).tar.gz + $(JLCHECKSUM) $< + +# We cannot use $(CONFIGURE_COMMON) in this step, because openssl's Configure scripts is picky +# and does not like that we pass make variables as arguments, it wants them in the environment +$(BUILDDIR)/openssl-$(OPENSSL_VER)/build-configured: $(SRCCACHE)/openssl-$(OPENSSL_VER)/source-extracted + 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)) $(OPENSSL_TARGET) + echo 1 > $@ + +$(BUILDDIR)/openssl-$(OPENSSL_VER)/build-compiled: $(BUILDDIR)/openssl-$(OPENSSL_VER)/build-configured + $(MAKE) -C $(dir $<) + echo 1 > $@ + +$(BUILDDIR)/openssl-$(OPENSSL_VER)/build-checked: $(BUILDDIR)/openssl-$(OPENSSL_VER)/build-compiled +ifeq ($(OS),$(BUILD_OS)) + $(MAKE) -C $(dir $@) test +endif + echo 1 > $@ + +$(eval $(call staged-install, \ + openssl,openssl-$(OPENSSL_VER), \ + MAKE_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))) + +clean-openssl: + -rm -f $(BUILDDIR)/-openssl-$(OPENSSL_VER)/build-configured $(BUILDDIR)/-openssl-$(OPENSSL_VER)/build-compiled + -$(MAKE) -C $(BUILDDIR)/-openssl-$(OPENSSL_VER) clean + +distclean-openssl: + rm -rf $(SRCCACHE)/-openssl-$(OPENSSL_VER).tar.gz \ + $(SRCCACHE)/-openssl-$(OPENSSL_VER) \ + $(BUILDDIR)/-openssl-$(OPENSSL_VER) + +get-openssl: $(SRCCACHE)/openssl-$(OPENSSL_VER).tar.gz +extract-openssl: $(SRCCACHE)/openssl-$(OPENSSL_VER)/source-extracted +configure-openssl: $(BUILDDIR)/openssl-$(OPENSSL_VER)/build-configured +compile-openssl: $(BUILDDIR)/openssl-$(OPENSSL_VER)/build-compiled +fastcheck-openssl: check-openssl +check-openssl: $(BUILDDIR)/openssl-$(OPENSSL_VER)/build-checked + +else # USE_BINARYBUILDER_OPENSSL + +$(eval $(call bb-install,openssl,OPENSSL,false)) + +endif diff --git a/deps/mbedtls.version b/deps/openssl.version similarity index 50% rename from deps/mbedtls.version rename to deps/openssl.version index ef88b8109f68c..7253e063167db 100644 --- a/deps/mbedtls.version +++ b/deps/openssl.version @@ -1,7 +1,6 @@ # -*- makefile -*- - ## jll artifact -MBEDTLS_JLL_NAME := MbedTLS +OPENSSL_JLL_NAME := OpenSSL ## source build -MBEDTLS_VER := 2.28.6 +OPENSSL_VER := 3.0.15 diff --git a/deps/patches/curl-8.6.0-build.patch b/deps/patches/curl-8.6.0-build.patch deleted file mode 100644 index 827b02808d505..0000000000000 --- a/deps/patches/curl-8.6.0-build.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 5cc2b016c36aaf5a08e2feb7c068fca5bb0a8052 Mon Sep 17 00:00:00 2001 -From: Daniel Stenberg -Date: Mon, 5 Feb 2024 15:22:08 +0100 -Subject: [PATCH] md4: include strdup.h for the memdup proto - -Reported-by: Erik Schnetter -Fixes #12849 -Closes #12863 ---- - lib/md4.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/lib/md4.c b/lib/md4.c -index 067c211e420afd..58dd1166cf924f 100644 ---- a/lib/md4.c -+++ b/lib/md4.c -@@ -28,6 +28,7 @@ - - #include - -+#include "strdup.h" - #include "curl_md4.h" - #include "warnless.h" diff --git a/deps/patches/curl-strdup.patch b/deps/patches/curl-strdup.patch new file mode 100644 index 0000000000000..1cb389fdc4c17 --- /dev/null +++ b/deps/patches/curl-strdup.patch @@ -0,0 +1,10 @@ +--- a/lib/md4.c ++++ b/lib/md4.c +@@ -23,6 +23,7 @@ + ***************************************************************************/ + + #include "curl_setup.h" ++#include "strdup.h" + + #if defined(USE_CURL_NTLM_CORE) + diff --git a/deps/patches/libssh2-mbedtls-size_t.patch b/deps/patches/libssh2-mbedtls-size_t.patch deleted file mode 100644 index 502adf6bdf439..0000000000000 --- a/deps/patches/libssh2-mbedtls-size_t.patch +++ /dev/null @@ -1,105 +0,0 @@ -From 6cad964056848d3d78ccc74600fbff6298baddcb Mon Sep 17 00:00:00 2001 -From: Viktor Szakats -Date: Tue, 30 May 2023 17:28:03 +0000 -Subject: [PATCH 1/1] mbedtls: use more size_t to sync up with crypto.h - -Ref: 5a96f494ee0b00282afb2db2e091246fc5e1774a #846 #879 - -Fixes #1053 -Closes #1054 ---- - src/mbedtls.c | 14 ++++++++------ - src/mbedtls.h | 13 ++++++------- - 2 files changed, 14 insertions(+), 13 deletions(-) - -diff --git a/src/mbedtls.c b/src/mbedtls.c -index e387cdb..cd14a4b 100644 ---- a/src/mbedtls.c -+++ b/src/mbedtls.c -@@ -186,7 +186,7 @@ _libssh2_mbedtls_cipher_dtor(_libssh2_cipher_ctx *ctx) - int - _libssh2_mbedtls_hash_init(mbedtls_md_context_t *ctx, - mbedtls_md_type_t mdtype, -- const unsigned char *key, unsigned long keylen) -+ const unsigned char *key, size_t keylen) - { - const mbedtls_md_info_t *md_info; - int ret, hmac; -@@ -221,7 +221,7 @@ _libssh2_mbedtls_hash_final(mbedtls_md_context_t *ctx, unsigned char *hash) - } - - int --_libssh2_mbedtls_hash(const unsigned char *data, unsigned long datalen, -+_libssh2_mbedtls_hash(const unsigned char *data, size_t datalen, - mbedtls_md_type_t mdtype, unsigned char *hash) - { - const mbedtls_md_info_t *md_info; -@@ -497,8 +497,9 @@ int - _libssh2_mbedtls_rsa_sha2_verify(libssh2_rsa_ctx * rsactx, - size_t hash_len, - const unsigned char *sig, -- unsigned long sig_len, -- const unsigned char *m, unsigned long m_len) -+ size_t sig_len, -+ const unsigned char *m, -+ size_t m_len) - { - int ret; - int md_type; -@@ -548,8 +549,9 @@ _libssh2_mbedtls_rsa_sha2_verify(libssh2_rsa_ctx * rsactx, - int - _libssh2_mbedtls_rsa_sha1_verify(libssh2_rsa_ctx * rsactx, - const unsigned char *sig, -- unsigned long sig_len, -- const unsigned char *m, unsigned long m_len) -+ size_t sig_len, -+ const unsigned char *m, -+ size_t m_len) - { - return _libssh2_mbedtls_rsa_sha2_verify(rsactx, SHA_DIGEST_LENGTH, - sig, sig_len, m, m_len); -diff --git a/src/mbedtls.h b/src/mbedtls.h -index d9592f7..03484da 100644 ---- a/src/mbedtls.h -+++ b/src/mbedtls.h -@@ -478,12 +478,12 @@ _libssh2_mbedtls_cipher_dtor(_libssh2_cipher_ctx *ctx); - int - _libssh2_mbedtls_hash_init(mbedtls_md_context_t *ctx, - mbedtls_md_type_t mdtype, -- const unsigned char *key, unsigned long keylen); -+ const unsigned char *key, size_t keylen); - - int - _libssh2_mbedtls_hash_final(mbedtls_md_context_t *ctx, unsigned char *hash); - int --_libssh2_mbedtls_hash(const unsigned char *data, unsigned long datalen, -+_libssh2_mbedtls_hash(const unsigned char *data, size_t datalen, - mbedtls_md_type_t mdtype, unsigned char *hash); - - _libssh2_bn * -@@ -526,9 +526,8 @@ _libssh2_mbedtls_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, - int - _libssh2_mbedtls_rsa_sha1_verify(libssh2_rsa_ctx *rsa, - const unsigned char *sig, -- unsigned long sig_len, -- const unsigned char *m, -- unsigned long m_len); -+ size_t sig_len, -+ const unsigned char *m, size_t m_len); - int - _libssh2_mbedtls_rsa_sha1_sign(LIBSSH2_SESSION *session, - libssh2_rsa_ctx *rsa, -@@ -540,8 +539,8 @@ int - _libssh2_mbedtls_rsa_sha2_verify(libssh2_rsa_ctx * rsactx, - size_t hash_len, - const unsigned char *sig, -- unsigned long sig_len, -- const unsigned char *m, unsigned long m_len); -+ size_t sig_len, -+ const unsigned char *m, size_t m_len); - int - _libssh2_mbedtls_rsa_sha2_sign(LIBSSH2_SESSION *session, - libssh2_rsa_ctx *rsa, --- -2.31.0 - diff --git a/deps/pcre.version b/deps/pcre.version index 681e97e197f51..78245a5777a0c 100644 --- a/deps/pcre.version +++ b/deps/pcre.version @@ -1,3 +1,4 @@ +# -*- makefile -*- ## jll artifact PCRE_JLL_NAME := PCRE2 diff --git a/doc/Manifest.toml b/doc/Manifest.toml index 490754c4c3068..e91958808828e 100644 --- a/doc/Manifest.toml +++ b/doc/Manifest.toml @@ -115,9 +115,9 @@ uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" version = "0.6.4" [[deps.LibCURL_jll]] -deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "OpenSSL_jll", "Zlib_jll", "nghttp2_jll"] uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" -version = "8.6.0+0" +version = "8.9.1+0" [[deps.LibGit2]] deps = ["LibGit2_jll", "NetworkOptions", "Printf", "SHA"] @@ -125,14 +125,14 @@ uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" version = "1.11.0" [[deps.LibGit2_jll]] -deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "OpenSSL_jll"] uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" -version = "1.8.0+0" +version = "1.8.4+0" [[deps.LibSSH2_jll]] -deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +deps = ["Artifacts", "Libdl", "OpenSSL_jll"] uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" -version = "1.11.0+1" +version = "1.11.3+0" [[deps.Libdl]] uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" @@ -159,11 +159,6 @@ git-tree-sha1 = "465a70f0fc7d443a00dcdc3267a497397b8a3899" uuid = "d0879d2d-cac2-40c8-9cee-1863dc0c7391" version = "0.1.2" -[[deps.MbedTLS_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" -version = "2.28.6+1" - [[deps.Mmap]] uuid = "a63ad114-7e13-5084-954f-fe012c677804" version = "1.11.0" @@ -177,8 +172,7 @@ uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" version = "1.2.0" [[deps.OpenSSL_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "7493f61f55a6cce7325f197443aa80d32554ba10" +deps = ["Artifacts", "Libdl", "NetworkOptions"] uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" version = "3.0.15+1" diff --git a/doc/src/devdocs/build/build.md b/doc/src/devdocs/build/build.md index 966ef3d102d1c..5fe038959edf0 100644 --- a/doc/src/devdocs/build/build.md +++ b/doc/src/devdocs/build/build.md @@ -195,7 +195,7 @@ uses are listed in [`deps/$(libname).version`](https://github.com/JuliaLang/juli - **[libgit2]** — Git linkable library, used by Julia's package manager. - **[curl]** — libcurl provides download and proxy support. - **[libssh2]** — library for SSH transport, used by libgit2 for packages with SSH remotes. -- **[mbedtls]** — library used for cryptography and transport layer security, used by libssh2 +- **[OpenSSL]** — library used for cryptography and transport layer security, used by libgit2 and libssh2. - **[utf8proc]** — a library for processing UTF-8 encoded Unicode strings. - **[LLVM libunwind]** — LLVM's fork of [libunwind], a library that determines the call-chain of a program. - **[ITTAPI]** — Intel's Instrumentation and Tracing Technology and Just-In-Time API. @@ -230,7 +230,7 @@ uses are listed in [`deps/$(libname).version`](https://github.com/JuliaLang/juli [utf8proc]: https://julialang.org/utf8proc/ [libunwind]: https://www.nongnu.org/libunwind [libssh2]: https://www.libssh2.org -[mbedtls]: https://tls.mbed.org/ +[OpenSSL]: https://www.openssl.org/ [pkg-config]: https://www.freedesktop.org/wiki/Software/pkg-config/ [powershell]: https://docs.microsoft.com/en-us/powershell/scripting/wmf/overview [which]: https://carlowood.github.io/which/ diff --git a/julia.spdx.json b/julia.spdx.json index 0e0067f00efb1..0d7ab1df94688 100644 --- a/julia.spdx.json +++ b/julia.spdx.json @@ -231,16 +231,16 @@ "summary": "libssh2 is a library implementing the SSH2 protocol, available under the revised BSD license." }, { - "name": "mbedtls", - "SPDXID": "SPDXRef-mbedtls", - "downloadLocation": "git+https://github.com/ARMmbed/mbedtls.git", + "name": "OpenSSL", + "SPDXID": "SPDXRef-OpenSSL", + "downloadLocation": "git+https://github.com/openssl/openssl.git", "filesAnalyzed": false, - "homepage": "https://tls.mbed.org", - "sourceInfo": "The version in use can be found in the file deps/mbedtls.version", + "homepage": "https://www.openssl.org", + "sourceInfo": "The version in use can be found in the file deps/openssl.version", "licenseConcluded": "Apache-2.0", "licenseDeclared": "Apache-2.0", - "copyrightText": "NOASSERTION", - "summary": "An open source, portable, easy to use, readable and flexible SSL library." + "copyrightText": "Copyright (c) 1998-2024 The OpenSSL Project Authors. Copyright (c) 1995-1998 Eric A. Young, Tim J. Hudson.", + "summary": "OpenSSL is a robust, commercial-grade, full-featured Open Source Toolkit for the TLS (formerly SSL), DTLS and QUIC (currently client side only) protocols.", }, { "name": "mpfr", @@ -560,7 +560,7 @@ "relatedSpdxElement": "SPDXRef-JuliaMain" }, { - "spdxElementId": "SPDXRef-mbedtls", + "spdxElementId": "SPDXRef-OpenSSL", "relationshipType": "BUILD_DEPENDENCY_OF", "relatedSpdxElement": "SPDXRef-JuliaMain" }, diff --git a/stdlib/LibCURL_jll/Project.toml b/stdlib/LibCURL_jll/Project.toml index d17090a1e5c3b..e7dac4c687ab1 100644 --- a/stdlib/LibCURL_jll/Project.toml +++ b/stdlib/LibCURL_jll/Project.toml @@ -1,11 +1,11 @@ name = "LibCURL_jll" uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" -version = "8.6.0+0" +version = "8.9.1+0" [deps] LibSSH2_jll = "29816b5a-b9ab-546f-933c-edad1886dfa8" nghttp2_jll = "8e850ede-7688-5339-a07c-302acd2aaf8d" -MbedTLS_jll = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +OpenSSL_jll = "458c3c95-2e84-50aa-8efc-19380b2a3a95" Zlib_jll = "83775a58-1f1d-513f-b197-d71354ab007a" Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" diff --git a/stdlib/LibCURL_jll/src/LibCURL_jll.jl b/stdlib/LibCURL_jll/src/LibCURL_jll.jl index 3291c97d811cb..5c1c2aa14b23a 100644 --- a/stdlib/LibCURL_jll/src/LibCURL_jll.jl +++ b/stdlib/LibCURL_jll/src/LibCURL_jll.jl @@ -3,7 +3,11 @@ ## dummy stub for https://github.com/JuliaBinaryWrappers/LibCURL_jll.jl baremodule LibCURL_jll -using Base, Libdl, nghttp2_jll +using Base, Libdl, nghttp2_jll, LibSSH2_jll, Zlib_jll +if !(Sys.iswindows() || Sys.isapple()) + # On Windows and macOS we use system SSL/crypto libraries + using OpenSSL_jll +end const PATH_list = String[] const LIBPATH_list = String[] diff --git a/stdlib/LibGit2_jll/Project.toml b/stdlib/LibGit2_jll/Project.toml index ceeb394f26231..6d3a17bb02cf8 100644 --- a/stdlib/LibGit2_jll/Project.toml +++ b/stdlib/LibGit2_jll/Project.toml @@ -1,9 +1,9 @@ name = "LibGit2_jll" uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" -version = "1.8.0+0" +version = "1.8.4+0" [deps] -MbedTLS_jll = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +OpenSSL_jll = "458c3c95-2e84-50aa-8efc-19380b2a3a95" LibSSH2_jll = "29816b5a-b9ab-546f-933c-edad1886dfa8" Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" diff --git a/stdlib/LibGit2_jll/src/LibGit2_jll.jl b/stdlib/LibGit2_jll/src/LibGit2_jll.jl index 15d303dfea6ee..b7ed19a939c5e 100644 --- a/stdlib/LibGit2_jll/src/LibGit2_jll.jl +++ b/stdlib/LibGit2_jll/src/LibGit2_jll.jl @@ -3,7 +3,11 @@ ## dummy stub for https://github.com/JuliaBinaryWrappers/LibGit2_jll.jl baremodule LibGit2_jll -using Base, Libdl, MbedTLS_jll, LibSSH2_jll +using Base, Libdl, LibSSH2_jll +if !(Sys.iswindows() || Sys.isapple()) + # On Windows and macOS we use system SSL/crypto libraries + using OpenSSL_jll +end const PATH_list = String[] const LIBPATH_list = String[] diff --git a/stdlib/LibGit2_jll/test/runtests.jl b/stdlib/LibGit2_jll/test/runtests.jl index 5bc74760b1603..6cf2d2b8a568d 100644 --- a/stdlib/LibGit2_jll/test/runtests.jl +++ b/stdlib/LibGit2_jll/test/runtests.jl @@ -7,5 +7,5 @@ using Test, Libdl, LibGit2_jll minor = Ref{Cint}(0) patch = Ref{Cint}(0) @test ccall((:git_libgit2_version, libgit2), Cint, (Ref{Cint}, Ref{Cint}, Ref{Cint}), major, minor, patch) == 0 - @test VersionNumber(major[], minor[], patch[]) == v"1.8.0" + @test VersionNumber(major[], minor[], patch[]) == v"1.8.4" end diff --git a/stdlib/LibSSH2_jll/Project.toml b/stdlib/LibSSH2_jll/Project.toml index def4fb02e399c..c45d4fc6565b7 100644 --- a/stdlib/LibSSH2_jll/Project.toml +++ b/stdlib/LibSSH2_jll/Project.toml @@ -1,9 +1,9 @@ name = "LibSSH2_jll" uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" -version = "1.11.0+1" +version = "1.11.3+0" [deps] -MbedTLS_jll = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +OpenSSL_jll = "458c3c95-2e84-50aa-8efc-19380b2a3a95" Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" diff --git a/stdlib/LibSSH2_jll/src/LibSSH2_jll.jl b/stdlib/LibSSH2_jll/src/LibSSH2_jll.jl index 351cbe0e3729b..e9392fe34a918 100644 --- a/stdlib/LibSSH2_jll/src/LibSSH2_jll.jl +++ b/stdlib/LibSSH2_jll/src/LibSSH2_jll.jl @@ -3,7 +3,11 @@ ## dummy stub for https://github.com/JuliaBinaryWrappers/LibSSH2_jll.jl baremodule LibSSH2_jll -using Base, Libdl, MbedTLS_jll +using Base, Libdl +if !Sys.iswindows() + # On Windows we use system SSL/crypto libraries + using OpenSSL_jll +end const PATH_list = String[] const LIBPATH_list = String[] diff --git a/stdlib/LibSSH2_jll/test/runtests.jl b/stdlib/LibSSH2_jll/test/runtests.jl index 58cfd9ac024cc..9a05270317752 100644 --- a/stdlib/LibSSH2_jll/test/runtests.jl +++ b/stdlib/LibSSH2_jll/test/runtests.jl @@ -3,6 +3,9 @@ using Test, Libdl, LibSSH2_jll @testset "LibSSH2_jll" begin - # We use a `startswith()` here because when built from source, this returns "1.9.0_DEV" - vn = startswith(unsafe_string(ccall((:libssh2_version, libssh2), Cstring, (Cint,), 0)), "1.9.0") + vn = unsafe_string(ccall((:libssh2_version, libssh2), Cstring, (Cint,), 0)) + # Depending on how LibSSH2_jll was installed (downloaded from + # BinaryBuilder or built from source here), the version number is + # either "1.11.1" or "1.11.1_DEV", respectively. + @test startswith(vn, "1.11.1") end diff --git a/stdlib/Makefile b/stdlib/Makefile index a10503a3566c6..3975f24b7ae3b 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -17,7 +17,7 @@ VERSDIR := v$(shell cut -d. -f1-2 < $(JULIAHOME)/VERSION) DIRS := $(build_datarootdir)/julia/stdlib/$(VERSDIR) $(build_prefix)/manifest/$(VERSDIR) $(foreach dir,$(DIRS),$(eval $(call dir_target,$(dir)))) -JLLS = DSFMT GMP CURL LIBGIT2 LLVM LIBSSH2 LIBUV MBEDTLS MPFR NGHTTP2 \ +JLLS = DSFMT GMP CURL LIBGIT2 LLVM LIBSSH2 LIBUV OPENSSL MPFR NGHTTP2 \ BLASTRAMPOLINE OPENBLAS OPENLIBM P7ZIP PCRE LIBSUITESPARSE ZLIB \ LLVMUNWIND CSL UNWIND LLD diff --git a/stdlib/Manifest.toml b/stdlib/Manifest.toml index 8953aa93ce4b2..8c638415062b2 100644 --- a/stdlib/Manifest.toml +++ b/stdlib/Manifest.toml @@ -91,9 +91,9 @@ uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" version = "0.6.4" [[deps.LibCURL_jll]] -deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "OpenSSL_jll", "Zlib_jll", "nghttp2_jll"] uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" -version = "8.6.0+0" +version = "8.9.1+0" [[deps.LibGit2]] deps = ["LibGit2_jll", "NetworkOptions", "Printf", "SHA"] @@ -101,14 +101,14 @@ uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" version = "1.11.0" [[deps.LibGit2_jll]] -deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "OpenSSL_jll"] uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" -version = "1.8.0+0" +version = "1.8.4+0" [[deps.LibSSH2_jll]] -deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +deps = ["Artifacts", "Libdl", "OpenSSL_jll"] uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" -version = "1.11.0+1" +version = "1.11.3+0" [[deps.LibUV_jll]] deps = ["Artifacts", "Libdl"] @@ -143,11 +143,6 @@ deps = ["Base64", "JuliaSyntaxHighlighting", "StyledStrings"] uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" version = "1.11.0" -[[deps.MbedTLS_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" -version = "2.28.6+1" - [[deps.Mmap]] uuid = "a63ad114-7e13-5084-954f-fe012c677804" version = "1.11.0" @@ -170,6 +165,11 @@ deps = ["Artifacts", "Libdl"] uuid = "05823500-19ac-5b8b-9628-191a04bc5112" version = "0.8.1+3" +[[deps.OpenSSL_jll]] +deps = ["Artifacts", "Libdl", "NetworkOptions"] +uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" +version = "3.0.15+1" + [[deps.PCRE2_jll]] deps = ["Artifacts", "Libdl"] uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15" diff --git a/stdlib/MbedTLS_jll/src/MbedTLS_jll.jl b/stdlib/MbedTLS_jll/src/MbedTLS_jll.jl deleted file mode 100644 index 6367213e2c4ab..0000000000000 --- a/stdlib/MbedTLS_jll/src/MbedTLS_jll.jl +++ /dev/null @@ -1,61 +0,0 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - -## dummy stub for https://github.com/JuliaBinaryWrappers/MbedTLS_jll.jl - -baremodule MbedTLS_jll -using Base, Libdl - -const PATH_list = String[] -const LIBPATH_list = String[] - -export libmbedcrypto, libmbedtls, libmbedx509 - -# These get calculated in __init__() -const PATH = Ref("") -const LIBPATH = Ref("") -artifact_dir::String = "" -libmbedcrypto_handle::Ptr{Cvoid} = C_NULL -libmbedcrypto_path::String = "" -libmbedtls_handle::Ptr{Cvoid} = C_NULL -libmbedtls_path::String = "" -libmbedx509_handle::Ptr{Cvoid} = C_NULL -libmbedx509_path::String = "" - -if Sys.iswindows() - const libmbedcrypto = "libmbedcrypto.dll" - const libmbedtls = "libmbedtls.dll" - const libmbedx509 = "libmbedx509.dll" -elseif Sys.isapple() - const libmbedcrypto = "@rpath/libmbedcrypto.7.dylib" - const libmbedtls = "@rpath/libmbedtls.14.dylib" - const libmbedx509 = "@rpath/libmbedx509.1.dylib" -else - const libmbedcrypto = "libmbedcrypto.so.7" - const libmbedtls = "libmbedtls.so.14" - const libmbedx509 = "libmbedx509.so.1" -end - -function __init__() - global libmbedcrypto_handle = dlopen(libmbedcrypto) - global libmbedcrypto_path = dlpath(libmbedcrypto_handle) - global libmbedtls_handle = dlopen(libmbedtls) - global libmbedtls_path = dlpath(libmbedtls_handle) - global libmbedx509_handle = dlopen(libmbedx509) - global libmbedx509_path = dlpath(libmbedx509_handle) - global artifact_dir = dirname(Sys.BINDIR) - LIBPATH[] = dirname(libmbedtls_path) - push!(LIBPATH_list, LIBPATH[]) -end - -# JLLWrappers API compatibility shims. Note that not all of these will really make sense. -# For instance, `find_artifact_dir()` won't actually be the artifact directory, because -# there isn't one. It instead returns the overall Julia prefix. -is_available() = true -find_artifact_dir() = artifact_dir -dev_jll() = error("stdlib JLLs cannot be dev'ed") -best_wrapper = nothing -get_libmbedcrypto_path() =libmbedcrypto_path -get_libmbedtls_path() = libmbedtls_path -get_libmbedx509_path() = libmbedx509_path - -end # module MbedTLS_jll diff --git a/stdlib/MbedTLS_jll/test/runtests.jl b/stdlib/MbedTLS_jll/test/runtests.jl deleted file mode 100644 index 5813a813a1e1f..0000000000000 --- a/stdlib/MbedTLS_jll/test/runtests.jl +++ /dev/null @@ -1,10 +0,0 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - -using Test, Libdl, MbedTLS_jll - -@testset "MbedTLS_jll" begin - vstr = zeros(UInt8, 32) - ccall((:mbedtls_version_get_string, libmbedcrypto), Cvoid, (Ref{UInt8},), vstr) - vn = VersionNumber(unsafe_string(pointer(vstr))) - @test vn == v"2.28.6" -end diff --git a/stdlib/MbedTLS_jll/Project.toml b/stdlib/OpenSSL_jll/Project.toml similarity index 66% rename from stdlib/MbedTLS_jll/Project.toml rename to stdlib/OpenSSL_jll/Project.toml index 61f3ea0d8b4dc..df00f99b205c9 100644 --- a/stdlib/MbedTLS_jll/Project.toml +++ b/stdlib/OpenSSL_jll/Project.toml @@ -1,13 +1,13 @@ -name = "MbedTLS_jll" -uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" -version = "2.28.6+1" +name = "OpenSSL_jll" +uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" +version = "3.0.15+1" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" [compat] -julia = "1.8" +julia = "1.6" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/stdlib/OpenSSL_jll/src/OpenSSL_jll.jl b/stdlib/OpenSSL_jll/src/OpenSSL_jll.jl new file mode 100644 index 0000000000000..bba9a0a299de9 --- /dev/null +++ b/stdlib/OpenSSL_jll/src/OpenSSL_jll.jl @@ -0,0 +1,58 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +## dummy stub for https://github.com/JuliaBinaryWrappers/OpenSSL_jll.jl + +baremodule OpenSSL_jll +using Base, Libdl, Base.BinaryPlatforms + +const PATH_list = String[] +const LIBPATH_list = String[] + +export libcrypto, libssl + +# These get calculated in __init__() +const PATH = Ref("") +const LIBPATH = Ref("") +artifact_dir::String = "" +libcrypto_handle::Ptr{Cvoid} = C_NULL +libcrypto_path::String = "" +libssl_handle::Ptr{Cvoid} = C_NULL +libssl_path::String = "" + +if Sys.iswindows() + if arch(HostPlatform()) == "x86_64" + const libcrypto = "libcrypto-3-x64.dll" + const libssl = "libssl-3-x64.dll" + else + const libcrypto = "libcrypto-3.dll" + const libssl = "libssl-3.dll" + end +elseif Sys.isapple() + const libcrypto = "@rpath/libcrypto.3.dylib" + const libssl = "@rpath/libssl.3.dylib" +else + const libcrypto = "libcrypto.so.3" + const libssl = "libssl.so.3" +end + +function __init__() + global libcrypto_handle = dlopen(libcrypto) + global libcrypto_path = dlpath(libcrypto_handle) + global libssl_handle = dlopen(libssl) + global libssl_path = dlpath(libssl_handle) + global artifact_dir = dirname(Sys.BINDIR) + LIBPATH[] = dirname(libssl_path) + push!(LIBPATH_list, LIBPATH[]) +end + +# JLLWrappers API compatibility shims. Note that not all of these will really make sense. +# For instance, `find_artifact_dir()` won't actually be the artifact directory, because +# there isn't one. It instead returns the overall Julia prefix. +is_available() = true +find_artifact_dir() = artifact_dir +dev_jll() = error("stdlib JLLs cannot be dev'ed") +best_wrapper = nothing +get_libcrypto_path() = libcrypto_path +get_libssl_path() = libssl_path + +end # module OpenSSL_jll diff --git a/stdlib/OpenSSL_jll/test/runtests.jl b/stdlib/OpenSSL_jll/test/runtests.jl new file mode 100644 index 0000000000000..35431d04bfcac --- /dev/null +++ b/stdlib/OpenSSL_jll/test/runtests.jl @@ -0,0 +1,10 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +using Test, Libdl, OpenSSL_jll + +@testset "OpenSSL_jll" begin + major = ccall((:OPENSSL_version_major, libcrypto), Cuint, ()) + minor = ccall((:OPENSSL_version_minor, libcrypto), Cuint, ()) + patch = ccall((:OPENSSL_version_patch, libcrypto), Cuint, ()) + @test VersionNumber(major, minor, patch) == v"3.0.15" +end diff --git a/stdlib/Project.toml b/stdlib/Project.toml index cc7ba99dd4e4f..92996cf017d0d 100644 --- a/stdlib/Project.toml +++ b/stdlib/Project.toml @@ -28,12 +28,12 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" MPFR_jll = "3a97d323-0669-5f0c-9066-3539efd106a3" Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" -MbedTLS_jll = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" Mmap = "a63ad114-7e13-5084-954f-fe012c677804" MozillaCACerts_jll = "14a3606d-f60d-562e-9121-12d972cd8159" NetworkOptions = "ca575930-c2e3-43a9-ace4-1e988b2c1908" OpenBLAS_jll = "4536629a-c528-5b80-bd46-f80d51c5b363" OpenLibm_jll = "05823500-19ac-5b8b-9628-191a04bc5112" +OpenSSL_jll = "458c3c95-2e84-50aa-8efc-19380b2a3a95" PCRE2_jll = "efcefdf7-47ab-520b-bdef-62a2eaa19f15" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" diff --git a/stdlib/stdlib.mk b/stdlib/stdlib.mk index b79059d3368b1..006b7a276a3b3 100644 --- a/stdlib/stdlib.mk +++ b/stdlib/stdlib.mk @@ -8,8 +8,8 @@ INDEPENDENT_STDLIBS := \ 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 \ - LibCURL_jll LibSSH2_jll LibGit2_jll nghttp2_jll MozillaCACerts_jll MbedTLS_jll \ - MPFR_jll OpenLibm_jll PCRE2_jll p7zip_jll Zlib_jll + LibCURL_jll LibSSH2_jll LibGit2_jll nghttp2_jll MozillaCACerts_jll \ + MPFR_jll OpenLibm_jll OpenSSL_jll PCRE2_jll p7zip_jll Zlib_jll STDLIBS := $(STDLIBS_WITHIN_SYSIMG) $(INDEPENDENT_STDLIBS) VERSDIR := v$(shell cut -d. -f1-2 < $(JULIAHOME)/VERSION) From 9a20417b767c02554db3a1d67d7cc3b101cdf112 Mon Sep 17 00:00:00 2001 From: Neven Sajko <4944410+nsajko@users.noreply.github.com> Date: Sun, 5 Jan 2025 03:39:52 +0100 Subject: [PATCH 134/342] Compiler: fix `tmerge(Const(s), Const(t))` st. `(s !== t) && (s == t)` (#56915) Updates #56913 --- Compiler/src/typelimits.jl | 5 +---- Compiler/test/inference.jl | 7 +++++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Compiler/src/typelimits.jl b/Compiler/src/typelimits.jl index e420db030715b..11245fbaee9b0 100644 --- a/Compiler/src/typelimits.jl +++ b/Compiler/src/typelimits.jl @@ -587,7 +587,7 @@ end @nospecializeinfer function tmerge_partial_struct(𝕃::PartialsLattice, @nospecialize(typea), @nospecialize(typeb)) aty = widenconst(typea) bty = widenconst(typeb) - if aty === bty + if aty === bty && !isType(aty) if typea isa PartialStruct if typeb isa PartialStruct nflds = min(length(typea.fields), length(typeb.fields)) @@ -605,9 +605,6 @@ end for i = 1:nflds ai = getfield_tfunc(𝕃, typea, Const(i)) bi = getfield_tfunc(𝕃, typeb, Const(i)) - # N.B.: We're assuming here that !isType(aty), because that case - # only arises when typea === typeb, which should have been caught - # before calling this. ft = fieldtype(aty, i) if is_lattice_equal(𝕃, ai, bi) || is_lattice_equal(𝕃, ai, ft) # Since ai===bi, the given type has no restrictions on complexity. diff --git a/Compiler/test/inference.jl b/Compiler/test/inference.jl index 9301a2809daf3..21d29c376bb27 100644 --- a/Compiler/test/inference.jl +++ b/Compiler/test/inference.jl @@ -2295,6 +2295,7 @@ let 𝕃ᵢ = InferenceLattice(MustAliasesLattice(BaseInferenceLattice.instance) @test tmerge(MustAlias(2, AliasableField{Any}, 1, Int), Const(nothing)) === Union{Int,Nothing} @test tmerge(Const(nothing), MustAlias(2, AliasableField{Any}, 1, Any)) === Any @test tmerge(Const(nothing), MustAlias(2, AliasableField{Any}, 1, Int)) === Union{Int,Nothing} + tmerge(Const(AbstractVector{<:Any}), Const(AbstractVector{T} where {T})) # issue #56913 @test isa_tfunc(MustAlias(2, AliasableField{Any}, 1, Bool), Const(Bool)) === Const(true) @test isa_tfunc(MustAlias(2, AliasableField{Any}, 1, Bool), Type{Bool}) === Const(true) @test isa_tfunc(MustAlias(2, AliasableField{Any}, 1, Int), Type{Bool}) === Const(false) @@ -2302,6 +2303,12 @@ let 𝕃ᵢ = InferenceLattice(MustAliasesLattice(BaseInferenceLattice.instance) @test ifelse_tfunc(MustAlias(2, AliasableField{Any}, 1, Int), Int, Int) === Union{} end +@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}}) + @test Type{AbstractVector} == Base.infer_return_type(Base.promote_typeof, Tuple{R, R, Vector{Any}, R, Vararg{R}}) +end + maybeget_mustalias_tmerge(x::AliasableField) = x.f maybeget_mustalias_tmerge(x) = x @test Base.return_types((Union{Nothing,AliasableField{Any}},); interp=MustAliasInterpreter()) do x From 468d5c2b07a0e065541e074cfcdf224029a61940 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Sat, 4 Jan 2025 23:13:23 -0500 Subject: [PATCH 135/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?Downloads=20stdlib=20from=20afd04be=20to=20e692e77=20(#56953)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: giordano <765740+giordano@users.noreply.github.com> --- .../md5 | 1 - .../sha512 | 1 - .../md5 | 1 + .../sha512 | 1 + stdlib/Downloads.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/Downloads-afd04be8aa94204c075c8aec83fca040ebb4ff98.tar.gz/md5 delete mode 100644 deps/checksums/Downloads-afd04be8aa94204c075c8aec83fca040ebb4ff98.tar.gz/sha512 create mode 100644 deps/checksums/Downloads-e692e77fb5427bf3c6e81514b323c39a88217eec.tar.gz/md5 create mode 100644 deps/checksums/Downloads-e692e77fb5427bf3c6e81514b323c39a88217eec.tar.gz/sha512 diff --git a/deps/checksums/Downloads-afd04be8aa94204c075c8aec83fca040ebb4ff98.tar.gz/md5 b/deps/checksums/Downloads-afd04be8aa94204c075c8aec83fca040ebb4ff98.tar.gz/md5 deleted file mode 100644 index f0d72ab470aeb..0000000000000 --- a/deps/checksums/Downloads-afd04be8aa94204c075c8aec83fca040ebb4ff98.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -9dbfa6c0a76d20b2ca8de844d08f3af4 diff --git a/deps/checksums/Downloads-afd04be8aa94204c075c8aec83fca040ebb4ff98.tar.gz/sha512 b/deps/checksums/Downloads-afd04be8aa94204c075c8aec83fca040ebb4ff98.tar.gz/sha512 deleted file mode 100644 index 7abbb06818d75..0000000000000 --- a/deps/checksums/Downloads-afd04be8aa94204c075c8aec83fca040ebb4ff98.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -f5d2469419f4a083f84c1f23e6e528f4115804e45bdfdbd897110bb346aaa70afc57c24f9166ae20fb4305c1d40f5a77de4cfed7b69aef93f09d0d4eff183e3d diff --git a/deps/checksums/Downloads-e692e77fb5427bf3c6e81514b323c39a88217eec.tar.gz/md5 b/deps/checksums/Downloads-e692e77fb5427bf3c6e81514b323c39a88217eec.tar.gz/md5 new file mode 100644 index 0000000000000..221a62b1cf231 --- /dev/null +++ b/deps/checksums/Downloads-e692e77fb5427bf3c6e81514b323c39a88217eec.tar.gz/md5 @@ -0,0 +1 @@ +cdaea923f7fa855409e8456159251f54 diff --git a/deps/checksums/Downloads-e692e77fb5427bf3c6e81514b323c39a88217eec.tar.gz/sha512 b/deps/checksums/Downloads-e692e77fb5427bf3c6e81514b323c39a88217eec.tar.gz/sha512 new file mode 100644 index 0000000000000..b537ef2e9e1f6 --- /dev/null +++ b/deps/checksums/Downloads-e692e77fb5427bf3c6e81514b323c39a88217eec.tar.gz/sha512 @@ -0,0 +1 @@ +e893fbe079a433c3038b79c4c2998d1ae9abaf92ff74152820a67e97ffee6f7f052085a7108410cbb1a3bd8cc6670736b0827c8b0608cc31941251dd6500d36a diff --git a/stdlib/Downloads.version b/stdlib/Downloads.version index 3d1da64bdfe11..40004d8337091 100644 --- a/stdlib/Downloads.version +++ b/stdlib/Downloads.version @@ -1,4 +1,4 @@ DOWNLOADS_BRANCH = master -DOWNLOADS_SHA1 = afd04be8aa94204c075c8aec83fca040ebb4ff98 +DOWNLOADS_SHA1 = e692e77fb5427bf3c6e81514b323c39a88217eec DOWNLOADS_GIT_URL := https://github.com/JuliaLang/Downloads.jl.git DOWNLOADS_TAR_URL = https://api.github.com/repos/JuliaLang/Downloads.jl/tarball/$1 From d848e2e9dafbdaf74000da5e109e2af8f49a4acd Mon Sep 17 00:00:00 2001 From: FX Coudert Date: Sun, 5 Jan 2025 11:24:25 +0100 Subject: [PATCH 136/342] Curl 8.11.1 and nghttp2 1.64.0 (#56951) Trying to update these two deps: Curl 8.11.1 and nghttp2 1.64.0 --- deps/checksums/curl | 70 ++++++++++++++-------------- deps/checksums/nghttp2 | 72 ++++++++++++++--------------- deps/curl.version | 5 +- deps/nghttp2.version | 2 +- stdlib/LibCURL_jll/Project.toml | 2 +- stdlib/Manifest.toml | 4 +- stdlib/nghttp2_jll/Project.toml | 2 +- stdlib/nghttp2_jll/test/runtests.jl | 2 +- 8 files changed, 79 insertions(+), 80 deletions(-) diff --git a/deps/checksums/curl b/deps/checksums/curl index f96fe5f1a15e3..5331e54d30d4a 100644 --- a/deps/checksums/curl +++ b/deps/checksums/curl @@ -1,36 +1,38 @@ LibCURL-a65b64f6eabc932f63c2c0a4a5fb5d75f3e688d0.tar.gz/md5/e8c53aa3fb963c80921787d5d565eb2c LibCURL-a65b64f6eabc932f63c2c0a4a5fb5d75f3e688d0.tar.gz/sha512/8e442ea834299df9c02acb87226c121395ad8e550025ac5ee1103df09c6ff43817e9e48dd1bcbc92c80331ef3ddff531962430269115179acbec2bab2de5b011 -LibCURL.v8.9.1+0.aarch64-apple-darwin.tar.gz/md5/8a1929a2dc1a6682ff9ff7f66cda25f4 -LibCURL.v8.9.1+0.aarch64-apple-darwin.tar.gz/sha512/e491542103f6e1a34caf96cfae7f31ba12588c50517ca2c974be907c664cd873b554009e538fd7db7d31ebe46d68330da3fcf14ffe9fcbbda73b6d1919ea966d -LibCURL.v8.9.1+0.aarch64-linux-gnu.tar.gz/md5/eb5f8fdb31189047527af3b98c6959b0 -LibCURL.v8.9.1+0.aarch64-linux-gnu.tar.gz/sha512/6fd5e489f63edec29efd20165b0888e86d0b53a19d352bebbdb0afc00a1f6478eec524143797307ab7a799cf924d2c76bd5ece9d9fd8fdc9346ba3c739a1fe83 -LibCURL.v8.9.1+0.aarch64-linux-musl.tar.gz/md5/6202ec4890ae02cf2a7999fe5e24d77c -LibCURL.v8.9.1+0.aarch64-linux-musl.tar.gz/sha512/caf00ed30075d000efc638586520dac2e22f8ba04924d42dbe27bc1bd715aa7b2dbede062de296fc080a33d0aead6099a870f38d017a69693097413056629b1b -LibCURL.v8.9.1+0.armv6l-linux-gnueabihf.tar.gz/md5/5bd474f4e09b4fe7658b2497861a580e -LibCURL.v8.9.1+0.armv6l-linux-gnueabihf.tar.gz/sha512/ff6b58cfff9a7433d9191766e3fe652f0b5b10fbc6da8fb03ca04ed44a46a36158fb7d8096932617011389fb5505844d5c4ef2c29bcf1c8da811287def4e91f9 -LibCURL.v8.9.1+0.armv6l-linux-musleabihf.tar.gz/md5/8f071c5389ba1df7d4d22683f068b6de -LibCURL.v8.9.1+0.armv6l-linux-musleabihf.tar.gz/sha512/b8be3a8df717d0921ec225ce87dd9cd4fc9e13fd1f39c4906d02f30dcae24971f1798b017f3af346c603030cfa80869c117cdb5dff8e7762ee2e72c4027ef7a1 -LibCURL.v8.9.1+0.armv7l-linux-gnueabihf.tar.gz/md5/120e51d99907522150d79c44812decfa -LibCURL.v8.9.1+0.armv7l-linux-gnueabihf.tar.gz/sha512/b512a75cb3185904661375760250132c58678f43002a9ba0608de60dcca6afc1e2eef567a9f42f2d3dfa0be1ff01cb15f68980adebada220728521b13367b77d -LibCURL.v8.9.1+0.armv7l-linux-musleabihf.tar.gz/md5/e8a59894ccb325fb424a3e5861c854f7 -LibCURL.v8.9.1+0.armv7l-linux-musleabihf.tar.gz/sha512/3bb4afef9b7be04f17a4e2e20e020bcfbf5fb4a36bc699a90337d76a108f75600fff49c877652956431946a948f42054497621593f1c6c593a537fe08ceda1c2 -LibCURL.v8.9.1+0.i686-linux-gnu.tar.gz/md5/1034cd95f6369cd994979c8653786639 -LibCURL.v8.9.1+0.i686-linux-gnu.tar.gz/sha512/5f7f755d17770dc8b995f2bbc817fda96db23da751439e5929526482b8f854f4ed73c6e930df0dd1657756f8951edd4f3c41be80f3b812a793678b6ededd855e -LibCURL.v8.9.1+0.i686-linux-musl.tar.gz/md5/ad4a4cf21d15b48ce27275af67079075 -LibCURL.v8.9.1+0.i686-linux-musl.tar.gz/sha512/9e5c6d0d91d966154e3ecd8cd71c9b31841debc036b847dec684dcf3189ca617cd0bca4b73cf9440e55133e36ebafb02730c598c133dc33a9e164ba43c689506 -LibCURL.v8.9.1+0.i686-w64-mingw32.tar.gz/md5/300a71d7ba8c858f9ed85d761dfeef32 -LibCURL.v8.9.1+0.i686-w64-mingw32.tar.gz/sha512/a916f60a7c8ed41a56686d1145be73dc0162349ce1d098dbd12441fcc97a3f0bd4c5750d3e58e4cfe7e9ba7e0d3817bf592bd99a946cd6b45b296636c3220766 -LibCURL.v8.9.1+0.powerpc64le-linux-gnu.tar.gz/md5/0657e472b888b089c448695d200346d0 -LibCURL.v8.9.1+0.powerpc64le-linux-gnu.tar.gz/sha512/a81f25260c4204a069a87463d9ef58169d9286125daaf23b4e2295fc8108ef536049fd07248ca3f1caa2aac3eb0b376d2c64281d0302dfea6f0a782dfb3988fd -LibCURL.v8.9.1+0.x86_64-apple-darwin.tar.gz/md5/3638b3365e97dd516d1eaa6f03892fe6 -LibCURL.v8.9.1+0.x86_64-apple-darwin.tar.gz/sha512/4e6c76fde045134c869dbaab52b28dc809541209077aa54d2e870b9aa29f3d43a8040f3194e06e519642348fc4de6aa49fcb04880a4707bae4e55206ac70f01b -LibCURL.v8.9.1+0.x86_64-linux-gnu.tar.gz/md5/e48dd6fe9078600bf6db0fdd6f986b76 -LibCURL.v8.9.1+0.x86_64-linux-gnu.tar.gz/sha512/e6c33bdac80c9463d6d067f77cf7f2f595258e5f292fd133b5f5782e678004bed925c8bcbba1c708f2f535a0db7a0527fce9acef5250469a958ee11dff533c8f -LibCURL.v8.9.1+0.x86_64-linux-musl.tar.gz/md5/2d219b4c0ba83dfce64b93c1e4d6ef24 -LibCURL.v8.9.1+0.x86_64-linux-musl.tar.gz/sha512/5fb8bb08d357ea3b7c9e417838bf37198ae673185c4f4564ecd1a06ce0e72c4c804909e8c6ffeafefb3460ad151308f662b3128ab5d4149f035de0fa9890506b -LibCURL.v8.9.1+0.x86_64-unknown-freebsd.tar.gz/md5/66e715f6934f360398e527f534f6f5c5 -LibCURL.v8.9.1+0.x86_64-unknown-freebsd.tar.gz/sha512/64334fb156c15b7aa56e4ef81b9d81f93be6ee4c7a61d921bb09cb9951eeb3309197ac89150bde0187e7cecd6e53626e91b7bba14f0daaa0ba472563541c9ff1 -LibCURL.v8.9.1+0.x86_64-w64-mingw32.tar.gz/md5/672ffcacf3e1bc72d7cf244af0cbc5a2 -LibCURL.v8.9.1+0.x86_64-w64-mingw32.tar.gz/sha512/ea265d172a242026cbf7e6b991904aa403a7f491a1c55f91b444776782ad0ca2fdf4882735d1ed04e90df8b38a754f4d0181ad8c17f5fbd75b40a6b908ebbd36 -curl-8.9.1.tar.bz2/md5/8feb255a16590f2465926d7627f86583 -curl-8.9.1.tar.bz2/sha512/27e4b36550b676c42d1a533ade5b2b35ac7ca95e1998bd05cc34b5dfa3bdc9c0539ec7000481230b6431baa549e64da1b46b39d6ba1f112e37458d7b35948c2e +LibCURL.v8.11.1+1.aarch64-apple-darwin.tar.gz/md5/890c65523227b4352344b78575cd4c5c +LibCURL.v8.11.1+1.aarch64-apple-darwin.tar.gz/sha512/fae539243adc805d8da0ac88cf67901ff1f12ae94e40293dc6a7e17072f8c0cb9f0a54b7e324bd52ad9361b764c8bc88728ff4495e0cd6dbf1eb93d2bae8994b +LibCURL.v8.11.1+1.aarch64-linux-gnu.tar.gz/md5/bf937fb6a8ea8a82b732821f3652641c +LibCURL.v8.11.1+1.aarch64-linux-gnu.tar.gz/sha512/230c9983e4c7810d3eee1a5eff7e8b8c44f76db7af8a8312a608609f87bc8a56031c337c06af00a536c10ed33725200aa137c3153ef6dcf6575cc7c350b3b461 +LibCURL.v8.11.1+1.aarch64-linux-musl.tar.gz/md5/b40ea4266dc48a1fbfa016fb8d0ca987 +LibCURL.v8.11.1+1.aarch64-linux-musl.tar.gz/sha512/032d6208ebe226da90d0ef1f1f2d20580fd4e37db68146d1e836a9be4c1fc5f7890f1b808337ca41f46a07a833b55f06f09a4a164f26d0824a649ea40b30233f +LibCURL.v8.11.1+1.aarch64-unknown-freebsd.tar.gz/md5/69097390c0bd3a32969e47608f24363f +LibCURL.v8.11.1+1.aarch64-unknown-freebsd.tar.gz/sha512/391019370a9c122e6425a3097edafe0980dc2077be015919e7914aa781ba10060e3af9ee1fa881d8536d0ca57783d0616a1b5735e2ae7e06ea4edfaee2994120 +LibCURL.v8.11.1+1.armv6l-linux-gnueabihf.tar.gz/md5/bc4ab567f8cc4cd88b2239123d103113 +LibCURL.v8.11.1+1.armv6l-linux-gnueabihf.tar.gz/sha512/0ecbf2380852744815a8f7e99e7c276c342f847907eb7b0d256905ba854ee59d37f83456fcdc8931dc39dbaed58f0949205b80d23e43e2b59195d18a539d4047 +LibCURL.v8.11.1+1.armv6l-linux-musleabihf.tar.gz/md5/18c896c544f02f7f2b976c03fc3772f1 +LibCURL.v8.11.1+1.armv6l-linux-musleabihf.tar.gz/sha512/e9a73670f1c3638c3a886055b32df5baadc41aad9829cfa0d4e05acd46d2d012464114ed6fd1e3d182a4adc266c1da97e9a683c7ba69e93f61592acf8567e336 +LibCURL.v8.11.1+1.armv7l-linux-gnueabihf.tar.gz/md5/4672f9d67ff357a2eda6f77d8f470659 +LibCURL.v8.11.1+1.armv7l-linux-gnueabihf.tar.gz/sha512/a2f2dc8d8e10c652a324a4da3d2337d2886626e1c417c68efbcfcefa443cb3ec81b52f2a212c4a7dbd6a5ae920e54d1bfdc02b68c2607d09784206cd4d11ffb0 +LibCURL.v8.11.1+1.armv7l-linux-musleabihf.tar.gz/md5/49d297563fd44a03f88f67bb7ea2a0be +LibCURL.v8.11.1+1.armv7l-linux-musleabihf.tar.gz/sha512/5cc3902571f04c96be38de53b5320876a3e7e54934090ff2a80304a7ca59a361ed9f3f328c3e3c06ef33550d221a8243e924b7ea49792753f839c12aceb1e979 +LibCURL.v8.11.1+1.i686-linux-gnu.tar.gz/md5/f05a86574278ecf7802edeffe1fee9ac +LibCURL.v8.11.1+1.i686-linux-gnu.tar.gz/sha512/e493b5836022a6280f21237fef423034a9701097cb271683e81d4b4e487a6289080d00016fbaaa8bddeb004d44626a0076fa7832835fe7f58b60af6798223f89 +LibCURL.v8.11.1+1.i686-linux-musl.tar.gz/md5/03340412ba27f231dbf2de58a1af871f +LibCURL.v8.11.1+1.i686-linux-musl.tar.gz/sha512/541fbdd5570432832d3835038b41df73aac8e0e7bc03f41c696dc12a57bd4784b4da1f485264fd1fba263fe9e520a7dbb0ef9a365275efc30dfc361ceab252f3 +LibCURL.v8.11.1+1.i686-w64-mingw32.tar.gz/md5/5f2071282d572bbb53dfcfb16d0d9608 +LibCURL.v8.11.1+1.i686-w64-mingw32.tar.gz/sha512/e4d6fbd518055e8f2a71b89ee9a33728e6e076729adeafc358fc40f47d032b739363c9b57df5bfb3c43244f7b833afc76ae255e70bcf43b81262d74278532a22 +LibCURL.v8.11.1+1.powerpc64le-linux-gnu.tar.gz/md5/806ee9b51c2bffd798c1682867a7a2a0 +LibCURL.v8.11.1+1.powerpc64le-linux-gnu.tar.gz/sha512/20ae5f47ad24e1fba8ecdc3a81aa81acb5c3c224041f12f8be48f9a0abd5ce44117b096a59fc8f861b6f8c6ad9e4177e3a3ba3e2dbecb2078d4bab19bdd4d239 +LibCURL.v8.11.1+1.x86_64-apple-darwin.tar.gz/md5/56cf7cf4ea22123e516843a5751eea17 +LibCURL.v8.11.1+1.x86_64-apple-darwin.tar.gz/sha512/5ae5569ade42cdf0a1aa8acfda7d1dd3df30d498637f83e93bd9f8be883ae777e789b417be24df83e42ebe32fb67cc328bedac3dc231d3569f585641175ed257 +LibCURL.v8.11.1+1.x86_64-linux-gnu.tar.gz/md5/a4a733fe879693e83e1f05b6ef742ea6 +LibCURL.v8.11.1+1.x86_64-linux-gnu.tar.gz/sha512/2767f49d4a528080a5c7fcdecd8374dd5498c5b1e0d65f58d027f6a9138cd00203732e5da1806b689efbaacb1ee905a6839a09eab35f0174279af314a34fca81 +LibCURL.v8.11.1+1.x86_64-linux-musl.tar.gz/md5/837a64073c3d8fd115cadf4af1b19235 +LibCURL.v8.11.1+1.x86_64-linux-musl.tar.gz/sha512/cf0559b65c213889ab0bad388ca6dc1699891e5cd2c5c34faf80cd60404b5f363eaa624d425fd463407d35c5cfd814c1a9964a2b3b638fa7e7a0a2919980ba8c +LibCURL.v8.11.1+1.x86_64-unknown-freebsd.tar.gz/md5/22726eb8caed9b279e6cddbfa328f2c6 +LibCURL.v8.11.1+1.x86_64-unknown-freebsd.tar.gz/sha512/b9e304575bb0e3241f938c545a91cc5b722e8dfc53d6ad270ea75b8fb05655ae8a03e5f844f5b8a75a84133d0883369bc6c46f0805be37ee840f2f1168994c37 +LibCURL.v8.11.1+1.x86_64-w64-mingw32.tar.gz/md5/aa5ce49a63d216776ef9fc11b6b3b012 +LibCURL.v8.11.1+1.x86_64-w64-mingw32.tar.gz/sha512/4e7fe5ff82ca9bafbaca476aa51273ee9590058350c889a6dd8a0eecaa024d19f0a26dd7078808d08dfdf2f5751daec51e88dc88253a4638274edb63ae93fd3c +curl-8.11.1.tar.bz2/md5/31dc730e6fff880a6ba92bdacead9d38 +curl-8.11.1.tar.bz2/sha512/30041e15b919684c46b6b3853950cba22e6fbc21157b1f682097277d2b20066ba71e51eb5d2c34bbd81b8bf4c2791255d6492ee21d49f606d71f66e211a6adde diff --git a/deps/checksums/nghttp2 b/deps/checksums/nghttp2 index e552dfe9329b0..6b4752d4e5527 100644 --- a/deps/checksums/nghttp2 +++ b/deps/checksums/nghttp2 @@ -1,36 +1,36 @@ -nghttp2-1.63.0.tar.bz2/md5/c29228929c3c323ecd0eae172f1eb9d5 -nghttp2-1.63.0.tar.bz2/sha512/a328b4642c6ca4395adfcaaf4e6eb6dbd39fa7bd86f872a76260af59a5a830e0ff5ad015865d6bc00e0baa8e4d0d9a67b4b97e9d78e5e05d1c53522364e5e235 -nghttp2.v1.63.0+1.aarch64-apple-darwin.tar.gz/md5/d11717d2fa4d04a374c55b86c790366a -nghttp2.v1.63.0+1.aarch64-apple-darwin.tar.gz/sha512/10dd24435818b66c92399941d3ea3280451f039e59112a866f973cdfe5602136e366f2bdb4638a1264f48fde737be4e50a49e44934971b4c69284377f4d9cf53 -nghttp2.v1.63.0+1.aarch64-linux-gnu.tar.gz/md5/5ebe2395d0d31b6481a4218468ec82a4 -nghttp2.v1.63.0+1.aarch64-linux-gnu.tar.gz/sha512/e7aff0eaa99be3b5e8539f160e1e5cf53bf1efa6b5f07d625796353a36ef12473946562731cedd570205229d263f81fd692b222a01297b09c89ce0e49edeff7a -nghttp2.v1.63.0+1.aarch64-linux-musl.tar.gz/md5/95c492eeca62b92baf8f8fa11a1da41f -nghttp2.v1.63.0+1.aarch64-linux-musl.tar.gz/sha512/10c0b3f560b1ff7ca9fe5cbc3340ec7789ecdeddf5d857d5c1245d1519074bd105f68c29714f36c8c9b688c5bf42133b30cbabed450410b79bb4f1f1d1474ef6 -nghttp2.v1.63.0+1.aarch64-unknown-freebsd.tar.gz/md5/c6fe5cea3d1386532f75f512e3641a7c -nghttp2.v1.63.0+1.aarch64-unknown-freebsd.tar.gz/sha512/20437e066e13b770f014e30b57830237bf38c3ecc56e716208c5103a7c242fec6cedcf78e641004891afa40ce945bfe1319d11aab4810a76ceeb6ff10373984c -nghttp2.v1.63.0+1.armv6l-linux-gnueabihf.tar.gz/md5/995dbd522109b882eaf7bedec84e8372 -nghttp2.v1.63.0+1.armv6l-linux-gnueabihf.tar.gz/sha512/faf7ca13cd1d3050a5c693c61a5e92b560e1c0c2e30833162cc7aeefcd31c018b2015dbdbf543f38ddec2aefe78927af5f30f3938dc6a67b3b84fc399513c8cf -nghttp2.v1.63.0+1.armv6l-linux-musleabihf.tar.gz/md5/7bf7063ee64eb9b41212a6c39111de4f -nghttp2.v1.63.0+1.armv6l-linux-musleabihf.tar.gz/sha512/3091a4373508e1913e69d76688fd31d57d8e01e15c39c8859b025ac19ff23a0d396dc771fb0a2860ee1913866c0b0dbc4432fbcd0283b5cbecfb02235c738762 -nghttp2.v1.63.0+1.armv7l-linux-gnueabihf.tar.gz/md5/645de11170289308ce00ed089853271c -nghttp2.v1.63.0+1.armv7l-linux-gnueabihf.tar.gz/sha512/bd974e629cd2626fc67a20b175e82e3a0dc742ee0c1b82b505395ebb7ce282def7d123b9bd8c4f7e3386db6c2c3d38d94475a00d96efb504a06fc2371db5a9e2 -nghttp2.v1.63.0+1.armv7l-linux-musleabihf.tar.gz/md5/8b5776769ec5577fde617814ccf57a7c -nghttp2.v1.63.0+1.armv7l-linux-musleabihf.tar.gz/sha512/7d463687abdfb600fcc11fd62b4973cdabdcfc076c5ace554af126ba6b0d925b9ff3eb3a9f730af6e4ef39d6ca1930084833a159d205a4230c88bbc82da7a3b6 -nghttp2.v1.63.0+1.i686-linux-gnu.tar.gz/md5/beb06b6d634fce5c15453c216c50d6b7 -nghttp2.v1.63.0+1.i686-linux-gnu.tar.gz/sha512/0616ffb2a98aa4cfdfbcaa408a6b33815a8e52af60417081854afb7b500e433f9fd63dff633df40507829217e96058f8b27184e50f442c175480e975f2387e13 -nghttp2.v1.63.0+1.i686-linux-musl.tar.gz/md5/ab15ac7ffaaeb7e69f7cad24ed3a6c4e -nghttp2.v1.63.0+1.i686-linux-musl.tar.gz/sha512/c9c18a6e255f4e3f81a9ee27b8ac58149507bce3dc9e79acbba8573ed66908c6cf3dcd29d9b989e47788977e6dec474c291f764fc1cfd718f20557001ca363c7 -nghttp2.v1.63.0+1.i686-w64-mingw32.tar.gz/md5/415858a5c10d7f2473174224e44ef3f6 -nghttp2.v1.63.0+1.i686-w64-mingw32.tar.gz/sha512/575c425df04c084980e8b9149579b787bf7ff38eecd958f38164db0bb0b4c331d4f9d6534f2c2cf1a105fc922ecba1d654a6a48a9a390f53bbcb4e8c2edbb0c7 -nghttp2.v1.63.0+1.powerpc64le-linux-gnu.tar.gz/md5/b2b8216a50aa7dd670e14ad47de31c3f -nghttp2.v1.63.0+1.powerpc64le-linux-gnu.tar.gz/sha512/c41570c8aa245fc2dce2a824cd73c4132ae2a65f9347d097462624917d637da34652c7f693e595a1f1ff1376171be4e2d48633d00dd6cafb00cd6cc974d9fa9e -nghttp2.v1.63.0+1.x86_64-apple-darwin.tar.gz/md5/878b3344f3656d663e33d7afc2fefb21 -nghttp2.v1.63.0+1.x86_64-apple-darwin.tar.gz/sha512/3f9cd4b20b149f8166f8411dc922c80a483113722f9a54c6274b3d4527dfd54bd5723fbd60535d8e90196f1d4e6e5c415f839b34cc4dc8c98eceee5466666471 -nghttp2.v1.63.0+1.x86_64-linux-gnu.tar.gz/md5/96fbea72cc42fa050fb0c9cb065588c8 -nghttp2.v1.63.0+1.x86_64-linux-gnu.tar.gz/sha512/47dd191ec2eb91b34ac9acd1802515778b2cea930c7c5876db3812566d3959e8a0e47bcee9601866180e40c9fd382d1599ca205a6229aaebdfa47e689f6ebd23 -nghttp2.v1.63.0+1.x86_64-linux-musl.tar.gz/md5/d68d6aac8629d95b2cd1b218152cc529 -nghttp2.v1.63.0+1.x86_64-linux-musl.tar.gz/sha512/fdac9dacd1392322cdc308997d7205b7194f897e21ff15fe4eda7c9c8a3b0b2b777cbc54723d884c341ef46467fc4fa056054ebff0f849090464ced031ff98f7 -nghttp2.v1.63.0+1.x86_64-unknown-freebsd.tar.gz/md5/61ecaf1d84e6b203ca7e601a91dc68e3 -nghttp2.v1.63.0+1.x86_64-unknown-freebsd.tar.gz/sha512/c25a017148ff7f01299a9a7cead87251f1a31fd404f4b1f5413fe9b09823ae471173f8d0828b096bb0ac7411e23d354f2c9e2596668d38d9a509831c6b4f5624 -nghttp2.v1.63.0+1.x86_64-w64-mingw32.tar.gz/md5/60ceb3ff3f5287b2782dfd98db4f1816 -nghttp2.v1.63.0+1.x86_64-w64-mingw32.tar.gz/sha512/971fd9e24c393fc594ae813caa7b14052320d924309bea0bd77c847ce0e86803cb803be051812ea029baf632deff6f9f8200dbc41f9bc143eba098adc294e757 +nghttp2-1.64.0.tar.bz2/md5/103421866471b6d5fc828189552d98a5 +nghttp2-1.64.0.tar.bz2/sha512/3b3d16168f6ea5a3e8a7b30b6545b86ff6be874771a1a8d502cbdc7c46f80195c1b8190b5279030aa2edea54fec40962cf245ce4fe89cdf89f06e3f091a34cda +nghttp2.v1.64.0+1.aarch64-apple-darwin.tar.gz/md5/67a5c302c3d1089682e2d6c251273f7b +nghttp2.v1.64.0+1.aarch64-apple-darwin.tar.gz/sha512/88abd96e47d85072abb74d65c0f4872134768b7703a9bb5e5e3f1fb8bdf4d0f6a9f07fbe76089c6746b22787774f362246092c3b2155e94345216aef9f67f2ac +nghttp2.v1.64.0+1.aarch64-linux-gnu.tar.gz/md5/f45a84bd28f598305002f154fb02e3da +nghttp2.v1.64.0+1.aarch64-linux-gnu.tar.gz/sha512/95e1034e1fcd5d96a5ed01e9870af27ee160cdcd624a196dbde31ad400768a55fae39ba11c22a868a5ec79e36e98dcf6a4f37c706e91e466fd01d9b8da868d78 +nghttp2.v1.64.0+1.aarch64-linux-musl.tar.gz/md5/a2680c3d4d94433c787fc1b75f4ab096 +nghttp2.v1.64.0+1.aarch64-linux-musl.tar.gz/sha512/8c02e4e3dfdefecc8c01b397ba8ece94be8f478aa63752d5310517728715b105101f371c281575de7e7c0678b31a7c7cfd021383d000b6f747992bbe47242047 +nghttp2.v1.64.0+1.aarch64-unknown-freebsd.tar.gz/md5/4d69a91c94fabf6af9f5197607639a58 +nghttp2.v1.64.0+1.aarch64-unknown-freebsd.tar.gz/sha512/8d679a0a9ee8a2136da71102eeaf511209c217c771a113fe2fa1736ac232a5637aeafa41ea53fb8ea2514857198cb907a4a8ea5667a325257f527cea4f2c5464 +nghttp2.v1.64.0+1.armv6l-linux-gnueabihf.tar.gz/md5/f44f3dde6ce2f4e34241a336c6f71934 +nghttp2.v1.64.0+1.armv6l-linux-gnueabihf.tar.gz/sha512/02bda6e05712de74805a6895a2f8f29b5930af2c62fed2b3e8a8fcd210c3542484131a5442c8ff707a7ac20c16eae93752609aeb6123b2296346c6399a0369b6 +nghttp2.v1.64.0+1.armv6l-linux-musleabihf.tar.gz/md5/a4dd8ed38b411d4b7c2a3411e6d59b6e +nghttp2.v1.64.0+1.armv6l-linux-musleabihf.tar.gz/sha512/a0552be25160d1878bfb10b30da23381d9d7f9ee7c749b0fb18a0a98ea1e9dcd53b103512b3fe2c98752063385b51551efff0dd0d9190db0105550595cd61d5e +nghttp2.v1.64.0+1.armv7l-linux-gnueabihf.tar.gz/md5/f0f309affb5726efdd93cc4ed0ef25c3 +nghttp2.v1.64.0+1.armv7l-linux-gnueabihf.tar.gz/sha512/55974dc62616e50d1cb1efda380edec6b69dfa175773abc48045ae34b545a19cc50b7a53b12b67dfd9bed9200fbba543875bb821d80e7c3dfcc2aaa3442a5a66 +nghttp2.v1.64.0+1.armv7l-linux-musleabihf.tar.gz/md5/ca090db026ea470523b8cb2c93eed8ac +nghttp2.v1.64.0+1.armv7l-linux-musleabihf.tar.gz/sha512/d2dccf74baa66abd5ecbb187efbd79bf8a43e0b920d7f4c94b6569dd71b74aa4eb6dfcd8d090bd8841496e3f4aa184028b907faf5a0ea3f91df3bb8e286a27c2 +nghttp2.v1.64.0+1.i686-linux-gnu.tar.gz/md5/aebffa8c32cc829f9fb7089ff972b215 +nghttp2.v1.64.0+1.i686-linux-gnu.tar.gz/sha512/f43e4d90f4ca755ea2b4fc90f10944562e9a7b9666b8469bb0fbe12df38c9db9625bfd6f4f4ec16d7da3cb5e3e9e3d85b1bffb56be18d746ae7be2c3dae9a306 +nghttp2.v1.64.0+1.i686-linux-musl.tar.gz/md5/64cc8696b37eeb2a225a02412d73e86d +nghttp2.v1.64.0+1.i686-linux-musl.tar.gz/sha512/2995ab7123630c2c7c606422b25a0a7761642d72177f26046b781209b13d7e90678923dacad35637df7cd171608d44f5d7d3c586768a1d4eaef0751a1f108c04 +nghttp2.v1.64.0+1.i686-w64-mingw32.tar.gz/md5/2ed9ff15d05f6cef7bf85bb19621a2fe +nghttp2.v1.64.0+1.i686-w64-mingw32.tar.gz/sha512/45f38653664cc7343b66561a9b5bfec341593504714afbcb35a856343e583d2e75cab8062b2ff23ebdf4625607748f5c70b1ae79cc047a4073eb8d01f8252338 +nghttp2.v1.64.0+1.powerpc64le-linux-gnu.tar.gz/md5/4622f699a44d02570298daf5864cf60b +nghttp2.v1.64.0+1.powerpc64le-linux-gnu.tar.gz/sha512/f2cc88fd537503ac138518b7f72a67c18508307c0dddca41d44c8496ca4dd8f15aa133e08f13e03b2fbb3c83272ea433456c9ebb929f648a7b2af13fcd048d71 +nghttp2.v1.64.0+1.x86_64-apple-darwin.tar.gz/md5/c6e5d0a179f065f4aab2b8661e6fc2d4 +nghttp2.v1.64.0+1.x86_64-apple-darwin.tar.gz/sha512/77073fecbdac780dea34c9cb42b019b7cfe8a125a1356cd7de2ffd3aebeb29aa6251008574efa8d0a017e86023248fdd93e50c4ed2952d8a23cb67e0cf557a74 +nghttp2.v1.64.0+1.x86_64-linux-gnu.tar.gz/md5/805f31fffc112ea45716b8a661911696 +nghttp2.v1.64.0+1.x86_64-linux-gnu.tar.gz/sha512/73ba29b4f65eeab2ea5c195cb17279d8234b6a650a1b58d0494a564725cd9c76c89321cd455280dd2627d6ba48e91a68be8bdcb5472eae9c3cfc3c2623892963 +nghttp2.v1.64.0+1.x86_64-linux-musl.tar.gz/md5/fbd3da6f5b100767ab7cb77ca6e6074b +nghttp2.v1.64.0+1.x86_64-linux-musl.tar.gz/sha512/493f632d1ba08a0e8114c883d7fef12e364b0b2556e57ed8fd8d8716c43251675f3f60808e32ec430949c4480d5eb052a7837abda2f3e7423ffc658b45805e41 +nghttp2.v1.64.0+1.x86_64-unknown-freebsd.tar.gz/md5/1dba5e39ebfa6c6aac668d5488fb0a41 +nghttp2.v1.64.0+1.x86_64-unknown-freebsd.tar.gz/sha512/259c7cac2cc45a5ebf0c9f90277d6aee68332fe37e8269f93a7d72fae40d41899e6ee63c211dcee81d6bcf056d81e89624e1d09f960039a950b8709b5966ee49 +nghttp2.v1.64.0+1.x86_64-w64-mingw32.tar.gz/md5/228fd64b1581ca3a8a45646b434bbf2a +nghttp2.v1.64.0+1.x86_64-w64-mingw32.tar.gz/sha512/c9ac17a35cd89e71c3a29165f29bb86bc589635bfafc70e64f7437200a886db8a74291ab40b255d977fa0b4bf8d88b12f75cf3ba75163dd906e08c30ec200b8f diff --git a/deps/curl.version b/deps/curl.version index ff360676b335a..fbbb55ffb17ea 100644 --- a/deps/curl.version +++ b/deps/curl.version @@ -3,7 +3,4 @@ CURL_JLL_NAME := LibCURL ## source build -# curl version 8.10 and later seem to be broken, probably due to a bug -# on Julia. See -# . -CURL_VER := 8.9.1 +CURL_VER := 8.11.1 diff --git a/deps/nghttp2.version b/deps/nghttp2.version index c9a39ea5ae757..a3cd46d457c2c 100644 --- a/deps/nghttp2.version +++ b/deps/nghttp2.version @@ -3,4 +3,4 @@ NGHTTP2_JLL_NAME := nghttp2 ## source build -NGHTTP2_VER := 1.63.0 +NGHTTP2_VER := 1.64.0 diff --git a/stdlib/LibCURL_jll/Project.toml b/stdlib/LibCURL_jll/Project.toml index e7dac4c687ab1..61d44beac14e1 100644 --- a/stdlib/LibCURL_jll/Project.toml +++ b/stdlib/LibCURL_jll/Project.toml @@ -1,6 +1,6 @@ name = "LibCURL_jll" uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" -version = "8.9.1+0" +version = "8.11.1+1" [deps] LibSSH2_jll = "29816b5a-b9ab-546f-933c-edad1886dfa8" diff --git a/stdlib/Manifest.toml b/stdlib/Manifest.toml index 8c638415062b2..63da40a5630f5 100644 --- a/stdlib/Manifest.toml +++ b/stdlib/Manifest.toml @@ -93,7 +93,7 @@ version = "0.6.4" [[deps.LibCURL_jll]] deps = ["Artifacts", "LibSSH2_jll", "Libdl", "OpenSSL_jll", "Zlib_jll", "nghttp2_jll"] uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" -version = "8.9.1+0" +version = "8.11.1+1" [[deps.LibGit2]] deps = ["LibGit2_jll", "NetworkOptions", "Printf", "SHA"] @@ -292,7 +292,7 @@ version = "5.11.0+0" [[deps.nghttp2_jll]] deps = ["Artifacts", "Libdl"] uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" -version = "1.63.0+1" +version = "1.64.0+1" [[deps.p7zip_jll]] deps = ["Artifacts", "Libdl"] diff --git a/stdlib/nghttp2_jll/Project.toml b/stdlib/nghttp2_jll/Project.toml index acc9444ab4a26..030f4a8a0b9d1 100644 --- a/stdlib/nghttp2_jll/Project.toml +++ b/stdlib/nghttp2_jll/Project.toml @@ -1,6 +1,6 @@ name = "nghttp2_jll" uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" -version = "1.63.0+1" +version = "1.64.0+1" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" diff --git a/stdlib/nghttp2_jll/test/runtests.jl b/stdlib/nghttp2_jll/test/runtests.jl index d667ce53e5252..13e7adaad9df6 100644 --- a/stdlib/nghttp2_jll/test/runtests.jl +++ b/stdlib/nghttp2_jll/test/runtests.jl @@ -11,5 +11,5 @@ end @testset "nghttp2_jll" begin info = unsafe_load(ccall((:nghttp2_version,libnghttp2), Ptr{nghttp2_info}, (Cint,), 0)) - @test VersionNumber(unsafe_string(info.version_str)) == v"1.63.0" + @test VersionNumber(unsafe_string(info.version_str)) == v"1.64.0" end From 3f0a5ae5f19c849ecaa8d7f4e76b07b2b64b19a9 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sun, 5 Jan 2025 12:14:52 +0100 Subject: [PATCH 137/342] Fix running Compiler tests standalone (#56952) --- Compiler/src/bootstrap.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/Compiler/src/bootstrap.jl b/Compiler/src/bootstrap.jl index ea7510df313c7..26fcfde5f256f 100644 --- a/Compiler/src/bootstrap.jl +++ b/Compiler/src/bootstrap.jl @@ -15,6 +15,7 @@ function activate_codegen!() end) end +global bootstrapping_compiler::Bool = false function bootstrap!() global bootstrapping_compiler = true let time() = ccall(:jl_clock_now, Float64, ()) From bee56f434ce2b534a75dfc035bbe033dd2ad87be Mon Sep 17 00:00:00 2001 From: FX Coudert Date: Sun, 5 Jan 2025 14:16:51 +0100 Subject: [PATCH 138/342] curl: remove patch (#56957) This issue was fixed upstream in Curl 8.7.0 and later: https://github.com/curl/curl/commit/5cc2b016c36aaf5a08e2feb7c068fca5bb0a8052 --- deps/curl.mk | 10 +--------- deps/patches/curl-strdup.patch | 10 ---------- 2 files changed, 1 insertion(+), 19 deletions(-) delete mode 100644 deps/patches/curl-strdup.patch diff --git a/deps/curl.mk b/deps/curl.mk index 29745448692c6..3d478e786ca8a 100644 --- a/deps/curl.mk +++ b/deps/curl.mk @@ -61,15 +61,7 @@ CURL_TLS_CONFIGURE_FLAGS := --with-openssl endif CURL_CONFIGURE_FLAGS += $(CURL_TLS_CONFIGURE_FLAGS) -$(SRCCACHE)/curl-$(CURL_VER)/curl-8.6.0-build.patch-applied: $(SRCCACHE)/curl-$(CURL_VER)/source-extracted - cd $(dir $@) && \ - patch -p1 -f < $(SRCDIR)/patches/curl-strdup.patch - echo 1 > $@ - -$(SRCCACHE)/curl-$(CURL_VER)/source-patched: $(SRCCACHE)/curl-$(CURL_VER)/curl-8.6.0-build.patch-applied - echo 1 > $@ - -$(BUILDDIR)/curl-$(CURL_VER)/build-configured: $(SRCCACHE)/curl-$(CURL_VER)/source-patched +$(BUILDDIR)/curl-$(CURL_VER)/build-configured: $(SRCCACHE)/curl-$(CURL_VER)/source-extracted mkdir -p $(dir $@) cd $(dir $@) && \ $(dir $<)/configure $(CURL_CONFIGURE_FLAGS) \ diff --git a/deps/patches/curl-strdup.patch b/deps/patches/curl-strdup.patch deleted file mode 100644 index 1cb389fdc4c17..0000000000000 --- a/deps/patches/curl-strdup.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- a/lib/md4.c -+++ b/lib/md4.c -@@ -23,6 +23,7 @@ - ***************************************************************************/ - - #include "curl_setup.h" -+#include "strdup.h" - - #if defined(USE_CURL_NTLM_CORE) - From 5ec41e90c20ee3825d32d2d374920ce0df81f73c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= <765740+giordano@users.noreply.github.com> Date: Sun, 5 Jan 2025 22:49:38 +0100 Subject: [PATCH 139/342] [deps] Update most jll stdlibs to newer builds (#56958) This is mainly to get checksums for `riscv64-linux-gnu` builds of many dependencies. We're only changing the build version for most packages, only packages upgraded to newer upstream versions are * libblastrampoline (only [change between v5.11.2 and v5.12.0](https://github.com/JuliaLinearAlgebra/libblastrampoline/compare/v5.11.2...v5.12.0) is the version number, for the rest it should be functionally equivalent) * openlibm: https://github.com/JuliaMath/openlibm/compare/v0.8.1...v0.8.4 Checksums updated with ``` make -f contrib/refresh_checksums.mk -j blastrampoline openlibm gmp libssh2 libuv pcre zlib dsfmt p7zip ``` --- contrib/refresh_checksums.mk | 2 +- deps/blastrampoline.version | 8 +- deps/checksums/blastrampoline | 74 ++++++------- deps/checksums/curl | 2 + deps/checksums/dsfmt | 70 ++++++------ deps/checksums/gmp | 124 +++++++++++----------- deps/checksums/libssh2 | 70 ++++++------ deps/checksums/libuv | 70 ++++++------ deps/checksums/nghttp2 | 2 + deps/checksums/openlibm | 74 ++++++------- deps/checksums/p7zip | 70 ++++++------ deps/checksums/pcre | 70 ++++++------ deps/checksums/zlib | 70 ++++++------ deps/openlibm.version | 8 +- stdlib/GMP_jll/Project.toml | 2 +- stdlib/LibSSH2_jll/Project.toml | 2 +- stdlib/LibUV_jll/Project.toml | 2 +- stdlib/OpenLibm_jll/Project.toml | 2 +- stdlib/PCRE2_jll/Project.toml | 2 +- stdlib/Zlib_jll/Project.toml | 2 +- stdlib/dSFMT_jll/Project.toml | 2 +- stdlib/libblastrampoline_jll/Project.toml | 2 +- stdlib/p7zip_jll/Project.toml | 2 +- 23 files changed, 380 insertions(+), 352 deletions(-) diff --git a/contrib/refresh_checksums.mk b/contrib/refresh_checksums.mk index 21ef72c26a03d..5a787b0b67cb1 100644 --- a/contrib/refresh_checksums.mk +++ b/contrib/refresh_checksums.mk @@ -19,7 +19,7 @@ all: checksum pack-checksum # Get this list via: # using BinaryBuilder # print("TRIPLETS=\"$(join(sort(triplet.(BinaryBuilder.supported_platforms(;experimental=true))), " "))\"") -TRIPLETS=aarch64-apple-darwin aarch64-linux-gnu aarch64-linux-musl aarch64-unknown-freebsd armv6l-linux-gnueabihf armv6l-linux-musleabihf armv7l-linux-gnueabihf armv7l-linux-musleabihf i686-linux-gnu i686-linux-musl i686-w64-mingw32 powerpc64le-linux-gnu x86_64-apple-darwin x86_64-linux-gnu x86_64-linux-musl x86_64-unknown-freebsd x86_64-w64-mingw32 +TRIPLETS=aarch64-apple-darwin aarch64-linux-gnu aarch64-linux-musl aarch64-unknown-freebsd armv6l-linux-gnueabihf armv6l-linux-musleabihf armv7l-linux-gnueabihf armv7l-linux-musleabihf i686-linux-gnu i686-linux-musl i686-w64-mingw32 powerpc64le-linux-gnu riscv64-linux-gnu x86_64-apple-darwin x86_64-linux-gnu x86_64-linux-musl x86_64-unknown-freebsd x86_64-w64-mingw32 CLANG_TRIPLETS=$(filter %-darwin %-freebsd,$(TRIPLETS)) NON_CLANG_TRIPLETS=$(filter-out %-darwin %-freebsd,$(TRIPLETS)) diff --git a/deps/blastrampoline.version b/deps/blastrampoline.version index 7e6dc61d1cbe7..1e4a75305a4dd 100644 --- a/deps/blastrampoline.version +++ b/deps/blastrampoline.version @@ -1,7 +1,9 @@ +# -*- makefile -*- + ## jll artifact BLASTRAMPOLINE_JLL_NAME := libblastrampoline ## source build -BLASTRAMPOLINE_VER := 5.11.2 -BLASTRAMPOLINE_BRANCH=v5.11.2 -BLASTRAMPOLINE_SHA1=c48da8a1225c2537ff311c28ef395152fb879eae +BLASTRAMPOLINE_VER := 5.12.0 +BLASTRAMPOLINE_BRANCH=v5.12.0 +BLASTRAMPOLINE_SHA1=b127bc8dd4758ffc064340fff2aef4ead552f386 diff --git a/deps/checksums/blastrampoline b/deps/checksums/blastrampoline index 987d4662e6cc7..9e007f6055cf9 100644 --- a/deps/checksums/blastrampoline +++ b/deps/checksums/blastrampoline @@ -1,36 +1,38 @@ -blastrampoline-c48da8a1225c2537ff311c28ef395152fb879eae.tar.gz/md5/0747a7c65427a5e6ff4820ea1079f095 -blastrampoline-c48da8a1225c2537ff311c28ef395152fb879eae.tar.gz/sha512/8d5c60ce84ae42e529506821b051e043c0d8861cd7e39780ebc858c2b8638d6628b2f9ceffd67c9ee18983c9c7e5a454f65cf14fb414907c28c90eb67e7de8fe -libblastrampoline.v5.11.2+0.aarch64-apple-darwin.tar.gz/md5/c0f71f80654d6025e29e763f7bf2de92 -libblastrampoline.v5.11.2+0.aarch64-apple-darwin.tar.gz/sha512/49a7f8f2aac286763d7ce2c086b60b84e9ed7eb9dbbd8ba00c5956840ea6c642f4b1d80cb69888045dfdce55dcde1ee2843df9fa63947d3ce8615faf1523a902 -libblastrampoline.v5.11.2+0.aarch64-linux-gnu.tar.gz/md5/7e9b45c623aa527d65f85edff7d056dd -libblastrampoline.v5.11.2+0.aarch64-linux-gnu.tar.gz/sha512/f41378f63a6513ca9b25febb8c01257711cd34e86303a081865696adadc41db5e39c1fd1fdf50ff1ea5d3224fe22ea7f8e571dc7001ee8708be2a27d41410eb5 -libblastrampoline.v5.11.2+0.aarch64-linux-musl.tar.gz/md5/1a2b0eafdaedc1870508948f4a8fd6d8 -libblastrampoline.v5.11.2+0.aarch64-linux-musl.tar.gz/sha512/5d9c8cce5a0abfa10b2907d9b44ad62e62cd9cd7c4c94c14b0ae93f83adff7c1c9f386c1b82dbc2f8f1f959c86c724663ae5dfdbcdd081cebcbf8a91be87da7b -libblastrampoline.v5.11.2+0.aarch64-unknown-freebsd.tar.gz/md5/3c518305add0202d56798c30cbd04345 -libblastrampoline.v5.11.2+0.aarch64-unknown-freebsd.tar.gz/sha512/ac292d999cd258052a95dd641bd06d22db3e6c0574077e9aecb63dca70c1810395921d9bc939a629cf38ece16de42d541dd03aef84d53cc6bd7b7d65bb743b66 -libblastrampoline.v5.11.2+0.armv6l-linux-gnueabihf.tar.gz/md5/fd47f376283002dc6821c4dac0127198 -libblastrampoline.v5.11.2+0.armv6l-linux-gnueabihf.tar.gz/sha512/e56b3e5b5f0bf2b3138484a49a922cb82608152de7dd972c52294eb8611cb76b95b06f33a1dc38f00dd02702ca1ef9b6f69572349b185695a55b269b91cf231f -libblastrampoline.v5.11.2+0.armv6l-linux-musleabihf.tar.gz/md5/70222a8dd72f03888401a2d0cf5a206c -libblastrampoline.v5.11.2+0.armv6l-linux-musleabihf.tar.gz/sha512/609894123a512831c9159312ea5f496de9361c60a838f9428ea5dc6aa9aa6bbb2b33856bf08868765e9af2548d8d386389747254d87d7ed403e492259d61ce32 -libblastrampoline.v5.11.2+0.armv7l-linux-gnueabihf.tar.gz/md5/966dfbf17d7eac1ff046b935e8202e7a -libblastrampoline.v5.11.2+0.armv7l-linux-gnueabihf.tar.gz/sha512/de173d9c17970bff612e1759dbcd9188f0bca0dffd21e0a98d2ed5b72a5ba60cc0097cec1e42cb2bc42f14c1c0bed3987b5bd4a04c7991c9e8d908f2aed231cd -libblastrampoline.v5.11.2+0.armv7l-linux-musleabihf.tar.gz/md5/90b43518c75e0071e4b2efe3aef344ec -libblastrampoline.v5.11.2+0.armv7l-linux-musleabihf.tar.gz/sha512/2bbb2676b381e588e6315576ed9a1d4cad4612aa6c1b5ec95fdd8434f0f0fcb07cc0b61162c0a1dac72217a008f01702f5bf63566a007622d7a3ab35461b6645 -libblastrampoline.v5.11.2+0.i686-linux-gnu.tar.gz/md5/ecf7b2fcdf8feb2114525290d09b99c7 -libblastrampoline.v5.11.2+0.i686-linux-gnu.tar.gz/sha512/10922aa2e567f1534340ec9422516ccf0ea625ae73a433ed864dc72926235fe1dc6c52c2ca716aca5eeac80544a99e76892a0f19fccd2c2b9103332fd2289980 -libblastrampoline.v5.11.2+0.i686-linux-musl.tar.gz/md5/6cf17a410bf50b3a87b9f2af0c6955e9 -libblastrampoline.v5.11.2+0.i686-linux-musl.tar.gz/sha512/30f78dd4948b26b14d04cf5e1821a381e9d8aa67c6b3547cf45a0d53a469829a98d7d47722c542699e65e1ae3411a86da094d8b354821ece1562288fa523b1f1 -libblastrampoline.v5.11.2+0.i686-w64-mingw32.tar.gz/md5/9c4c1fa7410f9e53687dbde1479deb3a -libblastrampoline.v5.11.2+0.i686-w64-mingw32.tar.gz/sha512/511eed07956b16555ab236905fe91c584d870e45d1a6b736b3b564f84ec66e8c12d9561efabad259ddc65b8965eb4cdc29b079d0a9a6a465b424b503399eae7b -libblastrampoline.v5.11.2+0.powerpc64le-linux-gnu.tar.gz/md5/816ee59bf7cc937399c273709882369b -libblastrampoline.v5.11.2+0.powerpc64le-linux-gnu.tar.gz/sha512/4e1095288ff02a9e0714f982be16782271643c1844100b38d5fcf02c2e2f62d0635457d52dd120792a59a62b905c60aa7e253a89c2f759d98c33d617c89e897f -libblastrampoline.v5.11.2+0.x86_64-apple-darwin.tar.gz/md5/9a4a86a441aa232e12e85bbf6e62f589 -libblastrampoline.v5.11.2+0.x86_64-apple-darwin.tar.gz/sha512/2d80b4c9149b8d62ae89fa3be32ccb297e815c9cd56b3481482c5f6ee253fc845d410807e099f4c1814a77e397c04511ebabc9d82352fc43ebe81a3306819ccc -libblastrampoline.v5.11.2+0.x86_64-linux-gnu.tar.gz/md5/45fbfd0422131044fff9ed44d12f13e1 -libblastrampoline.v5.11.2+0.x86_64-linux-gnu.tar.gz/sha512/c7e4f87aa0ab403be46b81967d40ebd4bd4b32af93a325cb16f64593c2261a365be3f338195cdfeada0cb6ecab8e33e4be1b380596ff0bb1c4a7b5e6aac3dccc -libblastrampoline.v5.11.2+0.x86_64-linux-musl.tar.gz/md5/161816fa857775d78bc671c444846844 -libblastrampoline.v5.11.2+0.x86_64-linux-musl.tar.gz/sha512/ba0ab54a9ccfb451b7b8fe46b2bd8e8a8135d2e1f2a896bfdf4bcc6e82812f56d93ef1e7b85671e58d388afe2876d79affdf59bfe7b1db5b76412008303a121e -libblastrampoline.v5.11.2+0.x86_64-unknown-freebsd.tar.gz/md5/aeaab847455f5a43c434155b09107cde -libblastrampoline.v5.11.2+0.x86_64-unknown-freebsd.tar.gz/sha512/24425c8bdc861404156bb5a8e950654904fb22ff6a5ebe52c873629e4dd1cfaccafaae74b779c2cb02370f012cf18c2142a105dd614938b2685db2cd7527c73d -libblastrampoline.v5.11.2+0.x86_64-w64-mingw32.tar.gz/md5/450afb701cc2899c7c083bd3f3e580a0 -libblastrampoline.v5.11.2+0.x86_64-w64-mingw32.tar.gz/sha512/e4d1785a06b051a4f16edd7343021eed61ac45cf45d26b4e3ef1e54cfaadb44da2e74b7d854e31b05a733dbb3004f3e85644967316c4f41d1ad64400fed126f2 +blastrampoline-b127bc8dd4758ffc064340fff2aef4ead552f386.tar.gz/md5/395f2035bcb52e886b55ac926a7bf183 +blastrampoline-b127bc8dd4758ffc064340fff2aef4ead552f386.tar.gz/sha512/9ae0fe2ca75dc0b2c784d5b7248caca29ed6d44258743ee2b32827032734757e9078dd6bcdf80a02b042deb5c7ca7b4e5be392be6700efde91427091fb53a03f +libblastrampoline.v5.12.0+0.aarch64-apple-darwin.tar.gz/md5/9a18b39bb575d0112834992043d302c0 +libblastrampoline.v5.12.0+0.aarch64-apple-darwin.tar.gz/sha512/4e406b155149414d3e4fd5db49ab56a87ed13577ebb399eaf8a251692c0b84e639c6e1a4eb20863e2638c31add0241ca916e57f91bb5a4aed07e2c56cc580870 +libblastrampoline.v5.12.0+0.aarch64-linux-gnu.tar.gz/md5/e100e93f0d6a104fc66c9f78a67150c5 +libblastrampoline.v5.12.0+0.aarch64-linux-gnu.tar.gz/sha512/f7e0c379e32d8163dbb4919b77e9637e1b16cf26618b9260222cf985bfab9ca3f36bebccd0e8360af68db925035c82127ba85d46b4a6578961dde6a049c7cf93 +libblastrampoline.v5.12.0+0.aarch64-linux-musl.tar.gz/md5/814a79e8cfe8744ca5a2a722f007fcaa +libblastrampoline.v5.12.0+0.aarch64-linux-musl.tar.gz/sha512/bc886b199500fc4245a95446d4c862fc636711e0875a9d5cf9aef661d819d00324adfd3e037d9c03e274be26034353d033fb041e7608ecef222e1d154f38337d +libblastrampoline.v5.12.0+0.aarch64-unknown-freebsd.tar.gz/md5/9b9a7fe0e45a73009bb9f8044f4a27a2 +libblastrampoline.v5.12.0+0.aarch64-unknown-freebsd.tar.gz/sha512/51d52afb13e326ef4750bdcad800aaf3db2c9e068b4c38bd148e312c63358b2228b81d23626d18b8983534a8a6f24df1b64b4e7121779d2535574ea907bd18ba +libblastrampoline.v5.12.0+0.armv6l-linux-gnueabihf.tar.gz/md5/1b6fd062d133b13e8efc63f08528fb51 +libblastrampoline.v5.12.0+0.armv6l-linux-gnueabihf.tar.gz/sha512/78d525f425ee27068b94b94f89ef44a51ffac9f642ffe66e177434804e59b4ac3ba875190aceee386a8d740f7903e979e5b91f0973138d0fc7753061c6f5f26d +libblastrampoline.v5.12.0+0.armv6l-linux-musleabihf.tar.gz/md5/506be2b7669aa171efcc541388cb5444 +libblastrampoline.v5.12.0+0.armv6l-linux-musleabihf.tar.gz/sha512/2975136376c3f61b8f227676c4e1368d1847d85ff469dddbc0a330635eac77c00072c7544ae4aa9981d16a4ab04d494be54fc951b434a56fbf14003c42626579 +libblastrampoline.v5.12.0+0.armv7l-linux-gnueabihf.tar.gz/md5/99403eae880f52aa97884143e2ca7215 +libblastrampoline.v5.12.0+0.armv7l-linux-gnueabihf.tar.gz/sha512/986dfcf5fe3ac731df3c71eb6b0bf3d7525511952d22cc9128ff35e6fcb330acf69e897aeb97920ebabd1ccccd1dd6ce9b6c16d0dbf661d39a103ce5b477462f +libblastrampoline.v5.12.0+0.armv7l-linux-musleabihf.tar.gz/md5/20adf8d2ef348f5362cb03e1a2780476 +libblastrampoline.v5.12.0+0.armv7l-linux-musleabihf.tar.gz/sha512/95068a3b5bcf17bd5f13373a2730a6508d3992f0aa83a91629527821cf038b9607327843cc44fb72730b63c01d3d70e2eb488eca8f48ed9444d7736f67745d02 +libblastrampoline.v5.12.0+0.i686-linux-gnu.tar.gz/md5/a56f833ad986fc3e9e64e5abdb16915f +libblastrampoline.v5.12.0+0.i686-linux-gnu.tar.gz/sha512/d478b4981dc17afb8aa8625fdbb23139f1c3edaa9aaa179e70d274984a056147b2e65e9f473b007733d094369f448823c33aa95fadd228016ecf9dfbf17f06bb +libblastrampoline.v5.12.0+0.i686-linux-musl.tar.gz/md5/8578119b3b3e84393e6324996e9506aa +libblastrampoline.v5.12.0+0.i686-linux-musl.tar.gz/sha512/b546de6687755ce43680f312008a23a8f9df422603098807f33e2ae969c9e9de0ca32a3319067d4f8fa1f782f21b6465638cd59e4c86fc6261fb4180f0ed116f +libblastrampoline.v5.12.0+0.i686-w64-mingw32.tar.gz/md5/b9e2800b8758d3fa0ac0597f738c399c +libblastrampoline.v5.12.0+0.i686-w64-mingw32.tar.gz/sha512/e0aa0ee2a750cfe702e0bd5861e352f97f433f67444dbc6e5814055fb32f571de318f640ac670c91bad233f8af85f0421daef71b7768a710de5b15febee28b27 +libblastrampoline.v5.12.0+0.powerpc64le-linux-gnu.tar.gz/md5/bab2048857c7c1ba4a6c3d540b9275c6 +libblastrampoline.v5.12.0+0.powerpc64le-linux-gnu.tar.gz/sha512/576026c970b19cc00480d7bb9439933c5bb432eec17def66b22f5c0dfd418bcf75bb10ccfc1b01fef48e8d504ebf953c5f6c63d504713315c43d9579ab5fa2e4 +libblastrampoline.v5.12.0+0.riscv64-linux-gnu.tar.gz/md5/f37e2849a948a8c8c8bfa6055e30909c +libblastrampoline.v5.12.0+0.riscv64-linux-gnu.tar.gz/sha512/89f30d52f1a1dcc0aa38b4b343534b7fadcff12d788f455172c043ea2511c03b2735fdacf8f794a6f62156cb5d82fb0e9e0edd04bb9c57a1ca3e680410456b17 +libblastrampoline.v5.12.0+0.x86_64-apple-darwin.tar.gz/md5/b07c42b602b91bf2229b1a5cfd8e37b3 +libblastrampoline.v5.12.0+0.x86_64-apple-darwin.tar.gz/sha512/ab064dff373826776f9b64a4a77e3418461d53d5119798a5e702967e4ac4f68c58cd8c3c0cc01bda3edeb613cf50b9d3171d9141c91ff9ef3a2c88a8e8f00a37 +libblastrampoline.v5.12.0+0.x86_64-linux-gnu.tar.gz/md5/c37b01242012e51e124711d5ad10cf97 +libblastrampoline.v5.12.0+0.x86_64-linux-gnu.tar.gz/sha512/3f9015bec4aaddc677cb3f3aebd432db8bad89b3f6e563634a37569afeb9fb0efa4f214166c984c2c1926831d5cd79fcd4d605d40675e0d1a7e494a76c066f02 +libblastrampoline.v5.12.0+0.x86_64-linux-musl.tar.gz/md5/c24e440a1757a45f087a2e1ac649fb45 +libblastrampoline.v5.12.0+0.x86_64-linux-musl.tar.gz/sha512/824b930d50df929fd22ead6dffad06593d2aad9fcb149f07f1c2f6d4b7b34911e89c2be5a1e9b8ad5ad8292ac29f9e5dbe6d7bb205d2b207432ade61ae5f8b68 +libblastrampoline.v5.12.0+0.x86_64-unknown-freebsd.tar.gz/md5/5721328a24473cefbb3e77ba85e46922 +libblastrampoline.v5.12.0+0.x86_64-unknown-freebsd.tar.gz/sha512/3537ea491828492f1cb68fa961dc5574b63a88b49abf19eb86f9d1a4544e1398fcd84d6338c6dcb9550ee3abcdcab0654f5cc2b85699c5ed5b3b31a1c35a199d +libblastrampoline.v5.12.0+0.x86_64-w64-mingw32.tar.gz/md5/450afb701cc2899c7c083bd3f3e580a0 +libblastrampoline.v5.12.0+0.x86_64-w64-mingw32.tar.gz/sha512/e4d1785a06b051a4f16edd7343021eed61ac45cf45d26b4e3ef1e54cfaadb44da2e74b7d854e31b05a733dbb3004f3e85644967316c4f41d1ad64400fed126f2 diff --git a/deps/checksums/curl b/deps/checksums/curl index 5331e54d30d4a..b0a223f42c5e2 100644 --- a/deps/checksums/curl +++ b/deps/checksums/curl @@ -24,6 +24,8 @@ LibCURL.v8.11.1+1.i686-w64-mingw32.tar.gz/md5/5f2071282d572bbb53dfcfb16d0d9608 LibCURL.v8.11.1+1.i686-w64-mingw32.tar.gz/sha512/e4d6fbd518055e8f2a71b89ee9a33728e6e076729adeafc358fc40f47d032b739363c9b57df5bfb3c43244f7b833afc76ae255e70bcf43b81262d74278532a22 LibCURL.v8.11.1+1.powerpc64le-linux-gnu.tar.gz/md5/806ee9b51c2bffd798c1682867a7a2a0 LibCURL.v8.11.1+1.powerpc64le-linux-gnu.tar.gz/sha512/20ae5f47ad24e1fba8ecdc3a81aa81acb5c3c224041f12f8be48f9a0abd5ce44117b096a59fc8f861b6f8c6ad9e4177e3a3ba3e2dbecb2078d4bab19bdd4d239 +LibCURL.v8.11.1+1.riscv64-linux-gnu.tar.gz/md5/2e029213e81955f39423733608c4ffa8 +LibCURL.v8.11.1+1.riscv64-linux-gnu.tar.gz/sha512/a634ae9de047bd8a93cbfaa3cd5375d895baf9917b5062653f15472527836b51eeb15006b5e1888251e3f09d8177b489ea9975580fe6d95bc759708fc9654fd1 LibCURL.v8.11.1+1.x86_64-apple-darwin.tar.gz/md5/56cf7cf4ea22123e516843a5751eea17 LibCURL.v8.11.1+1.x86_64-apple-darwin.tar.gz/sha512/5ae5569ade42cdf0a1aa8acfda7d1dd3df30d498637f83e93bd9f8be883ae777e789b417be24df83e42ebe32fb67cc328bedac3dc231d3569f585641175ed257 LibCURL.v8.11.1+1.x86_64-linux-gnu.tar.gz/md5/a4a733fe879693e83e1f05b6ef742ea6 diff --git a/deps/checksums/dsfmt b/deps/checksums/dsfmt index 99ba378adcd4c..9d5fa782663ec 100644 --- a/deps/checksums/dsfmt +++ b/deps/checksums/dsfmt @@ -1,36 +1,38 @@ -dSFMT.v2.2.5+1.aarch64-apple-darwin.tar.gz/md5/1ac287cb891e0bb758e5ae1195e661b7 -dSFMT.v2.2.5+1.aarch64-apple-darwin.tar.gz/sha512/c604d55fb955e9d707e26b654670f07f18ddd0dc93c1a2b678b9cea9b84a24e21c88eb49d39e3e74c930cdffa35e45f5a63e96ecb0a098e8ea538438dc7281bd -dSFMT.v2.2.5+1.aarch64-linux-gnu.tar.gz/md5/260e14855dbc7773a2ca906d58cc57f2 -dSFMT.v2.2.5+1.aarch64-linux-gnu.tar.gz/sha512/820ca4c6afde931e855b74015150f4ffbb513276c3fa7dbcc1ec8d34c02d4989fb7424a6e4f81f93d054811b5f54f8633d955b05acdb088387ee90f1c3b00915 -dSFMT.v2.2.5+1.aarch64-linux-musl.tar.gz/md5/7ddccbad6b5c9de4be187fe76637a0d8 -dSFMT.v2.2.5+1.aarch64-linux-musl.tar.gz/sha512/e3c225da00927096e3a6cd4abc681fba8f469cb74828e7054d4f5684d71dcb8e75c9a81f14fa10bfbb78f62f9567a31a92edcca8d797e5810a2a44a3fc17bc84 -dSFMT.v2.2.5+1.aarch64-unknown-freebsd.tar.gz/md5/84f560104ab5eac8f214559645235350 -dSFMT.v2.2.5+1.aarch64-unknown-freebsd.tar.gz/sha512/3668a37d2516c304b296e2dd7b93a45decb37774088b03438b6d7dec71766d98b2ca1d61c1b317f86ca118d078f53817b6bc86f0ed487185e18b5cc786060592 -dSFMT.v2.2.5+1.armv6l-linux-gnueabihf.tar.gz/md5/a70329e0a6c57009c6b6950fd34089f6 -dSFMT.v2.2.5+1.armv6l-linux-gnueabihf.tar.gz/sha512/4418c42165660adc050e872ef834f920c89ed6a0d2b816821672b1e862e947aad7efd023289da9bf05bb2eb9ec4b9d2561c403e2d5384d5314a4ba016b1f9cfc -dSFMT.v2.2.5+1.armv6l-linux-musleabihf.tar.gz/md5/6ffc798b8a0c847fa5cb93640bd66ab3 -dSFMT.v2.2.5+1.armv6l-linux-musleabihf.tar.gz/sha512/94e5ae07d0b1420abd7290519bce6f77deae634bbb4df31e3f02416bf509e555a9b1c9d19dd77ca76a308c2b86d5c9d4718b9ef83c13167b88a8181d8ca7e73a -dSFMT.v2.2.5+1.armv7l-linux-gnueabihf.tar.gz/md5/660d95aa08580ca1716a89c4d8b1eb24 -dSFMT.v2.2.5+1.armv7l-linux-gnueabihf.tar.gz/sha512/bc757a9f805047be5375f92c10a3f3eab69345a4ec5cc997f763e66be36144a74d414ff926df8e17b9d5a2394189269c3188c55e0b7c75a72495394d65510cef -dSFMT.v2.2.5+1.armv7l-linux-musleabihf.tar.gz/md5/78c487049092fe61949d506637c713bb -dSFMT.v2.2.5+1.armv7l-linux-musleabihf.tar.gz/sha512/03ddada4478f05eab7d2971b2deaf2cba91f084d7ce66fc8219bcb3cf5c308ea13959fed95568ca80f4ce11794e197092984919265716de8f2558e2cb30d94ce -dSFMT.v2.2.5+1.i686-linux-gnu.tar.gz/md5/11463fd3981a8c143d7aed691d18d4e0 -dSFMT.v2.2.5+1.i686-linux-gnu.tar.gz/sha512/db946a4fbd8a3163b8b1c25e02bfc4a841da7d2532892a99037bd48ac98e1840691e8cc0127d9457a82667a0131e4826cb4e9d0a13f127afc62da4eb68af5a3e -dSFMT.v2.2.5+1.i686-linux-musl.tar.gz/md5/a61405f72c9a3bba5718f078c68e61a5 -dSFMT.v2.2.5+1.i686-linux-musl.tar.gz/sha512/726f130bbbfd0dece4185b89a25a73f3b5b950ebfb7f86aea6e9cbcf9ae932e591d20b854de0b4985103dbf8b4b7cb3560661c5070af971cd2c1f3ec3e1ea7d2 -dSFMT.v2.2.5+1.i686-w64-mingw32.tar.gz/md5/3bc27ef8f26c7a26f096cf1d558d408d -dSFMT.v2.2.5+1.i686-w64-mingw32.tar.gz/sha512/ea3608d3ae3874ea57a1a08f69abe2a1638bc340db71c6fe3c4fd5637d8c54943bf16b099a46817387c1ed4cb5f3cd1c0ff19ae8a4ed85dd555555821af06374 -dSFMT.v2.2.5+1.powerpc64le-linux-gnu.tar.gz/md5/fd8c73961ef7c82201e6d86e8bf4324c -dSFMT.v2.2.5+1.powerpc64le-linux-gnu.tar.gz/sha512/1bd0ebd019cfc6f25f7ba007547c5ee297854655b93c55e90d8ead420875de5a087e38956693d5e901ff2abf667c72aa66fb34f587b82adf4b91b3d5d666b5c7 -dSFMT.v2.2.5+1.x86_64-apple-darwin.tar.gz/md5/c8c0cd02cb1aa5e363b0c28a3fc4cf65 -dSFMT.v2.2.5+1.x86_64-apple-darwin.tar.gz/sha512/ac29d4b8aae51349474c9191822f92f69105e19521afe2bd9fc6b16385256610ae31e34cd70d894ed03299f1fd155f0a1db79969d1ed35eea44d11521e2030ab -dSFMT.v2.2.5+1.x86_64-linux-gnu.tar.gz/md5/fa671f4ca14b171d53c8866d03f9162a -dSFMT.v2.2.5+1.x86_64-linux-gnu.tar.gz/sha512/2e242a1448da0508ea88cc1a106f1e74f8d7e7562cd82b80d86abf9a8b454653ad7612e25c30ce00c23757e8a5b7b5736253b00a52f9473af6c5d4df768138f2 -dSFMT.v2.2.5+1.x86_64-linux-musl.tar.gz/md5/c648294163882ec539ab646542c74880 -dSFMT.v2.2.5+1.x86_64-linux-musl.tar.gz/sha512/9e96a47d660854b6517364f0db40a2f4e0e3b814499a0349f7cf550b1c8d04589fca5eb4a75bf34f36d1b5d1b2277b3e9a961c887092abedd08f438e025329e7 -dSFMT.v2.2.5+1.x86_64-unknown-freebsd.tar.gz/md5/4960e4ab2ecb6ae1025f9e7bf4c9a7b8 -dSFMT.v2.2.5+1.x86_64-unknown-freebsd.tar.gz/sha512/a2e8bbe382a0ebdd7b69fafdc901f33767f53b9f8b37a89104f2ef897bb5ec27bc8d3bc21f5cff52ca4f29b3a6a10535f7e5f16ef917a9323858c75f1569ea60 -dSFMT.v2.2.5+1.x86_64-w64-mingw32.tar.gz/md5/386adb3b7593c222dc7a1060a1356b21 -dSFMT.v2.2.5+1.x86_64-w64-mingw32.tar.gz/sha512/fe2ab5021126807b37042e89a22ef9a869c6a0a028680df445773b2affd11c2b02148be07d53504ea3842bb38bb62fe039529688266c1cba3545a892bd4dc185 +dSFMT.v2.2.5+2.aarch64-apple-darwin.tar.gz/md5/4d9e6a1ed07d1fe1557845b763224eeb +dSFMT.v2.2.5+2.aarch64-apple-darwin.tar.gz/sha512/930e12a9b6ac82888f4122515a8a7cc3aa5d5363e500455b33c57efb7656041fe3f0fa68b02dd048b2a9f00abb56449415f1edf600ef09703aaed991e1d6f23d +dSFMT.v2.2.5+2.aarch64-linux-gnu.tar.gz/md5/260e14855dbc7773a2ca906d58cc57f2 +dSFMT.v2.2.5+2.aarch64-linux-gnu.tar.gz/sha512/820ca4c6afde931e855b74015150f4ffbb513276c3fa7dbcc1ec8d34c02d4989fb7424a6e4f81f93d054811b5f54f8633d955b05acdb088387ee90f1c3b00915 +dSFMT.v2.2.5+2.aarch64-linux-musl.tar.gz/md5/7ddccbad6b5c9de4be187fe76637a0d8 +dSFMT.v2.2.5+2.aarch64-linux-musl.tar.gz/sha512/e3c225da00927096e3a6cd4abc681fba8f469cb74828e7054d4f5684d71dcb8e75c9a81f14fa10bfbb78f62f9567a31a92edcca8d797e5810a2a44a3fc17bc84 +dSFMT.v2.2.5+2.aarch64-unknown-freebsd.tar.gz/md5/d592c490259f45acef2308fd61046404 +dSFMT.v2.2.5+2.aarch64-unknown-freebsd.tar.gz/sha512/4f4e100b4cd5301e815f29f911b3ddba845a90247f1d641ea11153f5845c700e6f94ccd4a1d46fbb9e64a0c5698c5419c52560f0629629ffd665cf9ddec24e17 +dSFMT.v2.2.5+2.armv6l-linux-gnueabihf.tar.gz/md5/a70329e0a6c57009c6b6950fd34089f6 +dSFMT.v2.2.5+2.armv6l-linux-gnueabihf.tar.gz/sha512/4418c42165660adc050e872ef834f920c89ed6a0d2b816821672b1e862e947aad7efd023289da9bf05bb2eb9ec4b9d2561c403e2d5384d5314a4ba016b1f9cfc +dSFMT.v2.2.5+2.armv6l-linux-musleabihf.tar.gz/md5/6ffc798b8a0c847fa5cb93640bd66ab3 +dSFMT.v2.2.5+2.armv6l-linux-musleabihf.tar.gz/sha512/94e5ae07d0b1420abd7290519bce6f77deae634bbb4df31e3f02416bf509e555a9b1c9d19dd77ca76a308c2b86d5c9d4718b9ef83c13167b88a8181d8ca7e73a +dSFMT.v2.2.5+2.armv7l-linux-gnueabihf.tar.gz/md5/660d95aa08580ca1716a89c4d8b1eb24 +dSFMT.v2.2.5+2.armv7l-linux-gnueabihf.tar.gz/sha512/bc757a9f805047be5375f92c10a3f3eab69345a4ec5cc997f763e66be36144a74d414ff926df8e17b9d5a2394189269c3188c55e0b7c75a72495394d65510cef +dSFMT.v2.2.5+2.armv7l-linux-musleabihf.tar.gz/md5/78c487049092fe61949d506637c713bb +dSFMT.v2.2.5+2.armv7l-linux-musleabihf.tar.gz/sha512/03ddada4478f05eab7d2971b2deaf2cba91f084d7ce66fc8219bcb3cf5c308ea13959fed95568ca80f4ce11794e197092984919265716de8f2558e2cb30d94ce +dSFMT.v2.2.5+2.i686-linux-gnu.tar.gz/md5/11463fd3981a8c143d7aed691d18d4e0 +dSFMT.v2.2.5+2.i686-linux-gnu.tar.gz/sha512/db946a4fbd8a3163b8b1c25e02bfc4a841da7d2532892a99037bd48ac98e1840691e8cc0127d9457a82667a0131e4826cb4e9d0a13f127afc62da4eb68af5a3e +dSFMT.v2.2.5+2.i686-linux-musl.tar.gz/md5/a61405f72c9a3bba5718f078c68e61a5 +dSFMT.v2.2.5+2.i686-linux-musl.tar.gz/sha512/726f130bbbfd0dece4185b89a25a73f3b5b950ebfb7f86aea6e9cbcf9ae932e591d20b854de0b4985103dbf8b4b7cb3560661c5070af971cd2c1f3ec3e1ea7d2 +dSFMT.v2.2.5+2.i686-w64-mingw32.tar.gz/md5/3bc27ef8f26c7a26f096cf1d558d408d +dSFMT.v2.2.5+2.i686-w64-mingw32.tar.gz/sha512/ea3608d3ae3874ea57a1a08f69abe2a1638bc340db71c6fe3c4fd5637d8c54943bf16b099a46817387c1ed4cb5f3cd1c0ff19ae8a4ed85dd555555821af06374 +dSFMT.v2.2.5+2.powerpc64le-linux-gnu.tar.gz/md5/fd8c73961ef7c82201e6d86e8bf4324c +dSFMT.v2.2.5+2.powerpc64le-linux-gnu.tar.gz/sha512/1bd0ebd019cfc6f25f7ba007547c5ee297854655b93c55e90d8ead420875de5a087e38956693d5e901ff2abf667c72aa66fb34f587b82adf4b91b3d5d666b5c7 +dSFMT.v2.2.5+2.riscv64-linux-gnu.tar.gz/md5/5c4981c2c016436faf6f33fa8df4204b +dSFMT.v2.2.5+2.riscv64-linux-gnu.tar.gz/sha512/9b56f0abbfb2731d23b99b5286b69c31bfc21eb14f49d88953680d5596c20c6b4d59520828f0a398915d56c82e169a36316f8e319dfe4e25a8e3f44f2aca4938 +dSFMT.v2.2.5+2.x86_64-apple-darwin.tar.gz/md5/e21e30097f1f02c5cc14cca3f73ce92f +dSFMT.v2.2.5+2.x86_64-apple-darwin.tar.gz/sha512/48b19706189eabcab2c823e6143ae22f4a330abb239c7a952913fe9973c5f750d72b113af32a82a1f6124c534495b26d1f81ccab407d8d15ee459dc83fb8d3cd +dSFMT.v2.2.5+2.x86_64-linux-gnu.tar.gz/md5/fa671f4ca14b171d53c8866d03f9162a +dSFMT.v2.2.5+2.x86_64-linux-gnu.tar.gz/sha512/2e242a1448da0508ea88cc1a106f1e74f8d7e7562cd82b80d86abf9a8b454653ad7612e25c30ce00c23757e8a5b7b5736253b00a52f9473af6c5d4df768138f2 +dSFMT.v2.2.5+2.x86_64-linux-musl.tar.gz/md5/c648294163882ec539ab646542c74880 +dSFMT.v2.2.5+2.x86_64-linux-musl.tar.gz/sha512/9e96a47d660854b6517364f0db40a2f4e0e3b814499a0349f7cf550b1c8d04589fca5eb4a75bf34f36d1b5d1b2277b3e9a961c887092abedd08f438e025329e7 +dSFMT.v2.2.5+2.x86_64-unknown-freebsd.tar.gz/md5/5a9b811be74f02202c57588f35582cb6 +dSFMT.v2.2.5+2.x86_64-unknown-freebsd.tar.gz/sha512/8dc6cae5cdf038fd5647cf86b85a15ac082d35b4532340e145b7e091839079ff47371aef6c3012a67692e492622b4f84db8f0ccf46049cc94926aed5c9cd9fb4 +dSFMT.v2.2.5+2.x86_64-w64-mingw32.tar.gz/md5/386adb3b7593c222dc7a1060a1356b21 +dSFMT.v2.2.5+2.x86_64-w64-mingw32.tar.gz/sha512/fe2ab5021126807b37042e89a22ef9a869c6a0a028680df445773b2affd11c2b02148be07d53504ea3842bb38bb62fe039529688266c1cba3545a892bd4dc185 dsfmt-2.2.5.tar.gz/md5/d22e476b52cdee7d5b90d2f289570073 dsfmt-2.2.5.tar.gz/sha512/951e8669350f750b8915a819e704eae0a9b9c9518b3e3b9a1905f9ca0d25cc4c2486cb479e258a4a114e9c26ceb73a6c4e9f1cc02ed19173aeb8f20189754f6b diff --git a/deps/checksums/gmp b/deps/checksums/gmp index c786fddafef5e..949e4d738a472 100644 --- a/deps/checksums/gmp +++ b/deps/checksums/gmp @@ -1,62 +1,66 @@ -GMP.v6.3.0+1.aarch64-apple-darwin.tar.gz/md5/70a730ecf64eefb5a13f4524e29a6388 -GMP.v6.3.0+1.aarch64-apple-darwin.tar.gz/sha512/51791b4ae0ede1db4c6e7759072d125ca56f6a3a3e43fd5970981a3b2d651f28fe0abefce4b3ad0589d3a46c143054d20fee801bbd423bd2a4c12ba97314c39c -GMP.v6.3.0+1.aarch64-linux-gnu-cxx03.tar.gz/md5/e2b0bf1317259972cdc4f0e6fc3c2bc8 -GMP.v6.3.0+1.aarch64-linux-gnu-cxx03.tar.gz/sha512/8de1dd5d6971c76693c67222725c9eb0a1d276a55a28cd49d94115123100bfe45144652421d4cde468dce67a5630736f4174c9491c8a6e2543aadcb44f1f2d12 -GMP.v6.3.0+1.aarch64-linux-gnu-cxx11.tar.gz/md5/2017b6215ed99c3aed8b04abe75cb3e9 -GMP.v6.3.0+1.aarch64-linux-gnu-cxx11.tar.gz/sha512/78b22106f96348f0d9222279fdf8d1e3f5bd400f771fb0c54dd4045985ee05b896e3097f788739eefab9a9ab09a885aad65c4adb31ae5ba59b7ab22ca10bb574 -GMP.v6.3.0+1.aarch64-linux-musl-cxx03.tar.gz/md5/6477f35f92203db871f56f047b99a1fe -GMP.v6.3.0+1.aarch64-linux-musl-cxx03.tar.gz/sha512/66a6d18979c1ee9a5d06323a717d0a5dd73efc196087349408e739d7aa0444e8ee1af4bd634f85dfd4cfa4c97c24dda4ba472b490f50409581aff967c81b0750 -GMP.v6.3.0+1.aarch64-linux-musl-cxx11.tar.gz/md5/4648558f1e42b8e679f5be494a910402 -GMP.v6.3.0+1.aarch64-linux-musl-cxx11.tar.gz/sha512/9b7ff68a412bccd423b3cffefbc6350db6db8f3f7657713767187c2c2ea3b09d835e1c80d34ab4407f79fccbec82594e024787def27b9ad2ee7ea01ef1607b53 -GMP.v6.3.0+1.aarch64-unknown-freebsd.tar.gz/md5/362bc3fdbcd6d74b9fddb8a4d640d99a -GMP.v6.3.0+1.aarch64-unknown-freebsd.tar.gz/sha512/8e560b4d1014382d784ccf7c9dc6365526566301ec6a28d115170c0be92b8e6033b6c08f922104e405cf978204579754f0740aae97d0a334e47ed6f684aa4af4 -GMP.v6.3.0+1.armv6l-linux-gnueabihf-cxx03.tar.gz/md5/6cabb238d148b3e2e76e8527e65893cd -GMP.v6.3.0+1.armv6l-linux-gnueabihf-cxx03.tar.gz/sha512/07b5673b4680781b7d42399213ecd491ede8883bbf1825689ad6678986a76581f6c4e53f17353f63bec8db8df5ed3fbddc228694eecc54ae7fc949f106bb8f14 -GMP.v6.3.0+1.armv6l-linux-gnueabihf-cxx11.tar.gz/md5/0257216ad4e96b404d456f07fcc30b09 -GMP.v6.3.0+1.armv6l-linux-gnueabihf-cxx11.tar.gz/sha512/ae8bbbbe3992f78186fe7535e450330e94e6630540eefbdfb51bb5014afd90feac0b1583e3fd2bbf226e61523647b3ec6324188bd6267c353a2a98594566c02b -GMP.v6.3.0+1.armv6l-linux-musleabihf-cxx03.tar.gz/md5/48b949c062ea27dc0dbcc07ea5387821 -GMP.v6.3.0+1.armv6l-linux-musleabihf-cxx03.tar.gz/sha512/03699c20b5c50dbd44f45a0f5f115c6b10b4e8de68d747bceba605c3090469c819b82ad7e57fe7702c1700c25aae6ab9394a22ded319bc58c80e9d20692b610e -GMP.v6.3.0+1.armv6l-linux-musleabihf-cxx11.tar.gz/md5/847ba3116072a523e1ff4ce83e5a18a8 -GMP.v6.3.0+1.armv6l-linux-musleabihf-cxx11.tar.gz/sha512/402548acd57f4112bf2435803f35ea93fd8d07f3df0e2f053b0bec6b08aa3dff4052990a724e2547ce35a29ee376b17d34b7e7e2ab45ecb4981ffc99c56f1a9f -GMP.v6.3.0+1.armv7l-linux-gnueabihf-cxx03.tar.gz/md5/5cc75b66059c3b8b5fbf9b8fcb781b10 -GMP.v6.3.0+1.armv7l-linux-gnueabihf-cxx03.tar.gz/sha512/1ef583d014c825e1d4e6d5f7e2d84c3ba183ba9490410f5d424760e275b7032e98f8377d87ed349d4969c6ef8f9b961a1e8df6f40efb406d41983446a9510303 -GMP.v6.3.0+1.armv7l-linux-gnueabihf-cxx11.tar.gz/md5/c0295c143bcb6b53d6184e2852ce35c5 -GMP.v6.3.0+1.armv7l-linux-gnueabihf-cxx11.tar.gz/sha512/3c74edb123a6f4147b416e5f7f25903bc859ac5f58f141bd463d3dff8cc2928fedf176f20869a1018a2731c1d7170444b3b3405c8f89c3fc22dc2edf9c036c24 -GMP.v6.3.0+1.armv7l-linux-musleabihf-cxx03.tar.gz/md5/a67696b02a7f67405dd84252c908e071 -GMP.v6.3.0+1.armv7l-linux-musleabihf-cxx03.tar.gz/sha512/73ba1809cfc68199401974f73e7a37b1fe00d4c0cf3e58ed85d161a8fbac4390aeb28591c3108fc503ef8fb5b131d027cb76dcf5d7731698997c2f377d929dce -GMP.v6.3.0+1.armv7l-linux-musleabihf-cxx11.tar.gz/md5/484f00cd5b0beec20f63cd6734d02611 -GMP.v6.3.0+1.armv7l-linux-musleabihf-cxx11.tar.gz/sha512/46fc56f945647f5c8577ad45f540a034f747604e5a89230d9d419b10d5f0571c7580e18e1138ea920efc08b25798c0c7110e15359de17dce3b6db7f07b8ceb3a -GMP.v6.3.0+1.i686-linux-gnu-cxx03.tar.gz/md5/d36d84638e2e5f927d15f07c55919f5f -GMP.v6.3.0+1.i686-linux-gnu-cxx03.tar.gz/sha512/61c62084ab90d25f7168281c7fb672f5bcafdf909afbf66847cfaa1077dd5474b2c27464eb76cac45f5e319aca0c4f7367fc238b83d2dde46ba90a7c1f396dfb -GMP.v6.3.0+1.i686-linux-gnu-cxx11.tar.gz/md5/d87627470bdcac981f7b004c27ac9a89 -GMP.v6.3.0+1.i686-linux-gnu-cxx11.tar.gz/sha512/2a34028687f75422b43f5365b0a8c9530b29473d41bfec4fb9822f074f813b8c6c1fc9efbfbb17a7e4d3d66f2549b5589b3fdbd08711a365330deb72be4958d0 -GMP.v6.3.0+1.i686-linux-musl-cxx03.tar.gz/md5/a2f2fc663bcacfc3e7d6aff29a52de23 -GMP.v6.3.0+1.i686-linux-musl-cxx03.tar.gz/sha512/a30a5d0ee78e747f074b3a5f0a26b9ba99b7553b3c83411a3cb9298814e605509194e9f0d8934caaa1cb7b78eef521805bbc86a297aebd06473ba80a20ffc443 -GMP.v6.3.0+1.i686-linux-musl-cxx11.tar.gz/md5/246b24935442815ff75a13b3dcf24756 -GMP.v6.3.0+1.i686-linux-musl-cxx11.tar.gz/sha512/ca351c4b93adf3f3e40f93c7b0cd61b33ec10049d39e8d33975f46d509efcded67600e6b19d8018a29ee893027d7a28edef0b19c1d70451d072a7a0989e9317d -GMP.v6.3.0+1.i686-w64-mingw32-cxx03.tar.gz/md5/c3b321ae48db0cb8dac4e09e2722e56c -GMP.v6.3.0+1.i686-w64-mingw32-cxx03.tar.gz/sha512/6a6feeb8baf6d499409a9010295b474a8c6de461fa0e34562d53e58190b66c50e278fae7560495cd85ea6f5b41f9e8c6e950ff4f451d26d0757e1d1696e8bca5 -GMP.v6.3.0+1.i686-w64-mingw32-cxx11.tar.gz/md5/3f633b0ff74c2a44350855fc6ce310b8 -GMP.v6.3.0+1.i686-w64-mingw32-cxx11.tar.gz/sha512/eecb17dec70fe84d90f47e1958672d273c865da9607ba3056c9c923a6ff9a3cab5b30414389d8f0c7f5ae5d87c05999964ed0900c80ae5afb525eaec00f401e2 -GMP.v6.3.0+1.powerpc64le-linux-gnu-cxx03.tar.gz/md5/8b5f113ad7fd4a312229cfe8c2d1abca -GMP.v6.3.0+1.powerpc64le-linux-gnu-cxx03.tar.gz/sha512/36525ffc0ac5c363810c47945c34c81daabf88cf1f9c60d236447249d06332d3f5a130b431ab2d1c0148eb5413a4fa66bdd50671f2e7fcb77858d9fcdf83a94c -GMP.v6.3.0+1.powerpc64le-linux-gnu-cxx11.tar.gz/md5/7f1237e9668136b00dd719a5cad3b6aa -GMP.v6.3.0+1.powerpc64le-linux-gnu-cxx11.tar.gz/sha512/46a6efe23173a12299da371121847d16d7950ffe5c87d1221b54c5e95dafbf723c4a327b1c2e832d4742a91254aa40fd5d8152d6d0801769b2efd4f83a042afd -GMP.v6.3.0+1.x86_64-apple-darwin.tar.gz/md5/cd2d1b309aea2c781a9c28470fd2f0eb -GMP.v6.3.0+1.x86_64-apple-darwin.tar.gz/sha512/d7f94d80f1ba170c9553601d1af323bef7bbb98575b80b58b3d7b37d69d81cdee0e132fb4fa20393a0e8719984c785d0c7e5c8ae2c29c62ffbd82b00375993d4 -GMP.v6.3.0+1.x86_64-linux-gnu-cxx03.tar.gz/md5/5be8efef65dafe52e5726ef24238ae36 -GMP.v6.3.0+1.x86_64-linux-gnu-cxx03.tar.gz/sha512/f4c303fe915c89fecdb5a333a30412e0cfb04e07b4f1bc2f726179243dbc61d60ae5b0773a6bd5da8a10cb8764e448bc88035a639ea88d2e06f04e55074d8551 -GMP.v6.3.0+1.x86_64-linux-gnu-cxx11.tar.gz/md5/66f9a3858d07591227f2bc057c3c988b -GMP.v6.3.0+1.x86_64-linux-gnu-cxx11.tar.gz/sha512/5611b9bfd24efac0a189bbd85533e1cd2bee7f833f5ae0a06343f2c1d92925e0d0f0758b99c43520293348ad61f98e1b470829514c35d208697988d8b469fc41 -GMP.v6.3.0+1.x86_64-linux-musl-cxx03.tar.gz/md5/edaa83f6432ff7e75e106d8bfd03d509 -GMP.v6.3.0+1.x86_64-linux-musl-cxx03.tar.gz/sha512/1587e7b91e387da9c23559826c161fa4d447250bd7b6565f0b9fedc36e7502dc2b59caa8157abcb7e7862d24d696470289bd650511b07e8711ecf5a462330b6d -GMP.v6.3.0+1.x86_64-linux-musl-cxx11.tar.gz/md5/e668c4f0c1246aa1510c36f246b1b483 -GMP.v6.3.0+1.x86_64-linux-musl-cxx11.tar.gz/sha512/cf4bd47a5ddb067a57e852855fbd637a93f3652c3327af256f74e9e265c9e0de7c5be78b3e7bcbf08a03916876ecdc05cc294149e2c3d472a30fedc2e6dded47 -GMP.v6.3.0+1.x86_64-unknown-freebsd.tar.gz/md5/4cbf56d2884aa357291321b182d07cb8 -GMP.v6.3.0+1.x86_64-unknown-freebsd.tar.gz/sha512/0c723b8e0f5fabf9e43945d3fb355c3d7b036662a8d6542629aaff27164f12d13b2a19f5c4964f165466705b231884b7f7193d7a01a0e9d3644da1d79af79631 -GMP.v6.3.0+1.x86_64-w64-mingw32-cxx03.tar.gz/md5/02e8f5d66c15731117cf805e0a4c4976 -GMP.v6.3.0+1.x86_64-w64-mingw32-cxx03.tar.gz/sha512/1f94805fe9f34f4e77c54e92625615d91ade617468483409037d0693c3bf106187916d9d21e92681673faae158b376133c0ede643f31bfc9f73ac29c9fd13bcc -GMP.v6.3.0+1.x86_64-w64-mingw32-cxx11.tar.gz/md5/10752137fccc73175872db07749d6f49 -GMP.v6.3.0+1.x86_64-w64-mingw32-cxx11.tar.gz/sha512/3a5d7e8125f3b538a2e59e9c6919db36c974575e6b1950451cb60307da68dc092c4ce21b8f49c40871aadf3bd07681b43eea9c7bf37ba383da9a0e80c30b176e +GMP.v6.3.0+2.aarch64-apple-darwin.tar.gz/md5/3fb601fcf70024fcc40889cf1b958441 +GMP.v6.3.0+2.aarch64-apple-darwin.tar.gz/sha512/7ecc97c1f22287e9d7f3e8073e1cc3c6b3c75aa4a350a55a0b6f92c5bf60339b52f8866994f5973077e1026b9d3b10a7bcd71ec2abf25c3cc1bf6ca1041c3e73 +GMP.v6.3.0+2.aarch64-linux-gnu-cxx03.tar.gz/md5/10581945c01bac319c9c2d76f1f7052c +GMP.v6.3.0+2.aarch64-linux-gnu-cxx03.tar.gz/sha512/3aa2799ef7783a4edb767a695bd2797776def8ce1b2dc471b2cc733371db9981d6c3f395fee2fb50b13c7ef74c1521d2787c29dc60a75e1b92652b94819b5364 +GMP.v6.3.0+2.aarch64-linux-gnu-cxx11.tar.gz/md5/c1f9765fccec8ec131faa5e31b7ac28f +GMP.v6.3.0+2.aarch64-linux-gnu-cxx11.tar.gz/sha512/aebde82400544dc7a2aef0a4531cee78f9abcac9352dfd5d86472a70d704b281de03325cc609583169ecbe4cb64623ab04a3d7fff9cf24c70991530fe530aa05 +GMP.v6.3.0+2.aarch64-linux-musl-cxx03.tar.gz/md5/b1f771c79f3b380555c1c96232074523 +GMP.v6.3.0+2.aarch64-linux-musl-cxx03.tar.gz/sha512/daca9d3b4179e99da8e61f4010f5965718c79d02627e0b3272e4d20c34dac0d933408dc7d760a6d6fa09546e436c800ad5da4a1d34283eac9558f3d2f97bebce +GMP.v6.3.0+2.aarch64-linux-musl-cxx11.tar.gz/md5/523c386457e9d48430b83f2db85ac10f +GMP.v6.3.0+2.aarch64-linux-musl-cxx11.tar.gz/sha512/18155dd92641bf6240606d23b0d3cab16bb9b63b6034a7c7c61f3728fb48a6b710fdc21c6477145c015c648557e97003b0cc6087b4b36a691daecb87272cd51a +GMP.v6.3.0+2.aarch64-unknown-freebsd.tar.gz/md5/7dd3f2813fd7e9e620a8123ae2340ab2 +GMP.v6.3.0+2.aarch64-unknown-freebsd.tar.gz/sha512/375b12dee41285b65b5cdd55f6b000a90fd431c3eeb788a928396a102594fb6fad257f2c4e707f11ce7d0e4d45bc82a77ac85d8a48fa0a42f969b48b8b2c1c23 +GMP.v6.3.0+2.armv6l-linux-gnueabihf-cxx03.tar.gz/md5/7d23f84102362ec3974ca2d84da33c4a +GMP.v6.3.0+2.armv6l-linux-gnueabihf-cxx03.tar.gz/sha512/51e419159fad75ca0ab12c31db29259be6fa280e66e2b980df4c99a0558615297741f633322978a409fbc071ec71834214b12d27d04ced0c043c569438dabd12 +GMP.v6.3.0+2.armv6l-linux-gnueabihf-cxx11.tar.gz/md5/5f809ffa56ec07cc04e3c4cb155faad0 +GMP.v6.3.0+2.armv6l-linux-gnueabihf-cxx11.tar.gz/sha512/e394afb93a2c0aebe0ac7887bb2610720cb926256f0f5e7b05f3b1a805d3f7967fb97f4227ccec049df554c6cd1c4d4e9414fc4fea33f201204dd87e207e33ff +GMP.v6.3.0+2.armv6l-linux-musleabihf-cxx03.tar.gz/md5/494564a56197edc5b8772c15eca7b117 +GMP.v6.3.0+2.armv6l-linux-musleabihf-cxx03.tar.gz/sha512/a7bd8bc19a030c56edd4d91e3cff16d78d4a9c1c1bec99897e55cfaca7e14cb99cee32e220473e207b78f0b5e0c0bf188c679d1748c010380485fad4d89758c5 +GMP.v6.3.0+2.armv6l-linux-musleabihf-cxx11.tar.gz/md5/751c36d4975d6ff88eb968123afc1845 +GMP.v6.3.0+2.armv6l-linux-musleabihf-cxx11.tar.gz/sha512/af471834ba32a970b4f358a263434b03e169dc48445aa5af412ec51e70668a41699f9c408d90f64b06dc9233360f70a03df859428fdc0d759e5696a3ae32f3f4 +GMP.v6.3.0+2.armv7l-linux-gnueabihf-cxx03.tar.gz/md5/ea9c867ae191a29647e8ccfb67947bc6 +GMP.v6.3.0+2.armv7l-linux-gnueabihf-cxx03.tar.gz/sha512/d6c44c945d1ef869155be087320d7750be549399b186aad8c92bba32ff5312bf09cbb2fb57be91be237be7d50f8f6ef0aea67070f50c024e6f5302485f405d5e +GMP.v6.3.0+2.armv7l-linux-gnueabihf-cxx11.tar.gz/md5/ee5becfac9fe3c448a5de322ddee66d7 +GMP.v6.3.0+2.armv7l-linux-gnueabihf-cxx11.tar.gz/sha512/bc9bb2ad83644cf0b9f2bb0bfce28938ee6e82dbc0de74d1f411a8eb5ab96c5ec00c648019384ec07f34a469bd984d6c62eac1bcb803eaa013b6c85547ec3277 +GMP.v6.3.0+2.armv7l-linux-musleabihf-cxx03.tar.gz/md5/23962e487398f02c8d660724d88bf7f6 +GMP.v6.3.0+2.armv7l-linux-musleabihf-cxx03.tar.gz/sha512/4c561053f79ed976a698c7382c5c94ebcbcd25ed27c939016bbb4af59948fd6bfb82e494e18fc7b4969941a7756c33afd2f177b3158f1b3d659215c25c958d2c +GMP.v6.3.0+2.armv7l-linux-musleabihf-cxx11.tar.gz/md5/4734feb61dd3f2a4e6e395f9ac7ccf57 +GMP.v6.3.0+2.armv7l-linux-musleabihf-cxx11.tar.gz/sha512/088a52c372681b4853fe7c4c70eb8625b58df6d79eea2a8982bd781458188930aa31dd9a121ff7a6d00cd8165f5d126155d7f931100aeff256b55a2281d44a90 +GMP.v6.3.0+2.i686-linux-gnu-cxx03.tar.gz/md5/e229a7a09d6c843f03028b036a54b786 +GMP.v6.3.0+2.i686-linux-gnu-cxx03.tar.gz/sha512/d92cccfdd7abe3ca5c6ee1eecfe3f7aebe875ca6b9f6257bf1181dc5ee9c873a930ebb2accc825596ee26dc45bd290a482f0405cfd7a3a1b0eb606f5ca897b70 +GMP.v6.3.0+2.i686-linux-gnu-cxx11.tar.gz/md5/01dbe43b15197cd39351dce91b3a62c9 +GMP.v6.3.0+2.i686-linux-gnu-cxx11.tar.gz/sha512/d6e7ea99f76e10b4f7733d8c7f4af3fb2fc09618510c222da1fb95e8b4c83b0aa7c5d2f896bb620546bf39041d6dc1b32ca74ddf5024ef1beb5526b374ba885c +GMP.v6.3.0+2.i686-linux-musl-cxx03.tar.gz/md5/ce2f8d8b59228888cb7f03da0c1aca70 +GMP.v6.3.0+2.i686-linux-musl-cxx03.tar.gz/sha512/cc024a2ca4b4f042c19f667c4c3c08e3041d9b9ea0279cc668a3c0212103e86444abbdb323304e05c506b44b3c1b32a55f90c04cc32e9d26ac013336821c9ac1 +GMP.v6.3.0+2.i686-linux-musl-cxx11.tar.gz/md5/c37741b3a03ef2e705d45124eae25afa +GMP.v6.3.0+2.i686-linux-musl-cxx11.tar.gz/sha512/c343ad2ea47d5775e6e4c50fd8d46745d39f3632f4ad479199f7583fd02b08a0126048625d3999b23a0534e4f5c2bf19d021436229689da7c794427102c7780b +GMP.v6.3.0+2.i686-w64-mingw32-cxx03.tar.gz/md5/52a773a2111f7b1f938e78263c4608b0 +GMP.v6.3.0+2.i686-w64-mingw32-cxx03.tar.gz/sha512/6ef89b7eda8f0709315c1080e4d57810f976939c755f160e34b04e4c199409c8c707036fae5a73fca3a16813cb4ceff8daca38d1ead73e36d7ff23506e5bb4b1 +GMP.v6.3.0+2.i686-w64-mingw32-cxx11.tar.gz/md5/88b1ff47d913fa301c95e9e2aecf42ce +GMP.v6.3.0+2.i686-w64-mingw32-cxx11.tar.gz/sha512/3d631ee81906627a8bd9194fa8f18b634467565c10e5e08db7d1a4b0943bae9391ae15a1c39533c9796edf24e1f0210d082e44dc7c1fbd9f93855f37e207da07 +GMP.v6.3.0+2.powerpc64le-linux-gnu-cxx03.tar.gz/md5/0b2c73cf7936500ce0f07577c4c76ba5 +GMP.v6.3.0+2.powerpc64le-linux-gnu-cxx03.tar.gz/sha512/30e099bd6384e801fb28b4741810122f82ab0760a4e09d6ab28559b72feff278a48150579907cb2920a624fc85287a197743331bc1808353d0855c198341bfa1 +GMP.v6.3.0+2.powerpc64le-linux-gnu-cxx11.tar.gz/md5/f496279b474948435f836ba39291c708 +GMP.v6.3.0+2.powerpc64le-linux-gnu-cxx11.tar.gz/sha512/c37d4fbba284af87fc16a24bf1fdfe80b42c84bd44f1859d1c9ee97fdbb489817b58db80a078729e19c8a5b8448f9234408a8e477fd15acf15521f3129e86acd +GMP.v6.3.0+2.riscv64-linux-gnu-cxx03.tar.gz/md5/f07fc6751104a407ea2515fda3f26880 +GMP.v6.3.0+2.riscv64-linux-gnu-cxx03.tar.gz/sha512/435b375da747d2dfba06a303b55118471c6ef705cc65afeabb5a59477cc98aa9a956b31c5e8b571126f63d922498b9a66510f8f6810a60f6a4fabba5ec368cdf +GMP.v6.3.0+2.riscv64-linux-gnu-cxx11.tar.gz/md5/493c24a7a7370f308f0da2955f40b5d5 +GMP.v6.3.0+2.riscv64-linux-gnu-cxx11.tar.gz/sha512/2e1a7562b759219d1a4283372e66fa1e907279c5b5feb8a858f6bd8de8b9c2ef3ddd09d5e812d93813fa781090574fd26d0cec85b211274db628681301a206f9 +GMP.v6.3.0+2.x86_64-apple-darwin.tar.gz/md5/c3bb785e10fe19cf1c47db6bc5e98fdd +GMP.v6.3.0+2.x86_64-apple-darwin.tar.gz/sha512/5280896654e1c7864d770ecbfc853a1c7837c2b1dd369047432d10f831762a26fdaeac4201ca419d8bf7c545c107800b892660f4484b5eb87bfaf42c919fb640 +GMP.v6.3.0+2.x86_64-linux-gnu-cxx03.tar.gz/md5/0fd62bb914554c3cb6b5dc0f5ec0d330 +GMP.v6.3.0+2.x86_64-linux-gnu-cxx03.tar.gz/sha512/78cdf0cdcdca4a0ddc87755f4afdb8f290fa946b3c5541a3e31145f8bd905884d59f38e9f5ee4fe96ceaedaf90881af795f4e3ecf1be922103b838964da101cf +GMP.v6.3.0+2.x86_64-linux-gnu-cxx11.tar.gz/md5/02f54f8895bae0d7a824374888300744 +GMP.v6.3.0+2.x86_64-linux-gnu-cxx11.tar.gz/sha512/83c865f6164400e56c28949c680cf92457daa270b745d89034e1bcc46af1eb93c96bce708561dee03b58162191f6448e4325e921daec11083bbc42dcf3a1ffda +GMP.v6.3.0+2.x86_64-linux-musl-cxx03.tar.gz/md5/8f3f26422f8bd0889b5c2ecd22d97101 +GMP.v6.3.0+2.x86_64-linux-musl-cxx03.tar.gz/sha512/680beb99936433bc1c3367e85f3a4129c5a99d4c4031a1da919293819f6d3f1b85be801a2f48af352c47d7cb6f394534333f1a0d0404ff41899952d55c4b1f75 +GMP.v6.3.0+2.x86_64-linux-musl-cxx11.tar.gz/md5/7ec0e3e9125c14a20d6d0044036f0996 +GMP.v6.3.0+2.x86_64-linux-musl-cxx11.tar.gz/sha512/c22e6a25ec854f9c199d5e76bc1dbcbe57c4cc219eb2b5f24418729252eee1a5c1d3e8bbf5b62d148cb408595e96f448f68a29a9425a902952bee666b6f051f6 +GMP.v6.3.0+2.x86_64-unknown-freebsd.tar.gz/md5/6782d7fd0bd15c189c4a1753ee0fb0eb +GMP.v6.3.0+2.x86_64-unknown-freebsd.tar.gz/sha512/04d7a95337e832f7ec228f160a09b74ed7908ef9cef1bd392555392a24ff63ce4a88b616b5426cd710dcb581e164bb94c04fe17f0b599adf3c3bc33106bcd886 +GMP.v6.3.0+2.x86_64-w64-mingw32-cxx03.tar.gz/md5/b4cb31e93c85cd453b7d8d392a365088 +GMP.v6.3.0+2.x86_64-w64-mingw32-cxx03.tar.gz/sha512/3bd84fa8f580b272eecb06077ef710ae8df661126e86afa2c901b298a2598975a07f840b922da0066dbf555f03376cba1b7e4915cd37617341fd420b6707276d +GMP.v6.3.0+2.x86_64-w64-mingw32-cxx11.tar.gz/md5/2342842254e7b47b26836366d29d6802 +GMP.v6.3.0+2.x86_64-w64-mingw32-cxx11.tar.gz/sha512/fb12be14433763d9de689a5df222802cd79d5c990da9a53855fd2f6f8e663a9838b444a310318c059cdb4962eb87d0d4cc2b54d163cf82b09377339c8e45510f gmp-6.3.0.tar.bz2/md5/c1cd6ef33085e9cb818b9b08371f9000 gmp-6.3.0.tar.bz2/sha512/3b684c9bcb9ede2b7e54d0ba4c9764bfa17c20d4f3000017c553b6f1e135b536949580ff37341680c25dc236cfe0ba1db8cfdfe619ce013656189ef0871b89f8 diff --git a/deps/checksums/libssh2 b/deps/checksums/libssh2 index fa05f325fa6a7..056d373656d98 100644 --- a/deps/checksums/libssh2 +++ b/deps/checksums/libssh2 @@ -1,36 +1,38 @@ -LibSSH2.v1.11.3+0.aarch64-apple-darwin.tar.gz/md5/87ba86e78421d6195aa6a46129ff61d4 -LibSSH2.v1.11.3+0.aarch64-apple-darwin.tar.gz/sha512/2b7129be9e9518337f59857474882a6a3448f358c931c66ab9f9ec67506c68d2356df591bd45925154844ca0d6f6e1f071d4c54d62039c5078b468fcb356187b -LibSSH2.v1.11.3+0.aarch64-linux-gnu.tar.gz/md5/84c6eb68e7797038d0863513fa4e292f -LibSSH2.v1.11.3+0.aarch64-linux-gnu.tar.gz/sha512/3012beb35fdf94136907037e8f5261a5cc94d102f461172321d4ed8f328da3789d521513dd03cb344c6fcb73675cd1d3ede606bf9a904fb811d40c43fd09d8aa -LibSSH2.v1.11.3+0.aarch64-linux-musl.tar.gz/md5/5a49057201e779f3427b794b72bf07a2 -LibSSH2.v1.11.3+0.aarch64-linux-musl.tar.gz/sha512/62a812efb4ad7b24bfeeb3bb89756004215c09a1cc01e0530f14ce4b8546f1dcbbac18155ac2ce08311c1790d659b14674e3bb3549ff68d1209d52b5e5986fff -LibSSH2.v1.11.3+0.aarch64-unknown-freebsd.tar.gz/md5/a5129167b7be7ac8ba2c873e164afb1b -LibSSH2.v1.11.3+0.aarch64-unknown-freebsd.tar.gz/sha512/f8d9cc5098a3b401fbbe98a24efaca0ea46f533ecaf11dbfe8f7e7e3853363af19914de62bd1cb5a573e55e90d5c6074532ddc6d64723c9e235b277f438ce6ef -LibSSH2.v1.11.3+0.armv6l-linux-gnueabihf.tar.gz/md5/5c59c95612bf9aa172e5d487002db509 -LibSSH2.v1.11.3+0.armv6l-linux-gnueabihf.tar.gz/sha512/5ba41e49365c2018d55c92e4a23d806ca9ab960a448593b08380527da21eec03f76cab89c34befbc56f4104002aa189d5cae6f655797f1447f395b51a14d40e2 -LibSSH2.v1.11.3+0.armv6l-linux-musleabihf.tar.gz/md5/4bc27411f0eddf82a787d1ede17ce2c3 -LibSSH2.v1.11.3+0.armv6l-linux-musleabihf.tar.gz/sha512/d6024b6949ac6867c56c66defbb99300a5661e0c73da6c330165bceba78d64063986c8851601ca74554b27944d5b02e3f602b1e71781097bbb8b12effc0cbbdb -LibSSH2.v1.11.3+0.armv7l-linux-gnueabihf.tar.gz/md5/40e1a0d323969b96ab121eb5a3ecc874 -LibSSH2.v1.11.3+0.armv7l-linux-gnueabihf.tar.gz/sha512/67ce15a5b1c1fe0fd1096ed5d2d9f44d83983de11c1bc651f5914d70d387a99ee6bde31716031b758f48981e2a9383599f077f02d61a5c783ee6d09a7bf445db -LibSSH2.v1.11.3+0.armv7l-linux-musleabihf.tar.gz/md5/9453c52394b1b06bd36c43e461a3b48f -LibSSH2.v1.11.3+0.armv7l-linux-musleabihf.tar.gz/sha512/c62068ecb1b88dbd08a2474e0b93cd313bdc4e1407a22cd9164a73b2d897564f12a3c34f6fc492b264af579b00e9335a0fe1fa853fbe0fbb18d8335b77d409b2 -LibSSH2.v1.11.3+0.i686-linux-gnu.tar.gz/md5/992453b1c59033aefa8d98b89f491ff6 -LibSSH2.v1.11.3+0.i686-linux-gnu.tar.gz/sha512/ebf14565d614086c4401e1a997a3aacc83f8e499ed836c429f87c4f95f1c8409713fad47f1c34a2b1cd23f90de3daf14caafba3c82b15642018592213607c874 -LibSSH2.v1.11.3+0.i686-linux-musl.tar.gz/md5/e0cb0566c724c107f4f04619080d4c0c -LibSSH2.v1.11.3+0.i686-linux-musl.tar.gz/sha512/af7d08dba5bb06eaf7ce8aeb12b69701d3c2829996a1c8e68510c106402a1166ad060687987df49365c26d30e8d6511c66f2a50ec810a493d2c090931ccf05a5 -LibSSH2.v1.11.3+0.i686-w64-mingw32.tar.gz/md5/c5e8d3145deb56d6df008522a5d3ea6f -LibSSH2.v1.11.3+0.i686-w64-mingw32.tar.gz/sha512/47f3c36747d2e42a4c0669ef468d395078328235d30056b7d67d76bd737b5118c1bbc720aef455c4d9017e7b9350e8cc043ed28264ea8a9ecb6833ca517f82aa -LibSSH2.v1.11.3+0.powerpc64le-linux-gnu.tar.gz/md5/12eba4aec5e320a4d0cf09225bca3f7c -LibSSH2.v1.11.3+0.powerpc64le-linux-gnu.tar.gz/sha512/d6b8413d77d8af3d29b867692f6c02b63e793f5e8f17c4777756d247c8e602b3ab87380031aefa60f2c3ddae5a3c7a1f1c739439f149db34a32c79f32e08048b -LibSSH2.v1.11.3+0.x86_64-apple-darwin.tar.gz/md5/f6e7cd35e16290b198c80c61a0fca5e5 -LibSSH2.v1.11.3+0.x86_64-apple-darwin.tar.gz/sha512/2c83814ef6ae78ec94a43f2997151dd7195c0a0f9cf456fcd3f780268bd1cbdd7ea55182fc5a1f8e1413c26889e54fccb01964b0b91dd4b925ecaa16b7df8d07 -LibSSH2.v1.11.3+0.x86_64-linux-gnu.tar.gz/md5/95aa96befc9f9007e6a000a95c1b7572 -LibSSH2.v1.11.3+0.x86_64-linux-gnu.tar.gz/sha512/6058dca6d933afb7fe5fc3374937b4432f202a5dfe3ebcc2f91f65777230c18d76801c38071f84f8362527ee08656a97f79da234ab5481265a7ccf29e94c20c5 -LibSSH2.v1.11.3+0.x86_64-linux-musl.tar.gz/md5/88b69d889d602bc3df420535dba30f9e -LibSSH2.v1.11.3+0.x86_64-linux-musl.tar.gz/sha512/7335954124074e7df786989db86e86e3bcf41f503b8e3b27d6ac18032c8025bec26180bd2c537b23349bcf5673eb67245531479b939670e620faf5aa13c8c4ab -LibSSH2.v1.11.3+0.x86_64-unknown-freebsd.tar.gz/md5/6d5f6e9455c35c5f6655cb4d46797db0 -LibSSH2.v1.11.3+0.x86_64-unknown-freebsd.tar.gz/sha512/9515d11bb5686e29eb5a37bbcb7ab07574da0869c82e5b3f0cf282bbc56792af31e6174521d58133968b997caa6db75ac9b195024144fd2c95fd1bbf689ebbf6 -LibSSH2.v1.11.3+0.x86_64-w64-mingw32.tar.gz/md5/e66cdac0c2d5ce2d160e482d780ad0c3 -LibSSH2.v1.11.3+0.x86_64-w64-mingw32.tar.gz/sha512/2dabb1e8da5ea496898751d5517ca37178e1a44c78c26fe33f87487a0b4acf7185f686ce8d6ea0e65e38a8fd56e5ff09fd70becda402a942b5e459707eb2a44e +LibSSH2.v1.11.3+1.aarch64-apple-darwin.tar.gz/md5/87ba86e78421d6195aa6a46129ff61d4 +LibSSH2.v1.11.3+1.aarch64-apple-darwin.tar.gz/sha512/2b7129be9e9518337f59857474882a6a3448f358c931c66ab9f9ec67506c68d2356df591bd45925154844ca0d6f6e1f071d4c54d62039c5078b468fcb356187b +LibSSH2.v1.11.3+1.aarch64-linux-gnu.tar.gz/md5/84c6eb68e7797038d0863513fa4e292f +LibSSH2.v1.11.3+1.aarch64-linux-gnu.tar.gz/sha512/3012beb35fdf94136907037e8f5261a5cc94d102f461172321d4ed8f328da3789d521513dd03cb344c6fcb73675cd1d3ede606bf9a904fb811d40c43fd09d8aa +LibSSH2.v1.11.3+1.aarch64-linux-musl.tar.gz/md5/5a49057201e779f3427b794b72bf07a2 +LibSSH2.v1.11.3+1.aarch64-linux-musl.tar.gz/sha512/62a812efb4ad7b24bfeeb3bb89756004215c09a1cc01e0530f14ce4b8546f1dcbbac18155ac2ce08311c1790d659b14674e3bb3549ff68d1209d52b5e5986fff +LibSSH2.v1.11.3+1.aarch64-unknown-freebsd.tar.gz/md5/a5129167b7be7ac8ba2c873e164afb1b +LibSSH2.v1.11.3+1.aarch64-unknown-freebsd.tar.gz/sha512/f8d9cc5098a3b401fbbe98a24efaca0ea46f533ecaf11dbfe8f7e7e3853363af19914de62bd1cb5a573e55e90d5c6074532ddc6d64723c9e235b277f438ce6ef +LibSSH2.v1.11.3+1.armv6l-linux-gnueabihf.tar.gz/md5/5c59c95612bf9aa172e5d487002db509 +LibSSH2.v1.11.3+1.armv6l-linux-gnueabihf.tar.gz/sha512/5ba41e49365c2018d55c92e4a23d806ca9ab960a448593b08380527da21eec03f76cab89c34befbc56f4104002aa189d5cae6f655797f1447f395b51a14d40e2 +LibSSH2.v1.11.3+1.armv6l-linux-musleabihf.tar.gz/md5/4bc27411f0eddf82a787d1ede17ce2c3 +LibSSH2.v1.11.3+1.armv6l-linux-musleabihf.tar.gz/sha512/d6024b6949ac6867c56c66defbb99300a5661e0c73da6c330165bceba78d64063986c8851601ca74554b27944d5b02e3f602b1e71781097bbb8b12effc0cbbdb +LibSSH2.v1.11.3+1.armv7l-linux-gnueabihf.tar.gz/md5/40e1a0d323969b96ab121eb5a3ecc874 +LibSSH2.v1.11.3+1.armv7l-linux-gnueabihf.tar.gz/sha512/67ce15a5b1c1fe0fd1096ed5d2d9f44d83983de11c1bc651f5914d70d387a99ee6bde31716031b758f48981e2a9383599f077f02d61a5c783ee6d09a7bf445db +LibSSH2.v1.11.3+1.armv7l-linux-musleabihf.tar.gz/md5/9453c52394b1b06bd36c43e461a3b48f +LibSSH2.v1.11.3+1.armv7l-linux-musleabihf.tar.gz/sha512/c62068ecb1b88dbd08a2474e0b93cd313bdc4e1407a22cd9164a73b2d897564f12a3c34f6fc492b264af579b00e9335a0fe1fa853fbe0fbb18d8335b77d409b2 +LibSSH2.v1.11.3+1.i686-linux-gnu.tar.gz/md5/992453b1c59033aefa8d98b89f491ff6 +LibSSH2.v1.11.3+1.i686-linux-gnu.tar.gz/sha512/ebf14565d614086c4401e1a997a3aacc83f8e499ed836c429f87c4f95f1c8409713fad47f1c34a2b1cd23f90de3daf14caafba3c82b15642018592213607c874 +LibSSH2.v1.11.3+1.i686-linux-musl.tar.gz/md5/e0cb0566c724c107f4f04619080d4c0c +LibSSH2.v1.11.3+1.i686-linux-musl.tar.gz/sha512/af7d08dba5bb06eaf7ce8aeb12b69701d3c2829996a1c8e68510c106402a1166ad060687987df49365c26d30e8d6511c66f2a50ec810a493d2c090931ccf05a5 +LibSSH2.v1.11.3+1.i686-w64-mingw32.tar.gz/md5/c5e8d3145deb56d6df008522a5d3ea6f +LibSSH2.v1.11.3+1.i686-w64-mingw32.tar.gz/sha512/47f3c36747d2e42a4c0669ef468d395078328235d30056b7d67d76bd737b5118c1bbc720aef455c4d9017e7b9350e8cc043ed28264ea8a9ecb6833ca517f82aa +LibSSH2.v1.11.3+1.powerpc64le-linux-gnu.tar.gz/md5/12eba4aec5e320a4d0cf09225bca3f7c +LibSSH2.v1.11.3+1.powerpc64le-linux-gnu.tar.gz/sha512/d6b8413d77d8af3d29b867692f6c02b63e793f5e8f17c4777756d247c8e602b3ab87380031aefa60f2c3ddae5a3c7a1f1c739439f149db34a32c79f32e08048b +LibSSH2.v1.11.3+1.riscv64-linux-gnu.tar.gz/md5/cc11dd403ecaa373241b3c30cd16bd24 +LibSSH2.v1.11.3+1.riscv64-linux-gnu.tar.gz/sha512/d195ad62cde58dfa1e3546efd70a5f6b8a0762a2a933c637120aa71eda45dc6dc4213e87f9f401e2e148bbd5fb10638e429ae514bcda5bada0940c70cb7ff15e +LibSSH2.v1.11.3+1.x86_64-apple-darwin.tar.gz/md5/f6e7cd35e16290b198c80c61a0fca5e5 +LibSSH2.v1.11.3+1.x86_64-apple-darwin.tar.gz/sha512/2c83814ef6ae78ec94a43f2997151dd7195c0a0f9cf456fcd3f780268bd1cbdd7ea55182fc5a1f8e1413c26889e54fccb01964b0b91dd4b925ecaa16b7df8d07 +LibSSH2.v1.11.3+1.x86_64-linux-gnu.tar.gz/md5/95aa96befc9f9007e6a000a95c1b7572 +LibSSH2.v1.11.3+1.x86_64-linux-gnu.tar.gz/sha512/6058dca6d933afb7fe5fc3374937b4432f202a5dfe3ebcc2f91f65777230c18d76801c38071f84f8362527ee08656a97f79da234ab5481265a7ccf29e94c20c5 +LibSSH2.v1.11.3+1.x86_64-linux-musl.tar.gz/md5/88b69d889d602bc3df420535dba30f9e +LibSSH2.v1.11.3+1.x86_64-linux-musl.tar.gz/sha512/7335954124074e7df786989db86e86e3bcf41f503b8e3b27d6ac18032c8025bec26180bd2c537b23349bcf5673eb67245531479b939670e620faf5aa13c8c4ab +LibSSH2.v1.11.3+1.x86_64-unknown-freebsd.tar.gz/md5/6d5f6e9455c35c5f6655cb4d46797db0 +LibSSH2.v1.11.3+1.x86_64-unknown-freebsd.tar.gz/sha512/9515d11bb5686e29eb5a37bbcb7ab07574da0869c82e5b3f0cf282bbc56792af31e6174521d58133968b997caa6db75ac9b195024144fd2c95fd1bbf689ebbf6 +LibSSH2.v1.11.3+1.x86_64-w64-mingw32.tar.gz/md5/e66cdac0c2d5ce2d160e482d780ad0c3 +LibSSH2.v1.11.3+1.x86_64-w64-mingw32.tar.gz/sha512/2dabb1e8da5ea496898751d5517ca37178e1a44c78c26fe33f87487a0b4acf7185f686ce8d6ea0e65e38a8fd56e5ff09fd70becda402a942b5e459707eb2a44e libssh2-a312b43325e3383c865a87bb1d26cb52e3292641.tar.gz/md5/06d5e2881ac023583c7fd6665d628a87 libssh2-a312b43325e3383c865a87bb1d26cb52e3292641.tar.gz/sha512/5dee8cce91853eb8c9968d7453b1ad0c3cd1411901d288f1731b7c7e4adf380313f61c2a66eee0d3b89eba79e420e13269bb3738bcf2c59f0b88276aa785fa8c diff --git a/deps/checksums/libuv b/deps/checksums/libuv index 49869af795d45..fb2904b308a90 100644 --- a/deps/checksums/libuv +++ b/deps/checksums/libuv @@ -1,36 +1,38 @@ -LibUV.v2.0.1+19.aarch64-apple-darwin.tar.gz/md5/f176c76e5e2096dea8443302cf9550b8 -LibUV.v2.0.1+19.aarch64-apple-darwin.tar.gz/sha512/4301b13953a08a758b86e30af3261fd9a291ce3829b4d98e71e2a2c040e322e284c5a6eb4bc7189cc352f4b1cf7041e2cfd3380d511d88c151df3101ad74594e -LibUV.v2.0.1+19.aarch64-linux-gnu.tar.gz/md5/c81515783363702a1bd4b65fd6d7f36b -LibUV.v2.0.1+19.aarch64-linux-gnu.tar.gz/sha512/011429365337f5a45e56ca7a42709866bb994c747a1170d870f5f3ddfff2d36138866ee9278ac01172bc71bde8dee404bcb9cae9c7b44222bf1cc883659df269 -LibUV.v2.0.1+19.aarch64-linux-musl.tar.gz/md5/e74d5ea4912dd326b2705638faa7b805 -LibUV.v2.0.1+19.aarch64-linux-musl.tar.gz/sha512/a26a9f2c9051816230324071c502321f7af3885d581a400615858a93a4cd457226048d15b0e7f6a73d12659763c705b5ab519e9f5b35c6d886b9fd5babbfe352 -LibUV.v2.0.1+19.aarch64-unknown-freebsd.tar.gz/md5/f2fe50ada3b6935af4f6b28fbc3940b2 -LibUV.v2.0.1+19.aarch64-unknown-freebsd.tar.gz/sha512/c4ba0190d21c6edb561062b2615792e9b4c2474dfc200d9dba12a3add44e1fbc0b74989748d85576f0a6e42d8e0bc02f6cb13b5963f3a56b00edffe6348a9f26 -LibUV.v2.0.1+19.armv6l-linux-gnueabihf.tar.gz/md5/6df38bcf5d0a61dee63d16b73d0c9a24 -LibUV.v2.0.1+19.armv6l-linux-gnueabihf.tar.gz/sha512/d5354a6532061de0a58965ce0e427bde52f9ae0ee39a98e1a33de4c414fddcba9ba139ddf91be7321a4ccc97bbf7a8a8357ff10cf60f83c0a6bff7d839d6d7a8 -LibUV.v2.0.1+19.armv6l-linux-musleabihf.tar.gz/md5/6f02a24cfbfae3032fadceaea1faed39 -LibUV.v2.0.1+19.armv6l-linux-musleabihf.tar.gz/sha512/7fd107eb9a5ea84b488ea02e4fbedc9fe13bb11be859986a47af38f40ad775dd9f738c790878a3503437bcac1eb26ad9fe26f4aa0d3cb45c980b4c5abc9aec99 -LibUV.v2.0.1+19.armv7l-linux-gnueabihf.tar.gz/md5/96b09dec72f7e9b7409fa2920e67c866 -LibUV.v2.0.1+19.armv7l-linux-gnueabihf.tar.gz/sha512/6a0f79fc15c944fabba5c65180b665bc9769c6ff25863e330049f48b3a4394b448492f5a9a76bb7f8dbd3ce44dfc6f9ccdc2c71c42e1c749e88070fe99b1db69 -LibUV.v2.0.1+19.armv7l-linux-musleabihf.tar.gz/md5/f44e4b2521a813181f943895bdb0dd3c -LibUV.v2.0.1+19.armv7l-linux-musleabihf.tar.gz/sha512/cda1413dca817f772e8b343db0c6de0ef6b8f269e9a6a2ef3403c2582aeab554f46281bbb1eb4659c259198ef47fe26aab648a281e66f80aaf2f2cda0a23ac05 -LibUV.v2.0.1+19.i686-linux-gnu.tar.gz/md5/1f231d89cf9c04515d2d107a5d786cc8 -LibUV.v2.0.1+19.i686-linux-gnu.tar.gz/sha512/089cb8a372cdee0cbc0e78fc201611bb9bafd99af9a78e09d6097a6b70e7c4aa001ebd86f944b0a885c072093c529bf86bcaa32bde4fc1934407a858c1a5a764 -LibUV.v2.0.1+19.i686-linux-musl.tar.gz/md5/01cfc2a9e2536dbd330267917abb19ce -LibUV.v2.0.1+19.i686-linux-musl.tar.gz/sha512/72f3588cb464a60e61f8998242aaa2abdf93df920a2feba5e1d66ef0f2498488df0ec415cbb499d7f75c47bdfc7e3a2fdda6a94383492e0ad13e464eb1314ff8 -LibUV.v2.0.1+19.i686-w64-mingw32.tar.gz/md5/8c6599aab9ed4c46e52f03683aac664e -LibUV.v2.0.1+19.i686-w64-mingw32.tar.gz/sha512/13f0565f7244a8bcf1ab43fac91a856dc86d214877033a3cefee8c2179c1a275dfd7dda32e9017763acac2ba42ab6799934a58f5feaa38fb6cf2253dd713f57a -LibUV.v2.0.1+19.powerpc64le-linux-gnu.tar.gz/md5/af0e43d9d0aa91dd82b63220d96991ef -LibUV.v2.0.1+19.powerpc64le-linux-gnu.tar.gz/sha512/9fabe3089e4fc60e910770c32d36300ce8ef36c28e8cc9c72fbecba6eb80285ee8174e84e4452fb4ce90ee7c7f94e99b03fce47d8c579bd614bfffd553f93666 -LibUV.v2.0.1+19.x86_64-apple-darwin.tar.gz/md5/871040e874eedae54553d8f1c91b9133 -LibUV.v2.0.1+19.x86_64-apple-darwin.tar.gz/sha512/d5eee08b65e4bb8b444c61ac277bec9ef944b9279dd7f0732b3cd91d47788c77938e5db71e019e01bbe7785a75df95faf14368764f700c6b7a6b9e4d96d6b4c2 -LibUV.v2.0.1+19.x86_64-linux-gnu.tar.gz/md5/d2d186952c6d017fe33f6a6bea63a3ea -LibUV.v2.0.1+19.x86_64-linux-gnu.tar.gz/sha512/15501534bf5721e6bb668aabe6dc6375349f7a284e28df0609d00982e7e456908bd6868722391afa7f44a5c82faedc8cf544f69a0e4fb9fb0d529b3ae3d44d78 -LibUV.v2.0.1+19.x86_64-linux-musl.tar.gz/md5/271d4d40a1ae53ed5b2376e5936cfcf9 -LibUV.v2.0.1+19.x86_64-linux-musl.tar.gz/sha512/1956f059ed01f66b72349d6561b04e6a89b7257c0f838d7fbdd2cee79bd126bb46b93bf944a042b5a6a235762a7a0cdd117207342dd55a0c58653a70b4a38d48 -LibUV.v2.0.1+19.x86_64-unknown-freebsd.tar.gz/md5/62fe8523948914fbe7e28bf0b8d73594 -LibUV.v2.0.1+19.x86_64-unknown-freebsd.tar.gz/sha512/e6486888028c96975f74bc9313cba9706f6bf2be085aa776c44cbb2886753b2eee62469a0be92eb0542df1d0f51db3b34c7ba5e46842e16c6ff1d20e11b75322 -LibUV.v2.0.1+19.x86_64-w64-mingw32.tar.gz/md5/ae103f24b6e1830cdbe02143826fe551 -LibUV.v2.0.1+19.x86_64-w64-mingw32.tar.gz/sha512/f814085c135815947f342ff24fa0e1015e283ccece84a5b8dd5ccec0f5928a129e5fd79100a33b131376ad696f70b5acadcc5a02a7e6544635ecf7e18003ba1c +LibUV.v2.0.1+20.aarch64-apple-darwin.tar.gz/md5/7b889e32bcb01afc19f9f3801b28a0fd +LibUV.v2.0.1+20.aarch64-apple-darwin.tar.gz/sha512/cfa58e835512957171c7f2dcc9171bd9ea1717f71ed6920b6cac2560da3c5b13440df0d14c5aee210df3346743d3605dec22d78891e8237f5c3867d5cb6d4f56 +LibUV.v2.0.1+20.aarch64-linux-gnu.tar.gz/md5/696ae3e79f9b838a98dae8152d980ff4 +LibUV.v2.0.1+20.aarch64-linux-gnu.tar.gz/sha512/74ac009cebfa3ec67209921296f5d395c2f888d825b0f3d3f3bad5432819deaf5ee758f88030e620530e94f4861734d7984b8ef981ae4eebc356d96e274d678d +LibUV.v2.0.1+20.aarch64-linux-musl.tar.gz/md5/d23a45e4d9cefad93e3e83cf990c095a +LibUV.v2.0.1+20.aarch64-linux-musl.tar.gz/sha512/80d06afae0b5ab657c5c743beeaff112c3cddabd2a2604f8fc16a50cab5db878b4ea8941496a11004c9464bcada13844528cc4fee209bdd8ba374d9b13351991 +LibUV.v2.0.1+20.aarch64-unknown-freebsd.tar.gz/md5/7957f7740cfe6dd5ccb4ff4cd2811b45 +LibUV.v2.0.1+20.aarch64-unknown-freebsd.tar.gz/sha512/923fc895d3fe41005e47d6af422ba450b32e94210c393065a891b44f83f016104d3073a9faa609cd7979bfeca9d0ed0c7164b37de5da92deeb4e8676311cc57f +LibUV.v2.0.1+20.armv6l-linux-gnueabihf.tar.gz/md5/c2ec51470a4d66e3bd23bed67c109cc9 +LibUV.v2.0.1+20.armv6l-linux-gnueabihf.tar.gz/sha512/d139d5a6a141933a83f0d10f8da9366d709013bd2ef005d2b783716fb13d165b87640b7d9f51dc2772a69fc6f63e8545901c96da2343506a2f940edf36332164 +LibUV.v2.0.1+20.armv6l-linux-musleabihf.tar.gz/md5/a1a432902cd687f692c5619e72de241b +LibUV.v2.0.1+20.armv6l-linux-musleabihf.tar.gz/sha512/209207dde41fa699adb72af9a6211d74366d393d335c9b0d4c9c9509c832123707bca27e8410c7b1c63f89fbae77dc15eba55031701e307f88d5c183b929d9f3 +LibUV.v2.0.1+20.armv7l-linux-gnueabihf.tar.gz/md5/bdb8124a2b3c9e42b1b9dc8ce813e664 +LibUV.v2.0.1+20.armv7l-linux-gnueabihf.tar.gz/sha512/2f8879b4f41aa6cab3b195a76dd02376bf5d47f51ac157541b0c8453d03cd2f51fac83f59b2cd2fa49a2395262d18d636251715f1a4912750aa3de56eab4d6f3 +LibUV.v2.0.1+20.armv7l-linux-musleabihf.tar.gz/md5/91ddead3be8fa8b06b37983cba074615 +LibUV.v2.0.1+20.armv7l-linux-musleabihf.tar.gz/sha512/3be790d1c580e2a69d76171b82cfd2f594135920e68f7f4ff7a6fdc42918130e628458492fa2a157947c25effd2de0a71d434fcc1c6fb1d741985bbbfcfac3c5 +LibUV.v2.0.1+20.i686-linux-gnu.tar.gz/md5/c906674ba1bffffb685f0f00189187c1 +LibUV.v2.0.1+20.i686-linux-gnu.tar.gz/sha512/c3e5b394959dc76e2abd51fe59f7e8bbb1755b3a008f019ad05c41ffe8fd9f42d0bf262a506b36f26a2f8f4b14c937eff70a9e1ba2c55f19fbc57e5ba9c2dacf +LibUV.v2.0.1+20.i686-linux-musl.tar.gz/md5/977204bc42355bbdb908693b3baa8e10 +LibUV.v2.0.1+20.i686-linux-musl.tar.gz/sha512/5fb2717575ee97545026b79c2acc0660eaa04827637138896aabbe69bffa0c11732de4f9aad9dd78ba68db265ccf5ff3aef244d7da0008cafc4a417423db361e +LibUV.v2.0.1+20.i686-w64-mingw32.tar.gz/md5/ae698bbab57855ad41bd850ef2ccc695 +LibUV.v2.0.1+20.i686-w64-mingw32.tar.gz/sha512/9c6530404babe8383c6a1db7fa1e81b40b08de0dc2d2be3507a6466c150acc842cca277e39680b21a6c7f5a6dbae618bd3f5c3ac8f11882898cc116d5e13e7d9 +LibUV.v2.0.1+20.powerpc64le-linux-gnu.tar.gz/md5/e68314bb638f210d2ec9326c617752ca +LibUV.v2.0.1+20.powerpc64le-linux-gnu.tar.gz/sha512/f74ce6b21cd2776cdf49b4c6c2ad551c0bf55951f8bd9090020e71d2b233f72907a3e145b9a95715c391b82ad36ab1a069bb9f87d54c219179021cc26902dd22 +LibUV.v2.0.1+20.riscv64-linux-gnu.tar.gz/md5/d8e1ffb730c784df14faff06027b724d +LibUV.v2.0.1+20.riscv64-linux-gnu.tar.gz/sha512/60e7699ac4dc353d0b9fbd34952bd68185ab301a449354b7e805b6759d3866ffa5906041cd9e6ff299cb9fe3f5a92f4c5bfd9c441210125d52f06d614afc84a5 +LibUV.v2.0.1+20.x86_64-apple-darwin.tar.gz/md5/15d8197dea20880edb96a8bf643fe95e +LibUV.v2.0.1+20.x86_64-apple-darwin.tar.gz/sha512/7d65d4d2e0720f997c164234b78a729f4d4239fbb0b01634f23081e2209ab010ef27deca1cc3824fd8e17630370efa86f1567aae035a246ab9f60a6c14ea6d3b +LibUV.v2.0.1+20.x86_64-linux-gnu.tar.gz/md5/013be6d2673a59cd00b2ea62d4e34e21 +LibUV.v2.0.1+20.x86_64-linux-gnu.tar.gz/sha512/f466af2a1f9ff83d887ecaa200d3042bd5685d6cd487af00bdf8c92bf1d4256017f2757084de3b7331071c473b254df43b03f580de09db3bb9268af759a5b0c7 +LibUV.v2.0.1+20.x86_64-linux-musl.tar.gz/md5/21099b0c3ad76c3d67fb24260ec39836 +LibUV.v2.0.1+20.x86_64-linux-musl.tar.gz/sha512/03279a4d29072246dd806d800b80d9db14b637235e211294d5840104056cd206b370a987a2b771216e762549d13b13432f1e1893510e4fba6c4b111bb3330a05 +LibUV.v2.0.1+20.x86_64-unknown-freebsd.tar.gz/md5/dfcce3d6c2c42f419987f8289b1ace02 +LibUV.v2.0.1+20.x86_64-unknown-freebsd.tar.gz/sha512/8ad3c51f43124b7ad43cbdfe92685ce448d3195eeff5838387ef3145f1bec89851106293eca501ab6f986c0714f9bf9ecbb5a7ef44935a76a95bbdecd4fd2fba +LibUV.v2.0.1+20.x86_64-w64-mingw32.tar.gz/md5/7c37d147586c06f00f6dea947d7e912d +LibUV.v2.0.1+20.x86_64-w64-mingw32.tar.gz/sha512/58762e5a7a8cfd4ee8f0c7ba2c2919fc3b922f673e9b6138ee3714062d8088cac8e3cd5bd244d262426260ac55cef609abb30c25b1a5e38123fb61476a522a53 libuv-af4172ec713ee986ba1a989b9e33993a07c60c9e.tar.gz/md5/c1a7d3c74ef3999052f3bfe426264353 libuv-af4172ec713ee986ba1a989b9e33993a07c60c9e.tar.gz/sha512/a3f16863b711ddeeb5ab8d135d7df7a4be19cc2b9821fc78c8cd3ba421231d39b7d8bd9965321455094fda01584842a58f60612d93082b4fe32210b8aa44d999 diff --git a/deps/checksums/nghttp2 b/deps/checksums/nghttp2 index 6b4752d4e5527..4520109441588 100644 --- a/deps/checksums/nghttp2 +++ b/deps/checksums/nghttp2 @@ -24,6 +24,8 @@ nghttp2.v1.64.0+1.i686-w64-mingw32.tar.gz/md5/2ed9ff15d05f6cef7bf85bb19621a2fe nghttp2.v1.64.0+1.i686-w64-mingw32.tar.gz/sha512/45f38653664cc7343b66561a9b5bfec341593504714afbcb35a856343e583d2e75cab8062b2ff23ebdf4625607748f5c70b1ae79cc047a4073eb8d01f8252338 nghttp2.v1.64.0+1.powerpc64le-linux-gnu.tar.gz/md5/4622f699a44d02570298daf5864cf60b nghttp2.v1.64.0+1.powerpc64le-linux-gnu.tar.gz/sha512/f2cc88fd537503ac138518b7f72a67c18508307c0dddca41d44c8496ca4dd8f15aa133e08f13e03b2fbb3c83272ea433456c9ebb929f648a7b2af13fcd048d71 +nghttp2.v1.64.0+1.riscv64-linux-gnu.tar.gz/md5/5ec27224b6a780e989479ae4b38e5b26 +nghttp2.v1.64.0+1.riscv64-linux-gnu.tar.gz/sha512/57cfc7297f1cd2b33578ccc5f0ae847ef4771c087fe1235edd541f6f07a9feb692c554c159a40118c619f16ec0bc3cc313af19a9e845240cc50427583505a9f0 nghttp2.v1.64.0+1.x86_64-apple-darwin.tar.gz/md5/c6e5d0a179f065f4aab2b8661e6fc2d4 nghttp2.v1.64.0+1.x86_64-apple-darwin.tar.gz/sha512/77073fecbdac780dea34c9cb42b019b7cfe8a125a1356cd7de2ffd3aebeb29aa6251008574efa8d0a017e86023248fdd93e50c4ed2952d8a23cb67e0cf557a74 nghttp2.v1.64.0+1.x86_64-linux-gnu.tar.gz/md5/805f31fffc112ea45716b8a661911696 diff --git a/deps/checksums/openlibm b/deps/checksums/openlibm index e8c17e1efd26e..172d8ed3fb413 100644 --- a/deps/checksums/openlibm +++ b/deps/checksums/openlibm @@ -1,36 +1,38 @@ -OpenLibm.v0.8.1+3.aarch64-apple-darwin.tar.gz/md5/9ce53048e8944f6edff44f75b731229c -OpenLibm.v0.8.1+3.aarch64-apple-darwin.tar.gz/sha512/3a14e28db0656b47a473e19ca0afae1f8b72dd01e108d6b6cb52dc24fc03e4a43db867616b375369e82177bb274fbcfeb8f24b488ee68871e8da8463e9090adf -OpenLibm.v0.8.1+3.aarch64-linux-gnu.tar.gz/md5/8b284fe2905c3e5315291f5e5f27ca8b -OpenLibm.v0.8.1+3.aarch64-linux-gnu.tar.gz/sha512/d326181349ee7f74b73611cd71f933e93c38c11d6db9a1cd4fee49d1ac06c7f244f4cfc6ab373dd52909064117405b3d4fa39e5c626464c066ab53f1cd26dc4a -OpenLibm.v0.8.1+3.aarch64-linux-musl.tar.gz/md5/dc40ad1f2e53a3b914dcca364b6ead77 -OpenLibm.v0.8.1+3.aarch64-linux-musl.tar.gz/sha512/3779d8cd23c5987a15666e2160e40f5a6fc5e7d350c9e3c86d8af8c99515a8cb1f3b5e8438dae0f3cf0b5e1cb2c0cb74c5dd5a06c65e0c2a2382d86dacfaf9fb -OpenLibm.v0.8.1+3.aarch64-unknown-freebsd.tar.gz/md5/f5e9441d81626b958396e585083e0bdb -OpenLibm.v0.8.1+3.aarch64-unknown-freebsd.tar.gz/sha512/1078823b0f5f48cd9f6dc753213b6b3f8112476c9df70192b042fd9bbb597fff34da009f376b6e67034681fcb07810a1a22b0dc83112fbbbaa60dac189164a41 -OpenLibm.v0.8.1+3.armv6l-linux-gnueabihf.tar.gz/md5/7c9e56f6124b85e7dee74601f8c16abd -OpenLibm.v0.8.1+3.armv6l-linux-gnueabihf.tar.gz/sha512/a78e15177992025462d334a9d5b10b9c7f6710d77ac36056fe7a1cc3bc3fada87f16696366578cfa5f325d5f746639c41c5d80b4885814014d29556d63bd4c7c -OpenLibm.v0.8.1+3.armv6l-linux-musleabihf.tar.gz/md5/78d9e3178fdf93a35f7d2b0b00753dc6 -OpenLibm.v0.8.1+3.armv6l-linux-musleabihf.tar.gz/sha512/ff7b78786f7035eaa08770ddf7d4eb2984595a318c3ac4dfbe4091ca398e00638df2e77bc2ab5fd159defd0927d4fe46b7e824cf055fbae4860bfa12347e8c5b -OpenLibm.v0.8.1+3.armv7l-linux-gnueabihf.tar.gz/md5/7c9e56f6124b85e7dee74601f8c16abd -OpenLibm.v0.8.1+3.armv7l-linux-gnueabihf.tar.gz/sha512/a78e15177992025462d334a9d5b10b9c7f6710d77ac36056fe7a1cc3bc3fada87f16696366578cfa5f325d5f746639c41c5d80b4885814014d29556d63bd4c7c -OpenLibm.v0.8.1+3.armv7l-linux-musleabihf.tar.gz/md5/78d9e3178fdf93a35f7d2b0b00753dc6 -OpenLibm.v0.8.1+3.armv7l-linux-musleabihf.tar.gz/sha512/ff7b78786f7035eaa08770ddf7d4eb2984595a318c3ac4dfbe4091ca398e00638df2e77bc2ab5fd159defd0927d4fe46b7e824cf055fbae4860bfa12347e8c5b -OpenLibm.v0.8.1+3.i686-linux-gnu.tar.gz/md5/69b0c561e8f70e12f78a47bbcc28d43f -OpenLibm.v0.8.1+3.i686-linux-gnu.tar.gz/sha512/916bedde7b75aaa10a7517aa6a24da924e896aa46159447722010aa60a8c0974da8c2aa847d0a5853d391e7f3b792371304aa18a6d72d998f38f2a00b7179c30 -OpenLibm.v0.8.1+3.i686-linux-musl.tar.gz/md5/0037f2e2113282d49967eba72f215c4b -OpenLibm.v0.8.1+3.i686-linux-musl.tar.gz/sha512/96666332a814232084340791384505acf964064dba4f7b62db51a7ae4416237decb40318dc07b9a041547fd4ff77f204f42bc5c7f029e590af1ee1dd6196d843 -OpenLibm.v0.8.1+3.i686-w64-mingw32.tar.gz/md5/a2a5ba90531660f1e758df91bb11c2f9 -OpenLibm.v0.8.1+3.i686-w64-mingw32.tar.gz/sha512/b177c124dbe2dd491b49bf01b58b639629e2039c60dbd8ef1acf42985a7bd5ac1c5950a803b19e3ed5436ebd0a83f1e7af505d5f90b270467600ecab3e8a5cda -OpenLibm.v0.8.1+3.powerpc64le-linux-gnu.tar.gz/md5/01997fb48464f94f59f4708bd26eabc3 -OpenLibm.v0.8.1+3.powerpc64le-linux-gnu.tar.gz/sha512/1e1d8901fd3aab0948be5c387b8d5bd0db12766fe00bf800ee3100aa0d5973c7aa03ef9c9b4e34942e5e2b46b64035d7f8d7b070113db031d4611f2a7dd02ca3 -OpenLibm.v0.8.1+3.x86_64-apple-darwin.tar.gz/md5/6cb5a472d6c1446acfca11bb8f7283d6 -OpenLibm.v0.8.1+3.x86_64-apple-darwin.tar.gz/sha512/e52f399002544d94536c3bda742d3cc5b0995929d656eeb0e808954fb800fd8e5cfc0ab57279fbccab44fc33a1207ab345d78e685d519ff7f02cca8f554b9c06 -OpenLibm.v0.8.1+3.x86_64-linux-gnu.tar.gz/md5/e1c7dc61e98d5b8aa68de3462a2620a4 -OpenLibm.v0.8.1+3.x86_64-linux-gnu.tar.gz/sha512/fe6d74a2522d75374b87ac9746d444d75a768e069f24f3fbfc6a140aa9d073fa54e8899861f839e647b9261e660c5f2b5555f52fab39ef84a74685b632e89df9 -OpenLibm.v0.8.1+3.x86_64-linux-musl.tar.gz/md5/5fe8eb59d21732a80f432720419324b3 -OpenLibm.v0.8.1+3.x86_64-linux-musl.tar.gz/sha512/0d1b22ca01eda89caa1832b63b1d7ddafe0fedf5906680e817100e2176cbbae95f576409706a9ea1834bc692b72009f4fd244586df30228d18e626bf25fc040a -OpenLibm.v0.8.1+3.x86_64-unknown-freebsd.tar.gz/md5/2bcdf32fdef91433763e32be029814d9 -OpenLibm.v0.8.1+3.x86_64-unknown-freebsd.tar.gz/sha512/97854736fc8c797abd5a5c331e5795dfa9124ac108a76fc2bcac518f5750a08884717d611bb98222b13387bcd27e1c3f4ec841547859e87fafbbe8c7dcd7381a -OpenLibm.v0.8.1+3.x86_64-w64-mingw32.tar.gz/md5/31a75f828f782130bf6a463521a11f04 -OpenLibm.v0.8.1+3.x86_64-w64-mingw32.tar.gz/sha512/d54f688940229a5fc3db958460556d362c81e2e0a7bac010537123e5ff102b17d84123ee2e164151d51fb8ee7524e0888531e14d2c5ebfb3d6847b03af0086ad -openlibm-ae2d91698508701c83cab83714d42a1146dccf85.tar.gz/md5/19408d70bf042a109e1c267a53740089 -openlibm-ae2d91698508701c83cab83714d42a1146dccf85.tar.gz/sha512/9597fdcbc4af8369e6eecc3f8e86f251661cc64d236578f3ee8a6b39e77a47951446e1a0fe1151513da153e7ed17bf39aa5a36c32153d0d0400232bed2839e22 +OpenLibm.v0.8.4+1.aarch64-apple-darwin.tar.gz/md5/5fcbd746e90712e396e76dc4e76724d0 +OpenLibm.v0.8.4+1.aarch64-apple-darwin.tar.gz/sha512/f4ac2bc38bdc723384b67119daa2974fb43da34b2e45cea2029ea48f92c84c4cad6dfb43521b09a1e89ddf8c5b8cc22a38fa4b78ba39ac7524fd6bd1ba897aa9 +OpenLibm.v0.8.4+1.aarch64-linux-gnu.tar.gz/md5/e24c967d04812058b69b8c561f0d9f2a +OpenLibm.v0.8.4+1.aarch64-linux-gnu.tar.gz/sha512/8100dd7cfd9e02c9cfeade7627eb6105e86e8f5eb99026462a9a5370f8dd99ad981024a8904d2d7c341b113730f1b2312909d9c9c2c9b48dce74d3e80b266947 +OpenLibm.v0.8.4+1.aarch64-linux-musl.tar.gz/md5/6f9454c31b548f9fd47fb6318aab9b12 +OpenLibm.v0.8.4+1.aarch64-linux-musl.tar.gz/sha512/1769348f3e2227f307923b8c5656ab4c797daa8bd8bed61fbdf4c72d84ba9b7ae097392cdafd5e0cee0004f846e2c2ddbf9b5e7edb2406606b37c5ed665cc693 +OpenLibm.v0.8.4+1.aarch64-unknown-freebsd.tar.gz/md5/acce062e568325b675a6ed6a7a8fabbd +OpenLibm.v0.8.4+1.aarch64-unknown-freebsd.tar.gz/sha512/8ade1ae5ded62622a5159a0e60a8f6ad8345debda0da3eff764ea1e8a9937e686055e253612d83c4ee0035aa3dd2d6267d2dbd687cfcffbaffc17a7d7879e05f +OpenLibm.v0.8.4+1.armv6l-linux-gnueabihf.tar.gz/md5/8fe0900a318393a290907f016bc654c3 +OpenLibm.v0.8.4+1.armv6l-linux-gnueabihf.tar.gz/sha512/167100a2d46e68462ef9a66915ced881d6358f05337bd38f2f77176f41cfd5be37e3c5226dd5d7d59147bd3e1aa7fb0893c1c81e9516134d3ab663b5752c4969 +OpenLibm.v0.8.4+1.armv6l-linux-musleabihf.tar.gz/md5/e8566719387984604f19dc5f9354a783 +OpenLibm.v0.8.4+1.armv6l-linux-musleabihf.tar.gz/sha512/532dd2b764fa15f7a838fb14cccafd2d4fe8fa4a132ea8394479a719c7aee11442f1b8a18e5d4a26ca820fa696d9d2afc7f5ec63dd96fa3b6763cea72b7026c3 +OpenLibm.v0.8.4+1.armv7l-linux-gnueabihf.tar.gz/md5/8fe0900a318393a290907f016bc654c3 +OpenLibm.v0.8.4+1.armv7l-linux-gnueabihf.tar.gz/sha512/167100a2d46e68462ef9a66915ced881d6358f05337bd38f2f77176f41cfd5be37e3c5226dd5d7d59147bd3e1aa7fb0893c1c81e9516134d3ab663b5752c4969 +OpenLibm.v0.8.4+1.armv7l-linux-musleabihf.tar.gz/md5/e8566719387984604f19dc5f9354a783 +OpenLibm.v0.8.4+1.armv7l-linux-musleabihf.tar.gz/sha512/532dd2b764fa15f7a838fb14cccafd2d4fe8fa4a132ea8394479a719c7aee11442f1b8a18e5d4a26ca820fa696d9d2afc7f5ec63dd96fa3b6763cea72b7026c3 +OpenLibm.v0.8.4+1.i686-linux-gnu.tar.gz/md5/9580d34e69d6067427b9c33db631cfd3 +OpenLibm.v0.8.4+1.i686-linux-gnu.tar.gz/sha512/46934f82791f69ac5f5da0dab7dcc6e3e9a4577c3bb529e9c0519c38f140c7b54517c55ff3579cd4ed4df68f0863e006aa98e51873f1dab452ce9f853996429a +OpenLibm.v0.8.4+1.i686-linux-musl.tar.gz/md5/66bfc9611d04c5d609e7824cb076d24b +OpenLibm.v0.8.4+1.i686-linux-musl.tar.gz/sha512/1bda2395d44c22aba3d1aab2b08ae06f763d3755037d454aa73f8e8134289a1ab5d65862bbc5a17a7a6b9f2918eb87e926b21527ddc4471e2ea20d605ba14e2d +OpenLibm.v0.8.4+1.i686-w64-mingw32.tar.gz/md5/0e97311b2f08b57d79085635f01ccced +OpenLibm.v0.8.4+1.i686-w64-mingw32.tar.gz/sha512/ae061ea406c06969332af58ed6fdfce2825326d771d30274d90775a1709b0361b7ca1dc7e6b0b76b93e4dd7a81d1842510a2c835251ee0a0978d6c839d96070e +OpenLibm.v0.8.4+1.powerpc64le-linux-gnu.tar.gz/md5/8ecfff7db76eee29591a654871e88855 +OpenLibm.v0.8.4+1.powerpc64le-linux-gnu.tar.gz/sha512/af03993b162316dd581f6ba5d1c23bca4c26cb22356ab229f326c42e111acbdf7ef45c9ad05894fe2d68794a63670cf89888653f788192a38b9255ce4bc72e28 +OpenLibm.v0.8.4+1.riscv64-linux-gnu.tar.gz/md5/2d6ae40b640f7d39c20ec7d151d6972d +OpenLibm.v0.8.4+1.riscv64-linux-gnu.tar.gz/sha512/3a9b69601e7e1013f236c0d9f7326f371d65d9c1231d5848995ebd822fd1eff0bd5f6b771fe2c21191076902e6a7c4febb4822f78cc0d15bb7f59396d9728236 +OpenLibm.v0.8.4+1.x86_64-apple-darwin.tar.gz/md5/bd671ab9fe01835cab3e42e7cfa790fb +OpenLibm.v0.8.4+1.x86_64-apple-darwin.tar.gz/sha512/8bf2e66df17effc1e8778453904ffc20127f785bf096873289e8fdd8b17069ca844faffbd9f7621b87a7cb0a0051037eb9402360f2a03cf8794fbac8f7719777 +OpenLibm.v0.8.4+1.x86_64-linux-gnu.tar.gz/md5/df7fab134fbce3b625e9a82376f23e79 +OpenLibm.v0.8.4+1.x86_64-linux-gnu.tar.gz/sha512/64d07434e0db79833f84a2225838456eb9532617d377a776b3a534a908b1673bc4f890903f95350e4045e05c29539d993a18ecadeb879761e279ec3947f74390 +OpenLibm.v0.8.4+1.x86_64-linux-musl.tar.gz/md5/ebef6bb7651d116b397e035f39adfb1b +OpenLibm.v0.8.4+1.x86_64-linux-musl.tar.gz/sha512/de9036073e5dba2721b4119ecbbd21a0c9f75b65aff9392b7e88e464da35b97135d62404477441d0dadd3a2f8d49f1082291b35bf4b626fb1096d36d401980bf +OpenLibm.v0.8.4+1.x86_64-unknown-freebsd.tar.gz/md5/bc09186ae191700d6cf9162796bb23ba +OpenLibm.v0.8.4+1.x86_64-unknown-freebsd.tar.gz/sha512/6b7198cd68418e370348c7011a5f9ccf910b62c9482334601dea0749b683724ddb7414bde3d8da7a5123c0fadc3f93d02274538070330db6428dabca5d007835 +OpenLibm.v0.8.4+1.x86_64-w64-mingw32.tar.gz/md5/b6b5335f4c83f7ebf0f74cf753358f00 +OpenLibm.v0.8.4+1.x86_64-w64-mingw32.tar.gz/sha512/e8351ddda305b757f337bb7ea26c441968843b23861676f0bdd7bcf83bb3969af790d4112307d3204eb87fac044dda9be305f349700ebe9ba2bfe3d6df24fde8 +openlibm-c4667caea25ae3487adf6760b4a1dcf32477a4b8.tar.gz/md5/287cf81f6c6b67177b322f7cb5cc8279 +openlibm-c4667caea25ae3487adf6760b4a1dcf32477a4b8.tar.gz/sha512/3c3efa8cb344719c2b6df45fbfe178efac6239cac12fc32dcc92074431d2e1a3039a60649cf3525424e0990081b6d40acb12176316c4ccb2940add0bb3a41e85 diff --git a/deps/checksums/p7zip b/deps/checksums/p7zip index 2fe4fb874bec4..6850967ace1b5 100644 --- a/deps/checksums/p7zip +++ b/deps/checksums/p7zip @@ -1,36 +1,38 @@ p7zip-17.05.tar.gz/md5/de921a08f37242a8eed8e4a758fbcb58 p7zip-17.05.tar.gz/sha512/97a7cfd15287998eb049c320548477be496c4ddf6b45c833c42adca4ab88719b07a442ae2e71cf2dc3b30a0777a3acab0a1a30f01fd85bacffa3fa9bd22c3f7d -p7zip.v17.5.0+1.aarch64-apple-darwin.tar.gz/md5/2a254e251901b3d1ddfd7aff23a6e5eb -p7zip.v17.5.0+1.aarch64-apple-darwin.tar.gz/sha512/8efb9a2c9bcab388e523adba3dc0b876e8ae34e2440c3eee01fd780eb87c8619c7a7bbdc46d703ccefff6aa6ad64c4e4b45b723136ab1f6fd6de4f52e75ebbbf -p7zip.v17.5.0+1.aarch64-linux-gnu.tar.gz/md5/bb1f3773fd409dbb91a10f7d9d2e99b5 -p7zip.v17.5.0+1.aarch64-linux-gnu.tar.gz/sha512/e95ccc342be644570d218d25403b91a7db9ee983fbf8cce3deff453355d68d426f9301eaac865a98691025b596b8cd77ebebf6184c0eaf8b2f294bc6763b9a4b -p7zip.v17.5.0+1.aarch64-linux-musl.tar.gz/md5/3fac518a6a70412294d71ca510958cf2 -p7zip.v17.5.0+1.aarch64-linux-musl.tar.gz/sha512/fc127790739bf8a8b918b2e83753d86f5e79ee8706bde4cc79d74d9f7d846aae99a109da4b2b3cc92ccedc1eef4d52a555a65a95f588e173e0fecc11f2ca21e6 -p7zip.v17.5.0+1.aarch64-unknown-freebsd.tar.gz/md5/4190f8d7d42572b3fdab0fa382417d43 -p7zip.v17.5.0+1.aarch64-unknown-freebsd.tar.gz/sha512/5b0cb08374b8561873f76cb2b8bcbb8de1ff4c91bde23222cc1b650c6ea2fff265e48b6190551ed136324a47d25e1d357a754295b674e74b4628b20223ad067d -p7zip.v17.5.0+1.armv6l-linux-gnueabihf.tar.gz/md5/355410848192de3b02d12fd663867f4b -p7zip.v17.5.0+1.armv6l-linux-gnueabihf.tar.gz/sha512/8f103b41e755d157d70dacca89a0ef4610bea109686b4005e8edd5f79ed2e6419c00c2625d0ab90e6e33fa389e670490d8de263c0bdae952cc34cbbf440e275f -p7zip.v17.5.0+1.armv6l-linux-musleabihf.tar.gz/md5/34363b227306fce34a728af54b71064f -p7zip.v17.5.0+1.armv6l-linux-musleabihf.tar.gz/sha512/8dd7b37ce6223c9fedcaa999eb806eb6dec8c4a3133d3c07e2456cb8543b8e4f5b881c1bff2d2e25f19b1312b18673e9013aeff87d6a274eec6c451b1ba0d6b9 -p7zip.v17.5.0+1.armv7l-linux-gnueabihf.tar.gz/md5/dbb1fc0cf3bea674442ff8cc932a94cd -p7zip.v17.5.0+1.armv7l-linux-gnueabihf.tar.gz/sha512/c4d71d905fa420391417786ed206a0c334475dd0df8baa1fc3f6560ce548db11805003d0d0b35bb622fe818c761f2b0abe0796d1cbfce2a922da69e697f056a2 -p7zip.v17.5.0+1.armv7l-linux-musleabihf.tar.gz/md5/d188b5dd453faedb616ba9c48fdeab6b -p7zip.v17.5.0+1.armv7l-linux-musleabihf.tar.gz/sha512/ea30a775370502ca9e271b87cbda528d0c51d63ce0df41883d4dbc1527a32f251d797f3692fcf9b883b5fbaaad80515b971a8f8fe09ba102978b19a0ecb58528 -p7zip.v17.5.0+1.i686-linux-gnu.tar.gz/md5/dc02bdde045a0b6b22cf14d6960e63ed -p7zip.v17.5.0+1.i686-linux-gnu.tar.gz/sha512/d2d0dd14a5fc1163fea2276e0925bfa8d075d5dba1d8018e4e3160977d3b09642b2e521d8e57d049abaf0e2ea391a846f0b0136b3c59e8b476c8c52ac5210447 -p7zip.v17.5.0+1.i686-linux-musl.tar.gz/md5/0b8658147938a8ec109ee2b3b0a0665f -p7zip.v17.5.0+1.i686-linux-musl.tar.gz/sha512/411b2950f5928c537b87ba0651c09c08e57afed765db9fee89eda8b12939ef0da94c8ba38c0a24ba46b4513a0e4cca798eb09f2b20a011099ed3cf14455dd19e -p7zip.v17.5.0+1.i686-w64-mingw32.tar.gz/md5/98bdd8767c77a35f71303ff490a3d363 -p7zip.v17.5.0+1.i686-w64-mingw32.tar.gz/sha512/14f08071af74297df8bfe1d9f7efa3c0212e62ace573848f17b729e4c36dc3861110f3c5cc9315364c318e5b040736443a24492e86d76161993653a309996eb3 -p7zip.v17.5.0+1.powerpc64le-linux-gnu.tar.gz/md5/b18c917b9852898a9b9d6d24bcc6863e -p7zip.v17.5.0+1.powerpc64le-linux-gnu.tar.gz/sha512/0148dc8a0bc9c95212d7f8e2f92ee24e968eb7290fe72c7ae02e286bf5c05dd6b1f10b32350a7ff37777ed5a8cc21f3303f464620f3394c7a4690ae98bf77299 -p7zip.v17.5.0+1.x86_64-apple-darwin.tar.gz/md5/da31752a2556644d39e48649bb0111de -p7zip.v17.5.0+1.x86_64-apple-darwin.tar.gz/sha512/0695ad111263d2fadfdf9a46ce7ee80def0bf60db7d1c2585ed2af6fc945fb169311a9f1ffc6f95fb43b0b03694d2d1be9136d3d78ba2ef2b19228987883a385 -p7zip.v17.5.0+1.x86_64-linux-gnu.tar.gz/md5/2fb55d86e4eaccb0488bd637d088b996 -p7zip.v17.5.0+1.x86_64-linux-gnu.tar.gz/sha512/38ac355157d59c09f308fc29964d0e9c1466c9633efd8d3c6ff3c738abce2af45ebc6b92a29f56d5e7baa4871f9f39b14ecfcbedd4e2f4ca7c0fe6627c6b13e7 -p7zip.v17.5.0+1.x86_64-linux-musl.tar.gz/md5/f0bd567a851d2dd9d306552ffafbca3a -p7zip.v17.5.0+1.x86_64-linux-musl.tar.gz/sha512/e60047a6e7e3496cb6658f87c8c88676f399cd9f3d0d7daa880b6be09cd5525f7f22776896f1375722b47555514ff8c018f02ce800ec3fd0ed922e16e8a6d657 -p7zip.v17.5.0+1.x86_64-unknown-freebsd.tar.gz/md5/d37bd26e39a3ec84f262636f70624341 -p7zip.v17.5.0+1.x86_64-unknown-freebsd.tar.gz/sha512/0604a880c19f9d72d5828edd75be641625c29f230b3a5e7d70ec3812c014c96b76ee7b45e0e80f49be63f109a48700e75d1e5be01b5ae7b46d42dafda9885e8c -p7zip.v17.5.0+1.x86_64-w64-mingw32.tar.gz/md5/f02c7b2481dee880b096340a8735350f -p7zip.v17.5.0+1.x86_64-w64-mingw32.tar.gz/sha512/08b717c1b072d1309f6af8973eb09b1a482abb7ae7d01fba79873d4310a7c11292e2e8779029f99cc60627ed0d064224bc87782e587c520f970b840b7b838052 +p7zip.v17.5.0+2.aarch64-apple-darwin.tar.gz/md5/2a254e251901b3d1ddfd7aff23a6e5eb +p7zip.v17.5.0+2.aarch64-apple-darwin.tar.gz/sha512/8efb9a2c9bcab388e523adba3dc0b876e8ae34e2440c3eee01fd780eb87c8619c7a7bbdc46d703ccefff6aa6ad64c4e4b45b723136ab1f6fd6de4f52e75ebbbf +p7zip.v17.5.0+2.aarch64-linux-gnu.tar.gz/md5/bb1f3773fd409dbb91a10f7d9d2e99b5 +p7zip.v17.5.0+2.aarch64-linux-gnu.tar.gz/sha512/e95ccc342be644570d218d25403b91a7db9ee983fbf8cce3deff453355d68d426f9301eaac865a98691025b596b8cd77ebebf6184c0eaf8b2f294bc6763b9a4b +p7zip.v17.5.0+2.aarch64-linux-musl.tar.gz/md5/3fac518a6a70412294d71ca510958cf2 +p7zip.v17.5.0+2.aarch64-linux-musl.tar.gz/sha512/fc127790739bf8a8b918b2e83753d86f5e79ee8706bde4cc79d74d9f7d846aae99a109da4b2b3cc92ccedc1eef4d52a555a65a95f588e173e0fecc11f2ca21e6 +p7zip.v17.5.0+2.aarch64-unknown-freebsd.tar.gz/md5/4190f8d7d42572b3fdab0fa382417d43 +p7zip.v17.5.0+2.aarch64-unknown-freebsd.tar.gz/sha512/5b0cb08374b8561873f76cb2b8bcbb8de1ff4c91bde23222cc1b650c6ea2fff265e48b6190551ed136324a47d25e1d357a754295b674e74b4628b20223ad067d +p7zip.v17.5.0+2.armv6l-linux-gnueabihf.tar.gz/md5/355410848192de3b02d12fd663867f4b +p7zip.v17.5.0+2.armv6l-linux-gnueabihf.tar.gz/sha512/8f103b41e755d157d70dacca89a0ef4610bea109686b4005e8edd5f79ed2e6419c00c2625d0ab90e6e33fa389e670490d8de263c0bdae952cc34cbbf440e275f +p7zip.v17.5.0+2.armv6l-linux-musleabihf.tar.gz/md5/34363b227306fce34a728af54b71064f +p7zip.v17.5.0+2.armv6l-linux-musleabihf.tar.gz/sha512/8dd7b37ce6223c9fedcaa999eb806eb6dec8c4a3133d3c07e2456cb8543b8e4f5b881c1bff2d2e25f19b1312b18673e9013aeff87d6a274eec6c451b1ba0d6b9 +p7zip.v17.5.0+2.armv7l-linux-gnueabihf.tar.gz/md5/dbb1fc0cf3bea674442ff8cc932a94cd +p7zip.v17.5.0+2.armv7l-linux-gnueabihf.tar.gz/sha512/c4d71d905fa420391417786ed206a0c334475dd0df8baa1fc3f6560ce548db11805003d0d0b35bb622fe818c761f2b0abe0796d1cbfce2a922da69e697f056a2 +p7zip.v17.5.0+2.armv7l-linux-musleabihf.tar.gz/md5/d188b5dd453faedb616ba9c48fdeab6b +p7zip.v17.5.0+2.armv7l-linux-musleabihf.tar.gz/sha512/ea30a775370502ca9e271b87cbda528d0c51d63ce0df41883d4dbc1527a32f251d797f3692fcf9b883b5fbaaad80515b971a8f8fe09ba102978b19a0ecb58528 +p7zip.v17.5.0+2.i686-linux-gnu.tar.gz/md5/dc02bdde045a0b6b22cf14d6960e63ed +p7zip.v17.5.0+2.i686-linux-gnu.tar.gz/sha512/d2d0dd14a5fc1163fea2276e0925bfa8d075d5dba1d8018e4e3160977d3b09642b2e521d8e57d049abaf0e2ea391a846f0b0136b3c59e8b476c8c52ac5210447 +p7zip.v17.5.0+2.i686-linux-musl.tar.gz/md5/0b8658147938a8ec109ee2b3b0a0665f +p7zip.v17.5.0+2.i686-linux-musl.tar.gz/sha512/411b2950f5928c537b87ba0651c09c08e57afed765db9fee89eda8b12939ef0da94c8ba38c0a24ba46b4513a0e4cca798eb09f2b20a011099ed3cf14455dd19e +p7zip.v17.5.0+2.i686-w64-mingw32.tar.gz/md5/98bdd8767c77a35f71303ff490a3d363 +p7zip.v17.5.0+2.i686-w64-mingw32.tar.gz/sha512/14f08071af74297df8bfe1d9f7efa3c0212e62ace573848f17b729e4c36dc3861110f3c5cc9315364c318e5b040736443a24492e86d76161993653a309996eb3 +p7zip.v17.5.0+2.powerpc64le-linux-gnu.tar.gz/md5/b18c917b9852898a9b9d6d24bcc6863e +p7zip.v17.5.0+2.powerpc64le-linux-gnu.tar.gz/sha512/0148dc8a0bc9c95212d7f8e2f92ee24e968eb7290fe72c7ae02e286bf5c05dd6b1f10b32350a7ff37777ed5a8cc21f3303f464620f3394c7a4690ae98bf77299 +p7zip.v17.5.0+2.riscv64-linux-gnu.tar.gz/md5/8d5f804091c2d21b2c35121d40d1024f +p7zip.v17.5.0+2.riscv64-linux-gnu.tar.gz/sha512/68042f32b8b9f8d422dc0390efa2502d4a1a816daf4adf1133128f9366ec93ee1c1dda699844c0c3c3649a6b55a16312bd6b8fe4aedd6780e6faf11509932a9a +p7zip.v17.5.0+2.x86_64-apple-darwin.tar.gz/md5/da31752a2556644d39e48649bb0111de +p7zip.v17.5.0+2.x86_64-apple-darwin.tar.gz/sha512/0695ad111263d2fadfdf9a46ce7ee80def0bf60db7d1c2585ed2af6fc945fb169311a9f1ffc6f95fb43b0b03694d2d1be9136d3d78ba2ef2b19228987883a385 +p7zip.v17.5.0+2.x86_64-linux-gnu.tar.gz/md5/2fb55d86e4eaccb0488bd637d088b996 +p7zip.v17.5.0+2.x86_64-linux-gnu.tar.gz/sha512/38ac355157d59c09f308fc29964d0e9c1466c9633efd8d3c6ff3c738abce2af45ebc6b92a29f56d5e7baa4871f9f39b14ecfcbedd4e2f4ca7c0fe6627c6b13e7 +p7zip.v17.5.0+2.x86_64-linux-musl.tar.gz/md5/f0bd567a851d2dd9d306552ffafbca3a +p7zip.v17.5.0+2.x86_64-linux-musl.tar.gz/sha512/e60047a6e7e3496cb6658f87c8c88676f399cd9f3d0d7daa880b6be09cd5525f7f22776896f1375722b47555514ff8c018f02ce800ec3fd0ed922e16e8a6d657 +p7zip.v17.5.0+2.x86_64-unknown-freebsd.tar.gz/md5/d37bd26e39a3ec84f262636f70624341 +p7zip.v17.5.0+2.x86_64-unknown-freebsd.tar.gz/sha512/0604a880c19f9d72d5828edd75be641625c29f230b3a5e7d70ec3812c014c96b76ee7b45e0e80f49be63f109a48700e75d1e5be01b5ae7b46d42dafda9885e8c +p7zip.v17.5.0+2.x86_64-w64-mingw32.tar.gz/md5/f02c7b2481dee880b096340a8735350f +p7zip.v17.5.0+2.x86_64-w64-mingw32.tar.gz/sha512/08b717c1b072d1309f6af8973eb09b1a482abb7ae7d01fba79873d4310a7c11292e2e8779029f99cc60627ed0d064224bc87782e587c520f970b840b7b838052 diff --git a/deps/checksums/pcre b/deps/checksums/pcre index 0c2732f8cc2b5..9e290c914baec 100644 --- a/deps/checksums/pcre +++ b/deps/checksums/pcre @@ -1,36 +1,38 @@ -PCRE2.v10.44.0+0.aarch64-apple-darwin.tar.gz/md5/14de26cfc0f6ff7635fac39e81e81a27 -PCRE2.v10.44.0+0.aarch64-apple-darwin.tar.gz/sha512/45079ecca5f4966a32895fcc63585f1dd60f306dc1cb5c098d42452fcff67f7f6b405c200a15747af4680151bb6a6374832a0119b8ddd743d2ed13d0beaef7c9 -PCRE2.v10.44.0+0.aarch64-linux-gnu.tar.gz/md5/3cf179ed36d37bff698ab81cf3d5797b -PCRE2.v10.44.0+0.aarch64-linux-gnu.tar.gz/sha512/db93e5a5c0c46b5536ed49515682d9bfe1d23f6ba8ae2468289ec8f2160140f39f5606a3c7095f45251f3663d8ccf2d6d7e5e8b1efb21c39bbf9a13b6ec60ef9 -PCRE2.v10.44.0+0.aarch64-linux-musl.tar.gz/md5/02baa415218f581a5ceeb7bf7fc0a090 -PCRE2.v10.44.0+0.aarch64-linux-musl.tar.gz/sha512/1685f37ed8f465ecc2f738fdf65d20bb1806934ff2c50194882282fb6c3900121c61c39210e4c0b89847493bfc3e15bb7b9136b0d968103b47c8662a78b412fe -PCRE2.v10.44.0+0.aarch64-unknown-freebsd.tar.gz/md5/4de065ea59ab4f622b46079df1d9d941 -PCRE2.v10.44.0+0.aarch64-unknown-freebsd.tar.gz/sha512/aa6df9edfb690d155a8b5a9390db7ca11622ac0020174cf070a33a075801bfe43bd4c80b8e28017989a8b7374d39897cdcf72ab0e1962e3e234239975f7ac0b4 -PCRE2.v10.44.0+0.armv6l-linux-gnueabihf.tar.gz/md5/f8a0907fbb20a06507fce849db098c4f -PCRE2.v10.44.0+0.armv6l-linux-gnueabihf.tar.gz/sha512/3f5bcc1742380a31683a81740d55e198d7ec8d8ea5a13d6d0556d6603e4fadbf0dc648093c44e36dd6d3793c52a5e3dae6f2f459c73e3d3b5a005f3395d26772 -PCRE2.v10.44.0+0.armv6l-linux-musleabihf.tar.gz/md5/8854c24183441aa6fd21989c00888904 -PCRE2.v10.44.0+0.armv6l-linux-musleabihf.tar.gz/sha512/a74d9378f071dc4cb021e5171d66cd4ac5de3b348e993fc90d824ce5d2f554f7c8af7af55ec31d874d302aaba7d542b6505cc5963e53656c28026a06a53ed48b -PCRE2.v10.44.0+0.armv7l-linux-gnueabihf.tar.gz/md5/04960309ee7cf69a53e280878d5880ef -PCRE2.v10.44.0+0.armv7l-linux-gnueabihf.tar.gz/sha512/a1644daf036daa3799368598427c87c23bcfdddac55a0d06adca08a2e9d617c893285855af562101b05129d0ed0d84d22f5a8a1703316ecd09aa1752b8330eef -PCRE2.v10.44.0+0.armv7l-linux-musleabihf.tar.gz/md5/1335defc6090be76c509840633f7cdfb -PCRE2.v10.44.0+0.armv7l-linux-musleabihf.tar.gz/sha512/9595052eeae4da413b930b14d7e89359a29220cd9e908325e0b7788c8f4a2feb2134e78a0d8f56007787f0fefadc9de31750db6104bbdd048fa50e1d785c2a8c -PCRE2.v10.44.0+0.i686-linux-gnu.tar.gz/md5/e2d6be1d19566c965c2afeb995aba52f -PCRE2.v10.44.0+0.i686-linux-gnu.tar.gz/sha512/4a9d981bb6aa9150b670db7c5d4d188c8391fcb2a16bc710ede7a84bf7ec546fc5fd9096a339720579d25b6dcb5674b2b5b28e9664e5ef589b1a5044ce38b6a7 -PCRE2.v10.44.0+0.i686-linux-musl.tar.gz/md5/23cf857bd3daea4f094fcec48a7712dc -PCRE2.v10.44.0+0.i686-linux-musl.tar.gz/sha512/534f0cfab0cd60db9498eff387f7280a8baaf893a98dd2e7a737e68ba6473ed8236e9da85116eefb9812ec5323c705a00fcaff010b1900f752de8bdff65ef3ad -PCRE2.v10.44.0+0.i686-w64-mingw32.tar.gz/md5/3d05764df2305f16e4ffab60031ad40c -PCRE2.v10.44.0+0.i686-w64-mingw32.tar.gz/sha512/3e21cc6b71849c1a361373de30567990dba13dfd8812e7a7b5e2734b572bf1d45aeb730289d329975e76932c4c40e476824be2ab8e80a40fb7a7e2f46159235a -PCRE2.v10.44.0+0.powerpc64le-linux-gnu.tar.gz/md5/596d7c29d1417ed8959ea3ae3b4df453 -PCRE2.v10.44.0+0.powerpc64le-linux-gnu.tar.gz/sha512/89e03bfd6890150e2c8dddc4e7d024f2e09421c25a3d0fef3b5cd7f6bab7d6402ec1e82b02ecb5d26d01dfa2fb6068d050513894c374b7f2244c8fcbf00d69e2 -PCRE2.v10.44.0+0.x86_64-apple-darwin.tar.gz/md5/18f13c78ff6388c601bd36788e526b31 -PCRE2.v10.44.0+0.x86_64-apple-darwin.tar.gz/sha512/7b43a289f54064fc3c292de98173ec91cde2e49402c99c7848cbdc0e6d90a23a86d41f521e3986fcc8d941ee070d09e29ddc89a4e23009b8e9333e577ae4a09c -PCRE2.v10.44.0+0.x86_64-linux-gnu.tar.gz/md5/9f45feca0955f81ceb898208b9c74e15 -PCRE2.v10.44.0+0.x86_64-linux-gnu.tar.gz/sha512/eac215838306f7b5adb2166c3f620a69ed52fbd752ef3673a887507963a826c305d9b078dbb5236dc9a45eaca0d34f77325aab41703745701a077c84822ec0d0 -PCRE2.v10.44.0+0.x86_64-linux-musl.tar.gz/md5/79f092c6e8e971027ac6c1f0987376fb -PCRE2.v10.44.0+0.x86_64-linux-musl.tar.gz/sha512/2c5655b0f719a7d442c89f1040f2973b03f8becd855a0cfd6c0a985a07b25de351a84e3b9daaebd952b62628db0d937de08a8d05ee4bcace7e72d6b5ce6b8435 -PCRE2.v10.44.0+0.x86_64-unknown-freebsd.tar.gz/md5/a0bc32a099a584d453458a76c892fe47 -PCRE2.v10.44.0+0.x86_64-unknown-freebsd.tar.gz/sha512/6649c1b9e9569a9decccf6ebaa61d44acdb9069208ec796777d8e70a908210f775be2142053f6a5762ebaa321e297f6d8b51db99629766bc702c498b5f772492 -PCRE2.v10.44.0+0.x86_64-w64-mingw32.tar.gz/md5/eeffb6164fba08b0d5c7f50afa081475 -PCRE2.v10.44.0+0.x86_64-w64-mingw32.tar.gz/sha512/f06db992a2070a88559c15224972aeb098d4291a4325970fc0fbbb7cdd539f4a2fd4f90c0de90a34fe454da6c38290f9e0c7fdf2fe8c441f687fe4491d652adc +PCRE2.v10.44.0+1.aarch64-apple-darwin.tar.gz/md5/14de26cfc0f6ff7635fac39e81e81a27 +PCRE2.v10.44.0+1.aarch64-apple-darwin.tar.gz/sha512/45079ecca5f4966a32895fcc63585f1dd60f306dc1cb5c098d42452fcff67f7f6b405c200a15747af4680151bb6a6374832a0119b8ddd743d2ed13d0beaef7c9 +PCRE2.v10.44.0+1.aarch64-linux-gnu.tar.gz/md5/3cf179ed36d37bff698ab81cf3d5797b +PCRE2.v10.44.0+1.aarch64-linux-gnu.tar.gz/sha512/db93e5a5c0c46b5536ed49515682d9bfe1d23f6ba8ae2468289ec8f2160140f39f5606a3c7095f45251f3663d8ccf2d6d7e5e8b1efb21c39bbf9a13b6ec60ef9 +PCRE2.v10.44.0+1.aarch64-linux-musl.tar.gz/md5/02baa415218f581a5ceeb7bf7fc0a090 +PCRE2.v10.44.0+1.aarch64-linux-musl.tar.gz/sha512/1685f37ed8f465ecc2f738fdf65d20bb1806934ff2c50194882282fb6c3900121c61c39210e4c0b89847493bfc3e15bb7b9136b0d968103b47c8662a78b412fe +PCRE2.v10.44.0+1.aarch64-unknown-freebsd.tar.gz/md5/4de065ea59ab4f622b46079df1d9d941 +PCRE2.v10.44.0+1.aarch64-unknown-freebsd.tar.gz/sha512/aa6df9edfb690d155a8b5a9390db7ca11622ac0020174cf070a33a075801bfe43bd4c80b8e28017989a8b7374d39897cdcf72ab0e1962e3e234239975f7ac0b4 +PCRE2.v10.44.0+1.armv6l-linux-gnueabihf.tar.gz/md5/f8a0907fbb20a06507fce849db098c4f +PCRE2.v10.44.0+1.armv6l-linux-gnueabihf.tar.gz/sha512/3f5bcc1742380a31683a81740d55e198d7ec8d8ea5a13d6d0556d6603e4fadbf0dc648093c44e36dd6d3793c52a5e3dae6f2f459c73e3d3b5a005f3395d26772 +PCRE2.v10.44.0+1.armv6l-linux-musleabihf.tar.gz/md5/8854c24183441aa6fd21989c00888904 +PCRE2.v10.44.0+1.armv6l-linux-musleabihf.tar.gz/sha512/a74d9378f071dc4cb021e5171d66cd4ac5de3b348e993fc90d824ce5d2f554f7c8af7af55ec31d874d302aaba7d542b6505cc5963e53656c28026a06a53ed48b +PCRE2.v10.44.0+1.armv7l-linux-gnueabihf.tar.gz/md5/04960309ee7cf69a53e280878d5880ef +PCRE2.v10.44.0+1.armv7l-linux-gnueabihf.tar.gz/sha512/a1644daf036daa3799368598427c87c23bcfdddac55a0d06adca08a2e9d617c893285855af562101b05129d0ed0d84d22f5a8a1703316ecd09aa1752b8330eef +PCRE2.v10.44.0+1.armv7l-linux-musleabihf.tar.gz/md5/1335defc6090be76c509840633f7cdfb +PCRE2.v10.44.0+1.armv7l-linux-musleabihf.tar.gz/sha512/9595052eeae4da413b930b14d7e89359a29220cd9e908325e0b7788c8f4a2feb2134e78a0d8f56007787f0fefadc9de31750db6104bbdd048fa50e1d785c2a8c +PCRE2.v10.44.0+1.i686-linux-gnu.tar.gz/md5/e2d6be1d19566c965c2afeb995aba52f +PCRE2.v10.44.0+1.i686-linux-gnu.tar.gz/sha512/4a9d981bb6aa9150b670db7c5d4d188c8391fcb2a16bc710ede7a84bf7ec546fc5fd9096a339720579d25b6dcb5674b2b5b28e9664e5ef589b1a5044ce38b6a7 +PCRE2.v10.44.0+1.i686-linux-musl.tar.gz/md5/23cf857bd3daea4f094fcec48a7712dc +PCRE2.v10.44.0+1.i686-linux-musl.tar.gz/sha512/534f0cfab0cd60db9498eff387f7280a8baaf893a98dd2e7a737e68ba6473ed8236e9da85116eefb9812ec5323c705a00fcaff010b1900f752de8bdff65ef3ad +PCRE2.v10.44.0+1.i686-w64-mingw32.tar.gz/md5/3d05764df2305f16e4ffab60031ad40c +PCRE2.v10.44.0+1.i686-w64-mingw32.tar.gz/sha512/3e21cc6b71849c1a361373de30567990dba13dfd8812e7a7b5e2734b572bf1d45aeb730289d329975e76932c4c40e476824be2ab8e80a40fb7a7e2f46159235a +PCRE2.v10.44.0+1.powerpc64le-linux-gnu.tar.gz/md5/596d7c29d1417ed8959ea3ae3b4df453 +PCRE2.v10.44.0+1.powerpc64le-linux-gnu.tar.gz/sha512/89e03bfd6890150e2c8dddc4e7d024f2e09421c25a3d0fef3b5cd7f6bab7d6402ec1e82b02ecb5d26d01dfa2fb6068d050513894c374b7f2244c8fcbf00d69e2 +PCRE2.v10.44.0+1.riscv64-linux-gnu.tar.gz/md5/8330a431f4da1d20cffdb64d2c270dfb +PCRE2.v10.44.0+1.riscv64-linux-gnu.tar.gz/sha512/a836d0b9feefd9ffd50cf29db72ab704e6ae442939322526e2a5613973eabc8e543c5546ce507b0c5f9e6f1ce324978aeb6e99f8833eb60fc90e74139e47c6d2 +PCRE2.v10.44.0+1.x86_64-apple-darwin.tar.gz/md5/18f13c78ff6388c601bd36788e526b31 +PCRE2.v10.44.0+1.x86_64-apple-darwin.tar.gz/sha512/7b43a289f54064fc3c292de98173ec91cde2e49402c99c7848cbdc0e6d90a23a86d41f521e3986fcc8d941ee070d09e29ddc89a4e23009b8e9333e577ae4a09c +PCRE2.v10.44.0+1.x86_64-linux-gnu.tar.gz/md5/9f45feca0955f81ceb898208b9c74e15 +PCRE2.v10.44.0+1.x86_64-linux-gnu.tar.gz/sha512/eac215838306f7b5adb2166c3f620a69ed52fbd752ef3673a887507963a826c305d9b078dbb5236dc9a45eaca0d34f77325aab41703745701a077c84822ec0d0 +PCRE2.v10.44.0+1.x86_64-linux-musl.tar.gz/md5/79f092c6e8e971027ac6c1f0987376fb +PCRE2.v10.44.0+1.x86_64-linux-musl.tar.gz/sha512/2c5655b0f719a7d442c89f1040f2973b03f8becd855a0cfd6c0a985a07b25de351a84e3b9daaebd952b62628db0d937de08a8d05ee4bcace7e72d6b5ce6b8435 +PCRE2.v10.44.0+1.x86_64-unknown-freebsd.tar.gz/md5/a0bc32a099a584d453458a76c892fe47 +PCRE2.v10.44.0+1.x86_64-unknown-freebsd.tar.gz/sha512/6649c1b9e9569a9decccf6ebaa61d44acdb9069208ec796777d8e70a908210f775be2142053f6a5762ebaa321e297f6d8b51db99629766bc702c498b5f772492 +PCRE2.v10.44.0+1.x86_64-w64-mingw32.tar.gz/md5/eeffb6164fba08b0d5c7f50afa081475 +PCRE2.v10.44.0+1.x86_64-w64-mingw32.tar.gz/sha512/f06db992a2070a88559c15224972aeb098d4291a4325970fc0fbbb7cdd539f4a2fd4f90c0de90a34fe454da6c38290f9e0c7fdf2fe8c441f687fe4491d652adc pcre2-10.44.tar.bz2/md5/9d1fe11e2e919c7b395e3e8f0a5c3eec pcre2-10.44.tar.bz2/sha512/ee91cc10a2962bc7818b03d368df3dd31f42ea9a7260ae51483ea8cd331b7431e36e63256b0adc213cc6d6741e7c90414fd420622308c0ae3fcb5dd878591be2 diff --git a/deps/checksums/zlib b/deps/checksums/zlib index f5e7353f32e3e..bd651003399b9 100644 --- a/deps/checksums/zlib +++ b/deps/checksums/zlib @@ -1,36 +1,38 @@ -Zlib.v1.3.1+1.aarch64-apple-darwin.tar.gz/md5/50b48e14f0b3578e3f398d130749a25d -Zlib.v1.3.1+1.aarch64-apple-darwin.tar.gz/sha512/d970e183035b3615b410f7b0da2c7a1d516234744491d65ed1ebc3800b55732f20bf00fcbb0cf91289b8b4660915282873fb23788896713cf8dfae2984a8fd85 -Zlib.v1.3.1+1.aarch64-linux-gnu.tar.gz/md5/ee42c0bae86fc39968c8cd6a77a801bf -Zlib.v1.3.1+1.aarch64-linux-gnu.tar.gz/sha512/5d21cbeab03d44008c6cbad114d45c917ebee2fe98de6b19686f4f6ba1fc67eeedf968b94ed1c2d4efb89e93be9efa342bcc8a57cb8a505085d177abae14bc2d -Zlib.v1.3.1+1.aarch64-linux-musl.tar.gz/md5/9091d1288736b218f7b016791dc1a9c8 -Zlib.v1.3.1+1.aarch64-linux-musl.tar.gz/sha512/b49cbfe734beb2af9ef8e847542d006765345cbb08aee0854779e35e03c98df25c93539b046547c6b66029987c49499ddf6cb207824b1e376900bfceaa79691a -Zlib.v1.3.1+1.aarch64-unknown-freebsd.tar.gz/md5/c73793872e3a2259519276b3ab2899ce -Zlib.v1.3.1+1.aarch64-unknown-freebsd.tar.gz/sha512/ce1e3ed5dfb01653471ace4c0cb2d8b521ccd02bc2a2c537e433a0dc497906ad21008645c645f2e0f2bb1f39c40e9a68d8cca0aeddc74ade0e188dc80748c2e8 -Zlib.v1.3.1+1.armv6l-linux-gnueabihf.tar.gz/md5/b686c85047b7dad2c2f08d1d16e7978a -Zlib.v1.3.1+1.armv6l-linux-gnueabihf.tar.gz/sha512/511fda619519dccedb264988e3b59a0e0fbf8f73d3ae290f238346209ebc0202a22f945257cea19afef64246574285e0322901a46bb48d7b48364c1e2eacd801 -Zlib.v1.3.1+1.armv6l-linux-musleabihf.tar.gz/md5/374be5cb926876f3f0492cfe0e193220 -Zlib.v1.3.1+1.armv6l-linux-musleabihf.tar.gz/sha512/4d3a2cc0c7c48146e63ed098da5a5acad75517197adc965550c123f7f8bcee0811a27be76fa37b6b0515eee4b5ba1c1a85c854e7b23bea36b5e21671805bedce -Zlib.v1.3.1+1.armv7l-linux-gnueabihf.tar.gz/md5/9febbc6a3d492e34c9ed53c95f3b799f -Zlib.v1.3.1+1.armv7l-linux-gnueabihf.tar.gz/sha512/4cee0e2cf572eb91028a09ef356e1aa6360949e046ceec03bd37574295ddcc4a7cefca9276f7565f152697d55b35f62af2ab107cdbf402b42846818629fea9c7 -Zlib.v1.3.1+1.armv7l-linux-musleabihf.tar.gz/md5/5d0d59a6cbbd1e63193ba6f7dbb755f9 -Zlib.v1.3.1+1.armv7l-linux-musleabihf.tar.gz/sha512/ee3f48b354168342ef63509b19a26aca3301fb3e5f4f6898afe2d3b44ee3380515efd6ced5d4e06e69736d851d19352deb9595bad82c051caccaee8c55e629d8 -Zlib.v1.3.1+1.i686-linux-gnu.tar.gz/md5/834350a64b2302a9caf0250a8f6068e5 -Zlib.v1.3.1+1.i686-linux-gnu.tar.gz/sha512/63dc158c4dfc42db97875893fcdd9784d9487af855bd576dbe04d1b967ad64510222df74a4cfb1b7e67386329d2a5686d7931b81720883fc1924f0d706a0a711 -Zlib.v1.3.1+1.i686-linux-musl.tar.gz/md5/e4f96efdeafa3d74c7c348059a8dc46a -Zlib.v1.3.1+1.i686-linux-musl.tar.gz/sha512/b47a571d94887ddcab8d7b50c6dce3afed3f56513a9d1859feaefebfad4a271d428b440df1d19ef3c2ed01ca4c8fd121ffc1572f5e252f27d0930f616cb47f18 -Zlib.v1.3.1+1.i686-w64-mingw32.tar.gz/md5/aaa1500c06b280d142e2900dbedf2a8f -Zlib.v1.3.1+1.i686-w64-mingw32.tar.gz/sha512/bc6668baf33bc8e130ae6a72f6cd89d9f1ccc95d2f3a3bcef20cde03ed7602de511f7646feed918918a24d8a2221a0be39eb2c0884c1adb6fe0d67b91cceb683 -Zlib.v1.3.1+1.powerpc64le-linux-gnu.tar.gz/md5/27dcad8557994cfd89d6fa7072bb843c -Zlib.v1.3.1+1.powerpc64le-linux-gnu.tar.gz/sha512/3b388dd286b273881d4344cff61c7da316c2bd2bab93072bf47ce4cb1cf9662158351b8febb0d5b1f8dfd9bc73cd32f7cae37fdd19b0ca91531bd3375df104bb -Zlib.v1.3.1+1.x86_64-apple-darwin.tar.gz/md5/9187319377191ae8b34162b375baa5db -Zlib.v1.3.1+1.x86_64-apple-darwin.tar.gz/sha512/895203434f161926978be52a223dd49a99454651a79c1c5e0529fa064f3f7ac2d7a069fed47a577b32523df22afadd6eb97d564dbd59c5d67ed90083add13c00 -Zlib.v1.3.1+1.x86_64-linux-gnu.tar.gz/md5/55d4d982d60cb643aa8688eb031b07ee -Zlib.v1.3.1+1.x86_64-linux-gnu.tar.gz/sha512/d8f94d22ffc37df027de23b2408c2000014c8b7b6c8539feca669ac1f2dbbe1679ca534c3be4d32c90fe38bbba27c795689226962fb067346b5ca213e64b9c4b -Zlib.v1.3.1+1.x86_64-linux-musl.tar.gz/md5/95d735bba178da4b8bee23903419919c -Zlib.v1.3.1+1.x86_64-linux-musl.tar.gz/sha512/370370f08133a720e3fbedcc434f102dc95225fda3ec8a399e782851bd4be57fb2b64a3ed62dc0559fb0c58d2e28db9b9e960efafd940982e4cb6652be0e81f1 -Zlib.v1.3.1+1.x86_64-unknown-freebsd.tar.gz/md5/df158f50fdb8ac1179fe6dad3bc62713 -Zlib.v1.3.1+1.x86_64-unknown-freebsd.tar.gz/sha512/f4ba4ccfeaf3fd2e172a2d5b3b1ae083ee9854022e71e062e29423e4179cb1fc49b2b99df49b3f5f231e2a0c5becc59b89644e9dcaf0fda9c97e83af7ea1c25d -Zlib.v1.3.1+1.x86_64-w64-mingw32.tar.gz/md5/9cc735c54ddf5d1ea0db60e05d6631ea -Zlib.v1.3.1+1.x86_64-w64-mingw32.tar.gz/sha512/8a2fd20944866cb7f717517ea0b80a134466e063f85bec87ffba56ca844f983f91060dfdc65f8faee1981d7329348c827b723aaad4fea36041e710b9e35c43de +Zlib.v1.3.1+2.aarch64-apple-darwin.tar.gz/md5/938c376c7513fa48d4b8b78cea741260 +Zlib.v1.3.1+2.aarch64-apple-darwin.tar.gz/sha512/ccece3f5618efe3e3699eb521167e2ee768932ea6f4e411d36619a941af3e9e32394beb260171d557930382f412f9be70f4c69215d3f7e448d4446b1690111ee +Zlib.v1.3.1+2.aarch64-linux-gnu.tar.gz/md5/44a14273caeea9c5cb34ce3e0ba9d1fc +Zlib.v1.3.1+2.aarch64-linux-gnu.tar.gz/sha512/8977bdc225404a01746fc14885e4823b4e2781c73a75e0ee0c8d9ca58b706c6cf9f98647b4e22bb09e7e09640caf4643e5210054a4624e06c76fc3eb2c2a2728 +Zlib.v1.3.1+2.aarch64-linux-musl.tar.gz/md5/dcef6c714555de9b2181b8c5b0a2c668 +Zlib.v1.3.1+2.aarch64-linux-musl.tar.gz/sha512/499701cc0fd1e52f3952da1b3c4377662c54390db9ebd6f5be82ecc0ba8754d2ca42b2f572b3a78ccdef30e527b7bed22c15511944f1299398587c529f8f4619 +Zlib.v1.3.1+2.aarch64-unknown-freebsd.tar.gz/md5/166f8a076a01a6f0979c712d7cec44e8 +Zlib.v1.3.1+2.aarch64-unknown-freebsd.tar.gz/sha512/7a1546b614cb5e2c0566774247269740d881c0a6d22ef6dca8010d77829b4e64594f4e609bb83299fa239d66909a4eb046d6d078268006723747f86e6c733e6b +Zlib.v1.3.1+2.armv6l-linux-gnueabihf.tar.gz/md5/1f0bcb50b545badbc9de1569f51c4668 +Zlib.v1.3.1+2.armv6l-linux-gnueabihf.tar.gz/sha512/1e4bea6fa41300ec770822dcd9335d1393c087db45d128e2c60d9315db01a69c984c98304b83af0725a99ae3a5cac4a273f4eea8a4213454608edbe0e55c74ce +Zlib.v1.3.1+2.armv6l-linux-musleabihf.tar.gz/md5/3a78103181bf8a74dfc0c6f7681bd3de +Zlib.v1.3.1+2.armv6l-linux-musleabihf.tar.gz/sha512/2a7c70266fd5928e46c8d71d95884054eaff2432d9fbce37eef67eb62af2b087f5f9fa3752a5d14f50cd058519d39a1b81450b30786a4f66eafbd16d18ef7b6b +Zlib.v1.3.1+2.armv7l-linux-gnueabihf.tar.gz/md5/4e202f829e7f478451e93da7be2b6f98 +Zlib.v1.3.1+2.armv7l-linux-gnueabihf.tar.gz/sha512/0734bc8a84b039b971a15620adb9b5da77d1b1992fb4c6adf9031fa8c592512645d424d2ce752efdda1f300f871c3d4f3b159794c3725fd113e1acd5512aed59 +Zlib.v1.3.1+2.armv7l-linux-musleabihf.tar.gz/md5/5000d1941b7e32dec4a2d125bbd22fff +Zlib.v1.3.1+2.armv7l-linux-musleabihf.tar.gz/sha512/6abd69ef6878fa6cdcf7fe94e4d7aedaae58d961122e131a414f3aea43b401a3812d9d847ab4b1690e9faf89d577935d7f547484edb6cb2814cbc1156159e8ed +Zlib.v1.3.1+2.i686-linux-gnu.tar.gz/md5/7a5de529294b9d8dba4ac1eeb4cbcbdc +Zlib.v1.3.1+2.i686-linux-gnu.tar.gz/sha512/72d52c4e2f01fe1436b22c854efff83068f6a65a9280556018c77bb843f81902c0c96f30132123d4dd6a66041e9391a418ceec227b2b2411f99a26df76d21c74 +Zlib.v1.3.1+2.i686-linux-musl.tar.gz/md5/d18b442e4d108397482fd852deb4241e +Zlib.v1.3.1+2.i686-linux-musl.tar.gz/sha512/6c367f7c522167db510cf42a84dfcce75fc129bb49800c05b90dfdfa5fb31fa20ed020e165f1b283b81f4568c9bf79d4c41f7ad4e42a3513cb13149a50707114 +Zlib.v1.3.1+2.i686-w64-mingw32.tar.gz/md5/b2c8af112298ae9e635054e4ba22e5ae +Zlib.v1.3.1+2.i686-w64-mingw32.tar.gz/sha512/0a28076fc8cf8daa925f4be76dd0025d01d8ad6bc269f87164749da0c3bea6f4b404ef097a2907ce2c009211d9f8387f844fe5e5b1bd2f6d77c9b35b2b1c7548 +Zlib.v1.3.1+2.powerpc64le-linux-gnu.tar.gz/md5/9ae4feb621ae088c323ff12235bdf5db +Zlib.v1.3.1+2.powerpc64le-linux-gnu.tar.gz/sha512/912134f741fe96217d1b8465510ac82d238d3d8a21519534fb88c568092dcc9eb8e51ef66b7ca56a2a7a881474f04edb7a6f7bf1ebf06bfff7708b3edd3487c0 +Zlib.v1.3.1+2.riscv64-linux-gnu.tar.gz/md5/43b61473a02e492f932ce60f726966a8 +Zlib.v1.3.1+2.riscv64-linux-gnu.tar.gz/sha512/4742503831da6a6b7945c6e5efd96bd6b03b8a63b73e68181e961b6f326ac5d805350219c43f4537165d1af0ac2ed496d5a72edd0c1d11e012ef12385a8f2e5f +Zlib.v1.3.1+2.x86_64-apple-darwin.tar.gz/md5/347a92686d81ed7c022d2e7310babb77 +Zlib.v1.3.1+2.x86_64-apple-darwin.tar.gz/sha512/a59b9c4f63124c893a2a11b886bbe03bfc75846599eb21997652bd62a2f28afe754d16127e964683552423bf1c0da160e46c32d0b584ed07e28f4e91904b9c67 +Zlib.v1.3.1+2.x86_64-linux-gnu.tar.gz/md5/0630f603e35ab56efdef331e29db436b +Zlib.v1.3.1+2.x86_64-linux-gnu.tar.gz/sha512/b936c328fad685c22473ff4cbfcc8bc48772ed9927c5b29c5d0503b95888efd0ca8d891f53cca45da7b5768ed4a1f6994f9e211167f4704c15c688cced90cac5 +Zlib.v1.3.1+2.x86_64-linux-musl.tar.gz/md5/252d8542bb5a53c479f4ffc067847e27 +Zlib.v1.3.1+2.x86_64-linux-musl.tar.gz/sha512/449809acbbff1fcbd89b9689e803f69d1f9cb49860f0b508b69c560cfcb51232640fcff17ede6ea75d9906edb5a8f38139afd890f18a34260ef5dbb5d167af36 +Zlib.v1.3.1+2.x86_64-unknown-freebsd.tar.gz/md5/79fa906629dff81c38b93001a7798040 +Zlib.v1.3.1+2.x86_64-unknown-freebsd.tar.gz/sha512/53dbcce99b2d6ec82ef86d76f3f574db304ab90f1b131c49b2c06f89bd2426afa4a31bfa8455e2ecdad64d4da71fef1b2d79f471efd55a8bbdc29e95c952a289 +Zlib.v1.3.1+2.x86_64-w64-mingw32.tar.gz/md5/92b083205ca44db131b7cf6b9c09eb21 +Zlib.v1.3.1+2.x86_64-w64-mingw32.tar.gz/sha512/1c3b7b414f09b1896c5a08f156c5e55f07ee012cf3f6fe50d5ba116405dcd9a80e5004ee7c774f7cc981e4d1b099efee85e16b8417cef2734cb7c12ec440d09a zlib-51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf.tar.gz/md5/7ce1b2766499af7d948130113b649028 zlib-51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf.tar.gz/sha512/79d032b8c93260ce6b9806f2289cdccce67e9d80865b5bb39ac46dadffc8ee009da51c551eead59c56249c7adfa164c1d5ebcf2b10a8645e0b11b5650176cb24 diff --git a/deps/openlibm.version b/deps/openlibm.version index f35b291260380..13129a0c0a860 100644 --- a/deps/openlibm.version +++ b/deps/openlibm.version @@ -1,7 +1,9 @@ +# -*- makefile -*- + ## jll artifact OPENLIBM_JLL_NAME := OpenLibm ## source build -OPENLIBM_VER := 0.8.1 -OPENLIBM_BRANCH=v0.8.1 -OPENLIBM_SHA1=ae2d91698508701c83cab83714d42a1146dccf85 +OPENLIBM_VER := 0.8.4 +OPENLIBM_BRANCH=v0.8.4 +OPENLIBM_SHA1=c4667caea25ae3487adf6760b4a1dcf32477a4b8 diff --git a/stdlib/GMP_jll/Project.toml b/stdlib/GMP_jll/Project.toml index 3a6fa12c95aef..a31688d0a9c07 100644 --- a/stdlib/GMP_jll/Project.toml +++ b/stdlib/GMP_jll/Project.toml @@ -1,6 +1,6 @@ name = "GMP_jll" uuid = "781609d7-10c4-51f6-84f2-b8444358ff6d" -version = "6.3.0+1" +version = "6.3.0+2" [deps] Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" diff --git a/stdlib/LibSSH2_jll/Project.toml b/stdlib/LibSSH2_jll/Project.toml index c45d4fc6565b7..09f07b559344c 100644 --- a/stdlib/LibSSH2_jll/Project.toml +++ b/stdlib/LibSSH2_jll/Project.toml @@ -1,6 +1,6 @@ name = "LibSSH2_jll" uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" -version = "1.11.3+0" +version = "1.11.3+1" [deps] OpenSSL_jll = "458c3c95-2e84-50aa-8efc-19380b2a3a95" diff --git a/stdlib/LibUV_jll/Project.toml b/stdlib/LibUV_jll/Project.toml index 74aae1c9249df..c6ec3ae228647 100644 --- a/stdlib/LibUV_jll/Project.toml +++ b/stdlib/LibUV_jll/Project.toml @@ -1,6 +1,6 @@ name = "LibUV_jll" uuid = "183b4373-6708-53ba-ad28-60e28bb38547" -version = "2.0.1+19" +version = "2.0.1+20" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" diff --git a/stdlib/OpenLibm_jll/Project.toml b/stdlib/OpenLibm_jll/Project.toml index a4c559e1ff4ef..1d52749032fa4 100644 --- a/stdlib/OpenLibm_jll/Project.toml +++ b/stdlib/OpenLibm_jll/Project.toml @@ -1,6 +1,6 @@ name = "OpenLibm_jll" uuid = "05823500-19ac-5b8b-9628-191a04bc5112" -version = "0.8.1+3" +version = "0.8.4+1" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" diff --git a/stdlib/PCRE2_jll/Project.toml b/stdlib/PCRE2_jll/Project.toml index fee83c7ce552c..24ac196a3b8a9 100644 --- a/stdlib/PCRE2_jll/Project.toml +++ b/stdlib/PCRE2_jll/Project.toml @@ -1,6 +1,6 @@ name = "PCRE2_jll" uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15" -version = "10.44.0+0" +version = "10.44.0+1" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" diff --git a/stdlib/Zlib_jll/Project.toml b/stdlib/Zlib_jll/Project.toml index dfe9ce845c8e0..40acd335c2327 100644 --- a/stdlib/Zlib_jll/Project.toml +++ b/stdlib/Zlib_jll/Project.toml @@ -1,6 +1,6 @@ name = "Zlib_jll" uuid = "83775a58-1f1d-513f-b197-d71354ab007a" -version = "1.3.1+1" +version = "1.3.1+2" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" diff --git a/stdlib/dSFMT_jll/Project.toml b/stdlib/dSFMT_jll/Project.toml index ca51184b75264..30209421a9994 100644 --- a/stdlib/dSFMT_jll/Project.toml +++ b/stdlib/dSFMT_jll/Project.toml @@ -1,6 +1,6 @@ name = "dSFMT_jll" uuid = "05ff407c-b0c1-5878-9df8-858cc2e60c36" -version = "2.2.5+1" +version = "2.2.5+2" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" diff --git a/stdlib/libblastrampoline_jll/Project.toml b/stdlib/libblastrampoline_jll/Project.toml index 8d5a3b7b20bcc..d1dde4c6074a7 100644 --- a/stdlib/libblastrampoline_jll/Project.toml +++ b/stdlib/libblastrampoline_jll/Project.toml @@ -1,6 +1,6 @@ name = "libblastrampoline_jll" uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" -version = "5.11.2+0" +version = "5.12.0+0" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" diff --git a/stdlib/p7zip_jll/Project.toml b/stdlib/p7zip_jll/Project.toml index 09a39880af418..214c5b19a8a4b 100644 --- a/stdlib/p7zip_jll/Project.toml +++ b/stdlib/p7zip_jll/Project.toml @@ -1,6 +1,6 @@ name = "p7zip_jll" uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" -version = "17.5.0+1" +version = "17.5.0+2" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" From 89afe2026671dee633747a7eeeb4db721395835b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= <765740+giordano@users.noreply.github.com> Date: Sun, 5 Jan 2025 23:50:15 +0100 Subject: [PATCH 140/342] [deps] Fix build systems of curl and openssl (#56960) * Curl was missing a dependency on OpenSSL after #56708 * openssl is missing configuration target for riscv64 --- deps/curl.mk | 4 ++++ deps/openssl.mk | 2 ++ 2 files changed, 6 insertions(+) diff --git a/deps/curl.mk b/deps/curl.mk index 3d478e786ca8a..6232d56e5e333 100644 --- a/deps/curl.mk +++ b/deps/curl.mk @@ -1,6 +1,10 @@ ## CURL ## include $(SRCDIR)/curl.version +ifeq ($(USE_SYSTEM_OPENSSL), 0) +$(BUILDDIR)/curl-$(CURL_VER)/build-configured: | $(build_prefix)/manifest/openssl +endif + ifeq ($(USE_SYSTEM_LIBSSH2), 0) $(BUILDDIR)/curl-$(CURL_VER)/build-configured: | $(build_prefix)/manifest/libssh2 endif diff --git a/deps/openssl.mk b/deps/openssl.mk index 0ced5737a49a2..6f96717b2fb74 100644 --- a/deps/openssl.mk +++ b/deps/openssl.mk @@ -34,6 +34,8 @@ else ifeq ($(ARCH),ppc64le) OPENSSL_TARGET := linux-ppc64le else ifeq ($(ARCH),powerpc64le) OPENSSL_TARGET := linux-ppc64le +else ifeq ($(ARCH),riscv64) +OPENSSL_TARGET := linux64-riscv64 endif else OPENSSL_TARGET := unknown From a3f336fd713ff9723073f4543dd5b7c43cfb399e Mon Sep 17 00:00:00 2001 From: Neven Sajko <4944410+nsajko@users.noreply.github.com> Date: Mon, 6 Jan 2025 07:16:47 +0100 Subject: [PATCH 141/342] fix handling of unknown setting in `@constprop`, fix error message (#56946) Co-authored-by: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> --- base/expr.jl | 3 ++- test/misc.jl | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/base/expr.jl b/base/expr.jl index 354fae3f0a592..84078829f77ed 100644 --- a/base/expr.jl +++ b/base/expr.jl @@ -401,13 +401,14 @@ macro constprop(setting) end function constprop_setting(@nospecialize setting) + s = setting isa(setting, QuoteNode) && (setting = setting.value) if setting === :aggressive return :aggressive_constprop elseif setting === :none return :no_constprop end - throw(ArgumentError(LazyString("@constprop "), setting, "not supported")) + throw(ArgumentError(LazyString("`Base.@constprop ", s, "` not supported"))) end """ diff --git a/test/misc.jl b/test/misc.jl index 5bbc2c3c65fa2..7070fd49f5f36 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -1612,3 +1612,15 @@ let errs = IOBuffer() '`, devnull, stdout, errs) @test occursin("disable_new_worlds", String(take!(errs))) end + +@testset "`@constprop`, `@assume_effects` handling of an unknown setting" begin + for x ∈ ("constprop", "assume_effects") + try + eval(Meta.parse("Base.@$x :unknown f() = 3")) + error("unexpectedly reached") + catch e + e::LoadError + @test e.error isa ArgumentError + end + end +end From c4825b064369ae406858541205ad4215a7e5e47f Mon Sep 17 00:00:00 2001 From: FX Coudert Date: Mon, 6 Jan 2025 10:18:41 +0100 Subject: [PATCH 142/342] Update LibGit2 to 1.9.0 (#56955) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New version: https://github.com/libgit2/libgit2/releases/tag/v1.9.0 --------- Co-authored-by: Mosè Giordano Co-authored-by: Antonio Rojas --- deps/checksums/libgit2 | 74 ++++++++++++++------------- deps/libgit2.version | 4 +- stdlib/LibGit2/src/consts.jl | 4 +- stdlib/LibGit2/src/types.jl | 36 +++++++++++-- stdlib/LibGit2/test/libgit2-tests.jl | 1 + stdlib/LibGit2_jll/Project.toml | 2 +- stdlib/LibGit2_jll/src/LibGit2_jll.jl | 4 +- stdlib/LibGit2_jll/test/runtests.jl | 2 +- stdlib/Manifest.toml | 2 +- 9 files changed, 81 insertions(+), 48 deletions(-) diff --git a/deps/checksums/libgit2 b/deps/checksums/libgit2 index 0a8d2a39ffc86..c1906c995cc73 100644 --- a/deps/checksums/libgit2 +++ b/deps/checksums/libgit2 @@ -1,36 +1,38 @@ -LibGit2.v1.8.4+0.aarch64-apple-darwin.tar.gz/md5/a2bca9483d0468b6836304068a8f8d99 -LibGit2.v1.8.4+0.aarch64-apple-darwin.tar.gz/sha512/bbc150e8c330f3cd666136334e15cfbd1017174193b3ece49b1c701aebd2774ef1b23e5e59ec8b05f23788db2ed8a3f103d7ff0fac364966eb5b5b2d814ffd22 -LibGit2.v1.8.4+0.aarch64-linux-gnu.tar.gz/md5/55f133dbf3a1e5ad37c69df3ea6b2274 -LibGit2.v1.8.4+0.aarch64-linux-gnu.tar.gz/sha512/c6f5a25f9b47be391f438867f076ed5b2539ddbb6542119b8225d52c7767705cda499940007b1f33801288426408a2d5ca3feb743e898b747fe0051df5ca7ad4 -LibGit2.v1.8.4+0.aarch64-linux-musl.tar.gz/md5/660b58d4e23b5f142731ccfcffff7b39 -LibGit2.v1.8.4+0.aarch64-linux-musl.tar.gz/sha512/e5d3add19efbbb59c7b79298b83d6342f70b2ad9415ead9460d9e78e117f2a98417a96f49ebfec62e2c18cf9519114e829c2d492e08c45b501aa25552ed97722 -LibGit2.v1.8.4+0.aarch64-unknown-freebsd.tar.gz/md5/67797f9177f007617b2e027673277453 -LibGit2.v1.8.4+0.aarch64-unknown-freebsd.tar.gz/sha512/1dff62cf24e842d978638ca0df9d67e0ed11250b6cb432880aad4603f292c456fcca10b6af304ed19954c22d24bcd8d3fe32e48c45bc2ea348d58eaa0ba6a1ad -LibGit2.v1.8.4+0.armv6l-linux-gnueabihf.tar.gz/md5/cc3264f393d133f9d34d796a1ddccac2 -LibGit2.v1.8.4+0.armv6l-linux-gnueabihf.tar.gz/sha512/8479dda021511747c6ef432eb9a092a54b2fe402e9010b5500faf01be3f2c4f6121fbb45849d6ba5e6a0f57318d6065956c58a5b5ea849e38b056d011ea0588d -LibGit2.v1.8.4+0.armv6l-linux-musleabihf.tar.gz/md5/4427150daaa544d04c0fa59b1b326831 -LibGit2.v1.8.4+0.armv6l-linux-musleabihf.tar.gz/sha512/b2a3cfd08022d012bb27e17bc4d67a0a1c09561420043a96111d029e582be0fdc619fe5227532ab7a902a5d43b5ef4ba1048d2c437c5bc9ac347d80535b60d9a -LibGit2.v1.8.4+0.armv7l-linux-gnueabihf.tar.gz/md5/f8afd5a5b5702dd0015829753244d223 -LibGit2.v1.8.4+0.armv7l-linux-gnueabihf.tar.gz/sha512/986f45f15b66109f372b41a2af2a6c4a7e03edb11ec4ad1cefba0c4cf16a6ddf3b490ba7d60e92a1f2eae91bc550f8d792f1ce66df64e0e2b3c66fbb6ff94cf7 -LibGit2.v1.8.4+0.armv7l-linux-musleabihf.tar.gz/md5/02534a7e25196d3cd504a6ef2993d051 -LibGit2.v1.8.4+0.armv7l-linux-musleabihf.tar.gz/sha512/31ba2fa0c71da0812fdadcf056bfd235379dc4d6960624a9b487bfcef2dd3b0ef3a618e7ed72850fd9e401cae0a143158c0ac48f6526c4845d80d2397eb08fb8 -LibGit2.v1.8.4+0.i686-linux-gnu.tar.gz/md5/0e73f9c928a69a552539f6aab5d44b0c -LibGit2.v1.8.4+0.i686-linux-gnu.tar.gz/sha512/6cca444bcfdef691cbd8ea249328a9f066a20ff23ac71f238a62d32bf40d236d4b4f6cb6d48862652b97791bd199bbf7f8851361ec2778c779a59168b0e08c01 -LibGit2.v1.8.4+0.i686-linux-musl.tar.gz/md5/a6cdca1ca0926ceb5827205005e80759 -LibGit2.v1.8.4+0.i686-linux-musl.tar.gz/sha512/37a456b7a31ca9a482976d3a7aab463dedaebf48aba1d16be5aceae2dbd9051679a0287776a93eabed70f6e9bb89ed4084564a88ed83e1d6a085ec6e32111be5 -LibGit2.v1.8.4+0.i686-w64-mingw32.tar.gz/md5/5ffb5489354195b163c55a6a83d059f0 -LibGit2.v1.8.4+0.i686-w64-mingw32.tar.gz/sha512/81423290e6122210102166b5878e6a101fde2dcdd16de2dea016a682d8aeb13a9db04230d0b6358bec3a8fb8db543b89c3b720c5cdf3418471e41db74bdff993 -LibGit2.v1.8.4+0.powerpc64le-linux-gnu.tar.gz/md5/d99482bb86f1347c83c2795ec10ed551 -LibGit2.v1.8.4+0.powerpc64le-linux-gnu.tar.gz/sha512/a52b1141c1562f7ff55e29e41f95791645f4cca437a8ae09842239a2c132b3b4479edf24abb907d4674b04ceffdc0003dd5d8314697a96b73580ae0cebb59ac1 -LibGit2.v1.8.4+0.x86_64-apple-darwin.tar.gz/md5/f385317d44621ba48d296ffe39d74250 -LibGit2.v1.8.4+0.x86_64-apple-darwin.tar.gz/sha512/25d6fd31a4207d0890b93aa30f98c430d349cfa3c4759e3a81254c39ec095162c916a6fdc6d91ca4b3df3892ac8836209d0927c3ca18b4dfbe5b067f5d79cae9 -LibGit2.v1.8.4+0.x86_64-linux-gnu.tar.gz/md5/9f881bf0428bfbeed1fce06fce156a3c -LibGit2.v1.8.4+0.x86_64-linux-gnu.tar.gz/sha512/ea6e90997ae1dd77cdf73b65995682d3b2563e40215b7316f2cc17982f8a35ac8f40d194d8d25c1a7334cb8443ec028516d05e64b841559b0c5dc15ce289e238 -LibGit2.v1.8.4+0.x86_64-linux-musl.tar.gz/md5/349b44527421615d99c08dca5299bbb6 -LibGit2.v1.8.4+0.x86_64-linux-musl.tar.gz/sha512/809c53ba91a3643ed534c49b1e3352ef8e6cf642dbcd45e21b7d2a2e4edb8235d2d35245c4e891362a2597c9b724cee93ec885c50259763e3d06f2d82cdbe3ee -LibGit2.v1.8.4+0.x86_64-unknown-freebsd.tar.gz/md5/01bb75c5eda895d47a55b9a231c0977e -LibGit2.v1.8.4+0.x86_64-unknown-freebsd.tar.gz/sha512/ba4ba6e681faf3d768d6a09d6ad0f82934fcbf635d42d4e92a9f0a2d545733757cebff759a720d79981eac8046f278c17b9ea982db3a0b7b774af686b790960b -LibGit2.v1.8.4+0.x86_64-w64-mingw32.tar.gz/md5/37f1e39363db20979948f9a1ebdf312f -LibGit2.v1.8.4+0.x86_64-w64-mingw32.tar.gz/sha512/d74108deed353ec26a56d020f533bdc35a881d640d621292e08ab259461f132e19afbdfee0e21915e6f54b7f0debc9cf4f5959d711104534e0ec85d3fe3a0ac1 -libgit2-3f4182d15eab74a302718f2de454ffadb1995626.tar.gz/md5/c502ae54871bd3afc0bd593a5cf05d68 -libgit2-3f4182d15eab74a302718f2de454ffadb1995626.tar.gz/sha512/7381abb66b42d8b667be12afa360a855627149d1f293a3091c05f02a528fdcc9e44fd7a5adebba8b30ee4ac1f4d1f029a2f0d0b49ada97a751159e0a61f8a54e +LibGit2.v1.9.0+0.aarch64-apple-darwin.tar.gz/md5/1e22c2cf3e6003addd9bf16026ac4a06 +LibGit2.v1.9.0+0.aarch64-apple-darwin.tar.gz/sha512/78d5e5d246534164e1d70cf69dea273bbb8386df24c13fc3c3571762df15f2714307e7ff4cae6f977eee9def121c94cfe33cfcd44a60905a8161d65d17565e90 +LibGit2.v1.9.0+0.aarch64-linux-gnu.tar.gz/md5/70bfe9da256442ea2c295a016a89d3b9 +LibGit2.v1.9.0+0.aarch64-linux-gnu.tar.gz/sha512/14916a5521aa1281b443e61beee2573bc55b76d88810a3bec8bdea677d95763da82f1a527975cdabcdaa213e69aa1640201a03656bdb505b886906795aad0c74 +LibGit2.v1.9.0+0.aarch64-linux-musl.tar.gz/md5/62f6e885de29a345cc5ee3e773c74471 +LibGit2.v1.9.0+0.aarch64-linux-musl.tar.gz/sha512/09e793209505ea954e608c609138b8865d8a1630340fa8ff032a55234bfb8277d2c3c31f26048ae4993bf8c3d8f165abd0b4ccd80526c61efca0807f634572df +LibGit2.v1.9.0+0.aarch64-unknown-freebsd.tar.gz/md5/6fcba6e43265aa7a1ea5bba85977d622 +LibGit2.v1.9.0+0.aarch64-unknown-freebsd.tar.gz/sha512/34b836d3c22436e74963141dbe1f9372cb7ee695ebb2054ee0af1353d4401e1dfb855e91341a1d06a24ce18d57caaa3aa1e2bc7063000fa4f9be40130eb6ff95 +LibGit2.v1.9.0+0.armv6l-linux-gnueabihf.tar.gz/md5/75ede2c2c7312adf06a2a9859cd6310f +LibGit2.v1.9.0+0.armv6l-linux-gnueabihf.tar.gz/sha512/9de567bee3aad33eebac51ad5b57b4fefaa4b778ce8510b2524a55cd223bfaf3051fd48c8713741e799d1464b308469580716dcb847a6eb97fd632727ca22a7d +LibGit2.v1.9.0+0.armv6l-linux-musleabihf.tar.gz/md5/e5341f0c76c89273c465cb43cbf0f284 +LibGit2.v1.9.0+0.armv6l-linux-musleabihf.tar.gz/sha512/1029d47c82ce20223b1c108da77a1a32ef0b91b9645040c1d941e7abdd161011736a81f4ad25006b32d83d4c07c548fcf1c8a3326cf3cb91d56fd443e2e9ced7 +LibGit2.v1.9.0+0.armv7l-linux-gnueabihf.tar.gz/md5/03191a1c4ff1c1ae764092b26c941783 +LibGit2.v1.9.0+0.armv7l-linux-gnueabihf.tar.gz/sha512/6bb113c722b550fb28fc84033a3a38565ed5305a7fa193eeb4949b979fcf4599b84c748f50dad2ad47481827138a6e405eaf727f719d219984a809088bbb2948 +LibGit2.v1.9.0+0.armv7l-linux-musleabihf.tar.gz/md5/1678d6e57aa887963b27917c884cbf36 +LibGit2.v1.9.0+0.armv7l-linux-musleabihf.tar.gz/sha512/52590e9ca4118e0dec70191353b2c76155363df77df6c0bb5741dfb3f333539a8ad75339796748a744c342b51c15869726cfe9bbf6ca78d524e7d2ccce4a4622 +LibGit2.v1.9.0+0.i686-linux-gnu.tar.gz/md5/3fc50746cb80e0455f8e7c7622cd433a +LibGit2.v1.9.0+0.i686-linux-gnu.tar.gz/sha512/20c97e1a816456267a16759378a5e968e6bca122d1e0dc7cc282cad2bf2a8e3929e90373752065d91dfb6688e39ac6db660d9bdbb3277f1b9cb04b5d3f46fd8c +LibGit2.v1.9.0+0.i686-linux-musl.tar.gz/md5/fadb5e051e3b21e68a61b2a3049f65c7 +LibGit2.v1.9.0+0.i686-linux-musl.tar.gz/sha512/369c8c64df89149e9ed600028c1ac96db24e7b2c1977146667b8aeba93aa7a3b4787a49734411448680654188ece33e740fa475108b80b876a5082edad722925 +LibGit2.v1.9.0+0.i686-w64-mingw32.tar.gz/md5/610da247e41070b73e71df7e41267846 +LibGit2.v1.9.0+0.i686-w64-mingw32.tar.gz/sha512/d5b61c885133e3002e48e0fc37ceed0bfeef070e8fc6b2d78ec5f3069ad80966ea5b3a2b3aeae1ca478e9a2f839309fd67c3a186ecf751f4642ff4cb4ca3cb38 +LibGit2.v1.9.0+0.powerpc64le-linux-gnu.tar.gz/md5/f05f5f07de55fd297c564b6cd4e54747 +LibGit2.v1.9.0+0.powerpc64le-linux-gnu.tar.gz/sha512/57b740ca3ef6b18994386d74f1cf39c97c1f58f5a63e749c1a0dcef8c43a915f13cc093a8e1d06cef1d1c60cf484ba0e38d20a96344df69dfc997daa63ee1137 +LibGit2.v1.9.0+0.riscv64-linux-gnu.tar.gz/md5/b043226b10e5cbbe4914be3392f5bf72 +LibGit2.v1.9.0+0.riscv64-linux-gnu.tar.gz/sha512/a580795dd9a7ee237cd1d51d55f5079588686b1adfe391a017de743946e1bd4e7d5e4f8b79a6f84f0ce165733ca1b67ea740d06fa18547c29616df2f73e3f289 +LibGit2.v1.9.0+0.x86_64-apple-darwin.tar.gz/md5/bad8607d4997ef82cd43edfc7579d0fb +LibGit2.v1.9.0+0.x86_64-apple-darwin.tar.gz/sha512/c7359d79949a6727973b1df2264b672bfcd1617b6d4c74d281ef70ac93bcadfe47f99f7a5d031eed36b65077668ba12f2b31bbe6d491542b6938816659070317 +LibGit2.v1.9.0+0.x86_64-linux-gnu.tar.gz/md5/21e5fd214a6358f643477973c22ec70c +LibGit2.v1.9.0+0.x86_64-linux-gnu.tar.gz/sha512/9e68cb6d25d85ad272fcb0d77deedce2daa9c62d7ce2fd7e9221647d021aa00e372f490ad29211d7ca2b5ddefb4addcc4733e25e3df038aaf26fe3cb269d8f56 +LibGit2.v1.9.0+0.x86_64-linux-musl.tar.gz/md5/e9ad320825b22ee378b33856ca266b12 +LibGit2.v1.9.0+0.x86_64-linux-musl.tar.gz/sha512/bd33b4d31a7622a0440bd0979ecc7bbdef7ba7a52bfc911f880c9430d57d2b9ea1c6c4e57697b5a2b63c2e00e07673b3dad6feac056a4f345ed6e3b0ef7aef77 +LibGit2.v1.9.0+0.x86_64-unknown-freebsd.tar.gz/md5/501c63c8810616e6764ff80c23fff0b5 +LibGit2.v1.9.0+0.x86_64-unknown-freebsd.tar.gz/sha512/109e5676899ba6992a68fcff6d7503f49cc3b748b4b0faffcf951f318f9730e242914b57a7848111e229642070fdbce29bc181cbc79ac2e794c6ef489bb27293 +LibGit2.v1.9.0+0.x86_64-w64-mingw32.tar.gz/md5/4e76fa8356407a7065b50298817ad462 +LibGit2.v1.9.0+0.x86_64-w64-mingw32.tar.gz/sha512/01204b29ff2f90a9204d2e91fb7d48a3b6bea008a77984e3e67423a04f630690073d648a7200168809999aa5885fa6035c5b099256724b0379229c257ef19b9f +libgit2-338e6fb681369ff0537719095e22ce9dc602dbf0.tar.gz/md5/0ce4a212921ef1752ea057a3be45e384 +libgit2-338e6fb681369ff0537719095e22ce9dc602dbf0.tar.gz/sha512/4eb018a85a59c6ac0514f09f19a40813d8a4bc5ea230bf54897aa2ef5f584796e8c680a27ac68985a3457e1ea1f554ba4af803b430d67a9065cf51ff317d7a89 diff --git a/deps/libgit2.version b/deps/libgit2.version index 9b908cff803e3..57744b6c96d8e 100644 --- a/deps/libgit2.version +++ b/deps/libgit2.version @@ -3,8 +3,8 @@ LIBGIT2_JLL_NAME := LibGit2 ## source build -LIBGIT2_BRANCH=v1.8.4 -LIBGIT2_SHA1=3f4182d15eab74a302718f2de454ffadb1995626 +LIBGIT2_BRANCH=v1.9.0 +LIBGIT2_SHA1=338e6fb681369ff0537719095e22ce9dc602dbf0 ## Other deps # Specify the version of the Mozilla CA Certificate Store to obtain. diff --git a/stdlib/LibGit2/src/consts.jl b/stdlib/LibGit2/src/consts.jl index 8c140e8c2aa30..1a523b381982b 100644 --- a/stdlib/LibGit2/src/consts.jl +++ b/stdlib/LibGit2/src/consts.jl @@ -45,8 +45,7 @@ const BLAME_USE_MAILMAP = Cuint(1 << 5) const BLAME_IGNORE_WHITESPACE = Cuint(1 << 6) # checkout -const CHECKOUT_NONE = Cuint(0) -const CHECKOUT_SAFE = Cuint(1 << 0) +const CHECKOUT_SAFE = Cuint(0) const CHECKOUT_FORCE = Cuint(1 << 1) const CHECKOUT_RECREATE_MISSING = Cuint(1 << 2) const CHECKOUT_ALLOW_CONFLICTS = Cuint(1 << 4) @@ -67,6 +66,7 @@ const CHECKOUT_DONT_REMOVE_EXISTING = Cuint(1 << 22) const CHECKOUT_DONT_WRITE_INDEX = Cuint(1 << 23) const CHECKOUT_DRY_RUN = Cuint(1 << 24) const CHECKOUT_CONFLICT_STYLE_ZDIFF3 = Cuint(1 << 25) +const CHECKOUT_NONE = Cuint(1 << 30) const CHECKOUT_UPDATE_SUBMODULES = Cuint(1 << 16) const CHECKOUT_UPDATE_SUBMODULES_IF_CHANGED = Cuint(1 << 17) diff --git a/stdlib/LibGit2/src/types.jl b/stdlib/LibGit2/src/types.jl index 9228bec175737..181baa4991a9b 100644 --- a/stdlib/LibGit2/src/types.jl +++ b/stdlib/LibGit2/src/types.jl @@ -237,6 +237,9 @@ Matches the [`git_remote_callbacks`](https://libgit2.org/libgit2/#HEAD/type/git_ @static if LibGit2.VERSION >= v"0.99.0" resolve_url::Ptr{Cvoid} = C_NULL end + @static if LibGit2.VERSION >= v"1.9.0" + update_refs::Ptr{Cvoid} = C_NULL + end end @assert Base.allocatedinline(RemoteCallbacks) @@ -924,7 +927,9 @@ struct ConfigEntry end include_depth::Cuint level::GIT_CONFIG - free::Ptr{Cvoid} + @static if LibGit2.VERSION < v"1.9.0" + free::Ptr{Cvoid} + end @static if LibGit2.VERSION < v"1.8.0" # In 1.8.0, the unused payload value has been removed payload::Ptr{Cvoid} @@ -936,6 +941,17 @@ function Base.show(io::IO, ce::ConfigEntry) print(io, "ConfigEntry(\"", unsafe_string(ce.name), "\", \"", unsafe_string(ce.value), "\")") end +""" + LibGit2.ConfigBackendEntry + +Matches the [`git_config_backend_entry`](https://libgit2.org/libgit2/#HEAD/type/git_config_backend_entry) struct. +""" +struct ConfigBackendEntry + entry::ConfigEntry + free::Ptr{Cvoid} +end +@assert Base.allocatedinline(ConfigBackendEntry) + """ LibGit2.split_cfg_entry(ce::LibGit2.ConfigEntry) -> Tuple{String,String,String,String} @@ -1138,15 +1154,20 @@ The fields represent: * `final_commit_id`: the [`GitHash`](@ref) of the commit where this section was last changed. * `final_start_line_number`: the *one based* line number in the file where the hunk starts, in the *final* version of the file. - * `final_signature`: the signature of the person who last modified this hunk. You will + * `final_signature`: the signature of the author of `final_commit_id`. You will + need to pass this to `Signature` to access its fields. + * `final_committer`: the signature of the committer of `final_commit_id`. You will need to pass this to `Signature` to access its fields. * `orig_commit_id`: the [`GitHash`](@ref) of the commit where this hunk was first found. * `orig_path`: the path to the file where the hunk originated. This may be different than the current/final path, for instance if the file has been moved. * `orig_start_line_number`: the *one based* line number in the file where the hunk starts, in the *original* version of the file at `orig_path`. - * `orig_signature`: the signature of the person who introduced this hunk. You will + * `orig_signature`: the signature of the author who introduced this hunk. You will + need to pass this to `Signature` to access its fields. + * `orig_committer`: the signature of the committer who introduced this hunk. You will need to pass this to `Signature` to access its fields. + * `summary`: a string summary. * `boundary`: `'1'` if the original commit is a "boundary" commit (for instance, if it's equal to an oldest commit set in `options`). """ @@ -1156,12 +1177,21 @@ The fields represent: final_commit_id::GitHash = GitHash() final_start_line_number::Csize_t = Csize_t(0) final_signature::Ptr{SignatureStruct} = Ptr{SignatureStruct}(C_NULL) + @static if LibGit2.VERSION >= v"1.9.0" + final_committer::Ptr{SignatureStruct} = Ptr{SignatureStruct}(C_NULL) + end orig_commit_id::GitHash = GitHash() orig_path::Cstring = Cstring(C_NULL) orig_start_line_number::Csize_t = Csize_t(0) orig_signature::Ptr{SignatureStruct} = Ptr{SignatureStruct}(C_NULL) + @static if LibGit2.VERSION >= v"1.9.0" + orig_committer::Ptr{SignatureStruct} = Ptr{SignatureStruct}(C_NULL) + end + @static if LibGit2.VERSION >= v"1.9.0" + summary::Cstring = Cstring(C_NULL) + end boundary::Char = '\0' end @assert Base.allocatedinline(BlameHunk) diff --git a/stdlib/LibGit2/test/libgit2-tests.jl b/stdlib/LibGit2/test/libgit2-tests.jl index 1dfa5429368b6..b186f67c65cf1 100644 --- a/stdlib/LibGit2/test/libgit2-tests.jl +++ b/stdlib/LibGit2/test/libgit2-tests.jl @@ -1152,6 +1152,7 @@ mktempdir() do dir function setup_clone_repo(cache_repo::AbstractString, path::AbstractString; name="AAAA", email="BBBB@BBBB.COM") repo = LibGit2.clone(cache_repo, path) + LibGit2.fetch(repo) # need to set this for merges to succeed cfg = LibGit2.GitConfig(repo) LibGit2.set!(cfg, "user.name", name) diff --git a/stdlib/LibGit2_jll/Project.toml b/stdlib/LibGit2_jll/Project.toml index 6d3a17bb02cf8..216fe9c3c6b41 100644 --- a/stdlib/LibGit2_jll/Project.toml +++ b/stdlib/LibGit2_jll/Project.toml @@ -1,6 +1,6 @@ name = "LibGit2_jll" uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" -version = "1.8.4+0" +version = "1.9.0+0" [deps] OpenSSL_jll = "458c3c95-2e84-50aa-8efc-19380b2a3a95" diff --git a/stdlib/LibGit2_jll/src/LibGit2_jll.jl b/stdlib/LibGit2_jll/src/LibGit2_jll.jl index b7ed19a939c5e..c69deb4a9d932 100644 --- a/stdlib/LibGit2_jll/src/LibGit2_jll.jl +++ b/stdlib/LibGit2_jll/src/LibGit2_jll.jl @@ -24,9 +24,9 @@ libgit2_path::String = "" if Sys.iswindows() const libgit2 = "libgit2.dll" elseif Sys.isapple() - const libgit2 = "@rpath/libgit2.1.8.dylib" + const libgit2 = "@rpath/libgit2.1.9.dylib" else - const libgit2 = "libgit2.so.1.8" + const libgit2 = "libgit2.so.1.9" end function __init__() diff --git a/stdlib/LibGit2_jll/test/runtests.jl b/stdlib/LibGit2_jll/test/runtests.jl index 6cf2d2b8a568d..06edefe335a2f 100644 --- a/stdlib/LibGit2_jll/test/runtests.jl +++ b/stdlib/LibGit2_jll/test/runtests.jl @@ -7,5 +7,5 @@ using Test, Libdl, LibGit2_jll minor = Ref{Cint}(0) patch = Ref{Cint}(0) @test ccall((:git_libgit2_version, libgit2), Cint, (Ref{Cint}, Ref{Cint}, Ref{Cint}), major, minor, patch) == 0 - @test VersionNumber(major[], minor[], patch[]) == v"1.8.4" + @test VersionNumber(major[], minor[], patch[]) == v"1.9.0" end diff --git a/stdlib/Manifest.toml b/stdlib/Manifest.toml index 63da40a5630f5..07807ecd454a0 100644 --- a/stdlib/Manifest.toml +++ b/stdlib/Manifest.toml @@ -103,7 +103,7 @@ version = "1.11.0" [[deps.LibGit2_jll]] deps = ["Artifacts", "LibSSH2_jll", "Libdl", "OpenSSL_jll"] uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" -version = "1.8.4+0" +version = "1.9.0+0" [[deps.LibSSH2_jll]] deps = ["Artifacts", "Libdl", "OpenSSL_jll"] From 4750dc2e6f574cbf5d47603b52e8881eff40bf88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= <765740+giordano@users.noreply.github.com> Date: Mon, 6 Jan 2025 11:44:43 +0100 Subject: [PATCH 143/342] [build] Enable Intel JIT events only on x86_64 (#56964) Currently we are enabling it for all Linux systems, but [Intel VTune supports only x86_64](https://www.intel.com/content/www/us/en/developer/articles/system-requirements/vtune-profiler-system-requirements.html) and building LLVM with ITTAPI support is problematic on some platforms (e.g. riscv64, ref: https://github.com/JuliaPackaging/Yggdrasil/pull/10204). --- Make.inc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Make.inc b/Make.inc index 2f2ffcad754c4..1c08f4a947b1c 100644 --- a/Make.inc +++ b/Make.inc @@ -486,11 +486,15 @@ endif # Set to 1 to enable profiling with perf ifeq ("$(OS)", "Linux") USE_PERF_JITEVENTS ?= 1 +ifeq ($(ARCH),x86_64) USE_INTEL_JITEVENTS ?= 1 -else +else # ARCH x86_64 +USE_INTEL_JITEVENTS ?= 0 +endif # ARCH x86_64 +else # OS Linux USE_PERF_JITEVENTS ?= 0 USE_INTEL_JITEVENTS ?= 0 -endif +endif # OS Linux JULIACODEGEN := LLVM From 10e20f12679a549d82337af14a2caa709e03b88b Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Mon, 6 Jan 2025 09:55:15 -0500 Subject: [PATCH 144/342] REPL: Limit method lookup when completing kwargs (#56963) --- stdlib/REPL/src/REPLCompletions.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index 0bffb1a1015cd..2c03c6d563c1e 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -1077,7 +1077,7 @@ function complete_keyword_argument(partial::String, last_idx::Int, context_modul kwargs_flag == 2 && return fail # one of the previous kwargs is invalid methods = Completion[] - complete_methods!(methods, funct, Any[Vararg{Any}], kwargs_ex, -1, kwargs_flag == 1) + complete_methods!(methods, funct, Any[Vararg{Any}], kwargs_ex, shift ? -1 : MAX_METHOD_COMPLETIONS, kwargs_flag == 1) # TODO: use args_ex instead of Any[Vararg{Any}] and only provide kwarg completion for # method calls compatible with the current arguments. From 7801351fb1b67251b8da6b9bae5aa83286865b1b Mon Sep 17 00:00:00 2001 From: Oscar Smith Date: Mon, 6 Jan 2025 11:05:02 -0600 Subject: [PATCH 145/342] optimize constant length `memorynew` intrinsic (take 2) (#56847) replaces https://github.com/JuliaLang/julia/pull/55913 (the rebase was more annoying than starting from scratch) This allows the compiler to better understand what's going on for `memorynew` with compile-time constant length, allowing for LLVM level escape analysis in some cases. There is more room to grow this (currently this only optimizes for fairly small Memory since bigger ones would require writing some more LLVM code, and we probably want a size limit on putting Memory on the stack to avoid stackoverflow. For larger ones, we could potentially inline the free so the Memory doesn't have to be swept by the GC, etc. ``` julia> function g() m = Memory{Int}(undef, 2) for i in 1:2 m[i] = i end m[1]+m[2] end julia> @btime g() 9.735 ns (1 allocation: 48 bytes) #before 1.719 ns (0 allocations: 0 bytes) #after ``` --- src/cgutils.cpp | 141 +++++++++++++++++++++++++++---------- src/codegen.cpp | 23 ++++-- src/llvm-alloc-helpers.cpp | 4 +- src/llvm-alloc-opt.cpp | 10 +-- src/pipeline.cpp | 1 + test/boundscheck_exec.jl | 50 +++++++++++++ 6 files changed, 182 insertions(+), 47 deletions(-) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 6aabc459d2c91..295dd93e869ba 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -3321,7 +3321,7 @@ static Value *emit_genericmemoryptr(jl_codectx_t &ctx, Value *mem, const jl_data LoadInst *LI = ctx.builder.CreateAlignedLoad(PPT, addr, Align(sizeof(char*))); LI->setOrdering(AtomicOrdering::NotAtomic); LI->setMetadata(LLVMContext::MD_nonnull, MDNode::get(ctx.builder.getContext(), None)); - jl_aliasinfo_t aliasinfo = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const); + jl_aliasinfo_t aliasinfo = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_memoryptr); aliasinfo.decorateInst(LI); Value *ptr = LI; if (AS) { @@ -3347,7 +3347,7 @@ static Value *emit_genericmemoryowner(jl_codectx_t &ctx, Value *t) return emit_guarded_test(ctx, foreign, t, [&] { addr = ctx.builder.CreateConstInBoundsGEP1_32(ctx.types().T_jlgenericmemory, m, 1); LoadInst *owner = ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, addr, Align(sizeof(void*))); - jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const); + jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_memoryptr); ai.decorateInst(owner); return ctx.builder.CreateSelect(ctx.builder.CreateIsNull(owner), t, owner); }); @@ -4432,6 +4432,105 @@ static int compare_cgparams(const jl_cgparams_t *a, const jl_cgparams_t *b) } #endif +static auto *emit_genericmemory_unchecked(jl_codectx_t &ctx, Value *cg_nbytes, Value *cg_typ) +{ + auto ptls = get_current_ptls(ctx); + auto call = prepare_call(jl_alloc_genericmemory_unchecked_func); + auto *alloc = ctx.builder.CreateCall(call, { ptls, cg_nbytes, cg_typ}); + alloc->setAttributes(call->getAttributes()); + alloc->addRetAttr(Attribute::getWithAlignment(alloc->getContext(), Align(JL_HEAP_ALIGNMENT))); + call->addRetAttr(Attribute::getWithDereferenceableBytes(call->getContext(), sizeof(jl_genericmemory_t))); + return alloc; +} + +static void emit_memory_zeroinit_and_stores(jl_codectx_t &ctx, jl_datatype_t *typ, Value* alloc, Value* nbytes, Value* nel, int zi) +{ + auto arg_typename = [&] JL_NOTSAFEPOINT { + std::string type_str; + auto eltype = jl_tparam1(typ); + if (jl_is_datatype(eltype)) + type_str = jl_symbol_name(((jl_datatype_t*)eltype)->name->name); + else if (jl_is_uniontype(eltype)) + type_str = "Union"; + else + type_str = ""; + return "Memory{" + type_str + "}[]"; + }; + setName(ctx.emission_context, alloc, arg_typename); + // set length (jl_alloc_genericmemory_unchecked_func doesn't have it) + Value *decay_alloc = decay_derived(ctx, alloc); + Value *len_field = ctx.builder.CreateStructGEP(ctx.types().T_jlgenericmemory, decay_alloc, 0); + auto len_store = ctx.builder.CreateAlignedStore(nel, len_field, Align(sizeof(void*))); + auto aliasinfo = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_memorylen); + aliasinfo.decorateInst(len_store); + //This avoids the length store from being deleted which is illegal + ctx.builder.CreateFence(AtomicOrdering::Release, SyncScope::SingleThread); + // zeroinit pointers and unions + if (zi) { + Value *memory_ptr = ctx.builder.CreateStructGEP(ctx.types().T_jlgenericmemory, decay_alloc, 1); + auto *load = ctx.builder.CreateAlignedLoad(ctx.types().T_ptr, memory_ptr, Align(sizeof(void*))); + aliasinfo = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_memoryptr); + aliasinfo.decorateInst(load); + auto int8t = getInt8Ty(ctx.builder.getContext()); + ctx.builder.CreateMemSet(load, ConstantInt::get(int8t, 0), nbytes, Align(sizeof(void*))); + } + return; +} + + +static jl_cgval_t emit_const_len_memorynew(jl_codectx_t &ctx, jl_datatype_t *typ, size_t nel, jl_genericmemory_t *inst) +{ + if (nel == 0) { + Value *empty_alloc = track_pjlvalue(ctx, literal_pointer_val(ctx, (jl_value_t*)inst)); + return mark_julia_type(ctx, empty_alloc, true, typ); + } + const jl_datatype_layout_t *layout = ((jl_datatype_t*)typ)->layout; + assert(((jl_datatype_t*)typ)->has_concrete_subtype && layout != NULL); + size_t elsz = layout->size; + int isboxed = layout->flags.arrayelem_isboxed; + int isunion = layout->flags.arrayelem_isunion; + int zi = ((jl_datatype_t*)typ)->zeroinit; + if (isboxed) + elsz = sizeof(void*); + size_t nbytes; + bool overflow = __builtin_mul_overflow(nel, elsz, &nbytes); + if (isunion) { + // an extra byte for each isbits union memory element, stored at m->ptr + m->length + overflow |= __builtin_add_overflow(nbytes, nel, &nbytes); + } + // overflow if signed size is too big or nel is too big (the latter matters iff elsz==0) + ssize_t tmp=1; + overflow |= __builtin_add_overflow(nel, 1, &tmp) || __builtin_add_overflow(nbytes, 1, &tmp); + if (overflow) + emit_error(ctx, prepare_call(jlargumenterror_func), "invalid GenericMemory size: the number of elements is either negative or too large for system address width"); + + auto T_size = ctx.types().T_size; + auto cg_typ = literal_pointer_val(ctx, (jl_value_t*) typ); + auto cg_nbytes = ConstantInt::get(T_size, nbytes); + auto cg_nel = ConstantInt::get(T_size, nel); + size_t tot = nbytes + LLT_ALIGN(sizeof(jl_genericmemory_t),JL_SMALL_BYTE_ALIGNMENT); + // if allocation fits within GC pools + int pooled = tot <= GC_MAX_SZCLASS; + Value *alloc, *decay_alloc, *memory_ptr; + jl_aliasinfo_t aliasinfo; + if (pooled) { + alloc = emit_allocobj(ctx, tot, cg_typ, false, JL_SMALL_BYTE_ALIGNMENT); + decay_alloc = decay_derived(ctx, alloc); + memory_ptr = ctx.builder.CreateStructGEP(ctx.types().T_jlgenericmemory, decay_alloc, 1); + setName(ctx.emission_context, memory_ptr, "memory_ptr"); + auto objref = emit_pointer_from_objref(ctx, alloc); + Value *memory_data = emit_ptrgep(ctx, objref, JL_SMALL_BYTE_ALIGNMENT); + auto *store = ctx.builder.CreateAlignedStore(memory_data, memory_ptr, Align(sizeof(void*))); + aliasinfo = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_memoryptr); + aliasinfo.decorateInst(store); + setName(ctx.emission_context, memory_data, "memory_data"); + } else { // just use the dynamic length version since the malloc will be slow anyway + alloc = emit_genericmemory_unchecked(ctx, cg_nbytes, cg_typ); + } + emit_memory_zeroinit_and_stores(ctx, typ, alloc, cg_nbytes, cg_nel, zi); + return mark_julia_type(ctx, alloc, true, typ); +} + static jl_cgval_t emit_memorynew(jl_codectx_t &ctx, jl_datatype_t *typ, jl_cgval_t nel, jl_genericmemory_t *inst) { emit_typecheck(ctx, nel, (jl_value_t*)jl_long_type, "memorynew"); @@ -4448,9 +4547,7 @@ static jl_cgval_t emit_memorynew(jl_codectx_t &ctx, jl_datatype_t *typ, jl_cgval if (isboxed) elsz = sizeof(void*); - auto ptls = get_current_ptls(ctx); auto T_size = ctx.types().T_size; - auto int8t = getInt8Ty(ctx.builder.getContext()); BasicBlock *emptymemBB, *nonemptymemBB, *retvalBB; emptymemBB = BasicBlock::Create(ctx.builder.getContext(), "emptymem"); nonemptymemBB = BasicBlock::Create(ctx.builder.getContext(), "nonemptymem"); @@ -4466,18 +4563,7 @@ static jl_cgval_t emit_memorynew(jl_codectx_t &ctx, jl_datatype_t *typ, jl_cgval ctx.builder.CreateBr(retvalBB); nonemptymemBB->insertInto(ctx.f); ctx.builder.SetInsertPoint(nonemptymemBB); - // else actually allocate mem - auto arg_typename = [&] JL_NOTSAFEPOINT { - std::string type_str; - auto eltype = jl_tparam1(typ); - if (jl_is_datatype(eltype)) - type_str = jl_symbol_name(((jl_datatype_t*)eltype)->name->name); - else if (jl_is_uniontype(eltype)) - type_str = "Union"; - else - type_str = ""; - return "Memory{" + type_str + "}[]"; - }; + auto cg_typ = literal_pointer_val(ctx, (jl_value_t*) typ); auto cg_elsz = ConstantInt::get(T_size, elsz); @@ -4501,27 +4587,10 @@ static jl_cgval_t emit_memorynew(jl_codectx_t &ctx, jl_datatype_t *typ, jl_cgval overflow = ctx.builder.CreateOr(overflow, tobignel); Value *notoverflow = ctx.builder.CreateNot(overflow); error_unless(ctx, prepare_call(jlargumenterror_func), notoverflow, "invalid GenericMemory size: the number of elements is either negative or too large for system address width"); - // actually allocate - auto call = prepare_call(jl_alloc_genericmemory_unchecked_func); - Value *alloc = ctx.builder.CreateCall(call, { ptls, nbytes, cg_typ}); - // set length (jl_alloc_genericmemory_unchecked_func doesn't have it) - Value *decay_alloc = decay_derived(ctx, alloc); - Value *len_field = ctx.builder.CreateStructGEP(ctx.types().T_jlgenericmemory, decay_alloc, 0); - auto len_store = ctx.builder.CreateAlignedStore(nel_unboxed, len_field, Align(sizeof(void*))); - auto aliasinfo = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_memorylen); - aliasinfo.decorateInst(len_store); - //This avoids the length store from being deleted which is illegal - ctx.builder.CreateFence(AtomicOrdering::Release, SyncScope::SingleThread); - // zeroinit pointers and unions - if (zi) { - Value *memory_ptr = ctx.builder.CreateStructGEP(ctx.types().T_jlgenericmemory, decay_alloc, 1); - auto *load = ctx.builder.CreateAlignedLoad(ctx.types().T_ptr, memory_ptr, Align(sizeof(void*))); - aliasinfo = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_memoryptr); - aliasinfo.decorateInst(load); - ctx.builder.CreateMemSet(load, ConstantInt::get(int8t, 0), nbytes, Align(sizeof(void*))); - } + // actually allocate the memory - setName(ctx.emission_context, alloc, arg_typename); + Value *alloc = emit_genericmemory_unchecked(ctx, nbytes, cg_typ); + emit_memory_zeroinit_and_stores(ctx, typ, alloc, nbytes, nel_unboxed, zi); ctx.builder.CreateBr(retvalBB); nonemptymemBB = ctx.builder.GetInsertBlock(); // phi node to choose which side of branch diff --git a/src/codegen.cpp b/src/codegen.cpp index 1ca45a98b0620..4b5676cc8216e 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -408,9 +408,9 @@ struct jl_tbaacache_t { tbaa_arrayptr = tbaa_make_child(mbuilder, "jtbaa_arrayptr", tbaa_array_scalar).first; tbaa_arraysize = tbaa_make_child(mbuilder, "jtbaa_arraysize", tbaa_array_scalar).first; tbaa_arrayselbyte = tbaa_make_child(mbuilder, "jtbaa_arrayselbyte", tbaa_array_scalar).first; - tbaa_memoryptr = tbaa_make_child(mbuilder, "jtbaa_memoryptr", tbaa_array_scalar, true).first; - tbaa_memorylen = tbaa_make_child(mbuilder, "jtbaa_memorylen", tbaa_array_scalar, true).first; - tbaa_memoryown = tbaa_make_child(mbuilder, "jtbaa_memoryown", tbaa_array_scalar, true).first; + tbaa_memoryptr = tbaa_make_child(mbuilder, "jtbaa_memoryptr", tbaa_array_scalar).first; + tbaa_memorylen = tbaa_make_child(mbuilder, "jtbaa_memorylen", tbaa_array_scalar).first; + tbaa_memoryown = tbaa_make_child(mbuilder, "jtbaa_memoryown", tbaa_array_scalar).first; tbaa_const = tbaa_make_child(mbuilder, "jtbaa_const", nullptr, true).first; } }; @@ -1179,6 +1179,7 @@ static const auto jl_alloc_genericmemory_unchecked_func = new JuliaFunction{ AttrBuilder FnAttrs(C); FnAttrs.addMemoryAttr(MemoryEffects::none()); FnAttrs.addAttribute(Attribute::NoUnwind); + FnAttrs.addAttribute(Attribute::Speculatable); + FnAttrs.addAttribute(Attribute::WillReturn); + FnAttrs.addAttribute(Attribute::NoRecurse); + FnAttrs.addAttribute(Attribute::NoSync); return AttributeList::get(C, AttributeSet::get(C, FnAttrs), Attributes(C, {Attribute::NonNull}), @@ -4470,7 +4475,17 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, jl_genericmemory_t *inst = (jl_genericmemory_t*)((jl_datatype_t*)typ)->instance; if (inst == NULL) return false; - *ret = emit_memorynew(ctx, typ, argv[2], inst); + if (argv[2].constant) { + if (!jl_is_long(argv[2].constant)) + return false; + size_t nel = jl_unbox_long(argv[2].constant); + if (nel < 0) + return false; + *ret = emit_const_len_memorynew(ctx, typ, nel, inst); + } + else { + *ret = emit_memorynew(ctx, typ, argv[2], inst); + } return true; } diff --git a/src/llvm-alloc-helpers.cpp b/src/llvm-alloc-helpers.cpp index 59fce1235e14e..194c6837860ca 100644 --- a/src/llvm-alloc-helpers.cpp +++ b/src/llvm-alloc-helpers.cpp @@ -250,8 +250,8 @@ void jl_alloc::runEscapeAnalysis(llvm::CallInst *I, EscapeAnalysisRequiredArgs r return true; } if (required.pass.gc_loaded_func == callee) { - required.use_info.haspreserve = true; - required.use_info.hasload = true; + // TODO add manual load->store forwarding + push_inst(inst); return true; } if (required.pass.typeof_func == callee) { diff --git a/src/llvm-alloc-opt.cpp b/src/llvm-alloc-opt.cpp index a9e1b1e02da42..7dd794a4d8847 100644 --- a/src/llvm-alloc-opt.cpp +++ b/src/llvm-alloc-opt.cpp @@ -752,11 +752,11 @@ void Optimizer::moveToStack(CallInst *orig_inst, size_t sz, bool has_ref, AllocF call->eraseFromParent(); return; } - //if (pass.gc_loaded_func == callee) { - // call->replaceAllUsesWith(new_i); - // call->eraseFromParent(); - // return; - //} + if (pass.gc_loaded_func == callee) { + // TODO: handle data pointer forwarding, length forwarding, and fence removal + user->replaceUsesOfWith(orig_i, Constant::getNullValue(orig_i->getType())); + return; + } if (pass.typeof_func == callee) { ++RemovedTypeofs; call->replaceAllUsesWith(tag); diff --git a/src/pipeline.cpp b/src/pipeline.cpp index 8c9054c0d65ff..39f896ba656d2 100644 --- a/src/pipeline.cpp +++ b/src/pipeline.cpp @@ -527,6 +527,7 @@ static void buildIntrinsicLoweringPipeline(ModulePassManager &MPM, PassBuilder * JULIA_PASS(FPM.addPass(LateLowerGCPass())); JULIA_PASS(FPM.addPass(FinalLowerGCPass())); if (O.getSpeedupLevel() >= 2) { + FPM.addPass(DSEPass()); FPM.addPass(GVNPass()); FPM.addPass(SCCPPass()); FPM.addPass(DCEPass()); diff --git a/test/boundscheck_exec.jl b/test/boundscheck_exec.jl index 10f46eb4a8031..85df1d64017b4 100644 --- a/test/boundscheck_exec.jl +++ b/test/boundscheck_exec.jl @@ -297,4 +297,54 @@ end typeintersect(Int, Integer) end |> only === Type{Int} +if bc_opt == bc_default +@testset "Array/Memory escape analysis" begin + function no_allocate(T::Type{<:Union{Memory, Vector}}) + v = T(undef, 2) + v[1] = 2 + v[2] = 3 + return v[1] + v[2] + end + function test_alloc(::Type{T}; broken=false) where T + @test (@allocated no_allocate(T)) == 0 broken=broken + end + @testset "$T" for T in [Memory, Vector] + @testset "$ET" for ET in [Int, Float32, Union{Int, Float64}] + no_allocate(T{ET}) #compile + # allocations aren't removed for Union eltypes which they theoretically could be eventually + test_alloc(T{ET}, broken=(ET==Union{Int, Float64})) + end + end + function f() # this was causing a bug on an in progress version of #55913. + m = Memory{Float64}(undef, 4) + m .= 1.0 + s = 0.0 + for x ∈ m + s += x + end + s + end + @test f() === 4.0 + function confuse_alias_analysis() + mem0 = Memory{Int}(undef, 1) + mem1 = Memory{Int}(undef, 1) + @inbounds mem0[1] = 3 + for width in 1:2 + @inbounds mem1[1] = mem0[1] + mem0 = mem1 + end + mem0[1] + end + @test confuse_alias_analysis() == 3 + @test (@allocated confuse_alias_analysis()) == 0 + function no_alias_prove(n) + m1 = Memory{Int}(undef,n) + m2 = Memory{Int}(undef,n) + m1 === m2 + end + no_alias_prove(1) + @test_broken (@allocated no_alias_prove(5)) == 0 +end +end + end From 5058dbad0462f0142f0a18be0a9aa1d62c76d2d0 Mon Sep 17 00:00:00 2001 From: Lilith Orion Hafner Date: Mon, 6 Jan 2025 12:29:36 -0600 Subject: [PATCH 146/342] Add compat annotation for sorting NTuples. (#56961) Thanks @stevengj for pointing this out https://github.com/JuliaLang/julia/pull/54494#discussion_r1903267695 --- base/sort.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/base/sort.jl b/base/sort.jl index e1680d545bdc6..8254f56b3f952 100644 --- a/base/sort.jl +++ b/base/sort.jl @@ -1739,10 +1739,13 @@ function sort!(v::AbstractVector{T}; end """ - sort(v; alg::Base.Sort.Algorithm=Base.Sort.defalg(v), lt=isless, by=identity, rev::Bool=false, order::Base.Order.Ordering=Base.Order.Forward) + sort(v::Union{AbstractVector, NTuple}; alg::Base.Sort.Algorithm=Base.Sort.defalg(v), lt=isless, by=identity, rev::Bool=false, order::Base.Order.Ordering=Base.Order.Forward) Variant of [`sort!`](@ref) that returns a sorted copy of `v` leaving `v` itself unmodified. +!!! compat "Julia 1.12" + Sorting `NTuple`s requires Julia 1.12 or later. + # Examples ```jldoctest julia> v = [3, 1, 2]; From 36472a70b3f19ff49831c29bbe244211948cf955 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 6 Jan 2025 13:58:32 -0500 Subject: [PATCH 147/342] gc: fix assertion / ASAN violation in gc_big_object_link (#56944) We somehow just got (un)lucky that `DFS!` at Compiler/src/ssair/domtree.jl:184 just happened to store exactly the same value as this pointer in this particular memory location previously, so that this branch on `undef` hit exactly the right value to fail. What are the odds? Seen on a CI run (with rr) The odds of this happening seem somewhere around 2^60 against, to 1 for each time. So that seems impressive we hit this even this once. But we did, and the proof is here, caught in rr: https://buildkite.com/julialang/julia-master/builds/43366#019425d7-67fd-4f33-a025-6d7cd6181649 ``` From worker 6: julia: /cache/build/tester-amdci5-10/julialang/julia-master/src/gc-stock.h:492: gc_big_object_link: Assertion `node->header != gc_bigval_sentinel_tag' failed. 2025-01-02 07:47:22 UTC From worker 6: 2025-01-02 07:47:22 UTC From worker 6: [3877] signal 6 (-6): Aborted 2025-01-02 07:47:22 UTC From worker 6: in expression starting at none:1 2025-01-02 07:47:22 UTC From worker 6: gsignal at /lib/x86_64-linux-gnu/libc.so.6 (unknown line) 2025-01-02 07:47:22 UTC From worker 6: abort at /lib/x86_64-linux-gnu/libc.so.6 (unknown line) 2025-01-02 07:47:22 UTC From worker 6: unknown function (ip: 0x7fb9a4b5040e) at /lib/x86_64-linux-gnu/libc.so.6 2025-01-02 07:47:22 UTC From worker 6: __assert_fail at /lib/x86_64-linux-gnu/libc.so.6 (unknown line) 2025-01-02 07:47:22 UTC From worker 6: gc_big_object_link at /cache/build/tester-amdci5-10/julialang/julia-master/src/gc-stock.h:492 [inlined] 2025-01-02 07:47:22 UTC From worker 6: gc_setmark_big at /cache/build/tester-amdci5-10/julialang/julia-master/src/gc-stock.c:276 2025-01-02 07:47:22 UTC From worker 6: jl_gc_big_alloc_inner at /cache/build/tester-amdci5-10/julialang/julia-master/src/gc-stock.h:491 ``` --- src/gc-stock.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gc-stock.c b/src/gc-stock.c index c1bc1d64ae199..1f6b58d71da3a 100644 --- a/src/gc-stock.c +++ b/src/gc-stock.c @@ -423,7 +423,7 @@ STATIC_INLINE void jl_batch_accum_free_size(jl_ptls_t ptls, uint64_t sz) JL_NOTS // big value list -// Size includes the tag and the tag is not cleared!! +// Size includes the tag and the tag field is undefined on return (must be set before the next GC safepoint) STATIC_INLINE jl_value_t *jl_gc_big_alloc_inner(jl_ptls_t ptls, size_t sz) { maybe_collect(ptls); @@ -448,6 +448,9 @@ STATIC_INLINE jl_value_t *jl_gc_big_alloc_inner(jl_ptls_t ptls, size_t sz) memset(v, 0xee, allocsz); #endif v->sz = allocsz; +#ifndef NDEBUG + v->header = 0; // must be initialized (and not gc_bigval_sentinel_tag) or gc_big_object_link assertions will get confused +#endif gc_big_object_link(ptls->gc_tls.heap.young_generation_of_bigvals, v); return jl_valueof(&v->header); } From a23a6dee7dcfda81c037c9e689944503d8f6135d Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 6 Jan 2025 15:46:30 -0500 Subject: [PATCH 148/342] fix handling of experimental module compile flag (#56945) Add a new `finish!` function which skips any inference/optimization and just directly uses the (uninferred) source as the result, setting all fields correctly assuming they might have come from a generated function in the very unlikely case it set some of them, and making sure this is now correctly synchronized with the cache lookup and insertion calls once again. This code feature was added without any tests in #37041, so I cannot guarantee there aren't any mistakes still lurking here, either mine or original. Fixes #53431 --- Compiler/src/typeinfer.jl | 72 ++++++++++++++++++++++++++++++++------- src/aotcompile.cpp | 6 ++-- src/gf.c | 27 +++++++++++++++ src/jitlayers.cpp | 30 ++-------------- src/julia_internal.h | 2 +- 5 files changed, 92 insertions(+), 45 deletions(-) diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index 45df4707e4caa..e2821f79cca0c 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -173,6 +173,39 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState) return nothing end +function finish!(interp::AbstractInterpreter, mi::MethodInstance, ci::CodeInstance, src::CodeInfo) + user_edges = src.edges + edges = user_edges isa SimpleVector ? user_edges : user_edges === nothing ? Core.svec() : Core.svec(user_edges...) + relocatability = 0x1 + const_flag = false + di = src.debuginfo + rettype = Any + exctype = Any + rettype_const = nothing + const_flags = 0x0 + ipo_effects = zero(UInt32) + min_world = src.min_world + max_world = src.max_world + if max_world >= get_world_counter() + max_world = typemax(UInt) + end + if max_world == typemax(UInt) + # if we can record all of the backedges in the global reverse-cache, + # we can now widen our applicability in the global cache too + store_backedges(ci, edges) + end + ccall(:jl_fill_codeinst, Cvoid, (Any, Any, Any, Any, Int32, UInt, UInt, UInt32, Any, Any, Any), + ci, rettype, exctype, nothing, const_flags, min_world, max_world, ipo_effects, nothing, di, edges) + ccall(:jl_update_codeinst, Cvoid, (Any, Any, Int32, UInt, UInt, UInt32, Any, UInt8, Any, Any), + ci, nothing, const_flag, min_world, max_world, ipo_effects, nothing, relocatability, di, edges) + code_cache(interp)[mi] = ci + if isdefined(interp, :codegen) + interp.codegen[ci] = src + end + engine_reject(interp, ci) + return nothing +end + function finish_nocycle(::AbstractInterpreter, frame::InferenceState) finishinfer!(frame, frame.interp) opt = frame.result.src @@ -826,7 +859,7 @@ function typeinf_edge(interp::AbstractInterpreter, method::Method, @nospecialize end end end - if ccall(:jl_get_module_infer, Cint, (Any,), method.module) == 0 && !generating_output(#=incremental=#false) + if ccall(:jl_get_module_infer, Cint, (Any,), method.module) == 0 add_remark!(interp, caller, "[typeinf_edge] Inference is disabled for the target module") return Future(MethodCallResult(interp, caller, method, Any, Any, Effects(), nothing, edgecycle, edgelimited)) end @@ -1096,15 +1129,6 @@ function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance, source_mod end end def = mi.def - if isa(def, Method) - if ccall(:jl_get_module_infer, Cint, (Any,), def.module) == 0 && !generating_output(#=incremental=#false) - src = retrieve_code_info(mi, get_inference_world(interp)) - src isa CodeInfo || return nothing - return CodeInstance(mi, cache_owner(interp), Any, Any, nothing, src, Int32(0), - get_inference_world(interp), get_inference_world(interp), - UInt32(0), nothing, UInt8(0), src.debuginfo, src.edges) - end - end ci = engine_reserve(interp, mi) # check cache again if it is still new after reserving in the engine let code = get(code_cache(interp), mi, nothing) @@ -1117,11 +1141,22 @@ function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance, source_mod end end end + if isa(def, Method) && ccall(:jl_get_module_infer, Cint, (Any,), def.module) == 0 + src = retrieve_code_info(mi, get_inference_world(interp)) + if src isa CodeInfo + finish!(interp, mi, ci, src) + else + engine_reject(interp, ci) + end + ccall(:jl_typeinf_timing_end, Cvoid, (UInt64,), start_time) + return ci + end result = InferenceResult(mi, typeinf_lattice(interp)) result.ci = ci frame = InferenceState(result, #=cache_mode=#:global, interp) if frame === nothing engine_reject(interp, ci) + ccall(:jl_typeinf_timing_end, Cvoid, (UInt64,), start_time) return nothing end typeinf(interp, frame) @@ -1263,18 +1298,29 @@ function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim:: callee in inspected && continue push!(inspected, callee) # now make sure everything has source code, if desired - # TODO: typeinf_code could return something with different edges/ages (needing an update to callee), which we don't handle here + mi = get_ci_mi(callee) + def = mi.def if use_const_api(callee) - src = codeinfo_for_const(interp, callee.def, code.rettype_const) + src = codeinfo_for_const(interp, mi, code.rettype_const) elseif haskey(interp.codegen, callee) src = interp.codegen[callee] + elseif isa(def, Method) && ccall(:jl_get_module_infer, Cint, (Any,), def.module) == 0 && !trim + src = retrieve_code_info(mi, get_inference_world(interp)) else - src = typeinf_code(interp, callee.def, true) + # TODO: typeinf_code could return something with different edges/ages/owner/abi (needing an update to callee), which we don't handle here + src = typeinf_code(interp, mi, true) end if src isa CodeInfo collectinvokes!(tocompile, src) + # It is somewhat ambiguous if typeinf_ext might have callee in the caches, + # but for the purpose of native compile, we always want them put there. + if iszero(ccall(:jl_mi_cache_has_ci, Cint, (Any, Any), mi, callee)) + code_cache(interp)[mi] = callee + end push!(codeinfos, callee) push!(codeinfos, src) + elseif trim + println("warning: failed to get code for ", mi) end end end diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 0600106c41aa6..b839ced8336da 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -429,7 +429,7 @@ static void resolve_workqueue(jl_codegen_params_t ¶ms, egal_set &method_root } } else if (params.params->trim) { - jl_safe_printf("warning: no code provided for function"); + jl_safe_printf("warning: no code provided for function "); jl_(codeinst->def); if (params.params->trim) abort(); @@ -441,7 +441,7 @@ static void resolve_workqueue(jl_codegen_params_t ¶ms, egal_set &method_root Function *pinvoke = nullptr; if (preal_decl.empty()) { if (invokeName.empty() && params.params->trim) { - jl_safe_printf("warning: bailed out to invoke when compiling:"); + jl_safe_printf("warning: bailed out to invoke when compiling: "); jl_(codeinst->def); abort(); } @@ -658,7 +658,7 @@ void *jl_emit_native_impl(jl_array_t *codeinfos, LLVMOrcThreadSafeModuleRef llvm else if (params.params->trim) { // if we're building a small image, we need to compile everything // to ensure that we have all the information we need. - jl_safe_printf("codegen failed to compile code root"); + jl_safe_printf("codegen failed to compile code root "); jl_(mi); abort(); } diff --git a/src/gf.c b/src/gf.c index 48cb8003072ca..d5fbcfc7dcd6a 100644 --- a/src/gf.c +++ b/src/gf.c @@ -581,6 +581,33 @@ JL_DLLEXPORT int jl_mi_cache_has_ci(jl_method_instance_t *mi, return 0; } +// look for something with an egal ABI and properties that is already in the JIT (compiled=true) or simply in the cache (compiled=false) +JL_DLLEXPORT jl_code_instance_t *jl_get_ci_equiv(jl_code_instance_t *ci JL_PROPAGATES_ROOT, int compiled) JL_NOTSAFEPOINT +{ + jl_value_t *def = ci->def; + jl_method_instance_t *mi = jl_get_ci_mi(ci); + jl_value_t *owner = ci->owner; + jl_value_t *rettype = ci->rettype; + size_t min_world = jl_atomic_load_relaxed(&ci->min_world); + size_t max_world = jl_atomic_load_relaxed(&ci->max_world); + jl_code_instance_t *codeinst = jl_atomic_load_relaxed(&mi->cache); + while (codeinst) { + if (codeinst != ci && + jl_atomic_load_relaxed(&codeinst->inferred) != NULL && + (!compiled || jl_atomic_load_relaxed(&codeinst->invoke) != NULL) && + jl_atomic_load_relaxed(&codeinst->min_world) <= min_world && + jl_atomic_load_relaxed(&codeinst->max_world) >= max_world && + jl_egal(codeinst->def, def) && + jl_egal(codeinst->owner, owner) && + jl_egal(codeinst->rettype, rettype)) { + return codeinst; + } + codeinst = jl_atomic_load_relaxed(&codeinst->next); + } + return (jl_code_instance_t*)jl_nothing; +} + + JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst( jl_method_instance_t *mi, jl_value_t *owner, jl_value_t *rettype, jl_value_t *exctype, diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 21d865891e45c..396a42505188a 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -301,32 +301,6 @@ static void finish_params(Module *M, jl_codegen_params_t ¶ms) JL_NOTSAFEPOIN } } -// look for something with an egal ABI that is already in the JIT -static jl_code_instance_t *jl_method_compiled_egal(jl_code_instance_t *ci JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT -{ - jl_value_t *def = ci->def; - jl_method_instance_t *mi = jl_get_ci_mi(ci); - jl_value_t *owner = ci->owner; - jl_value_t *rettype = ci->rettype; - size_t min_world = jl_atomic_load_relaxed(&ci->min_world); - size_t max_world = jl_atomic_load_relaxed(&ci->max_world); - jl_code_instance_t *codeinst = jl_atomic_load_relaxed(&mi->cache); - while (codeinst) { - if (codeinst != ci && - jl_atomic_load_relaxed(&codeinst->inferred) != NULL && - jl_atomic_load_relaxed(&codeinst->invoke) != NULL && - jl_atomic_load_relaxed(&codeinst->min_world) <= min_world && - jl_atomic_load_relaxed(&codeinst->max_world) >= max_world && - jl_egal(codeinst->def, def) && - jl_egal(codeinst->owner, owner) && - jl_egal(codeinst->rettype, rettype)) { - return codeinst; - } - codeinst = jl_atomic_load_relaxed(&codeinst->next); - } - return codeinst; -} - static int jl_analyze_workqueue(jl_code_instance_t *callee, jl_codegen_params_t ¶ms, bool forceall=false) JL_NOTSAFEPOINT_LEAVE JL_NOTSAFEPOINT_ENTER { jl_task_t *ct = jl_current_task; @@ -377,8 +351,8 @@ static int jl_analyze_workqueue(jl_code_instance_t *callee, jl_codegen_params_t } if (preal_decl.empty()) { // there may be an equivalent method already compiled (or at least registered with the JIT to compile), in which case we should be using that instead - jl_code_instance_t *compiled_ci = jl_method_compiled_egal(codeinst); - if (compiled_ci) { + jl_code_instance_t *compiled_ci = jl_get_ci_equiv(codeinst, 1); + if ((jl_value_t*)compiled_ci != jl_nothing) { codeinst = compiled_ci; uint8_t specsigflags; void *fptr; diff --git a/src/julia_internal.h b/src/julia_internal.h index 00103e9b00a48..446e313fbe03d 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -692,6 +692,7 @@ JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst( int32_t const_flags, size_t min_world, size_t max_world, uint32_t effects, jl_value_t *analysis_results, uint8_t relocatability, jl_debuginfo_t *di, jl_svec_t *edges /* , int absolute_max*/); +JL_DLLEXPORT jl_code_instance_t *jl_get_ci_equiv(jl_code_instance_t *ci JL_PROPAGATES_ROOT, int compiled) JL_NOTSAFEPOINT; STATIC_INLINE jl_method_instance_t *jl_get_ci_mi(jl_code_instance_t *ci JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT { @@ -1221,7 +1222,6 @@ JL_DLLEXPORT void jl_mi_cache_insert(jl_method_instance_t *mi JL_ROOTING_ARGUMEN JL_DLLEXPORT int jl_mi_try_insert(jl_method_instance_t *mi JL_ROOTING_ARGUMENT, jl_code_instance_t *expected_ci, jl_code_instance_t *ci JL_ROOTED_ARGUMENT JL_MAYBE_UNROOTED); -JL_DLLEXPORT int jl_mi_cache_has_ci(jl_method_instance_t *mi, jl_code_instance_t *ci) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_code_instance_t *jl_cached_uninferred(jl_code_instance_t *codeinst, size_t world); JL_DLLEXPORT jl_code_instance_t *jl_cache_uninferred(jl_method_instance_t *mi, jl_code_instance_t *checked, size_t world, jl_code_instance_t *newci JL_MAYBE_UNROOTED); JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst_for_uninferred(jl_method_instance_t *mi, jl_code_info_t *src); From ad5533cbda01015424851c77f672a540b08ca74c Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Mon, 6 Jan 2025 22:28:41 +0100 Subject: [PATCH 149/342] Add "mea culpa" to foreign module assignment error. (#56956) As requested in #56933, acknowledge that this error was missing in Julia 1.9 and 1.10 and provide a reference to the issue so that people have an easier starting point. --- src/module.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/module.c b/src/module.c index 38f4b980a72fd..df90180901f2c 100644 --- a/src/module.c +++ b/src/module.c @@ -290,7 +290,11 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, if (decode_restriction_kind(pku) != BINDING_KIND_DECLARED) { check_safe_newbinding(m, var); if (!alloc) - jl_errorf("Global %s.%s does not exist and cannot be assigned. Declare it using `global` before attempting assignment.", jl_symbol_name(m->name), jl_symbol_name(var)); + jl_errorf("Global %s.%s does not exist and cannot be assigned.\n" + "Note: Julia 1.9 and 1.10 inadvertently omitted this error check (#56933).\n" + "Hint: Declare it using `global %s` inside `%s` before attempting assignment.", + jl_symbol_name(m->name), jl_symbol_name(var), + jl_symbol_name(var), jl_symbol_name(m->name)); } jl_ptr_kind_union_t new_pku = encode_restriction((jl_value_t*)jl_any_type, BINDING_KIND_GLOBAL); if (!jl_atomic_cmpswap(&bpart->restriction, &pku, new_pku)) From 0787a62091f886b39537386c3d1eaba72cb673ed Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Mon, 6 Jan 2025 16:33:16 -0500 Subject: [PATCH 150/342] Make `Timer(f, ...)` tasks match the stickiness of the parent task. Add `spawn` kwarg. (#56745) --- NEWS.md | 2 ++ base/asyncevent.jl | 13 +++++++++++-- test/channels.jl | 7 +++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index 8f02045a213d6..1708866609427 100644 --- a/NEWS.md +++ b/NEWS.md @@ -112,6 +112,8 @@ New library features * New `ltruncate`, `rtruncate` and `ctruncate` functions for truncating strings to text width, accounting for char widths ([#55351]) * `isless` (and thus `cmp`, sorting, etc.) is now supported for zero-dimensional `AbstractArray`s ([#55772]) * `invoke` now supports passing a Method instead of a type signature making this interface somewhat more flexible for certain uncommon use cases ([#56692]). +* `Timer(f, ...)` will now match the stickiness of the parent task when creating timer tasks, which can be overridden + by the new `spawn` kwarg. This avoids the issue where sticky tasks i.e. `@async` make their parent sticky ([#56745]) * `invoke` now supports passing a CodeInstance instead of a type, which can enable certain compiler plugin workflows ([#56660]). * `sort` now supports `NTuple`s ([#54494]) diff --git a/base/asyncevent.jl b/base/asyncevent.jl index c6cb3d3fa73bb..8c708455976e2 100644 --- a/base/asyncevent.jl +++ b/base/asyncevent.jl @@ -275,7 +275,7 @@ end # timer with repeated callback """ - Timer(callback::Function, delay; interval = 0) + Timer(callback::Function, delay; interval = 0, spawn::Union{Nothing,Bool}=nothing) Create a timer that runs the function `callback` at each timer expiration. @@ -285,6 +285,13 @@ callback is only run once. The function `callback` is called with a single argum itself. Stop a timer by calling `close`. The `callback` may still be run one final time, if the timer has already expired. +If `spawn` is `true`, the created task will be spawned, meaning that it will be allowed +to move thread, which avoids the side-effect of forcing the parent task to get stuck to the thread +it is on. If `spawn` is `nothing` (default), the task will be spawned if the parent task isn't sticky. + +!!! compat "Julia 1.12" + The `spawn` argument was introduced in Julia 1.12. + # Examples Here the first number is printed after a delay of two seconds, then the following numbers are @@ -304,7 +311,8 @@ julia> begin 3 ``` """ -function Timer(cb::Function, timeout; kwargs...) +function Timer(cb::Function, timeout; spawn::Union{Nothing,Bool}=nothing, kwargs...) + sticky = spawn === nothing ? current_task().sticky : !spawn timer = Timer(timeout; kwargs...) t = @task begin unpreserve_handle(timer) @@ -319,6 +327,7 @@ function Timer(cb::Function, timeout; kwargs...) isopen(timer) || return end end + t.sticky = sticky # here we are mimicking parts of _trywait, in coordination with task `t` preserve_handle(timer) @lock timer.cond begin diff --git a/test/channels.jl b/test/channels.jl index eed7a7ecc0566..f3e5381a62e94 100644 --- a/test/channels.jl +++ b/test/channels.jl @@ -550,8 +550,11 @@ end # make sure 1-shot timers work let a = [] Timer(t -> push!(a, 1), 0.01, interval = 0) - sleep(0.2) - @test a == [1] + @test timedwait(() -> a == [1], 10) === :ok +end +let a = [] + Timer(t -> push!(a, 1), 0.01, interval = 0, spawn = true) + @test timedwait(() -> a == [1], 10) === :ok end # make sure that we don't accidentally create a one-shot timer From 0d6bd8cbe4673e7c7eb6237cc18de968b9bbdf63 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Mon, 6 Jan 2025 23:20:15 -0500 Subject: [PATCH 151/342] Update stdlib manifest (#56972) --- stdlib/Manifest.toml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/stdlib/Manifest.toml b/stdlib/Manifest.toml index 07807ecd454a0..6743d357fb8b3 100644 --- a/stdlib/Manifest.toml +++ b/stdlib/Manifest.toml @@ -2,7 +2,7 @@ julia_version = "1.12.0-DEV" manifest_format = "2.0" -project_hash = "d3a1f6b706609fe0c59521e1d770be6e2b8c489d" +project_hash = "1cb1aede0b4f0a2f12806233b9f188a63d6acf04" [[deps.ArgTools]] uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" @@ -58,7 +58,7 @@ version = "1.11.0" [[deps.GMP_jll]] deps = ["Artifacts", "Libdl"] uuid = "781609d7-10c4-51f6-84f2-b8444358ff6d" -version = "6.3.0+1" +version = "6.3.0+2" [[deps.InteractiveUtils]] deps = ["Markdown"] @@ -78,7 +78,7 @@ version = "18.1.7+3" [[deps.LLVMLibUnwind_jll]] deps = ["Artifacts", "Libdl"] uuid = "47c5dbc3-30ba-59ef-96a6-123e260183d9" -version = "12.0.1+0" +version = "19.1.4+0" [[deps.LazyArtifacts]] deps = ["Artifacts", "Pkg"] @@ -108,12 +108,12 @@ version = "1.9.0+0" [[deps.LibSSH2_jll]] deps = ["Artifacts", "Libdl", "OpenSSL_jll"] uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" -version = "1.11.3+0" +version = "1.11.3+1" [[deps.LibUV_jll]] deps = ["Artifacts", "Libdl"] uuid = "183b4373-6708-53ba-ad28-60e28bb38547" -version = "2.0.1+19" +version = "2.0.1+20" [[deps.LibUnwind_jll]] deps = ["Artifacts", "Libdl"] @@ -149,11 +149,11 @@ version = "1.11.0" [[deps.MozillaCACerts_jll]] uuid = "14a3606d-f60d-562e-9121-12d972cd8159" -version = "2024.3.11" +version = "2024.11.26" [[deps.NetworkOptions]] uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" -version = "1.2.0" +version = "1.3.0" [[deps.OpenBLAS_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] @@ -163,17 +163,17 @@ version = "0.3.28+3" [[deps.OpenLibm_jll]] deps = ["Artifacts", "Libdl"] uuid = "05823500-19ac-5b8b-9628-191a04bc5112" -version = "0.8.1+3" +version = "0.8.4+1" [[deps.OpenSSL_jll]] -deps = ["Artifacts", "Libdl", "NetworkOptions"] +deps = ["Artifacts", "Libdl"] uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" version = "3.0.15+1" [[deps.PCRE2_jll]] deps = ["Artifacts", "Libdl"] uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15" -version = "10.43.0+1" +version = "10.44.0+1" [[deps.Pkg]] deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "Random", "SHA", "TOML", "Tar", "UUIDs", "p7zip_jll"] @@ -272,12 +272,12 @@ version = "1.11.0" [[deps.Zlib_jll]] deps = ["Libdl"] uuid = "83775a58-1f1d-513f-b197-d71354ab007a" -version = "1.3.1+1" +version = "1.3.1+2" [[deps.dSFMT_jll]] deps = ["Artifacts", "Libdl"] uuid = "05ff407c-b0c1-5878-9df8-858cc2e60c36" -version = "2.2.5+1" +version = "2.2.5+2" [[deps.libLLVM_jll]] deps = ["Artifacts", "Libdl"] @@ -287,7 +287,7 @@ version = "18.1.7+3" [[deps.libblastrampoline_jll]] deps = ["Artifacts", "Libdl"] uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" -version = "5.11.0+0" +version = "5.12.0+0" [[deps.nghttp2_jll]] deps = ["Artifacts", "Libdl"] @@ -297,4 +297,4 @@ version = "1.64.0+1" [[deps.p7zip_jll]] deps = ["Artifacts", "Libdl"] uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" -version = "17.5.0+1" +version = "17.5.0+2" From 22134ca28e92df321bdd08502ddd86ad2d6d614f Mon Sep 17 00:00:00 2001 From: Eduardo Souza Date: Wed, 8 Jan 2025 01:11:27 +1100 Subject: [PATCH 152/342] Adding support for MMTk (non-moving immix) (#56288) This PR adds the possibility of building/running Julia using MMTk, running non-moving immix. The binding code (Rust) associated with it is in https://github.com/mmtk/mmtk-julia/tree/upstream-ready/immix. Instructions on how to build/run Julia with MMTk are described in the [`README`](https://github.com/mmtk/mmtk-julia/tree/upstream-ready/immix?tab=readme-ov-file#an-mmtk-binding-for-the-julia-programming-language) file inside the binding repo. --- Make.inc | 43 + base/timing.jl | 17 +- deps/Makefile | 11 +- .../md5 | 1 + .../sha512 | 1 + deps/mmtk_julia.mk | 71 + deps/mmtk_julia.version | 4 + src/Makefile | 46 +- src/gc-common.c | 50 + src/gc-common.h | 35 + src/gc-interface.h | 12 +- src/gc-mmtk.c | 1180 +++++++++++++++++ src/gc-stacks.c | 97 -- src/gc-stock.c | 193 ++- src/gc-stock.h | 26 +- src/gc-tls-mmtk.h | 23 + src/{gc-tls.h => gc-tls-stock.h} | 0 src/julia_internal.h | 2 +- src/julia_locks.h | 2 +- src/julia_threads.h | 6 +- src/llvm-gc-interface-passes.h | 3 + src/llvm-late-gc-lowering-mmtk.cpp | 96 ++ src/llvm-late-gc-lowering-stock.cpp | 9 + src/llvm-late-gc-lowering.cpp | 26 + src/staticdata.c | 2 + src/threading.c | 4 + .../InteractiveUtils/src/InteractiveUtils.jl | 1 + 27 files changed, 1751 insertions(+), 210 deletions(-) create mode 100644 deps/checksums/mmtk_julia-b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214.tar.gz/md5 create mode 100644 deps/checksums/mmtk_julia-b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214.tar.gz/sha512 create mode 100644 deps/mmtk_julia.mk create mode 100644 deps/mmtk_julia.version create mode 100644 src/gc-mmtk.c create mode 100644 src/gc-tls-mmtk.h rename src/{gc-tls.h => gc-tls-stock.h} (100%) create mode 100644 src/llvm-late-gc-lowering-mmtk.cpp create mode 100644 src/llvm-late-gc-lowering-stock.cpp diff --git a/Make.inc b/Make.inc index 1c08f4a947b1c..216fc6fd7adde 100644 --- a/Make.inc +++ b/Make.inc @@ -80,6 +80,9 @@ HAVE_SSP := 0 WITH_GC_VERIFY := 0 WITH_GC_DEBUG_ENV := 0 +# Use stock if MMTK_PLAN hasn't been defined +MMTK_PLAN ?= None + # Enable DTrace support WITH_DTRACE := 0 @@ -833,6 +836,31 @@ JCXXFLAGS += -DGC_DEBUG_ENV JCFLAGS += -DGC_DEBUG_ENV endif +ifneq (${MMTK_PLAN},None) +JCXXFLAGS += -DMMTK_GC +JCFLAGS += -DMMTK_GC +# Do a release build on the binding by default +MMTK_BUILD ?= release +ifeq (${MMTK_PLAN},Immix) +JCXXFLAGS += -DMMTK_PLAN_IMMIX +JCFLAGS += -DMMTK_PLAN_IMMIX +else +$(error "Unsupported MMTk plan: $(MMTK_PLAN)") +endif + +# Location of mmtk-julia binding +# (needed for api/*.h and .so file) +MMTK_JULIA_DIR ?= $(BUILDROOT)/usr/lib/mmtk_julia + +MMTK_DIR = ${MMTK_JULIA_DIR}/mmtk +MMTK_API_INC = ${MMTK_DIR}/api + +MMTK_LIB := -lmmtk_julia +else +MMTK_JULIA_INC := +MMTK_LIB := +endif + ifeq ($(WITH_DTRACE), 1) JCXXFLAGS += -DUSE_DTRACE JCFLAGS += -DUSE_DTRACE @@ -933,6 +961,21 @@ ARCH := $(BUILD_OS) endif endif +# MMTk is only available on x86_64 Linux for now +ifneq (${MMTK_PLAN},None) + +ifeq ($(OS),Linux) +MMTK_LIB_NAME := libmmtk_julia.so +else +$(error "Unsupported OS for MMTk") +endif + +ifneq ($(ARCH),x86_64) +$(error "Unsupported build architecture for MMTk") +endif + +endif + # Detect common pre-SSE2 JULIA_CPU_TARGET values known not to work (#7185) ifeq ($(MARCH),) ifneq ($(findstring $(ARCH),i386 i486 i586 i686),) diff --git a/base/timing.jl b/base/timing.jl index 1de3727756829..0088f8bb77eca 100644 --- a/base/timing.jl +++ b/base/timing.jl @@ -106,9 +106,14 @@ function gc_page_utilization_data() return Base.unsafe_wrap(Array, page_utilization_raw, JL_GC_N_MAX_POOLS, own=false) end + +const USING_STOCK_GC = occursin("stock", unsafe_string(ccall(:jl_gc_active_impl, Ptr{UInt8}, ()))) +# Full sweep reasons are currently only available for the stock GC +@static if 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] +end """ Base.full_sweep_reasons() @@ -124,11 +129,15 @@ The reasons are: Note that the set of reasons is not guaranteed to be stable across minor versions of Julia. """ function full_sweep_reasons() - reason = cglobal(:jl_full_sweep_reasons, UInt64) - reasons_as_array = Base.unsafe_wrap(Vector{UInt64}, reason, length(FULL_SWEEP_REASONS), own=false) d = Dict{Symbol, Int64}() - for (i, r) in enumerate(FULL_SWEEP_REASONS) - d[r] = reasons_as_array[i] + # populate the dictionary according to the reasons above for the stock GC + # otherwise return an empty dictionary for now + @static if USING_STOCK_GC + reason = cglobal(:jl_full_sweep_reasons, UInt64) + reasons_as_array = Base.unsafe_wrap(Vector{UInt64}, reason, length(FULL_SWEEP_REASONS), own=false) + for (i, r) in enumerate(FULL_SWEEP_REASONS) + d[r] = reasons_as_array[i] + end end return d end diff --git a/deps/Makefile b/deps/Makefile index d4ef52646cfdc..396b1021c2ddd 100644 --- a/deps/Makefile +++ b/deps/Makefile @@ -26,7 +26,7 @@ BUILDDIR := $(BUILDDIR)$(MAYBE_HOST) # custom Makefile rules: openlibm dsfmt libsuitesparse lapack blastrampoline openblas utf8proc objconv libwhich # CMake libs: llvm llvmunwind libgit2 libssh2 libtracyclient # -# downloadable via git: llvm-svn, libuv, libopenlibm, utf8proc, libgit2, libssh2, libtracyclient +# downloadable via git: llvm-svn, libuv, libopenlibm, utf8proc, libgit2, libssh2, libtracyclient, mmtk_julia # # to debug 'define' rules, replace eval at the usage site with info or error @@ -195,6 +195,10 @@ DEP_LIBS += libwhich endif endif +ifneq (${MMTK_PLAN},None) +DEP_LIBS += mmtk_julia +endif + DEP_LIBS_STAGED := $(DEP_LIBS) # list all targets @@ -202,7 +206,7 @@ DEP_LIBS_STAGED_ALL := llvm llvm-tools clang llvmunwind unwind libuv pcre \ openlibm dsfmt blastrampoline openblas lapack gmp mpfr patchelf utf8proc \ objconv openssl libssh2 nghttp2 curl libgit2 libwhich zlib p7zip csl \ sanitizers libsuitesparse lld libtracyclient ittapi nvtx JuliaSyntax \ - terminfo + terminfo mmtk_julia DEP_LIBS_ALL := $(DEP_LIBS_STAGED_ALL) ifneq ($(USE_BINARYBUILDER_OPENBLAS),0) @@ -266,6 +270,9 @@ include $(SRCDIR)/p7zip.mk include $(SRCDIR)/libtracyclient.mk include $(SRCDIR)/terminfo.mk +# MMTk +include $(SRCDIR)/mmtk_julia.mk + # vendored Julia libs include $(SRCDIR)/JuliaSyntax.mk diff --git a/deps/checksums/mmtk_julia-b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214.tar.gz/md5 b/deps/checksums/mmtk_julia-b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214.tar.gz/md5 new file mode 100644 index 0000000000000..fc6955c8f2e7b --- /dev/null +++ b/deps/checksums/mmtk_julia-b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214.tar.gz/md5 @@ -0,0 +1 @@ +1911cf084d26c48e2ed58af3d268b4b6 diff --git a/deps/checksums/mmtk_julia-b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214.tar.gz/sha512 b/deps/checksums/mmtk_julia-b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214.tar.gz/sha512 new file mode 100644 index 0000000000000..ea916976895a3 --- /dev/null +++ b/deps/checksums/mmtk_julia-b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214.tar.gz/sha512 @@ -0,0 +1 @@ +75beab54398989c46b62e714b242cf6705d88d220f40c21e494e0f29161437f5fbe9ba05b543d2353a1ad76f4239ac4025b476be0be864649f310f14935289fe diff --git a/deps/mmtk_julia.mk b/deps/mmtk_julia.mk new file mode 100644 index 0000000000000..ccf638e9211bb --- /dev/null +++ b/deps/mmtk_julia.mk @@ -0,0 +1,71 @@ +## MMTK ## + +# Both MMTK_MOVING and MMTK_PLAN should be specified in the Make.user file. +# At this point, since we only support non-moving this is always set to 0 +# FIXME: change it to `?:` when introducing moving plans +MMTK_MOVING := 0 +MMTK_VARS := MMTK_PLAN=$(MMTK_PLAN) MMTK_MOVING=$(MMTK_MOVING) + +# Download the binding, build it from source +ifeq (${MMTK_JULIA_DIR},$(BUILDROOT)/usr/lib/mmtk_julia) +$(eval $(call git-external,mmtk_julia,MMTK_JULIA,,,$(BUILDDIR))) + +MMTK_JULIA_DIR=$(BUILDROOT)/deps/$(BUILDDIR)/$(MMTK_JULIA_SRC_DIR) +MMTK_JULIA_LIB_PATH=$(MMTK_JULIA_DIR)/mmtk/target/$(MMTK_BUILD) +PROJECT_DIRS := JULIA_PATH=$(JULIAHOME) JULIA_BUILDROOT=$(BUILDROOT) MMTK_JULIA_DIR=$(MMTK_JULIA_DIR) + +$(BUILDDIR)/$(MMTK_JULIA_SRC_DIR)/build-compiled: $(BUILDROOT)/usr/lib/libmmtk_julia.so + @echo 1 > $@ + +# NB: use the absolute dir when creating the symlink +$(BUILDROOT)/usr/lib/libmmtk_julia.so: $(MMTK_JULIA_LIB_PATH)/libmmtk_julia.so + @ln -sf $(MMTK_JULIA_LIB_PATH)/libmmtk_julia.so $@ + +$(MMTK_JULIA_LIB_PATH)/libmmtk_julia.so: $(BUILDDIR)/$(MMTK_JULIA_SRC_DIR)/source-extracted + @$(PROJECT_DIRS) $(MMTK_VARS) $(MAKE) -C $(MMTK_JULIA_DIR) $(MMTK_BUILD) + +get-mmtk_julia: $(MMTK_JULIA_SRC_FILE) +extract-mmtk_julia: $(BUILDDIR)/$(MMTK_JULIA_SRC_DIR)/source-extracted +configure-mmtk_julia: extract-mmtk_julia +compile-mmtk_julia: $(BUILDROOT)/usr/lib/libmmtk_julia.so +fastcheck-mmtk_julia: #none +check-mmtk_julia: compile-mmtk_julia + +$(eval $(call symlink_install,mmtk_julia,$$(MMTK_JULIA_SRC_DIR),$$(BUILDROOT)/usr/lib)) + +# In this case, there is a custom version of the binding in MMTK_JULIA_DIR +# Build it and symlink libmmtk_julia.so file into $(BUILDROOT)/usr/lib +else + +PROJECT_DIRS := JULIA_PATH=$(JULIAHOME) JULIA_BUILDROOT=$(BUILDROOT) MMTK_JULIA_DIR=$(MMTK_JULIA_DIR) +MMTK_JULIA_LIB_PATH=$(MMTK_JULIA_DIR)/mmtk/target/$(MMTK_BUILD) + +install-mmtk_julia: compile-mmtk_julia $(build_prefix)/manifest/mmtk_julia + +compile-mmtk_julia: $(BUILDROOT)/usr/lib/libmmtk_julia.so + +version-check-mmtk_julia: $(MMTK_JULIA_DIR)/mmtk/target/$(MMTK_BUILD)/libmmtk_julia.so + +# NB: This will NOT run `cargo build` if there are changes in the Rust source files +# inside the binding repo. However the target below should remake the symlink if there +# are changes in the libmmtk_julia.so from the custom MMTK_JULIA_DIR folder +$(BUILDROOT)/usr/lib/libmmtk_julia.so: $(MMTK_JULIA_DIR)/mmtk/target/$(MMTK_BUILD)/libmmtk_julia.so + @ln -sf $(MMTK_JULIA_DIR)/mmtk/target/$(MMTK_BUILD)/libmmtk_julia.so $@ + +$(MMTK_JULIA_DIR)/mmtk/target/$(MMTK_BUILD)/libmmtk_julia.so: + @$(PROJECT_DIRS) $(MMTK_VARS) $(MAKE) -C $(MMTK_JULIA_DIR) $(MMTK_BUILD) + +MMTK_JULIA_VER := mmtk_julia_custom + +UNINSTALL_mmtk_julia := $(MMTK_JULIA_VER) manual_mmtk_julia + +define manual_mmtk_julia +uninstall-mmtk_julia: + -rm -f $(build_prefix)/manifest/mmtk_julia + -rm -f $(BUILDROOT)/usr/lib/libmmtk_julia.so +endef + +$(build_prefix)/manifest/mmtk_julia: $(BUILDROOT)/usr/lib/libmmtk_julia.so + @echo $(UNINSTALL_mmtk_julia) > $@ + +endif # MMTK_JULIA_DIR diff --git a/deps/mmtk_julia.version b/deps/mmtk_julia.version new file mode 100644 index 0000000000000..60f7cffe7b4de --- /dev/null +++ b/deps/mmtk_julia.version @@ -0,0 +1,4 @@ +MMTK_JULIA_BRANCH = master +MMTK_JULIA_SHA1 = b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214 +MMTK_JULIA_GIT_URL := https://github.com/mmtk/mmtk-julia.git +MMTK_JULIA_TAR_URL = https://github.com/mmtk/mmtk-julia/archive/refs/tags/v0.30.2.tar.gz diff --git a/src/Makefile b/src/Makefile index 9355ca2c4c675..b49d27e05ff28 100644 --- a/src/Makefile +++ b/src/Makefile @@ -29,6 +29,10 @@ ifeq ($(USECLANG),1) FLAGS += -Wno-return-type-c-linkage -Wno-atomic-alignment endif +ifneq (${MMTK_PLAN},None) +FLAGS += -I$(MMTK_API_INC) +endif + FLAGS += -DJL_BUILD_ARCH='"$(ARCH)"' ifeq ($(OS),WINNT) FLAGS += -DJL_BUILD_UNAME='"NT"' @@ -40,23 +44,41 @@ ifeq ($(OS),FreeBSD) FLAGS += -I$(LOCALBASE)/include endif +# GC source code. It depends on which GC implementation to use. +GC_SRCS := gc-common gc-stacks gc-alloc-profiler gc-heap-snapshot +ifneq (${MMTK_PLAN},None) +GC_SRCS += gc-mmtk +else +GC_SRCS += gc-stock gc-debug gc-pages gc-page-profiler +endif + SRCS := \ jltypes gf typemap smallintset ast builtins module interpreter symbol \ dlload sys init task array genericmemory staticdata toplevel jl_uv datatype \ simplevector runtime_intrinsics precompile jloptions mtarraylist \ - threading scheduler stackwalk gc-common gc-stock gc-debug gc-pages gc-stacks gc-alloc-profiler gc-page-profiler method \ - jlapi signal-handling safepoint timing subtype rtutils gc-heap-snapshot \ - crc32c APInt-C processor ircode opaque_closure codegen-stubs coverage runtime_ccall engine + threading scheduler stackwalk \ + method jlapi signal-handling safepoint timing subtype rtutils \ + crc32c APInt-C processor ircode opaque_closure codegen-stubs coverage runtime_ccall engine \ + $(GC_SRCS) RT_LLVMLINK := CG_LLVMLINK := ifeq ($(JULIACODEGEN),LLVM) +# Currently these files are used by both GCs. But we should make the list specific to stock, and MMTk should have its own implementation. +GC_CODEGEN_SRCS := llvm-final-gc-lowering llvm-late-gc-lowering llvm-gc-invariant-verifier +ifneq (${MMTK_PLAN},None) +FLAGS += -I$(MMTK_API_INC) +GC_CODEGEN_SRCS += llvm-late-gc-lowering-mmtk +else +GC_CODEGEN_SRCS += llvm-late-gc-lowering-stock +endif CODEGEN_SRCS := codegen jitlayers aotcompile debuginfo disasm llvm-simdloop \ - llvm-final-gc-lowering llvm-pass-helpers llvm-late-gc-lowering llvm-ptls \ - llvm-lower-handlers llvm-gc-invariant-verifier llvm-propagate-addrspaces \ + llvm-pass-helpers llvm-ptls \ + llvm-lower-handlers llvm-propagate-addrspaces \ 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 + llvm-remove-ni llvm-julia-licm llvm-demote-float16 llvm-cpufeatures pipeline llvm_api \ + $(GC_CODEGEN_SRCS) FLAGS += -I$(shell $(LLVM_CONFIG_HOST) --includedir) CG_LLVM_LIBS := all ifeq ($(USE_POLLY),1) @@ -99,7 +121,12 @@ ifeq ($(USE_SYSTEM_LIBUV),0) UV_HEADERS += uv.h UV_HEADERS += uv/*.h endif -PUBLIC_HEADERS := $(BUILDDIR)/julia_version.h $(wildcard $(SRCDIR)/support/*.h) $(addprefix $(SRCDIR)/,work-stealing-queue.h gc-interface.h gc-tls.h gc-tls-common.h julia.h julia_assert.h julia_threads.h julia_fasttls.h julia_locks.h julia_atomics.h jloptions.h) +PUBLIC_HEADERS := $(BUILDDIR)/julia_version.h $(wildcard $(SRCDIR)/support/*.h) $(addprefix $(SRCDIR)/,work-stealing-queue.h gc-interface.h gc-tls-common.h julia.h julia_assert.h julia_threads.h julia_fasttls.h julia_locks.h julia_atomics.h jloptions.h) +ifneq (${MMTK_PLAN},None) + PUBLIC_HEADERS += $(addprefix $(SRCDIR)/,gc-tls-mmtk.h) +else + PUBLIC_HEADERS += $(addprefix $(SRCDIR)/,gc-tls-stock.h) +endif ifeq ($(OS),WINNT) PUBLIC_HEADERS += $(addprefix $(SRCDIR)/,win32_ucontext.h) endif @@ -164,8 +191,8 @@ LIBJULIA_PATH_REL := libjulia 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) -CG_LIBS := $(LIBUNWIND) $(CG_LLVMLINK) $(OSLIBS) $(LIBTRACYCLIENT) $(LIBITTAPI) +RT_LIBS := $(WHOLE_ARCHIVE) $(LIBUV) $(WHOLE_ARCHIVE) $(LIBUTF8PROC) $(NO_WHOLE_ARCHIVE) $(LIBUNWIND) $(RT_LLVMLINK) $(OSLIBS) $(LIBTRACYCLIENT) $(LIBITTAPI) $(MMTK_LIB) +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) @@ -314,6 +341,7 @@ $(BUILDDIR)/debuginfo.o $(BUILDDIR)/debuginfo.dbg.obj: $(addprefix $(SRCDIR)/,de $(BUILDDIR)/disasm.o $(BUILDDIR)/disasm.dbg.obj: $(SRCDIR)/debuginfo.h $(SRCDIR)/processor.h $(BUILDDIR)/gc-debug.o $(BUILDDIR)/gc-debug.dbg.obj: $(SRCDIR)/gc-common.h $(SRCDIR)/gc-stock.h $(BUILDDIR)/gc-pages.o $(BUILDDIR)/gc-pages.dbg.obj: $(SRCDIR)/gc-common.h $(SRCDIR)/gc-stock.h +$(BUILDDIR)/gc-mmtk.o $(BUILDDIR)/gc-mmtk.dbg.obj: $(SRCDIR)/gc-common.h $(SRCDIR)/gc-heap-snapshot.h $(SRCDIR)/gc-alloc-profiler.h $(BUILDDIR)/gc-stacks.o $(BUILDDIR)/gc-stacks.dbg.obj: $(SRCDIR)/gc-common.h $(SRCDIR)/gc-stock.h $(BUILDDIR)/gc-stock.o $(BUILDDIR)/gc.dbg.obj: $(SRCDIR)/gc-common.h $(SRCDIR)/gc-stock.h $(SRCDIR)/gc-heap-snapshot.h $(SRCDIR)/gc-alloc-profiler.h $(SRCDIR)/gc-page-profiler.h $(BUILDDIR)/gc-heap-snapshot.o $(BUILDDIR)/gc-heap-snapshot.dbg.obj: $(SRCDIR)/gc-heap-snapshot.h diff --git a/src/gc-common.c b/src/gc-common.c index 3d578b81578b1..c07b707b17709 100644 --- a/src/gc-common.c +++ b/src/gc-common.c @@ -540,6 +540,38 @@ JL_DLLEXPORT jl_value_t *(jl_gc_alloc)(jl_ptls_t ptls, size_t sz, void *ty) return jl_gc_alloc_(ptls, sz, ty); } +JL_DLLEXPORT void *jl_malloc(size_t sz) +{ + return jl_gc_counted_malloc(sz); +} + +//_unchecked_calloc does not check for potential overflow of nm*sz +STATIC_INLINE void *_unchecked_calloc(size_t nm, size_t sz) { + size_t nmsz = nm*sz; + return jl_gc_counted_calloc(nmsz, 1); +} + +JL_DLLEXPORT void *jl_calloc(size_t nm, size_t sz) +{ + if (nm > SSIZE_MAX/sz) + return NULL; + return _unchecked_calloc(nm, sz); +} + +JL_DLLEXPORT void jl_free(void *p) +{ + if (p != NULL) { + size_t sz = memory_block_usable_size(p, 0); + return jl_gc_counted_free_with_size(p, sz); + } +} + +JL_DLLEXPORT void *jl_realloc(void *p, size_t sz) +{ + size_t old = p ? memory_block_usable_size(p, 0) : 0; + return jl_gc_counted_realloc_with_old_size(p, old, sz); +} + // =========================================================================== // // Generic Memory // =========================================================================== // @@ -668,6 +700,24 @@ JL_DLLEXPORT void jl_throw_out_of_memory_error(void) jl_throw(jl_memory_exception); } +// Sweeping mtarraylist_buffers: +// These buffers are made unreachable via `mtarraylist_resizeto` from mtarraylist.c +// and are freed at the end of GC via jl_gc_sweep_stack_pools_and_mtarraylist_buffers +void sweep_mtarraylist_buffers(void) JL_NOTSAFEPOINT +{ + for (int i = 0; i < gc_n_threads; i++) { + jl_ptls_t ptls = gc_all_tls_states[i]; + if (ptls == NULL) { + continue; + } + small_arraylist_t *buffers = &ptls->lazily_freed_mtarraylist_buffers; + void *buf; + while ((buf = small_arraylist_pop(buffers)) != NULL) { + free(buf); + } + } +} + #ifdef __cplusplus } #endif diff --git a/src/gc-common.h b/src/gc-common.h index 1745df17950f9..ca5e21084209e 100644 --- a/src/gc-common.h +++ b/src/gc-common.h @@ -24,6 +24,31 @@ extern "C" { #endif +// =========================================================================== // +// GC Big objects +// =========================================================================== // + +JL_EXTENSION typedef struct _bigval_t { + struct _bigval_t *next; + struct _bigval_t *prev; + size_t sz; +#ifdef _P64 // Add padding so that the value is 64-byte aligned + // (8 pointers of 8 bytes each) - (4 other pointers in struct) + void *_padding[8 - 4]; +#else + // (16 pointers of 4 bytes each) - (4 other pointers in struct) + void *_padding[16 - 4]; +#endif + //struct jl_taggedvalue_t <>; + union { + uintptr_t header; + struct { + uintptr_t gc:2; + } bits; + }; + // must be 64-byte aligned here, in 32 & 64 bit modes +} bigval_t; + // =========================================================================== // // GC Callbacks // =========================================================================== // @@ -187,4 +212,14 @@ extern jl_ptls_t* gc_all_tls_states; extern int gc_logging_enabled; +// =========================================================================== // +// MISC +// =========================================================================== // + +// number of stacks to always keep available per pool +#define MIN_STACK_MAPPINGS_PER_POOL 5 + +void _jl_free_stack(jl_ptls_t ptls, void *stkbuf, size_t bufsz) JL_NOTSAFEPOINT; +void sweep_mtarraylist_buffers(void) JL_NOTSAFEPOINT; + #endif // JL_GC_COMMON_H diff --git a/src/gc-interface.h b/src/gc-interface.h index eb6687d52d9ab..e4a27782f7520 100644 --- a/src/gc-interface.h +++ b/src/gc-interface.h @@ -98,6 +98,13 @@ JL_DLLEXPORT void jl_gc_set_max_memory(uint64_t max_mem); JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection); // Returns whether the thread with `tid` is a collector thread JL_DLLEXPORT int gc_is_collector_thread(int tid) JL_NOTSAFEPOINT; +// Returns which GC implementation is being used and possibly its version according to the list of supported GCs +// NB: it should clearly identify the GC by including e.g. ‘stock’ or ‘mmtk’ as a substring. +JL_DLLEXPORT const char* jl_gc_active_impl(void); +// Sweep Julia's stack pools and mtarray buffers. Note that this function has been added to the interface as +// each GC should implement it but it will most likely not be used by other code in the runtime. +// It still needs to be annotated with JL_DLLEXPORT since it is called from Rust by MMTk. +JL_DLLEXPORT void jl_gc_sweep_stack_pools_and_mtarraylist_buffers(jl_ptls_t ptls) JL_NOTSAFEPOINT; // ========================================================================= // // Metrics @@ -138,7 +145,6 @@ JL_DLLEXPORT uint64_t jl_gc_total_hrtime(void); // **must** also set the type of the returning object to be `ty`. The type `ty` may also be used to record // an allocation of that type in the allocation profiler. struct _jl_value_t *jl_gc_alloc_(struct _jl_tls_states_t * ptls, size_t sz, void *ty); - // Allocates small objects and increments Julia allocation counterst. Size of the object // header must be included in the object size. The (possibly unused in some implementations) // offset to the arena in which we're allocating is passed in the second parameter, and the @@ -198,6 +204,10 @@ JL_DLLEXPORT void *jl_gc_perm_alloc(size_t sz, int zero, unsigned align, // the allocated object. All objects stored in fields of this object // must be either permanently allocated or have other roots. struct _jl_value_t *jl_gc_permobj(size_t sz, void *ty) JL_NOTSAFEPOINT; +// This function notifies the GC about memory addresses that are set when loading the boot image. +// The GC may use that information to, for instance, determine that such objects should +// be treated as marked and belonged to the old generation in nursery collections. +void jl_gc_notify_image_load(const char* img_data, size_t len); // ========================================================================= // // Runtime Write-Barriers diff --git a/src/gc-mmtk.c b/src/gc-mmtk.c new file mode 100644 index 0000000000000..78882c8eb0225 --- /dev/null +++ b/src/gc-mmtk.c @@ -0,0 +1,1180 @@ +#include "gc-common.h" +#include "gc-tls-mmtk.h" +#include "mmtkMutator.h" +#include "threading.h" + +// File exists in the binding +#include "mmtk.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ========================================================================= // +// Julia specific +// ========================================================================= // + +extern jl_value_t *cmpswap_names JL_GLOBALLY_ROOTED; +extern const unsigned pool_sizes[]; +extern jl_mutex_t finalizers_lock; + +// FIXME: Should the values below be shared between both GC's? +// Note that MMTk uses a hard max heap limit, which is set by default +// as 70% of the free available memory. The min heap is set as the +// default_collect_interval variable below. + +// max_total_memory is a suggestion. We try very hard to stay +// under this limit, but we will go above it rather than halting. +#ifdef _P64 +typedef uint64_t memsize_t; +static const size_t default_collect_interval = 5600 * 1024 * sizeof(void*); +// We expose this to the user/ci as jl_gc_set_max_memory +static memsize_t max_total_memory = (memsize_t) 2 * 1024 * 1024 * 1024 * 1024 * 1024; +#else +typedef uint32_t memsize_t; +static const size_t default_collect_interval = 3200 * 1024 * sizeof(void*); +// Work really hard to stay within 2GB +// Alternative is to risk running out of address space +// on 32 bit architectures. +#define MAX32HEAP 1536 * 1024 * 1024 +static memsize_t max_total_memory = (memsize_t) MAX32HEAP; +#endif + +// ========================================================================= // +// Defined by the binding +// ========================================================================= // + +extern void mmtk_julia_copy_stack_check(int copy_stack); +extern void mmtk_gc_init(uintptr_t min_heap_size, uintptr_t max_heap_size, uintptr_t n_gcthreads, uintptr_t header_size, uintptr_t tag); +extern void mmtk_object_reference_write_post(void* mutator, const void* parent, const void* ptr); +extern void mmtk_object_reference_write_slow(void* mutator, const void* parent, const void* ptr); +extern void* mmtk_alloc(void* mutator, size_t size, size_t align, size_t offset, int allocator); +extern void mmtk_post_alloc(void* mutator, void* refer, size_t bytes, int allocator); +extern void mmtk_store_obj_size_c(void* obj, size_t size); +extern const void* MMTK_SIDE_LOG_BIT_BASE_ADDRESS; +extern const void* MMTK_SIDE_VO_BIT_BASE_ADDRESS; + +// ========================================================================= // +// GC Initialization and Control +// ========================================================================= // + +void jl_gc_init(void) { + // TODO: use jl_options.heap_size_hint to set MMTk's fixed heap size? (see issue: https://github.com/mmtk/mmtk-julia/issues/167) + JL_MUTEX_INIT(&finalizers_lock, "finalizers_lock"); + + arraylist_new(&to_finalize, 0); + arraylist_new(&finalizer_list_marked, 0); + + gc_num.allocd = 0; + gc_num.max_pause = 0; + gc_num.max_memory = 0; + + long long min_heap_size; + long long max_heap_size; + char* min_size_def = getenv("MMTK_MIN_HSIZE"); + char* min_size_gb = getenv("MMTK_MIN_HSIZE_G"); + + char* max_size_def = getenv("MMTK_MAX_HSIZE"); + char* max_size_gb = getenv("MMTK_MAX_HSIZE_G"); + + // default min heap currently set as Julia's default_collect_interval + if (min_size_def != NULL) { + char *p; + double min_size = strtod(min_size_def, &p); + min_heap_size = (long) 1024 * 1024 * min_size; + } else if (min_size_gb != NULL) { + char *p; + double min_size = strtod(min_size_gb, &p); + min_heap_size = (long) 1024 * 1024 * 1024 * min_size; + } else { + min_heap_size = default_collect_interval; + } + + // default max heap currently set as 70% the free memory in the system + if (max_size_def != NULL) { + char *p; + double max_size = strtod(max_size_def, &p); + max_heap_size = (long) 1024 * 1024 * max_size; + } else if (max_size_gb != NULL) { + char *p; + double max_size = strtod(max_size_gb, &p); + max_heap_size = (long) 1024 * 1024 * 1024 * max_size; + } else { + max_heap_size = uv_get_free_memory() * 70 / 100; + } + + // Assert that the number of stock GC threads is 0; MMTK uses the number of threads in jl_options.ngcthreads + assert(jl_n_gcthreads == 0); + + // Check that the julia_copy_stack rust feature has been defined when the COPY_STACK has been defined + int copy_stacks; + +#ifdef COPY_STACKS + copy_stacks = 1; +#else + copy_stacks = 0; +#endif + + mmtk_julia_copy_stack_check(copy_stacks); + + // if only max size is specified initialize MMTk with a fixed size heap + // TODO: We just assume mark threads means GC threads, and ignore the number of concurrent sweep threads. + // If the two values are the same, we can use either. Otherwise, we need to be careful. + uintptr_t gcthreads = jl_options.nmarkthreads; + if (max_size_def != NULL || (max_size_gb != NULL && (min_size_def == NULL && min_size_gb == NULL))) { + mmtk_gc_init(0, max_heap_size, gcthreads, (sizeof(jl_taggedvalue_t)), jl_buff_tag); + } else { + mmtk_gc_init(min_heap_size, max_heap_size, gcthreads, (sizeof(jl_taggedvalue_t)), jl_buff_tag); + } +} + +void jl_start_gc_threads(void) { + jl_ptls_t ptls = jl_current_task->ptls; + mmtk_initialize_collection((void *)ptls); +} + +void jl_init_thread_heap(struct _jl_tls_states_t *ptls) JL_NOTSAFEPOINT { + jl_thread_heap_common_t *heap = &ptls->gc_tls_common.heap; + small_arraylist_new(&heap->weak_refs, 0); + small_arraylist_new(&heap->live_tasks, 0); + for (int i = 0; i < JL_N_STACK_POOLS; i++) + small_arraylist_new(&heap->free_stacks[i], 0); + small_arraylist_new(&heap->mallocarrays, 0); + arraylist_new(&ptls->finalizers, 0); + // Initialize `lazily_freed_mtarraylist_buffers` + small_arraylist_new(&ptls->lazily_freed_mtarraylist_buffers, 0); + // Clear the malloc sz count + jl_atomic_store_relaxed(&ptls->gc_tls.malloc_sz_since_last_poll, 0); + // Create mutator + MMTk_Mutator mmtk_mutator = mmtk_bind_mutator((void *)ptls, ptls->tid); + // Copy the mutator to the thread local storage + memcpy(&ptls->gc_tls.mmtk_mutator, mmtk_mutator, sizeof(MMTkMutatorContext)); + // Call post_bind to maintain a list of active mutators and to reclaim the old mutator (which is no longer needed) + mmtk_post_bind_mutator(&ptls->gc_tls.mmtk_mutator, mmtk_mutator); + memset(&ptls->gc_tls_common.gc_num, 0, sizeof(ptls->gc_tls_common.gc_num)); +} + +void jl_free_thread_gc_state(struct _jl_tls_states_t *ptls) { + mmtk_destroy_mutator(&ptls->gc_tls.mmtk_mutator); +} + +JL_DLLEXPORT void jl_gc_set_max_memory(uint64_t max_mem) { + // MMTk currently does not allow setting the heap size at runtime +} + +STATIC_INLINE void maybe_collect(jl_ptls_t ptls) +{ + // Just do a safe point for general maybe_collect + jl_gc_safepoint_(ptls); +} + +// This is only used for malloc. We need to know if we need to do GC. However, keeping checking with MMTk (mmtk_gc_poll), +// is expensive. So we only check for every few allocations. +static inline void malloc_maybe_collect(jl_ptls_t ptls, size_t sz) +{ + // We do not need to carefully maintain malloc_sz_since_last_poll. We just need to + // avoid using mmtk_gc_poll too frequently, and try to be precise on our heap usage + // as much as we can. + if (ptls->gc_tls.malloc_sz_since_last_poll > 4096) { + jl_atomic_store_relaxed(&ptls->gc_tls.malloc_sz_since_last_poll, 0); + mmtk_gc_poll(ptls); + } else { + size_t curr = jl_atomic_load_relaxed(&ptls->gc_tls.malloc_sz_since_last_poll); + jl_atomic_store_relaxed(&ptls->gc_tls.malloc_sz_since_last_poll, curr + sz); + jl_gc_safepoint_(ptls); + } +} + +// This is called when the user calls for a GC with Gc.gc() +JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection) { + jl_task_t *ct = jl_current_task; + jl_ptls_t ptls = ct->ptls; + if (jl_atomic_load_acquire(&jl_gc_disable_counter)) { + size_t localbytes = jl_atomic_load_relaxed(&ptls->gc_tls_common.gc_num.allocd) + gc_num.interval; + jl_atomic_store_relaxed(&ptls->gc_tls_common.gc_num.allocd, -(int64_t)gc_num.interval); + static_assert(sizeof(_Atomic(uint64_t)) == sizeof(gc_num.deferred_alloc), ""); + jl_atomic_fetch_add_relaxed((_Atomic(uint64_t)*)&gc_num.deferred_alloc, localbytes); + return; + } + mmtk_handle_user_collection_request(ptls, collection); +} + + +// Based on jl_gc_collect from gc-stock.c +// called when stopping the thread in `mmtk_block_for_gc` +JL_DLLEXPORT void jl_gc_prepare_to_collect(void) +{ + // FIXME: set to JL_GC_AUTO since we're calling it from mmtk + // maybe just remove this? + JL_PROBE_GC_BEGIN(JL_GC_AUTO); + + jl_task_t *ct = jl_current_task; + jl_ptls_t ptls = ct->ptls; + if (jl_atomic_load_acquire(&jl_gc_disable_counter)) { + size_t localbytes = jl_atomic_load_relaxed(&ptls->gc_tls_common.gc_num.allocd) + gc_num.interval; + jl_atomic_store_relaxed(&ptls->gc_tls_common.gc_num.allocd, -(int64_t)gc_num.interval); + static_assert(sizeof(_Atomic(uint64_t)) == sizeof(gc_num.deferred_alloc), ""); + jl_atomic_fetch_add_relaxed((_Atomic(uint64_t)*)&gc_num.deferred_alloc, localbytes); + return; + } + + int8_t old_state = jl_atomic_load_relaxed(&ptls->gc_state); + jl_atomic_store_release(&ptls->gc_state, JL_GC_STATE_WAITING); + // `jl_safepoint_start_gc()` makes sure only one thread can run the GC. + uint64_t t0 = jl_hrtime(); + if (!jl_safepoint_start_gc(ct)) { + jl_gc_state_set(ptls, old_state, JL_GC_STATE_WAITING); + jl_safepoint_wait_thread_resume(ct); // block in thread-suspend now if requested, after clearing the gc_state + return; + } + + JL_TIMING_SUSPEND_TASK(GC, ct); + JL_TIMING(GC, GC); + + int last_errno = errno; +#ifdef _OS_WINDOWS_ + DWORD last_error = GetLastError(); +#endif + // Now we are ready to wait for other threads to hit the safepoint, + // we can do a few things that doesn't require synchronization. + // + // We must sync here with the tls_lock operations, so that we have a + // seq-cst order between these events now we know that either the new + // thread must run into our safepoint flag or we must observe the + // existence of the thread in the jl_n_threads count. + // + // TODO: concurrently queue objects + jl_fence(); + gc_n_threads = jl_atomic_load_acquire(&jl_n_threads); + gc_all_tls_states = jl_atomic_load_relaxed(&jl_all_tls_states); + jl_gc_wait_for_the_world(gc_all_tls_states, gc_n_threads); + JL_PROBE_GC_STOP_THE_WORLD(); + + uint64_t t1 = jl_hrtime(); + uint64_t duration = t1 - t0; + if (duration > gc_num.max_time_to_safepoint) + gc_num.max_time_to_safepoint = duration; + gc_num.time_to_safepoint = duration; + gc_num.total_time_to_safepoint += duration; + + if (!jl_atomic_load_acquire(&jl_gc_disable_counter)) { + JL_LOCK_NOGC(&finalizers_lock); // all the other threads are stopped, so this does not make sense, right? otherwise, failing that, this seems like plausibly a deadlock +#ifndef __clang_gcanalyzer__ + mmtk_block_thread_for_gc(); +#endif + JL_UNLOCK_NOGC(&finalizers_lock); + } + + gc_n_threads = 0; + gc_all_tls_states = NULL; + jl_safepoint_end_gc(); + jl_gc_state_set(ptls, old_state, JL_GC_STATE_WAITING); + JL_PROBE_GC_END(); + jl_safepoint_wait_thread_resume(ct); // block in thread-suspend now if requested, after clearing the gc_state + + // Only disable finalizers on current thread + // Doing this on all threads is racy (it's impossible to check + // or wait for finalizers on other threads without dead lock). + if (!ptls->finalizers_inhibited && ptls->locks.len == 0) { + JL_TIMING(GC, GC_Finalizers); + run_finalizers(ct, 0); + } + JL_PROBE_GC_FINALIZER(); + +#ifdef _OS_WINDOWS_ + SetLastError(last_error); +#endif + errno = last_errno; +} + +// ========================================================================= // +// GC Statistics +// ========================================================================= // + +JL_DLLEXPORT const char* jl_gc_active_impl(void) { + const char* mmtk_version = get_mmtk_version(); + return mmtk_version; +} + +int64_t last_gc_total_bytes = 0; +int64_t last_live_bytes = 0; // live_bytes at last collection +int64_t live_bytes = 0; + +// FIXME: The functions combine_thread_gc_counts and reset_thread_gc_counts +// are currently nearly identical for mmtk and for stock. However, the stats +// are likely different (e.g., MMTk doesn't track the bytes allocated in the fastpath, +// but only when the slowpath is called). We might need to adapt these later so that +// the statistics are the same or as close as possible for each GC. +static void combine_thread_gc_counts(jl_gc_num_t *dest, int update_heap) JL_NOTSAFEPOINT +{ + int gc_n_threads; + jl_ptls_t* gc_all_tls_states; + gc_n_threads = jl_atomic_load_acquire(&jl_n_threads); + gc_all_tls_states = jl_atomic_load_relaxed(&jl_all_tls_states); + for (int i = 0; i < gc_n_threads; i++) { + jl_ptls_t ptls = gc_all_tls_states[i]; + if (ptls) { + dest->allocd += (jl_atomic_load_relaxed(&ptls->gc_tls_common.gc_num.allocd) + gc_num.interval); + dest->malloc += jl_atomic_load_relaxed(&ptls->gc_tls_common.gc_num.malloc); + dest->realloc += jl_atomic_load_relaxed(&ptls->gc_tls_common.gc_num.realloc); + dest->poolalloc += jl_atomic_load_relaxed(&ptls->gc_tls_common.gc_num.poolalloc); + dest->bigalloc += jl_atomic_load_relaxed(&ptls->gc_tls_common.gc_num.bigalloc); + dest->freed += jl_atomic_load_relaxed(&ptls->gc_tls_common.gc_num.free_acc); + if (update_heap) { + jl_atomic_store_relaxed(&ptls->gc_tls_common.gc_num.alloc_acc, 0); + jl_atomic_store_relaxed(&ptls->gc_tls_common.gc_num.free_acc, 0); + } + } + } +} + +void reset_thread_gc_counts(void) JL_NOTSAFEPOINT +{ + int gc_n_threads; + jl_ptls_t* gc_all_tls_states; + gc_n_threads = jl_atomic_load_acquire(&jl_n_threads); + gc_all_tls_states = jl_atomic_load_relaxed(&jl_all_tls_states); + for (int i = 0; i < gc_n_threads; i++) { + jl_ptls_t ptls = gc_all_tls_states[i]; + if (ptls != NULL) { + // don't reset `pool_live_bytes` here + jl_atomic_store_relaxed(&ptls->gc_tls_common.gc_num.allocd, -(int64_t)gc_num.interval); + jl_atomic_store_relaxed(&ptls->gc_tls_common.gc_num.malloc, 0); + jl_atomic_store_relaxed(&ptls->gc_tls_common.gc_num.realloc, 0); + jl_atomic_store_relaxed(&ptls->gc_tls_common.gc_num.poolalloc, 0); + jl_atomic_store_relaxed(&ptls->gc_tls_common.gc_num.bigalloc, 0); + jl_atomic_store_relaxed(&ptls->gc_tls_common.gc_num.alloc_acc, 0); + jl_atomic_store_relaxed(&ptls->gc_tls_common.gc_num.free_acc, 0); + } + } +} + +// Retrieves Julia's `GC_Num` (structure that stores GC statistics). +JL_DLLEXPORT jl_gc_num_t jl_gc_num(void) { + jl_gc_num_t num = gc_num; + combine_thread_gc_counts(&num, 0); + return num; +} + +JL_DLLEXPORT int64_t jl_gc_diff_total_bytes(void) JL_NOTSAFEPOINT { + int64_t oldtb = last_gc_total_bytes; + int64_t newtb; + jl_gc_get_total_bytes(&newtb); + last_gc_total_bytes = newtb; + return newtb - oldtb; +} + +JL_DLLEXPORT int64_t jl_gc_sync_total_bytes(int64_t offset) JL_NOTSAFEPOINT +{ + int64_t oldtb = last_gc_total_bytes; + int64_t newtb; + jl_gc_get_total_bytes(&newtb); + last_gc_total_bytes = newtb - offset; + return newtb - oldtb; +} + +JL_DLLEXPORT int64_t jl_gc_pool_live_bytes(void) { + return 0; +} + +void jl_gc_count_allocd(size_t sz) JL_NOTSAFEPOINT +{ + jl_ptls_t ptls = jl_current_task->ptls; + jl_atomic_store_relaxed(&ptls->gc_tls_common.gc_num.allocd, + jl_atomic_load_relaxed(&ptls->gc_tls_common.gc_num.allocd) + sz); +} + +void jl_gc_count_freed(size_t sz) JL_NOTSAFEPOINT +{ +} + +int64_t inc_live_bytes(int64_t inc) JL_NOTSAFEPOINT +{ + jl_timing_counter_inc(JL_TIMING_COUNTER_HeapSize, inc); + return live_bytes += inc; +} + +void jl_gc_reset_alloc_count(void) JL_NOTSAFEPOINT +{ + combine_thread_gc_counts(&gc_num, 0); + inc_live_bytes(gc_num.deferred_alloc + gc_num.allocd); + gc_num.allocd = 0; + gc_num.deferred_alloc = 0; + reset_thread_gc_counts(); +} + +JL_DLLEXPORT int64_t jl_gc_live_bytes(void) { + return last_live_bytes; +} + +JL_DLLEXPORT void jl_gc_get_total_bytes(int64_t *bytes) JL_NOTSAFEPOINT +{ + jl_gc_num_t num = gc_num; + combine_thread_gc_counts(&num, 0); + // Sync this logic with `base/util.jl:GC_Diff` + *bytes = (num.total_allocd + num.deferred_alloc + num.allocd); +} + +JL_DLLEXPORT uint64_t jl_gc_get_max_memory(void) +{ + // FIXME: should probably return MMTk's heap size + return max_total_memory; +} + +// These are needed to collect MMTk statistics from a Julia program using ccall +JL_DLLEXPORT void (jl_mmtk_harness_begin)(void) +{ + jl_ptls_t ptls = jl_current_task->ptls; + mmtk_harness_begin(ptls); +} + +JL_DLLEXPORT void (jl_mmtk_harness_end)(void) +{ + mmtk_harness_end(); +} + +// ========================================================================= // +// Root Processing, Object Scanning and Julia-specific sweeping +// ========================================================================= // + +static void add_node_to_roots_buffer(RootsWorkClosure* closure, RootsWorkBuffer* buf, size_t* buf_len, void* root) { + if (root == NULL) + return; + + buf->ptr[*buf_len] = root; + *buf_len += 1; + if (*buf_len >= buf->cap) { + RootsWorkBuffer new_buf = (closure->report_nodes_func)(buf->ptr, *buf_len, buf->cap, closure->data, true); + *buf = new_buf; + *buf_len = 0; + } +} + +static void add_node_to_tpinned_roots_buffer(RootsWorkClosure* closure, RootsWorkBuffer* buf, size_t* buf_len, void* root) { + if (root == NULL) + return; + + buf->ptr[*buf_len] = root; + *buf_len += 1; + if (*buf_len >= buf->cap) { + RootsWorkBuffer new_buf = (closure->report_tpinned_nodes_func)(buf->ptr, *buf_len, buf->cap, closure->data, true); + *buf = new_buf; + *buf_len = 0; + } +} + +JL_DLLEXPORT void jl_gc_scan_vm_specific_roots(RootsWorkClosure* closure) +{ + // Create a new buf + RootsWorkBuffer buf = (closure->report_nodes_func)((void**)0, 0, 0, closure->data, true); + size_t len = 0; + + // add module + add_node_to_roots_buffer(closure, &buf, &len, jl_main_module); + + // buildin values + add_node_to_roots_buffer(closure, &buf, &len, jl_an_empty_vec_any); + add_node_to_roots_buffer(closure, &buf, &len, jl_module_init_order); + for (size_t i = 0; i < jl_current_modules.size; i += 2) { + if (jl_current_modules.table[i + 1] != HT_NOTFOUND) { + add_node_to_roots_buffer(closure, &buf, &len, jl_current_modules.table[i]); + } + } + add_node_to_roots_buffer(closure, &buf, &len, jl_anytuple_type_type); + for (size_t i = 0; i < N_CALL_CACHE; i++) { + jl_typemap_entry_t *v = jl_atomic_load_relaxed(&call_cache[i]); + add_node_to_roots_buffer(closure, &buf, &len, v); + } + add_node_to_roots_buffer(closure, &buf, &len, _jl_debug_method_invalidation); + + // constants + add_node_to_roots_buffer(closure, &buf, &len, jl_emptytuple_type); + add_node_to_roots_buffer(closure, &buf, &len, cmpswap_names); + + // jl_global_roots_table must be transitively pinned + RootsWorkBuffer tpinned_buf = (closure->report_tpinned_nodes_func)((void**)0, 0, 0, closure->data, true); + size_t tpinned_len = 0; + add_node_to_tpinned_roots_buffer(closure, &tpinned_buf, &tpinned_len, jl_global_roots_list); + add_node_to_tpinned_roots_buffer(closure, &tpinned_buf, &tpinned_len, jl_global_roots_keyset); + + // Push the result of the work. + (closure->report_nodes_func)(buf.ptr, len, buf.cap, closure->data, false); + (closure->report_tpinned_nodes_func)(tpinned_buf.ptr, tpinned_len, tpinned_buf.cap, closure->data, false); +} + +JL_DLLEXPORT void jl_gc_scan_julia_exc_obj(void* obj_raw, void* closure, ProcessSlotFn process_slot) { + jl_task_t *ta = (jl_task_t*)obj_raw; + + if (ta->excstack) { // inlining label `excstack` from mark_loop + + // the excstack should always be a heap object + assert(mmtk_object_is_managed_by_mmtk(ta->excstack)); + + process_slot(closure, &ta->excstack); + jl_excstack_t *excstack = ta->excstack; + size_t itr = ta->excstack->top; + size_t bt_index = 0; + size_t jlval_index = 0; + while (itr > 0) { + size_t bt_size = jl_excstack_bt_size(excstack, itr); + jl_bt_element_t *bt_data = jl_excstack_bt_data(excstack, itr); + for (; bt_index < bt_size; bt_index += jl_bt_entry_size(bt_data + bt_index)) { + jl_bt_element_t *bt_entry = bt_data + bt_index; + if (jl_bt_is_native(bt_entry)) + continue; + // Found an extended backtrace entry: iterate over any + // GC-managed values inside. + size_t njlvals = jl_bt_num_jlvals(bt_entry); + while (jlval_index < njlvals) { + jl_value_t** new_obj_slot = &bt_entry[2 + jlval_index].jlvalue; + jlval_index += 1; + process_slot(closure, new_obj_slot); + } + jlval_index = 0; + } + + jl_bt_element_t *stack_raw = (jl_bt_element_t *)(excstack+1); + jl_value_t** stack_obj_slot = &stack_raw[itr-1].jlvalue; + + itr = jl_excstack_next(excstack, itr); + bt_index = 0; + jlval_index = 0; + process_slot(closure, stack_obj_slot); + } + } +} + +// This is used in mmtk_sweep_malloced_memory and it is slightly different +// from jl_gc_free_memory from gc-stock.c as the stock GC updates the +// information in the global variable gc_heap_stats (which is specific to the stock GC) +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); + char *d = (char*)m->ptr; + size_t freed_bytes = memory_block_usable_size(d, isaligned); + assert(freed_bytes != 0); + if (isaligned) + jl_free_aligned(d); + else + free(d); + gc_num.freed += freed_bytes; + gc_num.freecall++; +} + +JL_DLLEXPORT void jl_gc_mmtk_sweep_malloced_memory(void) JL_NOTSAFEPOINT +{ + void* iter = mmtk_new_mutator_iterator(); + jl_ptls_t ptls2 = (jl_ptls_t)mmtk_get_next_mutator_tls(iter); + while(ptls2 != NULL) { + size_t n = 0; + size_t l = ptls2->gc_tls_common.heap.mallocarrays.len; + void **lst = ptls2->gc_tls_common.heap.mallocarrays.items; + // filter without preserving order + while (n < l) { + jl_genericmemory_t *m = (jl_genericmemory_t*)((uintptr_t)lst[n] & ~1); + if (mmtk_is_live_object(m)) { + n++; + } + else { + int isaligned = (uintptr_t)lst[n] & 1; + jl_gc_free_memory(m, isaligned); + l--; + lst[n] = lst[l]; + } + } + ptls2->gc_tls_common.heap.mallocarrays.len = l; + ptls2 = (jl_ptls_t)mmtk_get_next_mutator_tls(iter); + } + mmtk_close_mutator_iterator(iter); +} + +#define jl_genericmemory_elsize(a) (((jl_datatype_t*)jl_typetagof(a))->layout->size) + +// if data is inlined inside the genericmemory object --- to->ptr needs to be updated when copying the array +JL_DLLEXPORT void jl_gc_update_inlined_array(void* from, void* to) { + jl_value_t* jl_from = (jl_value_t*) from; + jl_value_t* jl_to = (jl_value_t*) to; + + uintptr_t tag_to = (uintptr_t)jl_typeof(jl_to); + jl_datatype_t *vt = (jl_datatype_t*)tag_to; + + if(vt->name == jl_genericmemory_typename) { + jl_genericmemory_t *a = (jl_genericmemory_t*)jl_from; + jl_genericmemory_t *b = (jl_genericmemory_t*)jl_to; + int how = jl_genericmemory_how(a); + + if (how == 0 && mmtk_object_is_managed_by_mmtk(a->ptr)) { // a is inlined (a->ptr points into the mmtk object) + size_t offset_of_data = ((size_t)a->ptr - (size_t)a); + if (offset_of_data > 0) { + b->ptr = (void*)((size_t) b + offset_of_data); + } + } + } +} + +// modified sweep_stack_pools from gc-stacks.c +JL_DLLEXPORT void jl_gc_mmtk_sweep_stack_pools(void) +{ + // Stack sweeping algorithm: + // // deallocate stacks if we have too many sitting around unused + // for (stk in halfof(free_stacks)) + // free_stack(stk, pool_sz); + // // then sweep the task stacks + // for (t in live_tasks) + // if (!gc-marked(t)) + // stkbuf = t->stkbuf + // bufsz = t->bufsz + // if (stkbuf) + // push(free_stacks[sz], stkbuf) + assert(gc_n_threads); + for (int i = 0; i < jl_n_threads; i++) { + jl_ptls_t ptls2 = gc_all_tls_states[i]; + if (ptls2 == NULL) + continue; + + // free half of stacks that remain unused since last sweep + for (int p = 0; p < JL_N_STACK_POOLS; p++) { + small_arraylist_t *al = &ptls2->gc_tls_common.heap.free_stacks[p]; + size_t n_to_free; + if (jl_atomic_load_relaxed(&ptls2->current_task) == NULL) { + n_to_free = al->len; // not alive yet or dead, so it does not need these anymore + } + else if (al->len > MIN_STACK_MAPPINGS_PER_POOL) { + n_to_free = al->len / 2; + if (n_to_free > (al->len - MIN_STACK_MAPPINGS_PER_POOL)) + n_to_free = al->len - MIN_STACK_MAPPINGS_PER_POOL; + } + else { + n_to_free = 0; + } + for (int n = 0; n < n_to_free; n++) { + void *stk = small_arraylist_pop(al); + free_stack(stk, pool_sizes[p]); + } + if (jl_atomic_load_relaxed(&ptls2->current_task) == NULL) { + small_arraylist_free(al); + } + } + if (jl_atomic_load_relaxed(&ptls2->current_task) == NULL) { + small_arraylist_free(ptls2->gc_tls_common.heap.free_stacks); + } + + small_arraylist_t *live_tasks = &ptls2->gc_tls_common.heap.live_tasks; + size_t n = 0; + size_t ndel = 0; + size_t l = live_tasks->len; + void **lst = live_tasks->items; + if (l == 0) + continue; + while (1) { + jl_task_t *t = (jl_task_t*)lst[n]; + if (mmtk_is_live_object(t)) { + jl_task_t *maybe_forwarded = (jl_task_t*)mmtk_get_possibly_forwarded(t); + live_tasks->items[n] = maybe_forwarded; + t = maybe_forwarded; + assert(jl_is_task(t)); + if (t->ctx.stkbuf == NULL) + ndel++; // jl_release_task_stack called + else + n++; + } else { + ndel++; + void *stkbuf = t->ctx.stkbuf; + size_t bufsz = t->ctx.bufsz; + if (stkbuf) { + t->ctx.stkbuf = NULL; + _jl_free_stack(ptls2, stkbuf, bufsz); + } +#ifdef _COMPILER_TSAN_ENABLED_ + if (t->ctx.tsan_state) { + __tsan_destroy_fiber(t->ctx.tsan_state); + t->ctx.tsan_state = NULL; + } +#endif + } + if (n >= l - ndel) + break; + void *tmp = lst[n]; + lst[n] = lst[n + ndel]; + lst[n + ndel] = tmp; + } + live_tasks->len -= ndel; + } +} + +JL_DLLEXPORT void jl_gc_sweep_stack_pools_and_mtarraylist_buffers(jl_ptls_t ptls) JL_NOTSAFEPOINT +{ + jl_gc_mmtk_sweep_stack_pools(); + sweep_mtarraylist_buffers(); +} + +JL_DLLEXPORT void* jl_gc_get_stackbase(int16_t tid) { + assert(tid >= 0); + jl_ptls_t ptls2 = jl_all_tls_states[tid]; + return ptls2->stackbase; +} + +JL_DLLEXPORT void jl_gc_update_stats(uint64_t inc, size_t mmtk_live_bytes, bool is_nursery_gc) { + gc_num.total_time += inc; + gc_num.pause += 1; + gc_num.full_sweep += !(is_nursery_gc); + gc_num.total_allocd += gc_num.allocd; + gc_num.allocd = 0; + live_bytes = mmtk_live_bytes; +} + +#define jl_genericmemory_data_owner_field_addr(a) ((jl_value_t**)((jl_genericmemory_t*)(a) + 1)) + +JL_DLLEXPORT void* jl_gc_get_owner_address_to_mmtk(void* m) { + return (void*)jl_genericmemory_data_owner_field_addr(m); +} + +// same as jl_genericmemory_how but with JL_DLLEXPORT +// we should probably inline this in Rust +JL_DLLEXPORT size_t jl_gc_genericmemory_how(void *arg) JL_NOTSAFEPOINT +{ + jl_genericmemory_t* m = (jl_genericmemory_t*)arg; + if (m->ptr == (void*)((char*)m + 16)) // JL_SMALL_BYTE_ALIGNMENT (from julia_internal.h) + return 0; + jl_value_t *owner = jl_genericmemory_data_owner_field(m); + if (owner == (jl_value_t*)m) + return 1; + if (owner == NULL) + return 2; + return 3; +} + +// ========================================================================= // +// Weak References and Finalizers +// ========================================================================= // + +JL_DLLEXPORT jl_weakref_t *jl_gc_new_weakref_th(jl_ptls_t ptls, jl_value_t *value) +{ + jl_weakref_t *wr = (jl_weakref_t*)jl_gc_alloc(ptls, sizeof(void*), jl_weakref_type); + wr->value = value; // NOTE: wb not needed here + mmtk_add_weak_candidate(wr); + return wr; +} + +JL_DLLEXPORT void* jl_gc_get_thread_finalizer_list(void* ptls_raw) { + jl_ptls_t ptls = (jl_ptls_t) ptls_raw; + return (void*)&ptls->finalizers; +} + +JL_DLLEXPORT void* jl_gc_get_to_finalize_list(void) { + return (void*)&to_finalize; +} + +JL_DLLEXPORT void* jl_gc_get_marked_finalizers_list(void) { + return (void*)&finalizer_list_marked; +} + +JL_DLLEXPORT int* jl_gc_get_have_pending_finalizers(void) { + return (int*)&jl_gc_have_pending_finalizers; +} + +// ========================================================================= // +// Allocation +// ========================================================================= // + +#define MMTK_DEFAULT_IMMIX_ALLOCATOR (0) +#define MMTK_IMMORTAL_BUMP_ALLOCATOR (0) + +int jl_gc_classify_pools(size_t sz, int *osize) +{ + if (sz > GC_MAX_SZCLASS) + return -1; // call big alloc function + size_t allocsz = sz + sizeof(jl_taggedvalue_t); + *osize = LLT_ALIGN(allocsz, 16); + return 0; // use MMTk's fastpath logic +} + +#define MMTK_MIN_ALIGNMENT 4 +// MMTk assumes allocation size is aligned to min alignment. +STATIC_INLINE size_t mmtk_align_alloc_sz(size_t sz) JL_NOTSAFEPOINT +{ + return (sz + MMTK_MIN_ALIGNMENT - 1) & ~(MMTK_MIN_ALIGNMENT - 1); +} + +STATIC_INLINE void* bump_alloc_fast(MMTkMutatorContext* mutator, uintptr_t* cursor, uintptr_t limit, size_t size, size_t align, size_t offset, int allocator) { + intptr_t delta = (-offset - *cursor) & (align - 1); + uintptr_t result = *cursor + (uintptr_t)delta; + + if (__unlikely(result + size > limit)) { + return (void*) mmtk_alloc(mutator, size, align, offset, allocator); + } else{ + *cursor = result + size; + return (void*)result; + } +} + +STATIC_INLINE void* mmtk_immix_alloc_fast(MMTkMutatorContext* mutator, size_t size, size_t align, size_t offset) { + ImmixAllocator* allocator = &mutator->allocators.immix[MMTK_DEFAULT_IMMIX_ALLOCATOR]; + return bump_alloc_fast(mutator, (uintptr_t*)&allocator->cursor, (intptr_t)allocator->limit, size, align, offset, 0); +} + +inline void mmtk_immix_post_alloc_slow(MMTkMutatorContext* mutator, void* obj, size_t size) { + mmtk_post_alloc(mutator, obj, size, 0); +} + +STATIC_INLINE void mmtk_immix_post_alloc_fast(MMTkMutatorContext* mutator, void* obj, size_t size) { + // FIXME: for now, we do nothing + // but when supporting moving, this is where we set the valid object (VO) bit +} + +STATIC_INLINE void* mmtk_immortal_alloc_fast(MMTkMutatorContext* mutator, size_t size, size_t align, size_t offset) { + BumpAllocator* allocator = &mutator->allocators.bump_pointer[MMTK_IMMORTAL_BUMP_ALLOCATOR]; + return bump_alloc_fast(mutator, (uintptr_t*)&allocator->cursor, (uintptr_t)allocator->limit, size, align, offset, 1); +} + +STATIC_INLINE void mmtk_immortal_post_alloc_fast(MMTkMutatorContext* mutator, void* obj, size_t size) { + // FIXME: Similarly, for now, we do nothing + // but when supporting moving, this is where we set the valid object (VO) bit + // and log (old gen) bit +} + +JL_DLLEXPORT jl_value_t *jl_mmtk_gc_alloc_default(jl_ptls_t ptls, int osize, size_t align, void *ty) +{ + // safepoint + jl_gc_safepoint_(ptls); + + jl_value_t *v; + if ((uintptr_t)ty != jl_buff_tag) { + // v needs to be 16 byte aligned, therefore v_tagged needs to be offset accordingly to consider the size of header + jl_taggedvalue_t *v_tagged = (jl_taggedvalue_t *)mmtk_immix_alloc_fast(&ptls->gc_tls.mmtk_mutator, LLT_ALIGN(osize, align), align, sizeof(jl_taggedvalue_t)); + v = jl_valueof(v_tagged); + mmtk_immix_post_alloc_fast(&ptls->gc_tls.mmtk_mutator, v, LLT_ALIGN(osize, align)); + } else { + // allocating an extra word to store the size of buffer objects + jl_taggedvalue_t *v_tagged = (jl_taggedvalue_t *)mmtk_immix_alloc_fast(&ptls->gc_tls.mmtk_mutator, LLT_ALIGN(osize+sizeof(jl_taggedvalue_t), align), align, 0); + jl_value_t* v_tagged_aligned = ((jl_value_t*)((char*)(v_tagged) + sizeof(jl_taggedvalue_t))); + v = jl_valueof(v_tagged_aligned); + mmtk_store_obj_size_c(v, LLT_ALIGN(osize+sizeof(jl_taggedvalue_t), align)); + mmtk_immix_post_alloc_fast(&ptls->gc_tls.mmtk_mutator, v, LLT_ALIGN(osize+sizeof(jl_taggedvalue_t), align)); + } + + ptls->gc_tls_common.gc_num.allocd += osize; + ptls->gc_tls_common.gc_num.poolalloc++; + + return v; +} + +JL_DLLEXPORT jl_value_t *jl_mmtk_gc_alloc_big(jl_ptls_t ptls, size_t sz) +{ + // safepoint + jl_gc_safepoint_(ptls); + + size_t offs = offsetof(bigval_t, header); + assert(sz >= sizeof(jl_taggedvalue_t) && "sz must include tag"); + static_assert(offsetof(bigval_t, header) >= sizeof(void*), "Empty bigval header?"); + static_assert(sizeof(bigval_t) % JL_HEAP_ALIGNMENT == 0, ""); + size_t allocsz = LLT_ALIGN(sz + offs, JL_CACHE_BYTE_ALIGNMENT); + if (allocsz < sz) { // overflow in adding offs, size was "negative" + assert(0 && "Error when allocating big object"); + jl_throw(jl_memory_exception); + } + + bigval_t *v = (bigval_t*)mmtk_alloc_large(&ptls->gc_tls.mmtk_mutator, allocsz, JL_CACHE_BYTE_ALIGNMENT, 0, 2); + + if (v == NULL) { + assert(0 && "Allocation failed"); + jl_throw(jl_memory_exception); + } + v->sz = allocsz; + + ptls->gc_tls_common.gc_num.allocd += allocsz; + ptls->gc_tls_common.gc_num.bigalloc++; + + jl_value_t *result = jl_valueof(&v->header); + mmtk_post_alloc(&ptls->gc_tls.mmtk_mutator, result, allocsz, 2); + + return result; +} + +// Instrumented version of jl_gc_small_alloc_inner, called into by LLVM-generated code. +JL_DLLEXPORT jl_value_t *jl_gc_small_alloc(jl_ptls_t ptls, int offset, int osize, jl_value_t* type) +{ + assert(jl_atomic_load_relaxed(&ptls->gc_state) == 0); + + jl_value_t *val = jl_mmtk_gc_alloc_default(ptls, osize, 16, NULL); + maybe_record_alloc_to_profile(val, osize, (jl_datatype_t*)type); + return val; +} + +// Instrumented version of jl_gc_big_alloc_inner, called into by LLVM-generated code. +JL_DLLEXPORT jl_value_t *jl_gc_big_alloc(jl_ptls_t ptls, size_t sz, jl_value_t *type) +{ + // TODO: assertion needed here? + assert(jl_atomic_load_relaxed(&ptls->gc_state) == 0); + + jl_value_t *val = jl_mmtk_gc_alloc_big(ptls, sz); + maybe_record_alloc_to_profile(val, sz, (jl_datatype_t*)type); + return val; +} + +inline jl_value_t *jl_gc_alloc_(jl_ptls_t ptls, size_t sz, void *ty) +{ + jl_value_t *v; + const size_t allocsz = sz + sizeof(jl_taggedvalue_t); + if (sz <= GC_MAX_SZCLASS) { + v = jl_mmtk_gc_alloc_default(ptls, allocsz, 16, ty); + } + else { + if (allocsz < sz) // overflow in adding offs, size was "negative" + jl_throw(jl_memory_exception); + v = jl_mmtk_gc_alloc_big(ptls, allocsz); + } + jl_set_typeof(v, ty); + maybe_record_alloc_to_profile(v, sz, (jl_datatype_t*)ty); + return v; +} + +// allocation wrappers that track allocation and let collection run +JL_DLLEXPORT void *jl_gc_counted_malloc(size_t sz) +{ + jl_gcframe_t **pgcstack = jl_get_pgcstack(); + jl_task_t *ct = jl_current_task; + void *data = malloc(sz); + if (data != NULL && pgcstack != NULL && ct->world_age) { + jl_ptls_t ptls = ct->ptls; + malloc_maybe_collect(ptls, sz); + jl_atomic_fetch_add_relaxed(&JULIA_MALLOC_BYTES, sz); + } + return data; +} + +JL_DLLEXPORT void *jl_gc_counted_calloc(size_t nm, size_t sz) +{ + jl_gcframe_t **pgcstack = jl_get_pgcstack(); + jl_task_t *ct = jl_current_task; + void *data = calloc(nm, sz); + if (data != NULL && pgcstack != NULL && ct->world_age) { + jl_ptls_t ptls = ct->ptls; + malloc_maybe_collect(ptls, nm * sz); + jl_atomic_fetch_add_relaxed(&JULIA_MALLOC_BYTES, nm * sz); + } + return data; +} + +JL_DLLEXPORT void jl_gc_counted_free_with_size(void *p, size_t sz) +{ + jl_gcframe_t **pgcstack = jl_get_pgcstack(); + jl_task_t *ct = jl_current_task; + free(p); + if (pgcstack != NULL && ct->world_age) { + jl_atomic_fetch_add_relaxed(&JULIA_MALLOC_BYTES, -sz); + } +} + +JL_DLLEXPORT void *jl_gc_counted_realloc_with_old_size(void *p, size_t old, size_t sz) +{ + jl_gcframe_t **pgcstack = jl_get_pgcstack(); + jl_task_t *ct = jl_current_task; + if (pgcstack && ct->world_age) { + jl_ptls_t ptls = ct->ptls; + malloc_maybe_collect(ptls, sz); + if (sz < old) + jl_atomic_fetch_add_relaxed(&JULIA_MALLOC_BYTES, old - sz); + else + jl_atomic_fetch_add_relaxed(&JULIA_MALLOC_BYTES, sz - old); + } + return realloc(p, sz); +} + +void *jl_gc_perm_alloc_nolock(size_t sz, int zero, unsigned align, unsigned offset) +{ + jl_ptls_t ptls = jl_current_task->ptls; + size_t allocsz = mmtk_align_alloc_sz(sz); + void* addr = mmtk_immortal_alloc_fast(&ptls->gc_tls.mmtk_mutator, allocsz, align, offset); + return addr; +} + +void *jl_gc_perm_alloc(size_t sz, int zero, unsigned align, unsigned offset) +{ + return jl_gc_perm_alloc_nolock(sz, zero, align, offset); +} + +jl_value_t *jl_gc_permobj(size_t sz, void *ty) JL_NOTSAFEPOINT +{ + const size_t allocsz = sz + sizeof(jl_taggedvalue_t); + unsigned align = (sz == 0 ? sizeof(void*) : (allocsz <= sizeof(void*) * 2 ? + sizeof(void*) * 2 : 16)); + jl_taggedvalue_t *o = (jl_taggedvalue_t*)jl_gc_perm_alloc(allocsz, 0, align, + sizeof(void*) % align); + + jl_ptls_t ptls = jl_current_task->ptls; + mmtk_immortal_post_alloc_fast(&ptls->gc_tls.mmtk_mutator, jl_valueof(o), allocsz); + o->header = (uintptr_t)ty; + return jl_valueof(o); +} + +JL_DLLEXPORT void *jl_gc_managed_malloc(size_t sz) +{ + jl_ptls_t ptls = jl_current_task->ptls; + maybe_collect(ptls); + size_t allocsz = LLT_ALIGN(sz, JL_CACHE_BYTE_ALIGNMENT); + if (allocsz < sz) // overflow in adding offs, size was "negative" + jl_throw(jl_memory_exception); + + int last_errno = errno; +#ifdef _OS_WINDOWS_ + DWORD last_error = GetLastError(); +#endif + void *b = malloc_cache_align(allocsz); + if (b == NULL) + jl_throw(jl_memory_exception); + + jl_atomic_store_relaxed(&ptls->gc_tls_common.gc_num.allocd, + jl_atomic_load_relaxed(&ptls->gc_tls_common.gc_num.allocd) + allocsz); + jl_atomic_store_relaxed(&ptls->gc_tls_common.gc_num.malloc, + jl_atomic_load_relaxed(&ptls->gc_tls_common.gc_num.malloc) + 1); + // FIXME: Should these be part of mmtk's heap? + // malloc_maybe_collect(ptls, sz); + // jl_atomic_fetch_add_relaxed(&JULIA_MALLOC_BYTES, allocsz); +#ifdef _OS_WINDOWS_ + SetLastError(last_error); +#endif + errno = last_errno; + // jl_gc_managed_malloc is currently always used for allocating array buffers. + maybe_record_alloc_to_profile((jl_value_t*)b, sz, (jl_datatype_t*)jl_buff_tag); + return b; +} + +void jl_gc_notify_image_load(const char* img_data, size_t len) +{ + mmtk_set_vm_space((void*)img_data, len); +} + +// ========================================================================= // +// Code specific to stock that is not supported by MMTk +// ========================================================================= // + +// mutex for page profile +uv_mutex_t page_profile_lock; + +JL_DLLEXPORT void jl_gc_take_page_profile(ios_t *stream) +{ + uv_mutex_lock(&page_profile_lock); + const char *str = "Page profiler in unsupported in MMTk."; + ios_write(stream, str, strlen(str)); + uv_mutex_unlock(&page_profile_lock); +} + +// this seems to be needed by the gc tests +#define JL_GC_N_MAX_POOLS 51 +JL_DLLEXPORT double jl_gc_page_utilization_stats[JL_GC_N_MAX_POOLS]; + +STATIC_INLINE void gc_dump_page_utilization_data(void) JL_NOTSAFEPOINT +{ + // FIXME: MMTk would have to provide its own stats +} + +#define MMTK_GC_PAGE_SZ (1 << 12) // MMTk's page size is defined in mmtk-core constants + +JL_DLLEXPORT uint64_t jl_get_pg_size(void) +{ + return MMTK_GC_PAGE_SZ; +} + +// Not used by mmtk +// Number of GC threads that may run parallel marking +int jl_n_markthreads; +// Number of GC threads that may run concurrent sweeping (0 or 1) +int jl_n_sweepthreads; +// `tid` of first GC thread +int gc_first_tid; +// Number of threads sweeping stacks +_Atomic(int) gc_n_threads_sweeping_stacks; +// counter for sharing work when sweeping stacks +_Atomic(int) gc_ptls_sweep_idx; +// counter for round robin of giving back stack pages to the OS +_Atomic(int) gc_stack_free_idx = 0; + +JL_DLLEXPORT void jl_gc_queue_root(const struct _jl_value_t *ptr) JL_NOTSAFEPOINT +{ + mmtk_unreachable(); +} + +JL_DLLEXPORT void jl_gc_queue_multiroot(const struct _jl_value_t *root, const void *stored, + struct _jl_datatype_t *dt) JL_NOTSAFEPOINT +{ + mmtk_unreachable(); +} + +JL_DLLEXPORT int jl_gc_mark_queue_obj(jl_ptls_t ptls, jl_value_t *obj) +{ + mmtk_unreachable(); + return 0; +} + +JL_DLLEXPORT void jl_gc_mark_queue_objarray(jl_ptls_t ptls, jl_value_t *parent, + jl_value_t **objs, size_t nobjs) +{ + mmtk_unreachable(); +} + +JL_DLLEXPORT size_t jl_gc_max_internal_obj_size(void) +{ + // TODO: meaningful for MMTk? + return GC_MAX_SZCLASS; +} + +JL_DLLEXPORT void jl_gc_schedule_foreign_sweepfunc(jl_ptls_t ptls, jl_value_t *obj) +{ + // FIXME: do we need to implement this? +} + +// gc-debug functions +JL_DLLEXPORT jl_taggedvalue_t *jl_gc_find_taggedvalue_pool(char *p, size_t *osize_p) +{ + return NULL; +} + +void jl_gc_debug_critical_error(void) JL_NOTSAFEPOINT +{ +} + +int gc_is_collector_thread(int tid) JL_NOTSAFEPOINT +{ + return 0; +} + +void jl_gc_debug_print_status(void) JL_NOTSAFEPOINT +{ + // May not be accurate but should be helpful enough + uint64_t pool_count = gc_num.poolalloc; + uint64_t big_count = gc_num.bigalloc; + jl_safe_printf("Allocations: %" PRIu64 " " + "(Pool: %" PRIu64 "; Big: %" PRIu64 "); GC: %d\n", + pool_count + big_count, pool_count, big_count, gc_num.pause); +} + +JL_DLLEXPORT size_t jl_gc_external_obj_hdr_size(void) +{ + return sizeof(bigval_t); +} + +void jl_print_gc_stats(JL_STREAM *s) +{ +} + +JL_DLLEXPORT int jl_gc_enable_conservative_gc_support(void) +{ + return 0; +} + +JL_DLLEXPORT int jl_gc_conservative_gc_support_enabled(void) +{ + return 0; +} + +// TODO: if this is needed, it can be added in MMTk +JL_DLLEXPORT jl_value_t *jl_gc_internal_obj_base_ptr(void *p) +{ + return NULL; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/gc-stacks.c b/src/gc-stacks.c index a0ca2561c5cf9..9387c7fb065ec 100644 --- a/src/gc-stacks.c +++ b/src/gc-stacks.c @@ -1,7 +1,6 @@ // This file is a part of Julia. License is MIT: https://julialang.org/license #include "gc-common.h" -#include "gc-stock.h" #include "threading.h" #ifndef _OS_WINDOWS_ # include @@ -21,9 +20,6 @@ # endif #endif -// number of stacks to always keep available per pool -#define MIN_STACK_MAPPINGS_PER_POOL 5 - const size_t jl_guard_size = (4096 * 8); static _Atomic(uint32_t) num_stack_mappings = 0; @@ -203,99 +199,6 @@ JL_DLLEXPORT void *jl_malloc_stack(size_t *bufsz, jl_task_t *owner) JL_NOTSAFEPO return stk; } -void sweep_stack_pool_loop(void) JL_NOTSAFEPOINT -{ - // Stack sweeping algorithm: - // // deallocate stacks if we have too many sitting around unused - // for (stk in halfof(free_stacks)) - // free_stack(stk, pool_sz); - // // then sweep the task stacks - // for (t in live_tasks) - // if (!gc-marked(t)) - // stkbuf = t->stkbuf - // bufsz = t->bufsz - // if (stkbuf) - // push(free_stacks[sz], stkbuf) - jl_atomic_fetch_add(&gc_n_threads_sweeping_stacks, 1); - while (1) { - int i = jl_atomic_fetch_add_relaxed(&gc_ptls_sweep_idx, -1); - if (i < 0) - break; - jl_ptls_t ptls2 = gc_all_tls_states[i]; - if (ptls2 == NULL) - continue; - assert(gc_n_threads); - // free half of stacks that remain unused since last sweep - if (i == jl_atomic_load_relaxed(&gc_stack_free_idx)) { - for (int p = 0; p < JL_N_STACK_POOLS; p++) { - small_arraylist_t *al = &ptls2->gc_tls_common.heap.free_stacks[p]; - size_t n_to_free; - if (jl_atomic_load_relaxed(&ptls2->current_task) == NULL) { - n_to_free = al->len; // not alive yet or dead, so it does not need these anymore - } - else if (al->len > MIN_STACK_MAPPINGS_PER_POOL) { - n_to_free = al->len / 2; - if (n_to_free > (al->len - MIN_STACK_MAPPINGS_PER_POOL)) - n_to_free = al->len - MIN_STACK_MAPPINGS_PER_POOL; - } - else { - n_to_free = 0; - } - for (int n = 0; n < n_to_free; n++) { - void *stk = small_arraylist_pop(al); - free_stack(stk, pool_sizes[p]); - } - if (jl_atomic_load_relaxed(&ptls2->current_task) == NULL) { - small_arraylist_free(al); - } - } - } - if (jl_atomic_load_relaxed(&ptls2->current_task) == NULL) { - small_arraylist_free(ptls2->gc_tls_common.heap.free_stacks); - } - - small_arraylist_t *live_tasks = &ptls2->gc_tls_common.heap.live_tasks; - size_t n = 0; - size_t ndel = 0; - size_t l = live_tasks->len; - void **lst = live_tasks->items; - if (l == 0) - continue; - while (1) { - jl_task_t *t = (jl_task_t*)lst[n]; - assert(jl_is_task(t)); - if (gc_marked(jl_astaggedvalue(t)->bits.gc)) { - if (t->ctx.stkbuf == NULL) - ndel++; // jl_release_task_stack called - else - n++; - } - else { - ndel++; - void *stkbuf = t->ctx.stkbuf; - size_t bufsz = t->ctx.bufsz; - if (stkbuf) { - t->ctx.stkbuf = NULL; - _jl_free_stack(ptls2, stkbuf, bufsz); - } -#ifdef _COMPILER_TSAN_ENABLED_ - if (t->ctx.tsan_state) { - __tsan_destroy_fiber(t->ctx.tsan_state); - t->ctx.tsan_state = NULL; - } -#endif - } - if (n >= l - ndel) - break; - void *tmp = lst[n]; - lst[n] = lst[n + ndel]; - lst[n + ndel] = tmp; - } - live_tasks->len -= ndel; - } - jl_atomic_fetch_add(&gc_n_threads_sweeping_stacks, -1); -} - // Builds a list of the live tasks. Racy: `live_tasks` can expand at any time. arraylist_t *jl_get_all_tasks_arraylist(void) JL_NOTSAFEPOINT { diff --git a/src/gc-stock.c b/src/gc-stock.c index 1f6b58d71da3a..d2d9104ad8d22 100644 --- a/src/gc-stock.c +++ b/src/gc-stock.c @@ -1013,22 +1013,102 @@ void gc_sweep_wait_for_all_stacks(void) JL_NOTSAFEPOINT } } -void sweep_mtarraylist_buffers(void) JL_NOTSAFEPOINT -{ - for (int i = 0; i < gc_n_threads; i++) { - jl_ptls_t ptls = gc_all_tls_states[i]; - if (ptls == NULL) { +extern const unsigned pool_sizes[]; + +void sweep_stack_pool_loop(void) JL_NOTSAFEPOINT +{ + // Stack sweeping algorithm: + // // deallocate stacks if we have too many sitting around unused + // for (stk in halfof(free_stacks)) + // free_stack(stk, pool_sz); + // // then sweep the task stacks + // for (t in live_tasks) + // if (!gc-marked(t)) + // stkbuf = t->stkbuf + // bufsz = t->bufsz + // if (stkbuf) + // push(free_stacks[sz], stkbuf) + jl_atomic_fetch_add(&gc_n_threads_sweeping_stacks, 1); + while (1) { + int i = jl_atomic_fetch_add_relaxed(&gc_ptls_sweep_idx, -1); + if (i < 0) + break; + jl_ptls_t ptls2 = gc_all_tls_states[i]; + if (ptls2 == NULL) continue; + assert(gc_n_threads); + // free half of stacks that remain unused since last sweep + if (i == jl_atomic_load_relaxed(&gc_stack_free_idx)) { + for (int p = 0; p < JL_N_STACK_POOLS; p++) { + small_arraylist_t *al = &ptls2->gc_tls_common.heap.free_stacks[p]; + size_t n_to_free; + if (jl_atomic_load_relaxed(&ptls2->current_task) == NULL) { + n_to_free = al->len; // not alive yet or dead, so it does not need these anymore + } + else if (al->len > MIN_STACK_MAPPINGS_PER_POOL) { + n_to_free = al->len / 2; + if (n_to_free > (al->len - MIN_STACK_MAPPINGS_PER_POOL)) + n_to_free = al->len - MIN_STACK_MAPPINGS_PER_POOL; + } + else { + n_to_free = 0; + } + for (int n = 0; n < n_to_free; n++) { + void *stk = small_arraylist_pop(al); + free_stack(stk, pool_sizes[p]); + } + if (jl_atomic_load_relaxed(&ptls2->current_task) == NULL) { + small_arraylist_free(al); + } + } } - small_arraylist_t *buffers = &ptls->lazily_freed_mtarraylist_buffers; - void *buf; - while ((buf = small_arraylist_pop(buffers)) != NULL) { - free(buf); + if (jl_atomic_load_relaxed(&ptls2->current_task) == NULL) { + small_arraylist_free(ptls2->gc_tls_common.heap.free_stacks); } + + small_arraylist_t *live_tasks = &ptls2->gc_tls_common.heap.live_tasks; + size_t n = 0; + size_t ndel = 0; + size_t l = live_tasks->len; + void **lst = live_tasks->items; + if (l == 0) + continue; + while (1) { + jl_task_t *t = (jl_task_t*)lst[n]; + assert(jl_is_task(t)); + if (gc_marked(jl_astaggedvalue(t)->bits.gc)) { + if (t->ctx.stkbuf == NULL) + ndel++; // jl_release_task_stack called + else + n++; + } + else { + ndel++; + void *stkbuf = t->ctx.stkbuf; + size_t bufsz = t->ctx.bufsz; + if (stkbuf) { + t->ctx.stkbuf = NULL; + _jl_free_stack(ptls2, stkbuf, bufsz); + } +#ifdef _COMPILER_TSAN_ENABLED_ + if (t->ctx.tsan_state) { + __tsan_destroy_fiber(t->ctx.tsan_state); + t->ctx.tsan_state = NULL; + } +#endif + } + if (n >= l - ndel) + break; + void *tmp = lst[n]; + lst[n] = lst[n + ndel]; + lst[n + ndel] = tmp; + } + live_tasks->len -= ndel; } + jl_atomic_fetch_add(&gc_n_threads_sweeping_stacks, -1); } -void sweep_stack_pools_and_mtarraylist_buffers(jl_ptls_t ptls) JL_NOTSAFEPOINT +JL_DLLEXPORT void jl_gc_sweep_stack_pools_and_mtarraylist_buffers(jl_ptls_t ptls) JL_NOTSAFEPOINT { // initialize ptls index for parallel sweeping of stack pools assert(gc_n_threads); @@ -3090,7 +3170,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) current_sweep_full = sweep_full; sweep_weak_refs(); uint64_t stack_pool_time = jl_hrtime(); - sweep_stack_pools_and_mtarraylist_buffers(ptls); + jl_gc_sweep_stack_pools_and_mtarraylist_buffers(ptls); stack_pool_time = jl_hrtime() - stack_pool_time; gc_num.total_stack_pool_sweep_time += stack_pool_time; gc_num.stack_pool_sweep_time = stack_pool_time; @@ -3648,61 +3728,6 @@ JL_DLLEXPORT uint64_t jl_gc_get_max_memory(void) // allocation wrappers that add to gc pressure -JL_DLLEXPORT void *jl_malloc(size_t sz) -{ - return jl_gc_counted_malloc(sz); -} - -//_unchecked_calloc does not check for potential overflow of nm*sz -STATIC_INLINE void *_unchecked_calloc(size_t nm, size_t sz) { - size_t nmsz = nm*sz; - return jl_gc_counted_calloc(nmsz, 1); -} - -JL_DLLEXPORT void *jl_calloc(size_t nm, size_t sz) -{ - if (nm > SSIZE_MAX/sz) - return NULL; - return _unchecked_calloc(nm, sz); -} - -JL_DLLEXPORT void jl_free(void *p) -{ - if (p != NULL) { - size_t sz = memory_block_usable_size(p, 0); - free(p); - jl_task_t *ct = jl_get_current_task(); - if (ct != NULL) - jl_batch_accum_free_size(ct->ptls, sz); - } -} - -JL_DLLEXPORT void *jl_realloc(void *p, size_t sz) -{ - size_t old = p ? memory_block_usable_size(p, 0) : 0; - void *data = realloc(p, sz); - jl_task_t *ct = jl_get_current_task(); - if (data != NULL && ct != NULL) { - sz = memory_block_usable_size(data, 0); - jl_ptls_t ptls = ct->ptls; - maybe_collect(ptls); - if (!(sz < old)) - jl_atomic_store_relaxed(&ptls->gc_tls_common.gc_num.allocd, - jl_atomic_load_relaxed(&ptls->gc_tls_common.gc_num.allocd) + (sz - old)); - jl_atomic_store_relaxed(&ptls->gc_tls_common.gc_num.realloc, - jl_atomic_load_relaxed(&ptls->gc_tls_common.gc_num.realloc) + 1); - - int64_t diff = sz - old; - if (diff < 0) { - jl_batch_accum_free_size(ptls, -diff); - } - else { - jl_batch_accum_heap_size(ptls, diff); - } - } - return data; -} - JL_DLLEXPORT void *jl_gc_counted_malloc(size_t sz) { void *data = malloc(sz); @@ -3739,12 +3764,34 @@ JL_DLLEXPORT void *jl_gc_counted_calloc(size_t nm, size_t sz) JL_DLLEXPORT void jl_gc_counted_free_with_size(void *p, size_t sz) { - return jl_free(p); + free(p); + jl_task_t *ct = jl_get_current_task(); + if (ct != NULL) + jl_batch_accum_free_size(ct->ptls, sz); } JL_DLLEXPORT void *jl_gc_counted_realloc_with_old_size(void *p, size_t old, size_t sz) { - return jl_realloc(p, sz); + void *data = realloc(p, sz); + jl_task_t *ct = jl_get_current_task(); + if (data != NULL && ct != NULL) { + sz = memory_block_usable_size(data, 0); + jl_ptls_t ptls = ct->ptls; + maybe_collect(ptls); + if (!(sz < old)) + jl_atomic_store_relaxed(&ptls->gc_tls_common.gc_num.allocd, + jl_atomic_load_relaxed(&ptls->gc_tls_common.gc_num.allocd) + (sz - old)); + jl_atomic_store_relaxed(&ptls->gc_tls_common.gc_num.realloc, + jl_atomic_load_relaxed(&ptls->gc_tls_common.gc_num.realloc) + 1); + int64_t diff = sz - old; + if (diff < 0) { + jl_batch_accum_free_size(ptls, -diff); + } + else { + jl_batch_accum_heap_size(ptls, diff); + } + } + return data; } // allocating blocks for Arrays and Strings @@ -4008,12 +4055,20 @@ JL_DLLEXPORT size_t jl_gc_external_obj_hdr_size(void) return sizeof(bigval_t); } - JL_DLLEXPORT void jl_gc_schedule_foreign_sweepfunc(jl_ptls_t ptls, jl_value_t *obj) { arraylist_push(&ptls->gc_tls.sweep_objs, obj); } +void jl_gc_notify_image_load(const char* img_data, size_t len) +{ + // Do nothing +} + +JL_DLLEXPORT const char* jl_gc_active_impl(void) { + return "Built with stock GC"; +} + #ifdef __cplusplus } #endif diff --git a/src/gc-stock.h b/src/gc-stock.h index b9a2e720f120a..d478ee1366da0 100644 --- a/src/gc-stock.h +++ b/src/gc-stock.h @@ -5,7 +5,6 @@ . non-moving, precise mark and sweep collector . pool-allocates small objects, keeps big objects on a simple list */ - #ifndef JL_GC_H #define JL_GC_H @@ -20,6 +19,7 @@ #include "julia_internal.h" #include "julia_assert.h" #include "threading.h" +#include "gc-common.h" #ifdef __cplusplus extern "C" { @@ -85,27 +85,6 @@ typedef struct _jl_gc_chunk_t { extern uintptr_t gc_bigval_sentinel_tag; -JL_EXTENSION typedef struct _bigval_t { - struct _bigval_t *next; - struct _bigval_t *prev; - size_t sz; -#ifdef _P64 // Add padding so that the value is 64-byte aligned - // (8 pointers of 8 bytes each) - (4 other pointers in struct) - void *_padding[8 - 4]; -#else - // (16 pointers of 4 bytes each) - (4 other pointers in struct) - void *_padding[16 - 4]; -#endif - //struct jl_taggedvalue_t <>; - union { - uintptr_t header; - struct { - uintptr_t gc:2; - } bits; - }; - // must be 64-byte aligned here, in 32 & 64 bit modes -} bigval_t; - // pool page metadata typedef struct _jl_gc_pagemeta_t { // next metadata structure in per-thread list @@ -519,9 +498,6 @@ extern uv_cond_t gc_threads_cond; 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) gc_n_threads_sweeping_stacks; -extern _Atomic(int) gc_ptls_sweep_idx; -extern _Atomic(int) gc_stack_free_idx; extern _Atomic(int) n_threads_running; extern uv_barrier_t thread_init_done; void gc_mark_queue_all_roots(jl_ptls_t ptls, jl_gc_markqueue_t *mq); diff --git a/src/gc-tls-mmtk.h b/src/gc-tls-mmtk.h new file mode 100644 index 0000000000000..5b69aef5d55fb --- /dev/null +++ b/src/gc-tls-mmtk.h @@ -0,0 +1,23 @@ +// This file is a part of Julia. License is MIT: https://julialang.org/license + +#ifndef JL_GC_TLS_H +#define JL_GC_TLS_H + +#include +#include "mmtkMutator.h" +#include "julia_atomics.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + MMTkMutatorContext mmtk_mutator; + _Atomic(size_t) malloc_sz_since_last_poll; +} jl_gc_tls_states_t; + +#ifdef __cplusplus +} +#endif + +#endif // JL_GC_TLS_H diff --git a/src/gc-tls.h b/src/gc-tls-stock.h similarity index 100% rename from src/gc-tls.h rename to src/gc-tls-stock.h diff --git a/src/julia_internal.h b/src/julia_internal.h index 446e313fbe03d..86043b9f07df7 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -226,7 +226,7 @@ extern volatile int profile_all_tasks; // 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. -// Because of that, this lock must be held in `jl_profile_task` and `sweep_stack_pools_and_mtarraylist_buffers`. +// Because of that, this lock must be held in `jl_profile_task` and `jl_gc_sweep_stack_pools_and_mtarraylist_buffers`. extern uv_mutex_t live_tasks_lock; // Ensures that we can safely write to `profile_bt_data_prof` and `profile_bt_size_cur`. // We want to avoid the case that: diff --git a/src/julia_locks.h b/src/julia_locks.h index 35bcf7dd97322..92d67b34b1692 100644 --- a/src/julia_locks.h +++ b/src/julia_locks.h @@ -116,7 +116,7 @@ class jl_unique_gcsafe_lock { { jl_task_t *ct = jl_current_task; gc_state = jl_gc_safe_enter(ct->ptls); // contains jl_gc_safepoint after enter - this->native = std::unique_lock(native); + this->native = std::unique_lock(native); ct->ptls->engine_nqueued++; // disables finalizers until inference is finished on this method graph } jl_unique_gcsafe_lock(jl_unique_gcsafe_lock &&native) = delete; diff --git a/src/julia_threads.h b/src/julia_threads.h index faa8ab9e0aaf4..b6ef65dc7fe52 100644 --- a/src/julia_threads.h +++ b/src/julia_threads.h @@ -4,7 +4,11 @@ #ifndef JL_THREADS_H #define JL_THREADS_H -#include "gc-tls.h" +#ifndef MMTK_GC +#include "gc-tls-stock.h" +#else +#include "gc-tls-mmtk.h" +#endif #include "gc-tls-common.h" #include "julia_atomics.h" #ifndef _OS_WINDOWS_ diff --git a/src/llvm-gc-interface-passes.h b/src/llvm-gc-interface-passes.h index 278987858eab7..7b2a4bb033203 100644 --- a/src/llvm-gc-interface-passes.h +++ b/src/llvm-gc-interface-passes.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -328,6 +329,7 @@ struct LateLowerGCFrame: private JuliaPassContext { private: CallInst *pgcstack; + Function *smallAllocFunc; void MaybeNoteDef(State &S, BBState &BBS, Value *Def, const ArrayRef &SafepointsSoFar, SmallVector &&RefinedPtr = SmallVector()); @@ -366,6 +368,7 @@ struct LateLowerGCFrame: private JuliaPassContext { void RefineLiveSet(LargeSparseBitVector &LS, State &S, ArrayRef CalleeRoots); Value *EmitTagPtr(IRBuilder<> &builder, Type *T, Type *T_size, Value *V); Value *EmitLoadTag(IRBuilder<> &builder, Type *T_size, Value *V); + Value* lowerGCAllocBytesLate(CallInst *target, Function &F); }; // The final GC lowering pass. This pass lowers platform-agnostic GC diff --git a/src/llvm-late-gc-lowering-mmtk.cpp b/src/llvm-late-gc-lowering-mmtk.cpp new file mode 100644 index 0000000000000..5539c8dbcf153 --- /dev/null +++ b/src/llvm-late-gc-lowering-mmtk.cpp @@ -0,0 +1,96 @@ +// This file is a part of Julia. License is MIT: https://julialang.org/license + +#include "llvm-gc-interface-passes.h" + +Value* LateLowerGCFrame::lowerGCAllocBytesLate(CallInst *target, Function &F) +{ + assert(target->arg_size() == 3); + + IRBuilder<> builder(target); + auto ptls = target->getArgOperand(0); + auto type = target->getArgOperand(2); + if (auto CI = dyn_cast(target->getArgOperand(1))) { + size_t sz = (size_t)CI->getZExtValue(); + // This is strongly architecture and OS dependent + int osize; + int offset = jl_gc_classify_pools(sz, &osize); + if (offset >= 0) { + // In this case instead of lowering julia.gc_alloc_bytes to jl_gc_small_alloc + // We do a slowpath/fastpath check and lower it only on the slowpath, returning + // the cursor and updating it in the fastpath. + auto pool_osize_i32 = ConstantInt::get(Type::getInt32Ty(F.getContext()), osize); + auto pool_osize = ConstantInt::get(Type::getInt64Ty(F.getContext()), osize); + + // Should we generate fastpath allocation sequence here? We should always generate fastpath here for MMTk. + // Setting this to false will increase allocation overhead a lot, and should only be used for debugging. + const bool INLINE_FASTPATH_ALLOCATION = true; + + if (INLINE_FASTPATH_ALLOCATION) { + // Assuming we use the first immix allocator. + // FIXME: We should get the allocator index and type from MMTk. + auto allocator_offset = offsetof(jl_tls_states_t, gc_tls) + offsetof(jl_gc_tls_states_t, mmtk_mutator) + offsetof(MMTkMutatorContext, allocators) + offsetof(Allocators, immix); + + auto cursor_pos = ConstantInt::get(Type::getInt64Ty(target->getContext()), allocator_offset + offsetof(ImmixAllocator, cursor)); + auto limit_pos = ConstantInt::get(Type::getInt64Ty(target->getContext()), allocator_offset + offsetof(ImmixAllocator, limit)); + + auto cursor_ptr = builder.CreateInBoundsGEP(Type::getInt8Ty(target->getContext()), ptls, cursor_pos); + auto cursor = builder.CreateAlignedLoad(Type::getInt64Ty(target->getContext()), cursor_ptr, Align(sizeof(void *)), "cursor"); + + // offset = 8 + auto delta_offset = builder.CreateNSWSub(ConstantInt::get(Type::getInt64Ty(target->getContext()), 0), ConstantInt::get(Type::getInt64Ty(target->getContext()), 8)); + auto delta_cursor = builder.CreateNSWSub(ConstantInt::get(Type::getInt64Ty(target->getContext()), 0), cursor); + auto delta_op = builder.CreateNSWAdd(delta_offset, delta_cursor); + // alignment 16 (15 = 16 - 1) + auto delta = builder.CreateAnd(delta_op, ConstantInt::get(Type::getInt64Ty(target->getContext()), 15), "delta"); + auto result = builder.CreateNSWAdd(cursor, delta, "result"); + + auto new_cursor = builder.CreateNSWAdd(result, pool_osize); + + auto limit_ptr = builder.CreateInBoundsGEP(Type::getInt8Ty(target->getContext()), ptls, limit_pos); + auto limit = builder.CreateAlignedLoad(Type::getInt64Ty(target->getContext()), limit_ptr, Align(sizeof(void *)), "limit"); + + auto gt_limit = builder.CreateICmpSGT(new_cursor, limit); + + auto slowpath = BasicBlock::Create(target->getContext(), "slowpath", target->getFunction()); + auto fastpath = BasicBlock::Create(target->getContext(), "fastpath", target->getFunction()); + + auto next_instr = target->getNextNode(); + SmallVector Weights{1, 9}; + + MDBuilder MDB(F.getContext()); + SplitBlockAndInsertIfThenElse(gt_limit, next_instr, &slowpath, &fastpath, false, false, MDB.createBranchWeights(Weights)); + + builder.SetInsertPoint(next_instr); + auto phiNode = builder.CreatePHI(target->getCalledFunction()->getReturnType(), 2, "phi_fast_slow"); + + // slowpath + builder.SetInsertPoint(slowpath); + auto pool_offs = ConstantInt::get(Type::getInt32Ty(F.getContext()), 1); + auto new_call = builder.CreateCall(smallAllocFunc, { ptls, pool_offs, pool_osize_i32, type }); + new_call->setAttributes(new_call->getCalledFunction()->getAttributes()); + builder.CreateBr(next_instr->getParent()); + + // fastpath + builder.SetInsertPoint(fastpath); + builder.CreateStore(new_cursor, cursor_ptr); + + // ptls->gc_tls.gc_num.allocd += osize; + auto pool_alloc_pos = ConstantInt::get(Type::getInt64Ty(target->getContext()), offsetof(jl_tls_states_t, gc_tls_common) + offsetof(jl_gc_tls_states_common_t, gc_num)); + auto pool_alloc_tls = builder.CreateInBoundsGEP(Type::getInt8Ty(target->getContext()), ptls, pool_alloc_pos); + auto pool_allocd = builder.CreateAlignedLoad(Type::getInt64Ty(target->getContext()), pool_alloc_tls, Align(sizeof(void *))); + auto pool_allocd_total = builder.CreateAdd(pool_allocd, pool_osize); + builder.CreateStore(pool_allocd_total, pool_alloc_tls); + + auto v_raw = builder.CreateNSWAdd(result, ConstantInt::get(Type::getInt64Ty(target->getContext()), sizeof(jl_taggedvalue_t))); + auto v_as_ptr = builder.CreateIntToPtr(v_raw, smallAllocFunc->getReturnType()); + builder.CreateBr(next_instr->getParent()); + + phiNode->addIncoming(new_call, slowpath); + phiNode->addIncoming(v_as_ptr, fastpath); + phiNode->takeName(target); + return phiNode; + } + } + } + return target; +} diff --git a/src/llvm-late-gc-lowering-stock.cpp b/src/llvm-late-gc-lowering-stock.cpp new file mode 100644 index 0000000000000..2a11487773396 --- /dev/null +++ b/src/llvm-late-gc-lowering-stock.cpp @@ -0,0 +1,9 @@ +// This file is a part of Julia. License is MIT: https://julialang.org/license + +#include "llvm-gc-interface-passes.h" + +Value* LateLowerGCFrame::lowerGCAllocBytesLate(CallInst *target, Function &F) +{ + // Do nothing for the stock GC + return target; +} diff --git a/src/llvm-late-gc-lowering.cpp b/src/llvm-late-gc-lowering.cpp index ff2cac6e49406..7d6fba65a79e7 100644 --- a/src/llvm-late-gc-lowering.cpp +++ b/src/llvm-late-gc-lowering.cpp @@ -2446,6 +2446,7 @@ void LateLowerGCFrame::PlaceRootsAndUpdateCalls(ArrayRef Colors, int PreAss bool LateLowerGCFrame::runOnFunction(Function &F, bool *CFGModified) { initAll(*F.getParent()); + smallAllocFunc = getOrDeclare(jl_well_known::GCSmallAlloc); LLVM_DEBUG(dbgs() << "GC ROOT PLACEMENT: Processing function " << F.getName() << "\n"); if (!pgcstack_getter && !adoptthread_func) return CleanupIR(F, nullptr, CFGModified); @@ -2460,6 +2461,31 @@ bool LateLowerGCFrame::runOnFunction(Function &F, bool *CFGModified) { std::map> CallFrames; // = OptimizeCallFrames(S, Ordering); PlaceRootsAndUpdateCalls(Colors.first, Colors.second, S, CallFrames); CleanupIR(F, &S, CFGModified); + + + // We lower the julia.gc_alloc_bytes intrinsic in this pass to insert slowpath/fastpath blocks for MMTk + // For now, we do nothing for the Stock GC + auto GCAllocBytes = getOrNull(jl_intrinsics::GCAllocBytes); + + if (GCAllocBytes) { + for (auto it = GCAllocBytes->user_begin(); it != GCAllocBytes->user_end(); ) { + if (auto *CI = dyn_cast(*it)) { + *CFGModified = true; + + assert(CI->getCalledOperand() == GCAllocBytes); + + auto newI = lowerGCAllocBytesLate(CI, F); + if (newI != CI) { + ++it; + CI->replaceAllUsesWith(newI); + CI->eraseFromParent(); + continue; + } + } + ++it; + } + } + return true; } diff --git a/src/staticdata.c b/src/staticdata.c index ca335bd0fefee..95d7ee94e15dc 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -659,6 +659,7 @@ static void jl_load_sysimg_so(void) plen = (size_t *)&jl_system_image_size; else jl_dlsym(jl_sysimg_handle, "jl_system_image_size", (void **)&plen, 1); + jl_gc_notify_image_load(sysimg_data, *plen); jl_restore_system_image_data(sysimg_data, *plen); } @@ -4227,6 +4228,7 @@ JL_DLLEXPORT jl_value_t *jl_restore_package_image_from_file(const char *fname, j jl_dlsym(pkgimg_handle, "jl_system_image_data", (void **)&pkgimg_data, 1); size_t *plen; jl_dlsym(pkgimg_handle, "jl_system_image_size", (void **)&plen, 1); + jl_gc_notify_image_load(pkgimg_data, *plen); jl_image_t pkgimage = jl_init_processor_pkgimg(pkgimg_handle); diff --git a/src/threading.c b/src/threading.c index ac9cc276d613a..77956786af3f4 100644 --- a/src/threading.c +++ b/src/threading.c @@ -773,6 +773,10 @@ void jl_init_threading(void) } int16_t ngcthreads = jl_n_markthreads + jl_n_sweepthreads; + if (strstr(jl_gc_active_impl(), "MMTk")) { + ngcthreads = 0; + } + jl_all_tls_states_size = nthreads + nthreadsi + ngcthreads; jl_n_threads_per_pool = (int*)malloc_s(2 * sizeof(int)); jl_n_threads_per_pool[0] = nthreadsi; diff --git a/stdlib/InteractiveUtils/src/InteractiveUtils.jl b/stdlib/InteractiveUtils/src/InteractiveUtils.jl index aa13fa3cdd31d..4a320282610cd 100644 --- a/stdlib/InteractiveUtils/src/InteractiveUtils.jl +++ b/stdlib/InteractiveUtils/src/InteractiveUtils.jl @@ -166,6 +166,7 @@ function versioninfo(io::IO=stdout; verbose::Bool=false) end println(io, " WORD_SIZE: ", Sys.WORD_SIZE) println(io, " LLVM: libLLVM-",Base.libllvm_version," (", Sys.JIT, ", ", Sys.CPU_NAME, ")") + println(io, " GC: ", unsafe_string(ccall(:jl_gc_active_impl, Ptr{UInt8}, ()))) println(io, """Threads: $(Threads.nthreads(:default)) default, $(Threads.nthreads(:interactive)) interactive, \ $(Threads.ngcthreads()) GC (on $(Sys.CPU_THREADS) virtual cores)""") From ec2b509aa08196f1bd375ccbaf9a0367e1f2ed1c Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Tue, 7 Jan 2025 18:15:29 +0100 Subject: [PATCH 153/342] Give undefined constants their own binding kind (#56968) As noted in https://github.com/JuliaLang/julia/pull/56649#discussion_r1855089367, there needs to be a separate kind for undefined constants, so we know whether or not it is safe to call `partition_restriction`. --- base/runtime_internals.jl | 6 ++++-- base/show.jl | 6 ++++-- src/julia.h | 8 ++++++-- src/julia_internal.h | 19 ++++++++++++++++--- src/module.c | 5 ++++- src/toplevel.c | 7 +++---- 6 files changed, 37 insertions(+), 14 deletions(-) diff --git a/base/runtime_internals.jl b/base/runtime_internals.jl index 13c467667c51e..67694e533ac47 100644 --- a/base/runtime_internals.jl +++ b/base/runtime_internals.jl @@ -228,10 +228,12 @@ const BINDING_KIND_IMPORTED = 0x5 const BINDING_KIND_FAILED = 0x6 const BINDING_KIND_DECLARED = 0x7 const BINDING_KIND_GUARD = 0x8 +const BINDING_KIND_UNDEF_CONST = 0x9 -is_some_const_binding(kind::UInt8) = (kind == BINDING_KIND_CONST || kind == BINDING_KIND_CONST_IMPORT) +is_defined_const_binding(kind::UInt8) = (kind == BINDING_KIND_CONST || kind == BINDING_KIND_CONST_IMPORT) +is_some_const_binding(kind::UInt8) = (is_defined_const_binding(kind) || kind == BINDING_KIND_UNDEF_CONST) is_some_imported(kind::UInt8) = (kind == BINDING_KIND_IMPLICIT || kind == BINDING_KIND_EXPLICIT || kind == BINDING_KIND_IMPORTED) -is_some_guard(kind::UInt8) = (kind == BINDING_KIND_GUARD || kind == BINDING_KIND_DECLARED || kind == BINDING_KIND_FAILED) +is_some_guard(kind::UInt8) = (kind == BINDING_KIND_GUARD || kind == BINDING_KIND_DECLARED || kind == BINDING_KIND_FAILED || kind == BINDING_KIND_UNDEF_CONST) function lookup_binding_partition(world::UInt, b::Core.Binding) ccall(:jl_get_binding_partition, Ref{Core.BindingPartition}, (Any, UInt), b, world) diff --git a/base/show.jl b/base/show.jl index 381c0e7d1480a..de45ca07e3131 100644 --- a/base/show.jl +++ b/base/show.jl @@ -1045,7 +1045,7 @@ function check_world_bounded(tn::Core.TypeName) isdefined(bnd, :partitions) || return nothing partition = @atomic bnd.partitions while true - if is_some_const_binding(binding_kind(partition)) && partition_restriction(partition) <: tn.wrapper + if is_defined_const_binding(binding_kind(partition)) && partition_restriction(partition) <: tn.wrapper max_world = @atomic partition.max_world max_world == typemax(UInt) && return nothing return Int(partition.min_world):Int(max_world) @@ -3364,9 +3364,11 @@ function print_partition(io::IO, partition::Core.BindingPartition) end print(io, " - ") kind = binding_kind(partition) - if is_some_const_binding(kind) + if is_defined_const_binding(kind) print(io, "constant binding to ") print(io, partition_restriction(partition)) + elseif kind == BINDING_KIND_UNDEF_CONST + print(io, "undefined const binding") elseif kind == BINDING_KIND_GUARD print(io, "undefined binding - guard entry") elseif kind == BINDING_KIND_FAILED diff --git a/src/julia.h b/src/julia.h index 5cafc9bfa5232..bfa9d0857c73c 100644 --- a/src/julia.h +++ b/src/julia.h @@ -623,7 +623,7 @@ typedef struct _jl_weakref_t { // N.B: Needs to be synced with runtime_internals.jl enum jl_partition_kind { - // Constant: This binding partition is a constant declared using `const` + // Constant: This binding partition is a constant declared using `const _ = ...` // ->restriction holds the constant value BINDING_KIND_CONST = 0x0, // Import Constant: This binding partition is a constant declared using `import A` @@ -649,7 +649,11 @@ enum jl_partition_kind { BINDING_KIND_DECLARED = 0x7, // Guard: The binding was looked at, but no global or import was resolved at the time // ->restriction is NULL. - BINDING_KIND_GUARD = 0x8 + BINDING_KIND_GUARD = 0x8, + // Undef Constant: This binding partition is a constant declared using `const`, but + // without a value. + // ->restriction is NULL + BINDING_KIND_UNDEF_CONST = 0x9 }; #ifdef _P64 diff --git a/src/julia_internal.h b/src/julia_internal.h index 86043b9f07df7..b1c32f6e2de6e 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -924,8 +924,13 @@ EXTERN_INLINE_DECLARE enum jl_partition_kind decode_restriction_kind(jl_ptr_kind uint8_t bits = (pku & 0x7); jl_value_t *val = (jl_value_t*)(pku & ~0x7); - if (val == NULL && bits == BINDING_KIND_IMPLICIT) { - return BINDING_KIND_GUARD; + if (val == NULL) { + if (bits == BINDING_KIND_IMPLICIT) { + return BINDING_KIND_GUARD; + } + if (bits == BINDING_KIND_CONST) { + return BINDING_KIND_UNDEF_CONST; + } } return (enum jl_partition_kind)bits; @@ -947,10 +952,14 @@ STATIC_INLINE jl_value_t *decode_restriction_value(jl_ptr_kind_union_t JL_PROPAG STATIC_INLINE jl_ptr_kind_union_t encode_restriction(jl_value_t *val, enum jl_partition_kind kind) JL_NOTSAFEPOINT { #ifdef _P64 - if (kind == BINDING_KIND_GUARD || kind == BINDING_KIND_DECLARED || kind == BINDING_KIND_FAILED) + if (kind == BINDING_KIND_GUARD || kind == BINDING_KIND_DECLARED || kind == BINDING_KIND_FAILED || kind == BINDING_KIND_UNDEF_CONST) assert(val == NULL); + else if (kind == BINDING_KIND_IMPLICIT || kind == BINDING_KIND_CONST) + assert(val != NULL); if (kind == BINDING_KIND_GUARD) kind = BINDING_KIND_IMPLICIT; + else if (kind == BINDING_KIND_UNDEF_CONST) + kind = BINDING_KIND_CONST; assert((((uintptr_t)val) & 0x7) == 0); return ((jl_ptr_kind_union_t)val) | kind; #else @@ -964,6 +973,10 @@ STATIC_INLINE int jl_bkind_is_some_import(enum jl_partition_kind kind) JL_NOTSAF } STATIC_INLINE int jl_bkind_is_some_constant(enum jl_partition_kind kind) JL_NOTSAFEPOINT { + return kind == BINDING_KIND_CONST || kind == BINDING_KIND_CONST_IMPORT || kind == BINDING_KIND_UNDEF_CONST; +} + +STATIC_INLINE int jl_bkind_is_defined_constant(enum jl_partition_kind kind) JL_NOTSAFEPOINT { return kind == BINDING_KIND_CONST || kind == BINDING_KIND_CONST_IMPORT; } diff --git a/src/module.c b/src/module.c index df90180901f2c..1b4c5bd78f667 100644 --- a/src/module.c +++ b/src/module.c @@ -400,7 +400,10 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_resolved(jl_binding_t *b) JL_DLLEXPORT jl_value_t *jl_bpart_get_restriction_value(jl_binding_partition_t *bpart) { jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - return decode_restriction_value(pku); + jl_value_t *v = decode_restriction_value(pku); + if (!v) + jl_throw(jl_undefref_exception); + return v; } typedef struct _modstack_t { diff --git a/src/toplevel.c b/src/toplevel.c index 11e1f9ad521a1..0f8fae8939faf 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -157,7 +157,7 @@ static jl_value_t *jl_eval_module_expr(jl_module_t *parent_module, jl_expr_t *ex else { jl_binding_t *b = jl_get_module_binding(parent_module, name, 1); jl_binding_partition_t *bpart = jl_get_binding_partition(b, ct->world_age); - jl_ptr_kind_union_t pku = encode_restriction(NULL, BINDING_KIND_CONST); + jl_ptr_kind_union_t pku = encode_restriction(NULL, BINDING_KIND_UNDEF_CONST); jl_ptr_kind_union_t new_pku = encode_restriction((jl_value_t*)newm, BINDING_KIND_CONST); if (!jl_atomic_cmpswap(&bpart->restriction, &pku, new_pku)) { if (decode_restriction_kind(pku) != BINDING_KIND_CONST) { @@ -749,8 +749,7 @@ JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val2(jl_binding_t *b, j while (1) { if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) { if (!val) { - JL_GC_POP(); - return bpart; + break; } jl_value_t *old = decode_restriction_value(pku); JL_GC_PROMISE_ROOTED(old); @@ -787,7 +786,7 @@ JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val2(jl_binding_t *b, j JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *val) { - return jl_declare_constant_val2(b, mod, var, val, BINDING_KIND_CONST); + return jl_declare_constant_val2(b, mod, var, val, val ? BINDING_KIND_CONST : BINDING_KIND_UNDEF_CONST); } JL_DLLEXPORT void jl_eval_const_decl(jl_module_t *m, jl_value_t *arg, jl_value_t *val) From 70aef64661235feb4a8ed38b41b806026f7922cd Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Tue, 7 Jan 2025 18:25:11 -0400 Subject: [PATCH 154/342] Properly mark `Meta.parse` as public (#56931) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is to remove the warning that the symbol is internal when checking the docstring for `Meta.parse` since it’s in the documentation. --- base/meta.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/base/meta.jl b/base/meta.jl index 0078e15bcd98b..85b54e8225d4e 100644 --- a/base/meta.jl +++ b/base/meta.jl @@ -16,6 +16,8 @@ export quot, show_sexpr, @dump +public parse + using Base: isidentifier, isoperator, isunaryoperator, isbinaryoperator, ispostfixoperator import Base: isexpr From d54f246b9c18d9730b1a7a47c815db5cd5b49f1c Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Tue, 7 Jan 2025 19:27:14 -0500 Subject: [PATCH 155/342] remove debug print call in `process_sysimg_args!` (#56983) I assume leaving this in was not intentional? --- base/Base_compiler.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/base/Base_compiler.jl b/base/Base_compiler.jl index 6582fe87e2045..91f327980389d 100644 --- a/base/Base_compiler.jl +++ b/base/Base_compiler.jl @@ -276,7 +276,6 @@ baremodule BuildSettings end function process_sysimg_args!() let i = 2 # skip file name while i <= length(Core.ARGS) - Core.println(Core.ARGS[i]) if Core.ARGS[i] == "--buildsettings" include(BuildSettings, ARGS[i+1]) elseif Core.ARGS[i] == "--buildroot" From fe1ed74032f8769e65ac9326190a38c70c2fff06 Mon Sep 17 00:00:00 2001 From: FX Coudert Date: Wed, 8 Jan 2025 02:35:53 +0100 Subject: [PATCH 156/342] Update suitesparse to 7.8.3 (#56959) New version: https://github.com/DrTimothyAldenDavis/SuiteSparse/releases/tag/v7.8.3 --- deps/checksums/suitesparse | 76 +++++++++++++++-------------- deps/libsuitesparse.version | 4 +- stdlib/Manifest.toml | 2 +- stdlib/SuiteSparse_jll/Project.toml | 2 +- 4 files changed, 44 insertions(+), 40 deletions(-) diff --git a/deps/checksums/suitesparse b/deps/checksums/suitesparse index bac143325196f..f4e47961d8cc3 100644 --- a/deps/checksums/suitesparse +++ b/deps/checksums/suitesparse @@ -1,36 +1,40 @@ -SuiteSparse-7.8.0.tar.gz/md5/ad42a80d28bb56a1fce15f6e7332e04e -SuiteSparse-7.8.0.tar.gz/sha512/91aff0aee26e938ba88a8f92db15b0db0ecc6ada3b60153bb299f53a45ccda131db4bc66f890c220034c900180d0bb3a5fb3e2686fec7d6174f5900a3ee64424 -SuiteSparse.v7.8.0+1.aarch64-apple-darwin.tar.gz/md5/38379e14a53663a9c23f32ed56801676 -SuiteSparse.v7.8.0+1.aarch64-apple-darwin.tar.gz/sha512/3f2a7aa7778a22d150bad9ecb8d03edfa75707a07545e65660c8ccc4b0a9fb058ccab29e21e4728741d40d390d28922d521d3841e16258cf8e26acacadfc1fbd -SuiteSparse.v7.8.0+1.aarch64-linux-gnu.tar.gz/md5/bc52c7df0a442c0fb9aafb83d60878f4 -SuiteSparse.v7.8.0+1.aarch64-linux-gnu.tar.gz/sha512/436e79ea0774d6ffb571b513e385ef48d9cc70b72010cffdc23d606ad6c8984c8b49e2422ce8881def0722f3f608e4ecb87e6752dd80cf7988addd330c5ded13 -SuiteSparse.v7.8.0+1.aarch64-linux-musl.tar.gz/md5/87e4c2588efc39723621ac5010ddf2e5 -SuiteSparse.v7.8.0+1.aarch64-linux-musl.tar.gz/sha512/17115826716bb48f16e4593941be275d47012d112e54d8826c75fde119ffc9f66accd02353b309365b59779d7af3ac220f31ab7cf7eea165b209a93ecdc4102f -SuiteSparse.v7.8.0+1.aarch64-unknown-freebsd.tar.gz/md5/108a78ec5d21c910b1f0d3cd58b2b18e -SuiteSparse.v7.8.0+1.aarch64-unknown-freebsd.tar.gz/sha512/730f93e317305073acda619044296eb1844bc1380719a9c2f2f255bebd7c0c827317ff99ce06a081521f9441c3ca7fbcb2362a310ef3c5d289f485b2628c3d80 -SuiteSparse.v7.8.0+1.armv6l-linux-gnueabihf.tar.gz/md5/b1490603aa129942d8e4c9581853cd0a -SuiteSparse.v7.8.0+1.armv6l-linux-gnueabihf.tar.gz/sha512/e23c3532784e295ae72b811d285c3729c3f8ac1b5ee1621e831b6b2824a5b357e4bfa49e09174de7763fc3ebcab6b84ef16536bc1cf6f4bc0543b1b229209178 -SuiteSparse.v7.8.0+1.armv6l-linux-musleabihf.tar.gz/md5/f8199358882f76dd30bcce741b837de1 -SuiteSparse.v7.8.0+1.armv6l-linux-musleabihf.tar.gz/sha512/2c8d4ec21bfe253d3d32a5f5f09601b9b2864149f63f53067b157f5f7315fb04236bf5b19a1e5b4569e2c73127dcbb1703d56c7d06fc3ab9ae155902b7a1c2a9 -SuiteSparse.v7.8.0+1.armv7l-linux-gnueabihf.tar.gz/md5/cc3aa1a013cc91e7076dddf20fba9f60 -SuiteSparse.v7.8.0+1.armv7l-linux-gnueabihf.tar.gz/sha512/a6b8cfbc345a089f12e55d8d44061dcce30f94c2d79fc520d6c5dfe433ac2e362d049fac72278cb59d4b3760ca08d5e350b7e2658fa5e8c77ce8608f67c2c4c4 -SuiteSparse.v7.8.0+1.armv7l-linux-musleabihf.tar.gz/md5/0d7797d31c30c53bf219cdc0a48e64dc -SuiteSparse.v7.8.0+1.armv7l-linux-musleabihf.tar.gz/sha512/a7df8938ee6a04f62169bedd29c8408951cf33a43e0f529fb4d1e360bdad6462a50b2af297adb5f51fd726e1ced1fc8fcda7feeeafbeb44000bfe02a8e29c29e -SuiteSparse.v7.8.0+1.i686-linux-gnu.tar.gz/md5/e48fa3d2e00f210e964c21e4ff27efae -SuiteSparse.v7.8.0+1.i686-linux-gnu.tar.gz/sha512/3088c2af476285eb8549cf6aa56381156d49513a274348f86fbf01aa9ce0712961471f83fa50b261f3f365a302b88eb20ef0bb35b58c07a2cfb5dc337fdb72c1 -SuiteSparse.v7.8.0+1.i686-linux-musl.tar.gz/md5/e55202dbeca107a0c25a4f09d5d68915 -SuiteSparse.v7.8.0+1.i686-linux-musl.tar.gz/sha512/0f4de2e62016914b4d1bcb9b13bd8cb2bebefc5f0a532e103948b9aae79a20462ac7b74a3e968d4f99076c37dbbafb747699cd151e831ff89d297f78478fb84f -SuiteSparse.v7.8.0+1.i686-w64-mingw32.tar.gz/md5/e8f4de53ec4ae74554e76bd52702d7a4 -SuiteSparse.v7.8.0+1.i686-w64-mingw32.tar.gz/sha512/f944f14e62408f04a9966cd927cbbbe26b00a4beccc85ab8923dc4028875b0395c6b5e56efba1fd2f29fb954543ca83e800685ffafcdfdd97351a7d4926349a8 -SuiteSparse.v7.8.0+1.powerpc64le-linux-gnu.tar.gz/md5/12058f122b548a37070770d1847f3ce9 -SuiteSparse.v7.8.0+1.powerpc64le-linux-gnu.tar.gz/sha512/f375feeb8448ea90ce8d9f31c7e1230f6868316f06094ba0155069dded4f8da2e1b54d462ef9cfc77abd76147740d4066236dcf1fcea91f8a7141819962ad0ae -SuiteSparse.v7.8.0+1.x86_64-apple-darwin.tar.gz/md5/1bd473f2a25f1ebcea8acc858e2594b4 -SuiteSparse.v7.8.0+1.x86_64-apple-darwin.tar.gz/sha512/034af137deee5bf0ebf3746745d09ad50ce135cd4768a2049bb9811478ff90e6ed8e2c990e277b4c3b38a3a5e9eaa856938eb86239ca445fa64b6dab6af7e996 -SuiteSparse.v7.8.0+1.x86_64-linux-gnu.tar.gz/md5/c58a86d9f25e6705941105d9e41f084c -SuiteSparse.v7.8.0+1.x86_64-linux-gnu.tar.gz/sha512/56447062802f01815ffb014624423c6fd3ab6e16b642b2fe37972a151b02865965c95ca3d1a455c6d51cd31633aea8a732b235b55d68e6779c17b293c488fa43 -SuiteSparse.v7.8.0+1.x86_64-linux-musl.tar.gz/md5/ba6e10ba61c209df94f18ab51fe2dd90 -SuiteSparse.v7.8.0+1.x86_64-linux-musl.tar.gz/sha512/3b8fc504cfb4a3b628d5b955a482bad08c85e09e529f833855a84b847721247aaa469f96adef6b218a1ba5896cde91664cc819ba33115e3cc309e72140841ca3 -SuiteSparse.v7.8.0+1.x86_64-unknown-freebsd.tar.gz/md5/a50c69142a42c14edac4ce94b86b138a -SuiteSparse.v7.8.0+1.x86_64-unknown-freebsd.tar.gz/sha512/963be0dccd1a594df08fe5135ef4ac13e1d707841c3e97d31ba5477d0d6ec26bad9be1c52d9fd78f199740a53950353adbdd767469f3bf01ea1e3ee843eb6c1a -SuiteSparse.v7.8.0+1.x86_64-w64-mingw32.tar.gz/md5/7ca11ba89bd09183cc5a9320d6e8a4a7 -SuiteSparse.v7.8.0+1.x86_64-w64-mingw32.tar.gz/sha512/e1d5def1103bbf0bb29c08cdd3bf21ba60456353694985c66f8e55a31d54a32c5b891e56e1ffe30f9e1223c49283d267e483e2f1b999f566099c239b3eed1d78 +SuiteSparse-7.8.3.tar.gz/md5/242e38ecfc8a3e3aa6b7d8d44849c5cf +SuiteSparse-7.8.3.tar.gz/sha512/fc0fd0aaf55a6712a3b8ca23bf7536a31d52033e090370ebbf291f05d0e073c7dcfd991a80b037f54663f524804582b87af86522c2e4435091527f0d3c189244 +SuiteSparse-e8285dd13a6d5b5cf52d8124793fc4d622d07554.tar.gz/md5/46541001073d1c3c85e18d910f8308f3 +SuiteSparse-e8285dd13a6d5b5cf52d8124793fc4d622d07554.tar.gz/sha512/f7470a447b934ca9315e216a07b97e363f11bc93186f9aa057b20b2d05092c58ae4f1b733de362de4a0730861c00be4ca5588d0b3ba65f018c1798b9122b9672 +SuiteSparse.v7.8.3+2.aarch64-apple-darwin.tar.gz/md5/e97424dc7b9e44cb18ca50b99d71a0a8 +SuiteSparse.v7.8.3+2.aarch64-apple-darwin.tar.gz/sha512/2d077c785fe1109ad83e001516394c027f0ba1d77186e73df3d89ee03aea7817f09e15c0b1302711aebd168e06675cc865e2936c4c654c9f65932434f974e9c6 +SuiteSparse.v7.8.3+2.aarch64-linux-gnu.tar.gz/md5/7b14b0fe44156b117ebee60811f666e6 +SuiteSparse.v7.8.3+2.aarch64-linux-gnu.tar.gz/sha512/dc726895c6f4c3e7a8d87507946cc0fd15e8d6c6d6d22698976df8c53aeec0532abb0c34bcb98767a6ee3b3146f60189a575a8e523be75b951d33535b6de5359 +SuiteSparse.v7.8.3+2.aarch64-linux-musl.tar.gz/md5/5a4e485cb6a7025196548e8bab4228c6 +SuiteSparse.v7.8.3+2.aarch64-linux-musl.tar.gz/sha512/9c091cd13b61a4d291751c294a080b95c9068b13bd805089c962e06fafdb12da08087709759d5310ceb2c115255b14c1a99c4ed45f660f8680dcc30f55ac6f49 +SuiteSparse.v7.8.3+2.aarch64-unknown-freebsd.tar.gz/md5/895f1b9b79455c3c26a9e3c64c335dc5 +SuiteSparse.v7.8.3+2.aarch64-unknown-freebsd.tar.gz/sha512/9876a711d79314dcf68bacf0460267f69474c736346bf9f098ed56c3430fca67d9b73d7d30fa6d3c5ac1cacb017f57be2d83b2310f695d51b73e3ce98234a10e +SuiteSparse.v7.8.3+2.armv6l-linux-gnueabihf.tar.gz/md5/9784404d2ff45a94a9ce9e671badcdf0 +SuiteSparse.v7.8.3+2.armv6l-linux-gnueabihf.tar.gz/sha512/8f49fc05c80f6b869810e5f128c04a5816ebc2ae24313ba699723be9550407a634486d0c95089325350381cd534d3e991cc07a80f509a612f6da27da32b1d6d0 +SuiteSparse.v7.8.3+2.armv6l-linux-musleabihf.tar.gz/md5/b26cdada5bd08e3284dd74e7bb14a770 +SuiteSparse.v7.8.3+2.armv6l-linux-musleabihf.tar.gz/sha512/78695ebab8c73bed06723e3052c471888e84e90681561e32469bac49784b8973af355a19db5ad3663373fde97b92ade112e48a0ece4209b9933c05faa9a7b83d +SuiteSparse.v7.8.3+2.armv7l-linux-gnueabihf.tar.gz/md5/4ae051735ae0c34ab2d5e1f0bec3f26c +SuiteSparse.v7.8.3+2.armv7l-linux-gnueabihf.tar.gz/sha512/efdd084c9bfac1cd9a4128aa7d6a4f0d682cd6c791dbcf1ed2f53b77f6e9c4ab9ed13f54ff6dc54603b5426bc09f7833defaca3d135cd1995d92a177d1d97eb0 +SuiteSparse.v7.8.3+2.armv7l-linux-musleabihf.tar.gz/md5/2e55d69017c5ec6fca694aabf1470dc1 +SuiteSparse.v7.8.3+2.armv7l-linux-musleabihf.tar.gz/sha512/1c75fa1536f5db13e1d613d61959dc1004570a5df45f75820f9554c7395f7492ad5edd5865d5b5c3f6aee65ffa33aa68dab1616547aeb7614da6bf708a748dc1 +SuiteSparse.v7.8.3+2.i686-linux-gnu.tar.gz/md5/817e2479c223e9c023ec431aea4b2361 +SuiteSparse.v7.8.3+2.i686-linux-gnu.tar.gz/sha512/c0e4482570bed4366f68df9635a6229289008c0754c3d636d26a44004e5c80ae04c6ab434b0dbf57baa05e4afc847716d9e059904faf9d10be7abdade2890803 +SuiteSparse.v7.8.3+2.i686-linux-musl.tar.gz/md5/e7a6c8f58a81e0ac511d44e878b9128d +SuiteSparse.v7.8.3+2.i686-linux-musl.tar.gz/sha512/54c00ba5bd8bb514e8cc29ce0ed596c642678ea1fe27571cbbb3210b9ad8940ecac2100e05b29d5db51804daab714c48d18dbf65650924b90c076078681990a3 +SuiteSparse.v7.8.3+2.i686-w64-mingw32.tar.gz/md5/3db74decc8363735a0a9f71f2558c2c9 +SuiteSparse.v7.8.3+2.i686-w64-mingw32.tar.gz/sha512/d5dc5e263a9705d2510f541ffe9c5a543a4a0ba7c104ad03142ef04de5a25cdb7da59eed3218cdf540b7b2167235206d438db283da682ba31568d99076fccece +SuiteSparse.v7.8.3+2.powerpc64le-linux-gnu.tar.gz/md5/78f008e14dfb2580da95ac58466d9d16 +SuiteSparse.v7.8.3+2.powerpc64le-linux-gnu.tar.gz/sha512/ea7370f5071c1e5bb2980f76f16ec88eded7fab6d7773c99fff9087adee446b5f4cefd16ff483aa92197fabea35cb3e486742a58fefa6fee0997a358ada14c8a +SuiteSparse.v7.8.3+2.riscv64-linux-gnu.tar.gz/md5/966c2093ab4d0652084652f54e58c5f7 +SuiteSparse.v7.8.3+2.riscv64-linux-gnu.tar.gz/sha512/febff4241ff15471a7a3bcb544a7e34ab71da1c516b3fcff89cd726d392c2fcea0bb970c8a2ee7a4461c341c7be02f47fcdc47f4a7f88307cceeb3f75327c625 +SuiteSparse.v7.8.3+2.x86_64-apple-darwin.tar.gz/md5/7a8b5ab88a83081545a411202caf5a1f +SuiteSparse.v7.8.3+2.x86_64-apple-darwin.tar.gz/sha512/186f5fb8a7117d8cf77b311ea0c137b270eca895aecd31dc616b86425c62ae3d0218938cf1cf54d5009b7ff8247f40ae21b6c452fdd339fead5622e710c03418 +SuiteSparse.v7.8.3+2.x86_64-linux-gnu.tar.gz/md5/001cb5ce58344f1186a51d6018a9c337 +SuiteSparse.v7.8.3+2.x86_64-linux-gnu.tar.gz/sha512/8cd407ff3e857cb49d26adde68746c0a73742c4556ab624b34eb5caa95a7c438d1aa6a7fb3b9d54341f0469ae7b19f78e09f2a2642f15f4795d9583162cf12e1 +SuiteSparse.v7.8.3+2.x86_64-linux-musl.tar.gz/md5/305e268c36927a94037419153d37fe91 +SuiteSparse.v7.8.3+2.x86_64-linux-musl.tar.gz/sha512/aebd921b721f8f71bbdc94aa60ae2f2c3bc5de21acbda0ae1e96e19dbc86c13cbe1921cd5938bbb4f9f83c84a2a6b4f980e743684e8236e7a979ead0042e9dec +SuiteSparse.v7.8.3+2.x86_64-unknown-freebsd.tar.gz/md5/81f85e3374a9b7bbe0a25b8cb88d3438 +SuiteSparse.v7.8.3+2.x86_64-unknown-freebsd.tar.gz/sha512/fb0b1c219d1ce35f79d945fccb5c5a2e1e8d9f32a2401dc3071781740c6c16e729746ffb02c76680e681f8978d19948b28612c97136f1396d030e69c3eb336d9 +SuiteSparse.v7.8.3+2.x86_64-w64-mingw32.tar.gz/md5/a3a68bafb213ea68006cdfdbb15e1457 +SuiteSparse.v7.8.3+2.x86_64-w64-mingw32.tar.gz/sha512/6db131bb8b0efbcbaf4ee9f2688dc1083a570da5fc9ddb044ffc9308fd5d6949241cd780e5246484ae6417b261bfd61683b6122c7dba7d1598d5e89be6d73acc diff --git a/deps/libsuitesparse.version b/deps/libsuitesparse.version index 6f841190cebc7..cc294f68c2d5a 100644 --- a/deps/libsuitesparse.version +++ b/deps/libsuitesparse.version @@ -4,5 +4,5 @@ LIBSUITESPARSE_JLL_NAME := SuiteSparse ## source build -LIBSUITESPARSE_VER := 7.8.0 -LIBSUITESPARSE_SHA1=58e6558408f6a51c08e35a5557d5e68cae32147e +LIBSUITESPARSE_VER := 7.8.3 +LIBSUITESPARSE_SHA1=d3c4926d2c47fd6ae558e898bfc072ade210a2a1 diff --git a/stdlib/Manifest.toml b/stdlib/Manifest.toml index 6743d357fb8b3..160ccac5ffa39 100644 --- a/stdlib/Manifest.toml +++ b/stdlib/Manifest.toml @@ -243,7 +243,7 @@ version = "1.11.0" [[deps.SuiteSparse_jll]] deps = ["Artifacts", "Libdl", "libblastrampoline_jll"] uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" -version = "7.8.0+1" +version = "7.8.3+2" [[deps.TOML]] deps = ["Dates"] diff --git a/stdlib/SuiteSparse_jll/Project.toml b/stdlib/SuiteSparse_jll/Project.toml index c91ef6743d653..3a1dc50a103fb 100644 --- a/stdlib/SuiteSparse_jll/Project.toml +++ b/stdlib/SuiteSparse_jll/Project.toml @@ -1,6 +1,6 @@ name = "SuiteSparse_jll" uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" -version = "7.8.0+1" +version = "7.8.3+2" [deps] libblastrampoline_jll = "8e850b90-86db-534c-a0d3-1478176c7d93" From 3c7bc45f14c8a2b70ccf1d92d4418cfaaa112b56 Mon Sep 17 00:00:00 2001 From: Alex Arslan Date: Tue, 7 Jan 2025 21:37:32 -0800 Subject: [PATCH 157/342] Update OpenLibm to 0.8.5 (#56984) This fixes building on FreeBSD AArch64, as there was a regression in OpenLibm 0.8.4; see https://github.com/JuliaMath/openlibm/pull/314. --- deps/checksums/openlibm | 76 ++++++++++++++++---------------- deps/openlibm.version | 6 +-- stdlib/Manifest.toml | 2 +- stdlib/OpenLibm_jll/Project.toml | 2 +- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/deps/checksums/openlibm b/deps/checksums/openlibm index 172d8ed3fb413..cad61fd42cf94 100644 --- a/deps/checksums/openlibm +++ b/deps/checksums/openlibm @@ -1,38 +1,38 @@ -OpenLibm.v0.8.4+1.aarch64-apple-darwin.tar.gz/md5/5fcbd746e90712e396e76dc4e76724d0 -OpenLibm.v0.8.4+1.aarch64-apple-darwin.tar.gz/sha512/f4ac2bc38bdc723384b67119daa2974fb43da34b2e45cea2029ea48f92c84c4cad6dfb43521b09a1e89ddf8c5b8cc22a38fa4b78ba39ac7524fd6bd1ba897aa9 -OpenLibm.v0.8.4+1.aarch64-linux-gnu.tar.gz/md5/e24c967d04812058b69b8c561f0d9f2a -OpenLibm.v0.8.4+1.aarch64-linux-gnu.tar.gz/sha512/8100dd7cfd9e02c9cfeade7627eb6105e86e8f5eb99026462a9a5370f8dd99ad981024a8904d2d7c341b113730f1b2312909d9c9c2c9b48dce74d3e80b266947 -OpenLibm.v0.8.4+1.aarch64-linux-musl.tar.gz/md5/6f9454c31b548f9fd47fb6318aab9b12 -OpenLibm.v0.8.4+1.aarch64-linux-musl.tar.gz/sha512/1769348f3e2227f307923b8c5656ab4c797daa8bd8bed61fbdf4c72d84ba9b7ae097392cdafd5e0cee0004f846e2c2ddbf9b5e7edb2406606b37c5ed665cc693 -OpenLibm.v0.8.4+1.aarch64-unknown-freebsd.tar.gz/md5/acce062e568325b675a6ed6a7a8fabbd -OpenLibm.v0.8.4+1.aarch64-unknown-freebsd.tar.gz/sha512/8ade1ae5ded62622a5159a0e60a8f6ad8345debda0da3eff764ea1e8a9937e686055e253612d83c4ee0035aa3dd2d6267d2dbd687cfcffbaffc17a7d7879e05f -OpenLibm.v0.8.4+1.armv6l-linux-gnueabihf.tar.gz/md5/8fe0900a318393a290907f016bc654c3 -OpenLibm.v0.8.4+1.armv6l-linux-gnueabihf.tar.gz/sha512/167100a2d46e68462ef9a66915ced881d6358f05337bd38f2f77176f41cfd5be37e3c5226dd5d7d59147bd3e1aa7fb0893c1c81e9516134d3ab663b5752c4969 -OpenLibm.v0.8.4+1.armv6l-linux-musleabihf.tar.gz/md5/e8566719387984604f19dc5f9354a783 -OpenLibm.v0.8.4+1.armv6l-linux-musleabihf.tar.gz/sha512/532dd2b764fa15f7a838fb14cccafd2d4fe8fa4a132ea8394479a719c7aee11442f1b8a18e5d4a26ca820fa696d9d2afc7f5ec63dd96fa3b6763cea72b7026c3 -OpenLibm.v0.8.4+1.armv7l-linux-gnueabihf.tar.gz/md5/8fe0900a318393a290907f016bc654c3 -OpenLibm.v0.8.4+1.armv7l-linux-gnueabihf.tar.gz/sha512/167100a2d46e68462ef9a66915ced881d6358f05337bd38f2f77176f41cfd5be37e3c5226dd5d7d59147bd3e1aa7fb0893c1c81e9516134d3ab663b5752c4969 -OpenLibm.v0.8.4+1.armv7l-linux-musleabihf.tar.gz/md5/e8566719387984604f19dc5f9354a783 -OpenLibm.v0.8.4+1.armv7l-linux-musleabihf.tar.gz/sha512/532dd2b764fa15f7a838fb14cccafd2d4fe8fa4a132ea8394479a719c7aee11442f1b8a18e5d4a26ca820fa696d9d2afc7f5ec63dd96fa3b6763cea72b7026c3 -OpenLibm.v0.8.4+1.i686-linux-gnu.tar.gz/md5/9580d34e69d6067427b9c33db631cfd3 -OpenLibm.v0.8.4+1.i686-linux-gnu.tar.gz/sha512/46934f82791f69ac5f5da0dab7dcc6e3e9a4577c3bb529e9c0519c38f140c7b54517c55ff3579cd4ed4df68f0863e006aa98e51873f1dab452ce9f853996429a -OpenLibm.v0.8.4+1.i686-linux-musl.tar.gz/md5/66bfc9611d04c5d609e7824cb076d24b -OpenLibm.v0.8.4+1.i686-linux-musl.tar.gz/sha512/1bda2395d44c22aba3d1aab2b08ae06f763d3755037d454aa73f8e8134289a1ab5d65862bbc5a17a7a6b9f2918eb87e926b21527ddc4471e2ea20d605ba14e2d -OpenLibm.v0.8.4+1.i686-w64-mingw32.tar.gz/md5/0e97311b2f08b57d79085635f01ccced -OpenLibm.v0.8.4+1.i686-w64-mingw32.tar.gz/sha512/ae061ea406c06969332af58ed6fdfce2825326d771d30274d90775a1709b0361b7ca1dc7e6b0b76b93e4dd7a81d1842510a2c835251ee0a0978d6c839d96070e -OpenLibm.v0.8.4+1.powerpc64le-linux-gnu.tar.gz/md5/8ecfff7db76eee29591a654871e88855 -OpenLibm.v0.8.4+1.powerpc64le-linux-gnu.tar.gz/sha512/af03993b162316dd581f6ba5d1c23bca4c26cb22356ab229f326c42e111acbdf7ef45c9ad05894fe2d68794a63670cf89888653f788192a38b9255ce4bc72e28 -OpenLibm.v0.8.4+1.riscv64-linux-gnu.tar.gz/md5/2d6ae40b640f7d39c20ec7d151d6972d -OpenLibm.v0.8.4+1.riscv64-linux-gnu.tar.gz/sha512/3a9b69601e7e1013f236c0d9f7326f371d65d9c1231d5848995ebd822fd1eff0bd5f6b771fe2c21191076902e6a7c4febb4822f78cc0d15bb7f59396d9728236 -OpenLibm.v0.8.4+1.x86_64-apple-darwin.tar.gz/md5/bd671ab9fe01835cab3e42e7cfa790fb -OpenLibm.v0.8.4+1.x86_64-apple-darwin.tar.gz/sha512/8bf2e66df17effc1e8778453904ffc20127f785bf096873289e8fdd8b17069ca844faffbd9f7621b87a7cb0a0051037eb9402360f2a03cf8794fbac8f7719777 -OpenLibm.v0.8.4+1.x86_64-linux-gnu.tar.gz/md5/df7fab134fbce3b625e9a82376f23e79 -OpenLibm.v0.8.4+1.x86_64-linux-gnu.tar.gz/sha512/64d07434e0db79833f84a2225838456eb9532617d377a776b3a534a908b1673bc4f890903f95350e4045e05c29539d993a18ecadeb879761e279ec3947f74390 -OpenLibm.v0.8.4+1.x86_64-linux-musl.tar.gz/md5/ebef6bb7651d116b397e035f39adfb1b -OpenLibm.v0.8.4+1.x86_64-linux-musl.tar.gz/sha512/de9036073e5dba2721b4119ecbbd21a0c9f75b65aff9392b7e88e464da35b97135d62404477441d0dadd3a2f8d49f1082291b35bf4b626fb1096d36d401980bf -OpenLibm.v0.8.4+1.x86_64-unknown-freebsd.tar.gz/md5/bc09186ae191700d6cf9162796bb23ba -OpenLibm.v0.8.4+1.x86_64-unknown-freebsd.tar.gz/sha512/6b7198cd68418e370348c7011a5f9ccf910b62c9482334601dea0749b683724ddb7414bde3d8da7a5123c0fadc3f93d02274538070330db6428dabca5d007835 -OpenLibm.v0.8.4+1.x86_64-w64-mingw32.tar.gz/md5/b6b5335f4c83f7ebf0f74cf753358f00 -OpenLibm.v0.8.4+1.x86_64-w64-mingw32.tar.gz/sha512/e8351ddda305b757f337bb7ea26c441968843b23861676f0bdd7bcf83bb3969af790d4112307d3204eb87fac044dda9be305f349700ebe9ba2bfe3d6df24fde8 -openlibm-c4667caea25ae3487adf6760b4a1dcf32477a4b8.tar.gz/md5/287cf81f6c6b67177b322f7cb5cc8279 -openlibm-c4667caea25ae3487adf6760b4a1dcf32477a4b8.tar.gz/sha512/3c3efa8cb344719c2b6df45fbfe178efac6239cac12fc32dcc92074431d2e1a3039a60649cf3525424e0990081b6d40acb12176316c4ccb2940add0bb3a41e85 +OpenLibm.v0.8.5+0.aarch64-apple-darwin.tar.gz/md5/5fcbd746e90712e396e76dc4e76724d0 +OpenLibm.v0.8.5+0.aarch64-apple-darwin.tar.gz/sha512/f4ac2bc38bdc723384b67119daa2974fb43da34b2e45cea2029ea48f92c84c4cad6dfb43521b09a1e89ddf8c5b8cc22a38fa4b78ba39ac7524fd6bd1ba897aa9 +OpenLibm.v0.8.5+0.aarch64-linux-gnu.tar.gz/md5/4d1b4cd566805b5179c5ecdd060da473 +OpenLibm.v0.8.5+0.aarch64-linux-gnu.tar.gz/sha512/a9fe1a3d2e3898c017eb8615b2f3dbb514995ff041ac964c931c99c60d8cfe4eab7563a9cd65058f42f83c812f33d998573a7c5cc56a2e3960a4657e459ed321 +OpenLibm.v0.8.5+0.aarch64-linux-musl.tar.gz/md5/413be59af62b3ce0ebafeca093e3179e +OpenLibm.v0.8.5+0.aarch64-linux-musl.tar.gz/sha512/7bd76373e047ba854066af61f1c56b2e3a4d28c266228d7b30f596eadbaec52b070548ae60d41840c425ad5d0829c6c0cdaf326f2f160ed7508877ab5ec1a4b1 +OpenLibm.v0.8.5+0.aarch64-unknown-freebsd.tar.gz/md5/80736f9022c695eb1198e0b591a8fa63 +OpenLibm.v0.8.5+0.aarch64-unknown-freebsd.tar.gz/sha512/c633644578265e7ccc259ceb0442457b8c09290b4861b66c86dd6be7b30c4e394e70728142798097d6fe3afcfb4d9d1bd7ef58513fe8eed5684a4fba51bf185a +OpenLibm.v0.8.5+0.armv6l-linux-gnueabihf.tar.gz/md5/8fe0900a318393a290907f016bc654c3 +OpenLibm.v0.8.5+0.armv6l-linux-gnueabihf.tar.gz/sha512/167100a2d46e68462ef9a66915ced881d6358f05337bd38f2f77176f41cfd5be37e3c5226dd5d7d59147bd3e1aa7fb0893c1c81e9516134d3ab663b5752c4969 +OpenLibm.v0.8.5+0.armv6l-linux-musleabihf.tar.gz/md5/e8566719387984604f19dc5f9354a783 +OpenLibm.v0.8.5+0.armv6l-linux-musleabihf.tar.gz/sha512/532dd2b764fa15f7a838fb14cccafd2d4fe8fa4a132ea8394479a719c7aee11442f1b8a18e5d4a26ca820fa696d9d2afc7f5ec63dd96fa3b6763cea72b7026c3 +OpenLibm.v0.8.5+0.armv7l-linux-gnueabihf.tar.gz/md5/8fe0900a318393a290907f016bc654c3 +OpenLibm.v0.8.5+0.armv7l-linux-gnueabihf.tar.gz/sha512/167100a2d46e68462ef9a66915ced881d6358f05337bd38f2f77176f41cfd5be37e3c5226dd5d7d59147bd3e1aa7fb0893c1c81e9516134d3ab663b5752c4969 +OpenLibm.v0.8.5+0.armv7l-linux-musleabihf.tar.gz/md5/e8566719387984604f19dc5f9354a783 +OpenLibm.v0.8.5+0.armv7l-linux-musleabihf.tar.gz/sha512/532dd2b764fa15f7a838fb14cccafd2d4fe8fa4a132ea8394479a719c7aee11442f1b8a18e5d4a26ca820fa696d9d2afc7f5ec63dd96fa3b6763cea72b7026c3 +OpenLibm.v0.8.5+0.i686-linux-gnu.tar.gz/md5/9580d34e69d6067427b9c33db631cfd3 +OpenLibm.v0.8.5+0.i686-linux-gnu.tar.gz/sha512/46934f82791f69ac5f5da0dab7dcc6e3e9a4577c3bb529e9c0519c38f140c7b54517c55ff3579cd4ed4df68f0863e006aa98e51873f1dab452ce9f853996429a +OpenLibm.v0.8.5+0.i686-linux-musl.tar.gz/md5/66bfc9611d04c5d609e7824cb076d24b +OpenLibm.v0.8.5+0.i686-linux-musl.tar.gz/sha512/1bda2395d44c22aba3d1aab2b08ae06f763d3755037d454aa73f8e8134289a1ab5d65862bbc5a17a7a6b9f2918eb87e926b21527ddc4471e2ea20d605ba14e2d +OpenLibm.v0.8.5+0.i686-w64-mingw32.tar.gz/md5/0e97311b2f08b57d79085635f01ccced +OpenLibm.v0.8.5+0.i686-w64-mingw32.tar.gz/sha512/ae061ea406c06969332af58ed6fdfce2825326d771d30274d90775a1709b0361b7ca1dc7e6b0b76b93e4dd7a81d1842510a2c835251ee0a0978d6c839d96070e +OpenLibm.v0.8.5+0.powerpc64le-linux-gnu.tar.gz/md5/8ecfff7db76eee29591a654871e88855 +OpenLibm.v0.8.5+0.powerpc64le-linux-gnu.tar.gz/sha512/af03993b162316dd581f6ba5d1c23bca4c26cb22356ab229f326c42e111acbdf7ef45c9ad05894fe2d68794a63670cf89888653f788192a38b9255ce4bc72e28 +OpenLibm.v0.8.5+0.riscv64-linux-gnu.tar.gz/md5/69e06de135940666791c984941e9c4ad +OpenLibm.v0.8.5+0.riscv64-linux-gnu.tar.gz/sha512/2ac84deb7eb80a6a6237eff6fe861fd2907b3c95d1a76366dea062f3f35228dbc67aa40bd982e646508b4ff7cb6ef029111e2c0325039e60679800d6c6886be5 +OpenLibm.v0.8.5+0.x86_64-apple-darwin.tar.gz/md5/bd671ab9fe01835cab3e42e7cfa790fb +OpenLibm.v0.8.5+0.x86_64-apple-darwin.tar.gz/sha512/8bf2e66df17effc1e8778453904ffc20127f785bf096873289e8fdd8b17069ca844faffbd9f7621b87a7cb0a0051037eb9402360f2a03cf8794fbac8f7719777 +OpenLibm.v0.8.5+0.x86_64-linux-gnu.tar.gz/md5/df7fab134fbce3b625e9a82376f23e79 +OpenLibm.v0.8.5+0.x86_64-linux-gnu.tar.gz/sha512/64d07434e0db79833f84a2225838456eb9532617d377a776b3a534a908b1673bc4f890903f95350e4045e05c29539d993a18ecadeb879761e279ec3947f74390 +OpenLibm.v0.8.5+0.x86_64-linux-musl.tar.gz/md5/ebef6bb7651d116b397e035f39adfb1b +OpenLibm.v0.8.5+0.x86_64-linux-musl.tar.gz/sha512/de9036073e5dba2721b4119ecbbd21a0c9f75b65aff9392b7e88e464da35b97135d62404477441d0dadd3a2f8d49f1082291b35bf4b626fb1096d36d401980bf +OpenLibm.v0.8.5+0.x86_64-unknown-freebsd.tar.gz/md5/1115497539f00a37af18aa6516d52268 +OpenLibm.v0.8.5+0.x86_64-unknown-freebsd.tar.gz/sha512/71a2c06d141b3671fd220f2d88d72e845848b6d2b08a7b3a6c4bb1d5cc27cc450e1e681647bb583e7ed6375d5a70748401e95e61dc95d7808f33a9aa06755337 +OpenLibm.v0.8.5+0.x86_64-w64-mingw32.tar.gz/md5/b6b5335f4c83f7ebf0f74cf753358f00 +OpenLibm.v0.8.5+0.x86_64-w64-mingw32.tar.gz/sha512/e8351ddda305b757f337bb7ea26c441968843b23861676f0bdd7bcf83bb3969af790d4112307d3204eb87fac044dda9be305f349700ebe9ba2bfe3d6df24fde8 +openlibm-db24332879c320606c37f77fea165e6ecb49153c.tar.gz/md5/2375dd448e77e59152442a4b33abda01 +openlibm-db24332879c320606c37f77fea165e6ecb49153c.tar.gz/sha512/36054e7051990d04913f054a0542e2e104273f61308e9a442c2dab3dd392d40c03f264fbeca93c4296218eed85dad71028989a225088254013d752f4407d57ef diff --git a/deps/openlibm.version b/deps/openlibm.version index 13129a0c0a860..788701a66301b 100644 --- a/deps/openlibm.version +++ b/deps/openlibm.version @@ -4,6 +4,6 @@ OPENLIBM_JLL_NAME := OpenLibm ## source build -OPENLIBM_VER := 0.8.4 -OPENLIBM_BRANCH=v0.8.4 -OPENLIBM_SHA1=c4667caea25ae3487adf6760b4a1dcf32477a4b8 +OPENLIBM_VER := 0.8.5 +OPENLIBM_BRANCH=v0.8.5 +OPENLIBM_SHA1=db24332879c320606c37f77fea165e6ecb49153c diff --git a/stdlib/Manifest.toml b/stdlib/Manifest.toml index 160ccac5ffa39..f029a210320cc 100644 --- a/stdlib/Manifest.toml +++ b/stdlib/Manifest.toml @@ -163,7 +163,7 @@ version = "0.3.28+3" [[deps.OpenLibm_jll]] deps = ["Artifacts", "Libdl"] uuid = "05823500-19ac-5b8b-9628-191a04bc5112" -version = "0.8.4+1" +version = "0.8.5+0" [[deps.OpenSSL_jll]] deps = ["Artifacts", "Libdl"] diff --git a/stdlib/OpenLibm_jll/Project.toml b/stdlib/OpenLibm_jll/Project.toml index 1d52749032fa4..431528ee3f400 100644 --- a/stdlib/OpenLibm_jll/Project.toml +++ b/stdlib/OpenLibm_jll/Project.toml @@ -1,6 +1,6 @@ name = "OpenLibm_jll" uuid = "05823500-19ac-5b8b-9628-191a04bc5112" -version = "0.8.4+1" +version = "0.8.5+0" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" From b8ab9f37469d9c19eeac1f9b5d40a499d3a176e8 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Wed, 8 Jan 2025 08:14:34 -0500 Subject: [PATCH 158/342] Revert "add fenv cache to task struct (#51288)" (#56982) This reverts commit 12aa9dea03a8a6bbe2891d3ca6ce34a21ec84734. un-fixes #51277 Alternatively, we could add a flag for whether the state is non-default so we know whether `fesetenv` is necessary, if this behavior is considered desireable. --- src/julia.h | 4 ---- src/task.c | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/julia.h b/src/julia.h index bfa9d0857c73c..4084b340d91e5 100644 --- a/src/julia.h +++ b/src/julia.h @@ -20,7 +20,6 @@ #include "libsupport.h" #include #include -#include #include "htable.h" #include "arraylist.h" @@ -2314,9 +2313,6 @@ typedef struct _jl_task_t { _Atomic(uint64_t) finished_at; // hidden state: - // cached floating point environment - // only updated at task switch - fenv_t fenv; // id of owning thread - does not need to be defined until the task runs _Atomic(int16_t) tid; diff --git a/src/task.c b/src/task.c index 1a50d6fcbcf65..d56d60eb58cb5 100644 --- a/src/task.c +++ b/src/task.c @@ -541,7 +541,6 @@ JL_NO_ASAN static void ctx_switch(jl_task_t *lastt) jl_set_pgcstack(&t->gcstack); jl_signal_fence(); lastt->ptls = NULL; - fegetenv(&lastt->fenv); #ifdef MIGRATE_TASKS ptls->previous_task = lastt; #endif @@ -734,7 +733,6 @@ JL_DLLEXPORT void jl_switch(void) JL_NOTSAFEPOINT_LEAVE JL_NOTSAFEPOINT_ENTER 0 == ptls->finalizers_inhibited); ptls->finalizers_inhibited = finalizers_inhibited; jl_timing_block_task_enter(ct, ptls, blk); (void)blk; - fesetenv(&ct->fenv); sig_atomic_t other_defer_signal = ptls->defer_signal; ptls->defer_signal = defer_signal; @@ -1147,7 +1145,6 @@ JL_DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, jl_value_t *completion t->excstack = NULL; t->ctx.started = 0; t->priority = 0; - fegetenv(&t->fenv); jl_atomic_store_relaxed(&t->tid, -1); t->threadpoolid = ct->threadpoolid; t->ptls = NULL; @@ -1254,7 +1251,6 @@ CFI_NORETURN if (!pt->sticky && !pt->ctx.copy_stack) jl_atomic_store_release(&pt->tid, -1); #endif - fesetenv(&ct->fenv); ct->ctx.started = 1; if (ct->metrics_enabled) { From 98dc249622fa23e073419caeaa1213c69e1a0295 Mon Sep 17 00:00:00 2001 From: rileysheridan Date: Wed, 8 Jan 2025 08:26:02 -0500 Subject: [PATCH 159/342] Add tests for Base.cwstring (#56123) Co-authored-by: Sukera <11753998+Seelengrab@users.noreply.github.com> Co-authored-by: Lilith Orion Hafner --- test/strings/basic.jl | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/strings/basic.jl b/test/strings/basic.jl index 3fc611a660975..f90ce8c697ed8 100644 --- a/test/strings/basic.jl +++ b/test/strings/basic.jl @@ -1423,3 +1423,20 @@ end @test transcode(String, transcode(UInt8, transcode(UInt16, str))) == str end end + +if Sys.iswindows() + @testset "cwstring" begin + # empty string + str_0 = "" + # string with embedded NUL character + str_1 = "Au\000B" + # string with terminating NUL character + str_2 = "Wordu\000" + # "Regular" string with UTF-8 characters of differing byte counts + str_3 = "aܣ𒀀" + @test Base.cwstring(str_0) == UInt16[0x0000] + @test_throws ArgumentError Base.cwstring(str_1) + @test_throws ArgumentError Base.cwstring(str_2) + @test Base.cwstring(str_3) == UInt16[0x0061, 0x0723, 0xd808, 0xdc00, 0x0000] + end +end From 38b41b5f6cbef96643f1495e1c6ea2470b6e7250 Mon Sep 17 00:00:00 2001 From: Michael Abbott <32575566+mcabbott@users.noreply.github.com> Date: Wed, 8 Jan 2025 08:29:43 -0500 Subject: [PATCH 160/342] Allow `map!(f, array)` (#40632) ...there's really no sensible interpretation of `map!(f, array)` other than `map!(f, array, array)`. --------- Co-authored-by: Lilith Orion Hafner --- NEWS.md | 1 + base/abstractarray.jl | 25 +++++++++++++++++++++++-- test/abstractarray.jl | 2 +- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/NEWS.md b/NEWS.md index 1708866609427..6c378c8186007 100644 --- a/NEWS.md +++ b/NEWS.md @@ -117,6 +117,7 @@ New library features * `invoke` now supports passing a CodeInstance instead of a type, which can enable certain compiler plugin workflows ([#56660]). * `sort` now supports `NTuple`s ([#54494]) +* `map!(f, A)` now stores the results in `A`, like `map!(f, A, A)`. or `A .= f.(A)` ([#40632]). Standard library changes ------------------------ diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 6d222e7e26281..a370b79976ab0 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -3503,11 +3503,32 @@ julia> map!(+, zeros(Int, 5), 100:999, 1:3) ``` """ function map!(f::F, dest::AbstractArray, As::AbstractArray...) where {F} - isempty(As) && throw(ArgumentError( - """map! requires at least one "source" argument""")) + @assert !isempty(As) # should dispatch to map!(f, A) map_n!(f, dest, As) end +""" + map!(function, array) + +Like [`map`](@ref), but stores the result in the same array. +!!! compat "Julia 1.12" + This method requires Julia 1.12 or later. To support previous versions too, + use the equivalent `map!(function, array, array)`. + +# Examples +```jldoctest +julia> a = [1 2 3; 4 5 6]; + +julia> map!(x -> x^3, a); + +julia> a +2×3 Matrix{$Int}: + 1 8 27 + 64 125 216 +``` +""" +map!(f::F, inout::AbstractArray) where F = map!(f, inout, inout) + """ map(f, A::AbstractArray...) -> N-array diff --git a/test/abstractarray.jl b/test/abstractarray.jl index c7ec61704c1bc..d1f30eacafacc 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -908,7 +908,7 @@ test_ind2sub(TestAbstractArray) include("generic_map_tests.jl") generic_map_tests(map, map!) -@test_throws ArgumentError map!(-, [1]) +@test map!(-, [1]) == [-1] test_UInt_indexing(TestAbstractArray) test_13315(TestAbstractArray) From b58dcc5f3f10a20fab7317586155c9b6f07c38fc Mon Sep 17 00:00:00 2001 From: Lilith Orion Hafner Date: Wed, 8 Jan 2025 07:34:03 -0600 Subject: [PATCH 161/342] Fix and test lcm([1//2, 1//2]) == 1//1 (#56423) --- base/intfuncs.jl | 11 ++++++++++- test/intfuncs.jl | 7 +++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index db3b1fdeeb521..13a5007e4c74b 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -150,7 +150,16 @@ gcd(a::T, b::T) where T<:Real = throw(MethodError(gcd, (a,b))) lcm(a::T, b::T) where T<:Real = throw(MethodError(lcm, (a,b))) gcd(abc::AbstractArray{<:Real}) = reduce(gcd, abc; init=zero(eltype(abc))) -lcm(abc::AbstractArray{<:Real}) = reduce(lcm, abc; init=one(eltype(abc))) +function lcm(abc::AbstractArray{<:Real}) + # Using reduce with init=one(eltype(abc)) is buggy for Rationals. + l = length(abc) + if l == 0 + eltype(abc) <: Integer && return one(eltype(abc)) + throw(ArgumentError("lcm has no identity for $(eltype(abc))")) + end + l == 1 && return abs(only(abc)) + return reduce(lcm, abc) +end function gcd(abc::AbstractArray{<:Integer}) a = zero(eltype(abc)) diff --git a/test/intfuncs.jl b/test/intfuncs.jl index 6f1bde69dddfe..38f29344d2f30 100644 --- a/test/intfuncs.jl +++ b/test/intfuncs.jl @@ -191,6 +191,13 @@ end @test lcm(T[2, 4, 6]) ⟷ T(12) end + + # Issue #55379 + @test lcm([1//2; 1//2]) === lcm([1//2, 1//2]) === lcm(1//2, 1//2) === 1//2 + @test gcd(Int[]) === 0 + @test lcm(Int[]) === 1 + @test gcd(Rational{Int}[]) === 0//1 + @test_throws ArgumentError("lcm has no identity for Rational{$Int}") lcm(Rational{Int}[]) end ⟷(a::Tuple{T, T, T}, b::Tuple{T, T, T}) where T <: Union{Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Int128, UInt128} = a === b From 75cdffeb0f37b438950534712755a4f7cebbdd8c Mon Sep 17 00:00:00 2001 From: FX Coudert Date: Wed, 8 Jan 2025 16:34:38 +0100 Subject: [PATCH 162/342] Install correct libgcc_s on darwin (#56965) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/JuliaLang/julia/issues/48056 We could simplify the logic a lot if we assume that modern Julia is always built against GCC ≥ 12. Would that be a fair assumption. --- deps/csl.mk | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/deps/csl.mk b/deps/csl.mk index fefe71a5e871c..a50a08fab8506 100644 --- a/deps/csl.mk +++ b/deps/csl.mk @@ -75,12 +75,24 @@ else $(eval $(call copy_csl,$(call versioned_libname,libgcc_s_seh,1))) endif else -ifeq ($(APPLE_ARCH),arm64) +ifeq ($(OS),Darwin) +# On macOS, libgcc_s has soversion 1.1 always on aarch64 and only for GCC 12+ +# (-> libgfortran 5) on x86_64 +ifeq ($(ARCH),aarch64) +$(eval $(call copy_csl,$(call versioned_libname,libgcc_s,1.1))) +else +ifeq ($(LIBGFORTRAN_VERSION),5) $(eval $(call copy_csl,$(call versioned_libname,libgcc_s,1.1))) else $(eval $(call copy_csl,$(call versioned_libname,libgcc_s,1))) endif endif +else +# Other targets just use libgcc_s.1 +$(eval $(call copy_csl,$(call versioned_libname,libgcc_s,1))) +endif +endif + # winpthread is only Windows, pthread is only others ifeq ($(OS),WINNT) $(eval $(call copy_csl,$(call versioned_libname,libwinpthread,1))) From 64d4c6b13185cf460fa2be9e6b561ebf8721e25e Mon Sep 17 00:00:00 2001 From: Lilith Orion Hafner Date: Wed, 8 Jan 2025 12:37:57 -0600 Subject: [PATCH 163/342] Clarify mathematical definition of `lcm` (#56992) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some folks define `lcm(x::T,y::T)` as any `z::T` such that there exists `a::T, b::T` with `a*x==z` and `b*y==z` and for all `zʹ::T` such that there exist `a::T, b::T` with `a*x==zʹ` and `b*y==zʹ`, there also exists `c::T` with `z*c==zʹ`. This is a reasonable definition, but not what we use. Notably, it makes `lcm(x::Rational, y::Rational) = z::Rational` true for all finite, nonzero `x`, `y`, and `z`. The definition we use requires `a`, `b`, and `c` to all be _integers_, not rationals in the case of `lcm(x::Rational, y::Rational)`. This clarifies what we mean when we define `lcm(x::Rational, y::Rational)` and also how the generic function should be extended. See [this thread](https://github.com/JuliaLang/julia/pull/56423#discussion_r1826999933) for more discussion --- base/intfuncs.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index 13a5007e4c74b..dc81f2bd3e489 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -97,6 +97,9 @@ end Least common (positive) multiple (or zero if any argument is zero). The arguments may be integer and rational numbers. +``a`` is a multiple of ``b`` if there exists an integer ``m`` such +that ``a=mb``. + !!! compat "Julia 1.4" Rational arguments require Julia 1.4 or later. From 8bf280277db13a10c50f218d6940b8766c58a39a Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 8 Jan 2025 13:47:27 -0500 Subject: [PATCH 164/342] CodeInstance: remove relocatability field (#56975) This field lost its meaning awhile back and is better tracked only as part of the compressed CodeInfo instead of trying to accurately copy and update this field. --- Compiler/src/typeinfer.jl | 21 +++++---------------- Compiler/test/abioverride.jl | 2 +- base/boot.jl | 6 +++--- src/gf.c | 17 +++++++---------- src/jltypes.c | 13 ++++++------- src/julia.h | 1 - src/julia_internal.h | 2 +- src/method.c | 4 ---- src/opaque_closure.c | 2 +- src/staticdata.c | 23 ++++++++++++----------- src/staticdata_utils.c | 16 +--------------- src/toplevel.c | 2 +- test/precompile.jl | 7 +++---- 13 files changed, 41 insertions(+), 75 deletions(-) diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index e2821f79cca0c..49cc711dc72df 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -120,7 +120,6 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState) end inferred_result = nothing uncompressed = inferred_result - relocatability = 0x1 const_flag = is_result_constabi_eligible(result) discard_src = caller.cache_mode === CACHE_MODE_NULL || const_flag if !discard_src @@ -139,22 +138,14 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState) elseif ci.owner === nothing # The global cache can only handle objects that codegen understands inferred_result = nothing - else - relocatability = 0x0 - end - if isa(inferred_result, String) - t = @_gc_preserve_begin inferred_result - relocatability = unsafe_load(unsafe_convert(Ptr{UInt8}, inferred_result), Core.sizeof(inferred_result)) - @_gc_preserve_end t end end - # n.b. relocatability = !isa(inferred_result, String) || inferred_result[end] if !@isdefined di di = DebugInfo(result.linfo) end - ccall(:jl_update_codeinst, Cvoid, (Any, Any, Int32, UInt, UInt, UInt32, Any, UInt8, Any, Any), + ccall(:jl_update_codeinst, Cvoid, (Any, Any, Int32, UInt, UInt, UInt32, Any, Any, Any), ci, inferred_result, const_flag, first(result.valid_worlds), last(result.valid_worlds), encode_effects(result.ipo_effects), - result.analysis_results, relocatability, di, edges) + result.analysis_results, di, edges) engine_reject(interp, ci) if !discard_src && isdefined(interp, :codegen) && uncompressed isa CodeInfo # record that the caller could use this result to generate code when required, if desired, to avoid repeating n^2 work @@ -176,7 +167,6 @@ end function finish!(interp::AbstractInterpreter, mi::MethodInstance, ci::CodeInstance, src::CodeInfo) user_edges = src.edges edges = user_edges isa SimpleVector ? user_edges : user_edges === nothing ? Core.svec() : Core.svec(user_edges...) - relocatability = 0x1 const_flag = false di = src.debuginfo rettype = Any @@ -196,8 +186,8 @@ function finish!(interp::AbstractInterpreter, mi::MethodInstance, ci::CodeInstan end ccall(:jl_fill_codeinst, Cvoid, (Any, Any, Any, Any, Int32, UInt, UInt, UInt32, Any, Any, Any), ci, rettype, exctype, nothing, const_flags, min_world, max_world, ipo_effects, nothing, di, edges) - ccall(:jl_update_codeinst, Cvoid, (Any, Any, Int32, UInt, UInt, UInt32, Any, UInt8, Any, Any), - ci, nothing, const_flag, min_world, max_world, ipo_effects, nothing, relocatability, di, edges) + ccall(:jl_update_codeinst, Cvoid, (Any, Any, Int32, UInt, UInt, UInt32, Any, Any, Any), + ci, nothing, const_flag, min_world, max_world, ipo_effects, nothing, di, edges) code_cache(interp)[mi] = ci if isdefined(interp, :codegen) interp.codegen[ci] = src @@ -523,7 +513,6 @@ function finishinfer!(me::InferenceState, interp::AbstractInterpreter) rettype_const = nothing const_flags = 0x0 end - relocatability = 0x1 di = nothing edges = empty_edges # `edges` will be updated within `finish!` ci = result.ci @@ -827,7 +816,7 @@ function codeinst_as_edge(interp::AbstractInterpreter, sv::InferenceState, @nosp end end ci = CodeInstance(mi, cache_owner(interp), Any, Any, nothing, nothing, zero(Int32), - min_world, max_world, zero(UInt32), nothing, zero(UInt8), nothing, edges) + min_world, max_world, zero(UInt32), nothing, nothing, edges) if max_world == typemax(UInt) # if we can record all of the backedges in the global reverse-cache, # we can now widen our applicability in the global cache too diff --git a/Compiler/test/abioverride.jl b/Compiler/test/abioverride.jl index e257074852099..da9b1f92786e5 100644 --- a/Compiler/test/abioverride.jl +++ b/Compiler/test/abioverride.jl @@ -46,7 +46,7 @@ let world = Base.tls_world_age() #=owner=#SecondArgConstOverride(1), new_source.rettype, Any#=new_source.exctype is missing=#, #=inferred_const=#nothing, #=code=#nothing, #=const_flags=#Int32(0), new_source.min_world, new_source.max_world, #=new_source.ipo_purity_bits is missing=#UInt32(0), - #=analysis_results=#nothing, #=not relocatable?=#UInt8(0), new_source.debuginfo, new_source.edges) + #=analysis_results=#nothing, new_source.debuginfo, new_source.edges) # Poke the CI into the global cache # This isn't necessary, but does conveniently give it the mandatory permanent GC-root before calling `invoke` diff --git a/base/boot.jl b/base/boot.jl index 4652524530703..05788844fde66 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -561,11 +561,11 @@ function CodeInstance( mi::Union{MethodInstance, ABIOverride}, owner, @nospecialize(rettype), @nospecialize(exctype), @nospecialize(inferred_const), @nospecialize(inferred), const_flags::Int32, min_world::UInt, max_world::UInt, effects::UInt32, @nospecialize(analysis_results), - relocatability::UInt8, di::Union{DebugInfo,Nothing}, edges::SimpleVector) + di::Union{DebugInfo,Nothing}, edges::SimpleVector) return ccall(:jl_new_codeinst, Ref{CodeInstance}, - (Any, Any, Any, Any, Any, Any, Int32, UInt, UInt, UInt32, Any, UInt8, Any, Any), + (Any, Any, Any, Any, Any, Any, Int32, UInt, UInt, UInt32, Any, Any, Any), mi, owner, rettype, exctype, inferred_const, inferred, const_flags, min_world, max_world, - effects, analysis_results, relocatability, di, edges) + effects, analysis_results, di, edges) end GlobalRef(m::Module, s::Symbol) = ccall(:jl_module_globalref, Ref{GlobalRef}, (Any, Any), m, s) Module(name::Symbol=:anonymous, std_imports::Bool=true, default_names::Bool=true) = ccall(:jl_f_new_module, Ref{Module}, (Any, Bool, Bool), name, std_imports, default_names) diff --git a/src/gf.c b/src/gf.c index d5fbcfc7dcd6a..080d1ebd52ba8 100644 --- a/src/gf.c +++ b/src/gf.c @@ -323,7 +323,7 @@ jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_a jl_code_instance_t *codeinst = jl_new_codeinst(mi, jl_nothing, (jl_value_t*)jl_any_type, (jl_value_t*)jl_any_type, jl_nothing, jl_nothing, - 0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL, NULL); + 0, 1, ~(size_t)0, 0, jl_nothing, NULL, NULL); jl_mi_cache_insert(mi, codeinst); jl_atomic_store_relaxed(&codeinst->specptr.fptr1, fptr); jl_atomic_store_relaxed(&codeinst->invoke, jl_fptr_args); @@ -564,7 +564,7 @@ JL_DLLEXPORT jl_code_instance_t *jl_get_method_inferred( } codeinst = jl_new_codeinst( mi, owner, rettype, (jl_value_t*)jl_any_type, NULL, NULL, - 0, min_world, max_world, 0, jl_nothing, 0, di, edges); + 0, min_world, max_world, 0, jl_nothing, di, edges); jl_mi_cache_insert(mi, codeinst); return codeinst; } @@ -614,7 +614,6 @@ JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst( jl_value_t *inferred_const, jl_value_t *inferred, int32_t const_flags, size_t min_world, size_t max_world, uint32_t effects, jl_value_t *analysis_results, - uint8_t relocatability, jl_debuginfo_t *di, jl_svec_t *edges /*, int absolute_max*/) { assert(min_world <= max_world && "attempting to set invalid world constraints"); @@ -645,7 +644,6 @@ JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst( jl_atomic_store_relaxed(&codeinst->next, NULL); jl_atomic_store_relaxed(&codeinst->ipo_purity_bits, effects); codeinst->analysis_results = analysis_results; - codeinst->relocatability = relocatability; return codeinst; } @@ -653,11 +651,10 @@ JL_DLLEXPORT void jl_update_codeinst( jl_code_instance_t *codeinst, jl_value_t *inferred, int32_t const_flags, size_t min_world, size_t max_world, uint32_t effects, jl_value_t *analysis_results, - uint8_t relocatability, jl_debuginfo_t *di, jl_svec_t *edges /* , int absolute_max*/) + jl_debuginfo_t *di, jl_svec_t *edges /* , int absolute_max*/) { assert(min_world <= max_world && "attempting to set invalid world constraints"); //assert((!jl_is_method(codeinst->def->def.value) || max_world != ~(size_t)0 || min_world <= 1 || jl_svec_len(edges) != 0) && "missing edges"); - codeinst->relocatability = relocatability; codeinst->analysis_results = analysis_results; jl_gc_wb(codeinst, analysis_results); jl_atomic_store_relaxed(&codeinst->ipo_purity_bits, effects); @@ -715,7 +712,7 @@ JL_DLLEXPORT void jl_fill_codeinst( JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst_uninit(jl_method_instance_t *mi, jl_value_t *owner) { - jl_code_instance_t *codeinst = jl_new_codeinst(mi, owner, NULL, NULL, NULL, NULL, 0, 0, 0, 0, NULL, 0, NULL, NULL); + jl_code_instance_t *codeinst = jl_new_codeinst(mi, owner, NULL, NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL); jl_atomic_store_relaxed(&codeinst->min_world, 1); // make temporarily invalid before returning, so that jl_fill_codeinst is valid later return codeinst; } @@ -2908,7 +2905,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t jl_read_codeinst_invoke(unspec, &specsigflags, &invoke, &fptr, 1); jl_code_instance_t *codeinst = jl_new_codeinst(mi, jl_nothing, (jl_value_t*)jl_any_type, (jl_value_t*)jl_any_type, NULL, NULL, - 0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL, NULL); + 0, 1, ~(size_t)0, 0, jl_nothing, NULL, NULL); codeinst->rettype_const = unspec->rettype_const; jl_atomic_store_relaxed(&codeinst->specptr.fptr, fptr); jl_atomic_store_relaxed(&codeinst->invoke, invoke); @@ -2929,7 +2926,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t if (!jl_code_requires_compiler(src, 0)) { jl_code_instance_t *codeinst = jl_new_codeinst(mi, jl_nothing, (jl_value_t*)jl_any_type, (jl_value_t*)jl_any_type, NULL, NULL, - 0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL, NULL); + 0, 1, ~(size_t)0, 0, jl_nothing, NULL, NULL); jl_atomic_store_release(&codeinst->invoke, jl_fptr_interpret_call); jl_mi_cache_insert(mi, codeinst); record_precompile_statement(mi, 0, 0); @@ -3019,7 +3016,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t jl_read_codeinst_invoke(ucache, &specsigflags, &invoke, &fptr, 1); codeinst = jl_new_codeinst(mi, jl_nothing, (jl_value_t*)jl_any_type, (jl_value_t*)jl_any_type, NULL, NULL, - 0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL, NULL); + 0, 1, ~(size_t)0, 0, jl_nothing, NULL, NULL); codeinst->rettype_const = ucache->rettype_const; // unspec is always not specsig, but might use specptr jl_atomic_store_relaxed(&codeinst->specptr.fptr, fptr); diff --git a/src/jltypes.c b/src/jltypes.c index fbdfe497ea312..b478ce7ea98fd 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3638,7 +3638,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_code_instance_type = jl_new_datatype(jl_symbol("CodeInstance"), core, jl_any_type, jl_emptysvec, - jl_perm_symsvec(18, + jl_perm_symsvec(17, "def", "owner", "next", @@ -3653,9 +3653,9 @@ void jl_init_types(void) JL_GC_DISABLED //"absolute_max", "ipo_purity_bits", "analysis_results", - "specsigflags", "precompile", "relocatability", + "specsigflags", "precompile", "invoke", "specptr"), // function object decls - jl_svec(18, + jl_svec(17, jl_any_type, jl_any_type, jl_any_type, @@ -3672,13 +3672,12 @@ void jl_init_types(void) JL_GC_DISABLED jl_any_type, jl_bool_type, jl_bool_type, - jl_uint8_type, jl_any_type, jl_any_type), // fptrs jl_emptysvec, 0, 1, 1); jl_svecset(jl_code_instance_type->types, 2, jl_code_instance_type); - const static uint32_t code_instance_constfields[1] = { 0b000001000011100011 }; // Set fields 1, 2, 6-8, 13 as const - const static uint32_t code_instance_atomicfields[1] = { 0b110110111100011100 }; // Set fields 3-5, 9-12, 14-15, 17-18 as atomic + const static uint32_t code_instance_constfields[1] = { 0b00001000011100011 }; // Set fields 1, 2, 6-8, 13 as const + const static uint32_t code_instance_atomicfields[1] = { 0b11110111100011100 }; // Set fields 3-5, 9-12, 14-17 as atomic // Fields 4-5 are only operated on by construction and deserialization, so are effectively const at runtime // Fields ipo_purity_bits and analysis_results are not currently threadsafe or reliable, as they get mutated after optimization, but are not declared atomic // and there is no way to tell (during inference) if their value is finalized yet (to wait for them to be narrowed if applicable) @@ -3854,8 +3853,8 @@ void jl_init_types(void) JL_GC_DISABLED jl_svecset(jl_method_type->types, 13, jl_method_instance_type); //jl_svecset(jl_debuginfo_type->types, 0, jl_method_instance_type); // union(jl_method_instance_type, jl_method_type, jl_symbol_type) jl_svecset(jl_method_instance_type->types, 4, jl_code_instance_type); + jl_svecset(jl_code_instance_type->types, 15, jl_voidpointer_type); jl_svecset(jl_code_instance_type->types, 16, jl_voidpointer_type); - jl_svecset(jl_code_instance_type->types, 17, jl_voidpointer_type); jl_svecset(jl_binding_type->types, 0, jl_globalref_type); jl_svecset(jl_binding_partition_type->types, 3, jl_binding_partition_type); diff --git a/src/julia.h b/src/julia.h index 4084b340d91e5..b5416568b7ae9 100644 --- a/src/julia.h +++ b/src/julia.h @@ -467,7 +467,6 @@ typedef struct _jl_code_instance_t { // & 0b010 == invokeptr matches specptr // & 0b100 == From image _Atomic(uint8_t) precompile; // if set, this will be added to the output system image - uint8_t relocatability; // nonzero if all roots are built into sysimg or tagged by module key _Atomic(jl_callptr_t) invoke; // jlcall entry point usually, but if this codeinst belongs to an OC Method, then this is an jl_fptr_args_t fptr1 instead, unless it is not, because it is a special token object instead union _jl_generic_specptr_t { _Atomic(void*) fptr; diff --git a/src/julia_internal.h b/src/julia_internal.h index b1c32f6e2de6e..f8dd49eab65a3 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -691,7 +691,7 @@ JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst( jl_value_t *inferred_const, jl_value_t *inferred, int32_t const_flags, size_t min_world, size_t max_world, uint32_t effects, jl_value_t *analysis_results, - uint8_t relocatability, jl_debuginfo_t *di, jl_svec_t *edges /* , int absolute_max*/); + jl_debuginfo_t *di, jl_svec_t *edges /* , int absolute_max*/); JL_DLLEXPORT jl_code_instance_t *jl_get_ci_equiv(jl_code_instance_t *ci JL_PROPAGATES_ROOT, int compiled) JL_NOTSAFEPOINT; STATIC_INLINE jl_method_instance_t *jl_get_ci_mi(jl_code_instance_t *ci JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT diff --git a/src/method.c b/src/method.c index 8e3bb7d0060b7..0d173d960c90f 100644 --- a/src/method.c +++ b/src/method.c @@ -1384,10 +1384,6 @@ JL_DLLEXPORT jl_method_t* jl_method_def(jl_svec_t *argdata, // at the time of writing the system image (such occur first in the list of // roots). These are the cases with `key = 0` that do not prevent // serialization. -// - CodeInstances have a `relocatability` field which when 1 indicates that -// every root is "safe," meaning it was either added at sysimg creation or is -// tagged with a non-zero `key`. Even a single unsafe root will cause this to -// have value 0. // Get the key of the current (final) block of roots static uint64_t current_root_id(jl_array_t *root_blocks) diff --git a/src/opaque_closure.c b/src/opaque_closure.c index 2d11d763be662..a10b5c617753c 100644 --- a/src/opaque_closure.c +++ b/src/opaque_closure.c @@ -169,7 +169,7 @@ JL_DLLEXPORT jl_opaque_closure_t *jl_new_opaque_closure_from_code_info(jl_tuplet if (!jl_is_svec(edges)) edges = jl_emptysvec; // OC doesn't really have edges, so just drop them for now inst = jl_new_codeinst(mi, jl_nothing, rt_ub, (jl_value_t*)jl_any_type, NULL, (jl_value_t*)ci, - 0, world, world, 0, jl_nothing, 0, ci->debuginfo, edges); + 0, world, world, 0, jl_nothing, ci->debuginfo, edges); jl_mi_cache_insert(mi, inst); } diff --git a/src/staticdata.c b/src/staticdata.c index 95d7ee94e15dc..bdeecb911e3eb 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -499,7 +499,6 @@ void *native_functions; // opaque jl_native_code_desc_t blob used for fetching // table of struct field addresses to rewrite during saving static htable_t field_replace; static htable_t bits_replace; -static htable_t relocatable_ext_cis; // array of definitions for the predefined function pointers // (reverse of fptr_to_id) @@ -924,11 +923,17 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_ } jl_value_t *inferred = jl_atomic_load_relaxed(&ci->inferred); if (inferred && inferred != jl_nothing) { // disregard if there is nothing here to delete (e.g. builtins, unspecialized) - if (!is_relocatable_ci(&relocatable_ext_cis, ci)) - record_field_change((jl_value_t**)&ci->inferred, jl_nothing); - else if (jl_is_method(mi->def.method) && // don't delete toplevel code - mi->def.method->source) { // don't delete code from optimized opaque closures that can't be reconstructed (and builtins) - if (jl_atomic_load_relaxed(&ci->max_world) != ~(size_t)0 || // delete all code that cannot run + jl_method_t *def = mi->def.method; + if (jl_is_method(def)) { // don't delete toplevel code + int is_relocatable = jl_is_code_info(inferred) || + (jl_is_string(inferred) && jl_string_len(inferred) > 0 && jl_string_data(inferred)[jl_string_len(inferred) - 1]); + if (!is_relocatable) { + record_field_change((jl_value_t**)&ci->inferred, jl_nothing); + } + else if (def->source == NULL) { + // don't delete code from optimized opaque closures that can't be reconstructed (and builtins) + } + else if (jl_atomic_load_relaxed(&ci->max_world) != ~(size_t)0 || // delete all code that cannot run jl_atomic_load_relaxed(&ci->invoke) == jl_fptr_const_return) { // delete all code that just returns a constant record_field_change((jl_value_t**)&ci->inferred, jl_nothing); } @@ -1801,7 +1806,6 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED jl_atomic_store_release(&newci->min_world, 1); jl_atomic_store_release(&newci->max_world, 0); } - newci->relocatability = 0; } jl_atomic_store_relaxed(&newci->invoke, NULL); jl_atomic_store_relaxed(&newci->specsigflags, 0); @@ -2865,7 +2869,7 @@ static void jl_prepare_serialization_data(jl_array_t *mod_array, jl_array_t *new // Extract `new_ext_cis` and `edges` now (from info prepared by jl_collect_methcache_from_mod) *method_roots_list = jl_alloc_vec_any(0); // Collect the new method roots for external specializations - jl_collect_new_roots(&relocatable_ext_cis, *method_roots_list, *new_ext_cis, worklist_key); + jl_collect_new_roots(*method_roots_list, *new_ext_cis, worklist_key); *edges = jl_alloc_vec_any(0); jl_collect_internal_cis(*edges, world); } @@ -3368,7 +3372,6 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli assert((ct->reentrant_timing & 0b1110) == 0); ct->reentrant_timing |= 0b1000; if (worklist) { - htable_new(&relocatable_ext_cis, 0); jl_prepare_serialization_data(mod_array, newly_inferred, jl_worklist_key(worklist), &extext_methods, &new_ext_cis, &method_roots_list, &edges); if (!emit_split) { @@ -3385,8 +3388,6 @@ JL_DLLEXPORT void jl_create_system_image(void **_native_data, jl_array_t *workli jl_save_system_image_to_stream(ff, mod_array, worklist, extext_methods, new_ext_cis, method_roots_list, edges); if (_native_data != NULL) native_functions = NULL; - if (worklist) - htable_free(&relocatable_ext_cis); // make sure we don't run any Julia code concurrently before this point // Re-enable running julia code for postoutput hooks, atexit, etc. jl_gc_enable_finalizers(ct, 1); diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index 5ff7a7b1b1fc0..5de85a8d6ec77 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -215,17 +215,6 @@ static int has_backedge_to_worklist(jl_method_instance_t *mi, htable_t *visited, return found; } -static int is_relocatable_ci(htable_t *relocatable_ext_cis, jl_code_instance_t *ci) -{ - if (!ci->relocatability) - return 0; - jl_method_instance_t *mi = jl_get_ci_mi(ci); - jl_method_t *m = mi->def.method; - if (!ptrhash_has(relocatable_ext_cis, ci) && jl_object_in_image((jl_value_t*)m) && (!jl_is_method(m) || jl_object_in_image((jl_value_t*)m->module))) - return 0; - return 1; -} - // Given the list of CodeInstances that were inferred during the build, select // those that are (1) external, (2) still valid, (3) are inferred to be called // from the worklist or explicitly added by a `precompile` statement, and @@ -247,8 +236,6 @@ static jl_array_t *queue_external_cis(jl_array_t *list) for (i = n0; i-- > 0; ) { jl_code_instance_t *ci = (jl_code_instance_t*)jl_array_ptr_ref(list, i); assert(jl_is_code_instance(ci)); - if (!ci->relocatability) - continue; 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)) { @@ -275,7 +262,7 @@ static jl_array_t *queue_external_cis(jl_array_t *list) } // New roots for external methods -static void jl_collect_new_roots(htable_t *relocatable_ext_cis, jl_array_t *roots, jl_array_t *new_ext_cis, uint64_t key) +static void jl_collect_new_roots(jl_array_t *roots, jl_array_t *new_ext_cis, uint64_t key) { htable_t mset; htable_new(&mset, 0); @@ -286,7 +273,6 @@ static void jl_collect_new_roots(htable_t *relocatable_ext_cis, jl_array_t *root jl_method_t *m = jl_get_ci_mi(ci)->def.method; assert(jl_is_method(m)); ptrhash_put(&mset, (void*)m, (void*)m); - ptrhash_put(relocatable_ext_cis, (void*)ci, (void*)ci); } int nwithkey; void *const *table = mset.table; diff --git a/src/toplevel.c b/src/toplevel.c index 0f8fae8939faf..95a053f6135f6 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -640,7 +640,7 @@ JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst_for_uninferred(jl_method_instan jl_code_instance_t *ci = jl_new_codeinst(mi, (jl_value_t*)jl_uninferred_sym, (jl_value_t*)jl_any_type, (jl_value_t*)jl_any_type, jl_nothing, (jl_value_t*)src, 0, src->min_world, src->max_world, - 0, NULL, 1, NULL, NULL); + 0, NULL, NULL, NULL); return ci; } diff --git a/test/precompile.jl b/test/precompile.jl index 2d4a4d310b4e0..3b193e1facd7c 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -801,7 +801,7 @@ precompile_test_harness("code caching") do dir mi = minternal.specializations::Core.MethodInstance @test mi.specTypes == Tuple{typeof(M.getelsize),Vector{Int32}} ci = mi.cache - @test ci.relocatability == 0 + @test (codeunits(ci.inferred::String)[end]) === 0x01 @test ci.inferred !== nothing # ...and that we can add "untracked" roots & non-relocatable CodeInstances to them too Base.invokelatest() do @@ -812,7 +812,7 @@ precompile_test_harness("code caching") do dir mi = mispecs[2]::Core.MethodInstance mi.specTypes == Tuple{typeof(M.getelsize),Vector{M.X2}} ci = mi.cache - @test ci.relocatability == 0 + @test (codeunits(ci.inferred::String)[end]) == 0x00 # PkgA loads PkgB, and both add roots to the same `push!` method (both before and after loading B) Cache_module2 = :Cachea1544c83560f0c99 write(joinpath(dir, "$Cache_module2.jl"), @@ -1721,8 +1721,7 @@ precompile_test_harness("issue #46296") do load_path mi = first(Base.specializations(first(methods(identity)))) ci = Core.CodeInstance(mi, nothing, Any, Any, nothing, nothing, zero(Int32), typemin(UInt), - typemax(UInt), zero(UInt32), nothing, 0x00, - Core.DebugInfo(mi), Core.svec()) + typemax(UInt), zero(UInt32), nothing, Core.DebugInfo(mi), Core.svec()) __init__() = @assert ci isa Core.CodeInstance From 0868becb74faeea7a88b3050d3e960f2ca9962ba Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 8 Jan 2025 17:47:00 -0500 Subject: [PATCH 165/342] cfunction: fix segfault when jl_type_infer doesn't run (#56998) [Multivectors](https://s3.amazonaws.com/julialang-reports/nanosoldier/pkgeval/by_date/2025-01/05/Multivectors.primary.log) tried to recurse here too much though a generated function generator ending up back in inference, leading to a segfault here. --- src/codegen.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 4b5676cc8216e..4b0f4ebd765fa 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7483,7 +7483,8 @@ static Function *gen_cfun_wrapper( if (lam) { // TODO: this isn't ideal to be unconditionally calling type inference from here codeinst = jl_type_infer(lam, world, SOURCE_MODE_NOT_REQUIRED); - astrt = codeinst->rettype; + if (codeinst) + astrt = codeinst->rettype; if (astrt != (jl_value_t*)jl_bottom_type && jl_type_intersection(astrt, declrt) == jl_bottom_type) { // Do not warn if the function never returns since it is From 11ce1714308460d08bd4d2acbf4a743816f898ad Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Wed, 8 Jan 2025 19:52:02 -0300 Subject: [PATCH 166/342] GC: report times spent in each step of sweeping (#56993) We've been using this patch for a while (e.g., https://github.com/RelationalAI/julia/pull/176), and it has proven valuable for identifying the most expensive part of sweeping in a customer workload. Specifically, it highlighted that the madvise stage was the bottleneck. These metrics allowed us to effectively determine whether concurrent page sweeping would be beneficial. --- base/timing.jl | 3 ++ src/gc-interface.h | 3 ++ src/gc-stock.c | 97 ++++++++++++++++++++++++++-------------------- 3 files changed, 60 insertions(+), 43 deletions(-) diff --git a/base/timing.jl b/base/timing.jl index 0088f8bb77eca..65c2a643d6a52 100644 --- a/base/timing.jl +++ b/base/timing.jl @@ -24,6 +24,9 @@ struct GC_Num mark_time ::Int64 stack_pool_sweep_time ::Int64 total_sweep_time ::Int64 + total_sweep_page_walk_time ::Int64 + total_sweep_madvise_time ::Int64 + total_sweep_free_mallocd_memory_time ::Int64 total_mark_time ::Int64 total_stack_pool_sweep_time::Int64 last_full_sweep ::Int64 diff --git a/src/gc-interface.h b/src/gc-interface.h index e4a27782f7520..826e91355b17a 100644 --- a/src/gc-interface.h +++ b/src/gc-interface.h @@ -46,6 +46,9 @@ typedef struct { uint64_t mark_time; uint64_t stack_pool_sweep_time; uint64_t total_sweep_time; + uint64_t total_sweep_page_walk_time; + uint64_t total_sweep_madvise_time; + uint64_t total_sweep_free_mallocd_memory_time; uint64_t total_mark_time; uint64_t total_stack_pool_sweep_time; uint64_t last_full_sweep; diff --git a/src/gc-stock.c b/src/gc-stock.c index d2d9104ad8d22..8118b3c5629ae 100644 --- a/src/gc-stock.c +++ b/src/gc-stock.c @@ -984,9 +984,12 @@ STATIC_INLINE void gc_sweep_pool_page(gc_page_profiler_serializer_t *s, jl_gc_pa // sweep over all memory that is being used and not in a pool static void gc_sweep_other(jl_ptls_t ptls, int sweep_full) JL_NOTSAFEPOINT { + uint64_t t_free_mallocd_memory_start = jl_hrtime(); gc_sweep_foreign_objs(); sweep_malloced_memory(); sweep_big(ptls); + uint64_t t_free_mallocd_memory_end = jl_hrtime(); + gc_num.total_sweep_free_mallocd_memory_time += t_free_mallocd_memory_end - t_free_mallocd_memory_start; jl_engine_sweep(gc_all_tls_states); } @@ -1380,58 +1383,63 @@ static void gc_sweep_pool(void) } } - // the actual sweeping - jl_gc_padded_page_stack_t *new_gc_allocd_scratch = (jl_gc_padded_page_stack_t *) calloc_s(n_threads * sizeof(jl_gc_padded_page_stack_t)); - jl_ptls_t ptls = jl_current_task->ptls; - gc_sweep_wake_all_pages(ptls, new_gc_allocd_scratch); - gc_sweep_pool_parallel(ptls); - gc_sweep_wait_for_all_pages(); - - // reset half-pages pointers - for (int t_i = 0; t_i < n_threads; t_i++) { - jl_ptls_t ptls2 = gc_all_tls_states[t_i]; - if (ptls2 != NULL) { - ptls2->gc_tls.page_metadata_allocd = new_gc_allocd_scratch[t_i].stack; - for (int i = 0; i < JL_GC_N_POOLS; i++) { - jl_gc_pool_t *p = &ptls2->gc_tls.heap.norm_pools[i]; - p->newpages = NULL; + uint64_t t_page_walk_start = jl_hrtime(); + { + // the actual sweeping + jl_gc_padded_page_stack_t *new_gc_allocd_scratch = (jl_gc_padded_page_stack_t *) calloc_s(n_threads * sizeof(jl_gc_padded_page_stack_t)); + jl_ptls_t ptls = jl_current_task->ptls; + gc_sweep_wake_all_pages(ptls, new_gc_allocd_scratch); + gc_sweep_pool_parallel(ptls); + gc_sweep_wait_for_all_pages(); + + // reset half-pages pointers + for (int t_i = 0; t_i < n_threads; t_i++) { + jl_ptls_t ptls2 = gc_all_tls_states[t_i]; + if (ptls2 != NULL) { + ptls2->gc_tls.page_metadata_allocd = new_gc_allocd_scratch[t_i].stack; + for (int i = 0; i < JL_GC_N_POOLS; i++) { + jl_gc_pool_t *p = &ptls2->gc_tls.heap.norm_pools[i]; + p->newpages = NULL; + } } } - } - // merge free lists - for (int t_i = 0; t_i < n_threads; t_i++) { - jl_ptls_t ptls2 = gc_all_tls_states[t_i]; - if (ptls2 == NULL) { - continue; - } - jl_gc_pagemeta_t *pg = jl_atomic_load_relaxed(&ptls2->gc_tls.page_metadata_allocd.bottom); - while (pg != NULL) { - jl_gc_pagemeta_t *pg2 = pg->next; - if (pg->fl_begin_offset != UINT16_MAX) { - char *cur_pg = pg->data; - jl_taggedvalue_t *fl_beg = (jl_taggedvalue_t*)(cur_pg + pg->fl_begin_offset); - jl_taggedvalue_t *fl_end = (jl_taggedvalue_t*)(cur_pg + pg->fl_end_offset); - *pfl[t_i * JL_GC_N_POOLS + pg->pool_n] = fl_beg; - pfl[t_i * JL_GC_N_POOLS + pg->pool_n] = &fl_end->next; + // merge free lists + for (int t_i = 0; t_i < n_threads; t_i++) { + jl_ptls_t ptls2 = gc_all_tls_states[t_i]; + if (ptls2 == NULL) { + continue; + } + jl_gc_pagemeta_t *pg = jl_atomic_load_relaxed(&ptls2->gc_tls.page_metadata_allocd.bottom); + while (pg != NULL) { + jl_gc_pagemeta_t *pg2 = pg->next; + if (pg->fl_begin_offset != UINT16_MAX) { + char *cur_pg = pg->data; + jl_taggedvalue_t *fl_beg = (jl_taggedvalue_t*)(cur_pg + pg->fl_begin_offset); + jl_taggedvalue_t *fl_end = (jl_taggedvalue_t*)(cur_pg + pg->fl_end_offset); + *pfl[t_i * JL_GC_N_POOLS + pg->pool_n] = fl_beg; + pfl[t_i * JL_GC_N_POOLS + pg->pool_n] = &fl_end->next; + } + pg = pg2; } - pg = pg2; } - } - // null out terminal pointers of free lists - for (int t_i = 0; t_i < n_threads; t_i++) { - jl_ptls_t ptls2 = gc_all_tls_states[t_i]; - if (ptls2 != NULL) { - for (int i = 0; i < JL_GC_N_POOLS; i++) { - *pfl[t_i * JL_GC_N_POOLS + i] = NULL; + // null out terminal pointers of free lists + for (int t_i = 0; t_i < n_threads; t_i++) { + jl_ptls_t ptls2 = gc_all_tls_states[t_i]; + if (ptls2 != NULL) { + for (int i = 0; i < JL_GC_N_POOLS; i++) { + *pfl[t_i * JL_GC_N_POOLS + i] = NULL; + } } } - } - // cleanup - free(pfl); - free(new_gc_allocd_scratch); + // cleanup + free(pfl); + free(new_gc_allocd_scratch); + } + uint64_t t_page_walk_end = jl_hrtime(); + gc_num.total_sweep_page_walk_time += t_page_walk_end - t_page_walk_start; #ifdef _P64 // only enable concurrent sweeping on 64bit // wake thread up to sweep concurrently @@ -1439,7 +1447,10 @@ static void gc_sweep_pool(void) uv_sem_post(&gc_sweep_assists_needed); } else { + uint64_t t_madvise_start = jl_hrtime(); gc_free_pages(); + uint64_t t_madvise_end = jl_hrtime(); + gc_num.total_sweep_madvise_time += t_madvise_end - t_madvise_start; } #else gc_free_pages(); From 4250be80f52531fda3c72542c3e351c5ad67b4a5 Mon Sep 17 00:00:00 2001 From: Simeon David Schaub Date: Thu, 9 Jan 2025 11:37:29 +0100 Subject: [PATCH 167/342] add detection for zen 5 (#56967) ref https://github.com/llvm/llvm-project/commit/149a150b50c112e26fc5acbdd58250c44ccd777f --------- Co-authored-by: gbaraldi --- src/features_x86.h | 28 +++++++++++++++++++++++++++- src/processor_x86.cpp | 35 ++++++++++++++++++++++++++++++++--- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/features_x86.h b/src/features_x86.h index 2ecc8fee32a38..b6e2b23985b4f 100644 --- a/src/features_x86.h +++ b/src/features_x86.h @@ -5,6 +5,13 @@ #else #define JL_X86_64ONLY_VER(x) x #endif +// The code is similar to what is here so the bits can be used as reference +// https://github.com/llvm/llvm-project/blob/3f7905733820851bc4f65cb4af693c3101cbf20d/llvm/lib/TargetParser/Host.cpp#L1257 + +// The way the bits here work is an index into the features array. This is a bit array +// The index works as follows: +// 32*i + j where i is the index into the array and j is the bit in the array. +// There is a reference to what each index corresponds to in _get_host_cpu // X86 features definition // EAX=1: ECX @@ -79,6 +86,7 @@ JL_FEATURE_DEF(avx512vp2intersect, 32 * 4 + 8, 0) JL_FEATURE_DEF(serialize, 32 * 4 + 14, 110000) JL_FEATURE_DEF(tsxldtrk, 32 * 4 + 16, 110000) JL_FEATURE_DEF(pconfig, 32 * 4 + 18, 0) +// JL_FEATURE_DEF(ibt, 32 * 4 + 20, 0) JL_FEATURE_DEF_NAME(amx_bf16, 32 * 4 + 22, 110000, "amx-bf16") JL_FEATURE_DEF(avx512fp16, 32 * 4 + 23, 140000) JL_FEATURE_DEF_NAME(amx_tile, 32 * 4 + 24, 110000, "amx-tile") @@ -110,10 +118,28 @@ JL_FEATURE_DEF(clzero, 32 * 8 + 0, 0) JL_FEATURE_DEF(wbnoinvd, 32 * 8 + 9, 0) // EAX=7,ECX=1: EAX +JL_FEATURE_DEF(sha512, 32 * 9 + 0, 170000) +JL_FEATURE_DEF(sm3, 32 * 9 + 1, 170000) +JL_FEATURE_DEF(sm4, 32 * 9 + 2, 170000) +JL_FEATURE_DEF(raoint, 32 * 9 + 3, 170000) JL_FEATURE_DEF(avxvnni, 32 * 9 + 4, 120000) JL_FEATURE_DEF(avx512bf16, 32 * 9 + 5, 0) +JL_FEATURE_DEF(cmpccxadd, 32 * 9 + 7, 160000) +JL_FEATURE_DEF_NAME(amx_fp16, 32 * 9 + 21, 160000, "amx-fp16") +JL_FEATURE_DEF(hreset, 32 * 9 + 22, 160000) +JL_FEATURE_DEF(avxifma, 32 * 9 + 23, 160000) + +// EAX=7,ECX=1: EBX +JL_FEATURE_DEF(avxvnniint8, 32 * 10 + 4, 160000) +JL_FEATURE_DEF(avxneconvert, 32 * 10 + 5, 160000) +JL_FEATURE_DEF_NAME(amx_complex, 32 * 10 + 8, 170000, "amx-complex") +JL_FEATURE_DEF(avxvnniint16, 32 * 10 + 10, 170000) +JL_FEATURE_DEF(prefetchi, 32 * 10 + 14, 160000) +JL_FEATURE_DEF(usermsr, 32 * 10 + 15, 170000) +// JL_FEATURE_DEF(avx10, 32 * 10 + 19, 170000) // TODO: What to do about avx10 and it's mess? +// JL_FEATURE_DEF(apxf, 32 * 10 + 21, 190000) // EAX=0x14,ECX=0: EBX -JL_FEATURE_DEF(ptwrite, 32 * 10 + 4, 0) +JL_FEATURE_DEF(ptwrite, 32 * 11 + 4, 0) #undef JL_X86_64ONLY_VER diff --git a/src/processor_x86.cpp b/src/processor_x86.cpp index f1dff063de1d9..bf765be160ed2 100644 --- a/src/processor_x86.cpp +++ b/src/processor_x86.cpp @@ -96,9 +96,10 @@ enum class CPU : uint32_t { amd_znver2, amd_znver3, amd_znver4, + amd_znver5, }; -static constexpr size_t feature_sz = 11; +static constexpr size_t feature_sz = 12; static constexpr FeatureName feature_names[] = { #define JL_FEATURE_DEF(name, bit, llvmver) {#name, bit, llvmver}, #define JL_FEATURE_DEF_NAME(name, bit, llvmver, str) {str, bit, llvmver}, @@ -141,6 +142,10 @@ static constexpr FeatureDep deps[] = { {vpclmulqdq, avx}, {vpclmulqdq, pclmul}, {avxvnni, avx2}, + {avxvnniint8, avx2}, + {avxvnniint16, avx2}, + {avxifma, avx2}, + {avxneconvert, avx2}, {avx512f, avx2}, {avx512dq, avx512f}, {avx512ifma, avx512f}, @@ -159,6 +164,8 @@ static constexpr FeatureDep deps[] = { {avx512fp16, avx512vl}, {amx_int8, amx_tile}, {amx_bf16, amx_tile}, + {amx_fp16, amx_tile}, + {amx_complex, amx_tile}, {sse4a, sse3}, {xop, fma4}, {fma4, avx}, @@ -166,6 +173,9 @@ static constexpr FeatureDep deps[] = { {xsaveopt, xsave}, {xsavec, xsave}, {xsaves, xsave}, + {sha512, avx2}, + {sm3, avx}, + {sm4, avx2}, }; // We require cx16 on 64bit by default. This can be overwritten with `-cx16` @@ -236,6 +246,7 @@ constexpr auto znver2 = znver1 | get_feature_masks(clwb, rdpid, wbnoinvd); constexpr auto znver3 = znver2 | get_feature_masks(shstk, pku, vaes, vpclmulqdq); constexpr auto znver4 = znver3 | get_feature_masks(avx512f, avx512cd, avx512dq, avx512bw, avx512vl, avx512ifma, avx512vbmi, avx512vbmi2, avx512vnni, avx512bitalg, avx512vpopcntdq, avx512bf16, gfni, shstk, xsaves); +constexpr auto znver5 = znver4 | get_feature_masks(avxvnni, movdiri, movdir64b, avx512vp2intersect, prefetchi, avxvnni); } @@ -298,6 +309,7 @@ static constexpr CPUSpec cpus[] = { {"znver2", CPU::amd_znver2, CPU::generic, 0, Feature::znver2}, {"znver3", CPU::amd_znver3, CPU::amd_znver2, 120000, Feature::znver3}, {"znver4", CPU::amd_znver4, CPU::amd_znver3, 160000, Feature::znver4}, + {"znver5", CPU::amd_znver5, CPU::amd_znver4, 190000, Feature::znver5}, }; static constexpr size_t ncpu_names = sizeof(cpus) / sizeof(cpus[0]); @@ -575,6 +587,9 @@ static CPU get_amd_processor_name(uint32_t family, uint32_t model, const uint32_ return CPU::amd_znver4; } return CPU::amd_znver3; // fallback + case 26: + // if (model <= 0x77) + return CPU::amd_znver5; } } @@ -660,11 +675,12 @@ static NOINLINE std::pair> _get_host_cpu(void) int32_t info7[4]; jl_cpuidex(info7, 7, 1); features[9] = info7[0]; + features[10] = info7[1]; } if (maxleaf >= 0x14) { int32_t info14[4]; jl_cpuidex(info14, 0x14, 0); - features[10] = info14[1]; + features[11] = info14[1]; } // Fix up AVX bits to account for OS support and match LLVM model @@ -705,7 +721,20 @@ static NOINLINE std::pair> _get_host_cpu(void) else { cpu = uint32_t(CPU::generic); } - + /* Feature bits to register map + feature[0] = ecx + feature[1] = edx + feature[2] = leaf 7 ebx + feature[3] = leaf 7 ecx + feature[4] = leaf 7 edx + feature[5] = leaf 0x80000001 ecx + feature[6] = leaf 0x80000001 edx + feature[7] = leaf 0xd subleaf 1 eax + feature[8] = leaf 0x80000008 ebx + feature[9] = leaf 7 ebx subleaf 1 eax + feature[10] = leaf 7 ebx subleaf 1 ebx + feature[11] = leaf 0x14 ebx + */ return std::make_pair(cpu, features); } From 1ebacacc5a82e16930bd5ae70b641a3cbd6ee883 Mon Sep 17 00:00:00 2001 From: Will Tebbutt Date: Thu, 9 Jan 2025 11:30:55 +0000 Subject: [PATCH 168/342] fix deepcopy for non-trivial circular references (#56990) Resolves #56775 . Credit for this fix rests entirely with bbrehm . --------- Co-authored-by: Lilith Orion Hafner Co-authored-by: Neven Sajko <4944410+nsajko@users.noreply.github.com> --- base/deepcopy.jl | 7 +++++-- test/copy.jl | 9 +++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/base/deepcopy.jl b/base/deepcopy.jl index c4f9ae1a6cb10..f60ce2043dd5a 100644 --- a/base/deepcopy.jl +++ b/base/deepcopy.jl @@ -120,11 +120,14 @@ function _deepcopy_memory_t(@nospecialize(x::Memory), T, stackdict::IdDict) end return dest end -@eval function deepcopy_internal(x::Array{T, N}, stackdict::IdDict) where {T, N} +function deepcopy_internal(x::Array{T, N}, stackdict::IdDict) where {T, N} if haskey(stackdict, x) return stackdict[x]::typeof(x) end - stackdict[x] = $(Expr(:new, :(Array{T, N}), :(deepcopy_internal(x.ref, stackdict)), :(x.size))) + y = stackdict[x] = Array{T, N}(undef, ntuple(Returns(0), Val{N}())) + setfield!(y, :ref, deepcopy_internal(x.ref, stackdict)) + setfield!(y, :size, x.size) + y end function deepcopy_internal(x::GenericMemoryRef, stackdict::IdDict) if haskey(stackdict, x) diff --git a/test/copy.jl b/test/copy.jl index 559bf5d3e757a..f5cc57c86feaa 100644 --- a/test/copy.jl +++ b/test/copy.jl @@ -253,6 +253,15 @@ end @test copyto!(s, String[]) == [1, 2] # No error end +@testset "circular reference arrays" begin + # issue 56775 + p = Any[nothing] + p[1] = p + p2 = deepcopy(p) + @test p2 === p2[1] + @test p2 !== p +end + @testset "deepcopy_internal arrays" begin @test (@inferred Base.deepcopy_internal(zeros(), IdDict())) == zeros() end From cfd3922cabfdfca0b417651ee4cea5a649cbebe5 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Thu, 9 Jan 2025 17:28:11 +0100 Subject: [PATCH 169/342] Add basic code for binding partition revalidation (#56649) This adds the binding partition revalidation code from #54654. This is the last piece of that PR that hasn't been merged yet - however the TODO in that PR still stands for future work. This PR itself adds a callback that gets triggered by deleting a binding. It will then walk all code in the system and invalidate code instances of Methods whose lowered source referenced the given global. This walk is quite slow. Future work will add backedges and optimizations to make this faster, but the basic functionality should be in place with this PR. --- base/Base_compiler.jl | 1 + base/invalidation.jl | 111 ++++++++++++++++++++++++++++++++++++++++++ src/gf.c | 5 ++ src/module.c | 26 +++++++++- test/rebinding.jl | 7 +++ 5 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 base/invalidation.jl diff --git a/base/Base_compiler.jl b/base/Base_compiler.jl index 91f327980389d..db3ebb0232e38 100644 --- a/base/Base_compiler.jl +++ b/base/Base_compiler.jl @@ -255,6 +255,7 @@ include("ordering.jl") using .Order include("coreir.jl") +include("invalidation.jl") # For OS specific stuff # We need to strcat things here, before strings are really defined diff --git a/base/invalidation.jl b/base/invalidation.jl new file mode 100644 index 0000000000000..40a010ab7361c --- /dev/null +++ b/base/invalidation.jl @@ -0,0 +1,111 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +struct GlobalRefIterator + mod::Module +end +IteratorSize(::Type{GlobalRefIterator}) = SizeUnknown() +globalrefs(mod::Module) = GlobalRefIterator(mod) + +function iterate(gri::GlobalRefIterator, i = 1) + m = gri.mod + table = ccall(:jl_module_get_bindings, Ref{SimpleVector}, (Any,), m) + i == length(table) && return nothing + b = table[i] + b === nothing && return iterate(gri, i+1) + return ((b::Core.Binding).globalref, i+1) +end + +const TYPE_TYPE_MT = Type.body.name.mt +const NONFUNCTION_MT = Core.MethodTable.name.mt +function foreach_module_mtable(visit, m::Module, world::UInt) + for gb in globalrefs(m) + binding = gb.binding + bpart = lookup_binding_partition(world, binding) + if is_defined_const_binding(binding_kind(bpart)) + v = partition_restriction(bpart) + uw = unwrap_unionall(v) + name = gb.name + if isa(uw, DataType) + tn = uw.name + if tn.module === m && tn.name === name && tn.wrapper === v && isdefined(tn, :mt) + # this is the original/primary binding for the type (name/wrapper) + mt = tn.mt + if mt !== nothing && mt !== TYPE_TYPE_MT && mt !== NONFUNCTION_MT + @assert mt.module === m + visit(mt) || return false + end + end + elseif isa(v, Module) && v !== m && parentmodule(v) === m && _nameof(v) === name + # this is the original/primary binding for the submodule + foreach_module_mtable(visit, v, world) || return false + elseif isa(v, Core.MethodTable) && v.module === m && v.name === name + # this is probably an external method table here, so let's + # assume so as there is no way to precisely distinguish them + visit(v) || return false + end + end + end + return true +end + +function foreach_reachable_mtable(visit, world::UInt) + visit(TYPE_TYPE_MT) || return + visit(NONFUNCTION_MT) || return + for mod in loaded_modules_array() + foreach_module_mtable(visit, mod, world) + end +end + +function should_invalidate_code_for_globalref(gr::GlobalRef, src::CodeInfo) + found_any = false + labelchangemap = nothing + stmts = src.code + isgr(g::GlobalRef) = gr.mod == g.mod && gr.name === g.name + isgr(g) = false + for i = 1:length(stmts) + stmt = stmts[i] + if isgr(stmt) + found_any = true + continue + end + for ur in Compiler.userefs(stmt) + arg = ur[] + # If any of the GlobalRefs in this stmt match the one that + # we are about, we need to move out all GlobalRefs to preserve + # effect order, in case we later invalidate a different GR + if isa(arg, GlobalRef) + if isgr(arg) + @assert !isa(stmt, PhiNode) + found_any = true + break + end + end + end + end + return found_any +end + +function invalidate_code_for_globalref!(gr::GlobalRef, new_max_world::UInt) + valid_in_valuepos = false + foreach_reachable_mtable(new_max_world) do mt::Core.MethodTable + for method in MethodList(mt) + if isdefined(method, :source) + src = _uncompressed_ir(method) + old_stmts = src.code + if should_invalidate_code_for_globalref(gr, src) + for mi in specializations(method) + ci = mi.cache + while true + if ci.max_world > new_max_world + ccall(:jl_invalidate_code_instance, Cvoid, (Any, UInt), ci, new_max_world) + end + isdefined(ci, :next) || break + ci = ci.next + end + end + end + end + end + return true + end +end diff --git a/src/gf.c b/src/gf.c index 080d1ebd52ba8..ba28edfbeeff7 100644 --- a/src/gf.c +++ b/src/gf.c @@ -1867,6 +1867,11 @@ static void invalidate_code_instance(jl_code_instance_t *replaced, size_t max_wo JL_UNLOCK(&replaced_mi->def.method->writelock); } +JL_DLLEXPORT void jl_invalidate_code_instance(jl_code_instance_t *replaced, size_t max_world) +{ + invalidate_code_instance(replaced, max_world, 1); +} + static void _invalidate_backedges(jl_method_instance_t *replaced_mi, size_t max_world, int depth) { jl_array_t *backedges = replaced_mi->backedges; if (backedges) { diff --git a/src/module.c b/src/module.c index 1b4c5bd78f667..004371b9144b2 100644 --- a/src/module.c +++ b/src/module.c @@ -1032,6 +1032,21 @@ JL_DLLEXPORT void jl_set_const(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var jl_gc_wb(bpart, val); } +void jl_invalidate_binding_refs(jl_globalref_t *ref, size_t new_world) +{ + static jl_value_t *invalidate_code_for_globalref = NULL; + if (invalidate_code_for_globalref == NULL && jl_base_module != NULL) + invalidate_code_for_globalref = jl_get_global(jl_base_module, jl_symbol("invalidate_code_for_globalref!")); + if (!invalidate_code_for_globalref) + jl_error("Binding invalidation is not permitted during bootstrap."); + if (jl_generating_output()) + jl_error("Binding invalidation is not permitted during image generation."); + jl_value_t *boxed_world = jl_box_ulong(new_world); + JL_GC_PUSH1(&boxed_world); + jl_call2((jl_function_t*)invalidate_code_for_globalref, (jl_value_t*)ref, boxed_world); + JL_GC_POP(); +} + extern jl_mutex_t world_counter_lock; JL_DLLEXPORT void jl_disable_binding(jl_globalref_t *gr) { @@ -1046,9 +1061,11 @@ JL_DLLEXPORT void jl_disable_binding(jl_globalref_t *gr) JL_LOCK(&world_counter_lock); jl_task_t *ct = jl_current_task; + size_t last_world = ct->world_age; size_t new_max_world = jl_atomic_load_acquire(&jl_world_counter); - // TODO: Trigger invalidation here - (void)ct; + ct->world_age = jl_typeinf_world; + jl_invalidate_binding_refs(gr, new_max_world); + ct->world_age = last_world; jl_atomic_store_release(&bpart->max_world, new_max_world); jl_atomic_store_release(&jl_world_counter, new_max_world + 1); JL_UNLOCK(&world_counter_lock); @@ -1334,6 +1351,11 @@ JL_DLLEXPORT void jl_add_to_module_init_list(jl_value_t *mod) jl_array_ptr_1d_push(jl_module_init_order, mod); } +JL_DLLEXPORT jl_svec_t *jl_module_get_bindings(jl_module_t *m) +{ + return jl_atomic_load_relaxed(&m->bindings); +} + JL_DLLEXPORT void jl_init_restored_module(jl_value_t *mod) { if (!jl_generating_output() || jl_options.incremental) { diff --git a/test/rebinding.jl b/test/rebinding.jl index c93c34be7a75c..ad0ad1fc1643d 100644 --- a/test/rebinding.jl +++ b/test/rebinding.jl @@ -33,4 +33,11 @@ module Rebinding @test Base.@world(Foo, defined_world_age) == typeof(x) @test Base.@world(Rebinding.Foo, defined_world_age) == typeof(x) @test Base.@world((@__MODULE__).Foo, defined_world_age) == typeof(x) + + # Test invalidation (const -> undefined) + const delete_me = 1 + f_return_delete_me() = delete_me + @test f_return_delete_me() == 1 + Base.delete_binding(@__MODULE__, :delete_me) + @test_throws UndefVarError f_return_delete_me() end From 3d85309e800fcc8368a8291cc76bc28a10067b10 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Thu, 9 Jan 2025 17:29:39 +0100 Subject: [PATCH 170/342] Consolidate various isdefined functionality into a new builtin (#56985) In #54999 I extended `:isdefined` with the ability to specify whether or not to consider imported bindings defined. As a result, we now have two mechanisms for querying `isdefined` on globals (the other being `Core.isdefined`) with incompatible feature sets (`Core.isdefined` supports an atomic ordering argument, but not `allow_import`). Additionally, only one of them had proper codegen support. I also don't like to have IR forms for things that could be perfectly well handled by builtin calls (along the lines of #56713). So this tries to clean that all up by: 1. Adding a new builtin `isdefinedglobal` that has the full feature set 2. Dropping `:isdefined` on globals as an IR form (the frontend form gets lowered to the intrinsic if called on globals) 3. Wiring up codegen and correcting inference for that new builtin An additional motivation is that `isdefined` on globals needs support for partition edges (like other builtins), and having to have a special case for :isdefined was marginally annoying. Just using an intrinsic for this is much cleaner. Lastly, the reason for a new intrinsic over extending the existing `isdefined`, is that over time we've moved away from conflating fields and globals for Module (e.g. introducing `getglobal`/`setglobal!`), so this is a natural extension of that. Of course, the existing behavior is retained for ordinary `isdefined`. --- Compiler/src/Compiler.jl | 4 +- Compiler/src/abstractinterpretation.jl | 105 +++++++++++++++++++------ Compiler/src/ssair/verify.jl | 4 +- base/boot.jl | 2 +- base/docs/basedocs.jl | 34 ++++++++ doc/src/base/base.md | 1 + doc/src/devdocs/ast.md | 7 +- src/builtin_proto.h | 1 + src/builtins.c | 28 +++++++ src/codegen.cpp | 98 +++++++++++++++-------- src/interpreter.c | 13 +-- src/julia-syntax.scm | 10 ++- src/staticdata.c | 5 +- test/meta.jl | 2 +- test/syntax.jl | 34 ++++---- 15 files changed, 245 insertions(+), 103 deletions(-) diff --git a/Compiler/src/Compiler.jl b/Compiler/src/Compiler.jl index a9ab27a682ad7..ea939f86422c5 100644 --- a/Compiler/src/Compiler.jl +++ b/Compiler/src/Compiler.jl @@ -49,7 +49,7 @@ using Core: ABIOverride, Builtin, CodeInstance, IntrinsicFunction, MethodInstanc using Base using Base: @_foldable_meta, @_gc_preserve_begin, @_gc_preserve_end, @nospecializeinfer, - BINDING_KIND_GLOBAL, Base, BitVector, Bottom, Callable, DataTypeFieldDesc, + BINDING_KIND_GLOBAL, BINDING_KIND_UNDEF_CONST, Base, BitVector, Bottom, Callable, DataTypeFieldDesc, EffectsOverride, Filter, Generator, IteratorSize, JLOptions, NUM_EFFECTS_OVERRIDES, OneTo, Ordering, RefValue, SizeUnknown, _NAMEDTUPLE_NAME, _array_for, _bits_findnext, _methods_by_ftype, _uniontypes, all, allocatedinline, any, @@ -58,7 +58,7 @@ using Base: @_foldable_meta, @_gc_preserve_begin, @_gc_preserve_end, @nospeciali datatype_pointerfree, decode_effects_override, diff_names, fieldindex, generating_output, get_nospecializeinfer_sig, get_world_counter, has_free_typevars, hasgenerator, hasintersect, indexed_iterate, isType, is_file_tracked, is_function_def, - is_meta_expr, is_meta_expr_head, is_nospecialized, is_nospecializeinfer, + is_meta_expr, is_meta_expr_head, is_nospecialized, is_nospecializeinfer, is_defined_const_binding, is_some_const_binding, is_some_guard, is_some_imported, is_valid_intrinsic_elptr, isbitsunion, isconcretedispatch, isdispatchelem, isexpr, isfieldatomic, isidentityfree, iskindtype, ismutabletypename, ismutationfree, issingletontype, isvarargtype, isvatuple, diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index f2d4461a9874a..0c340a89d9878 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -2637,21 +2637,14 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f), elseif f === Core.getfield && argtypes_are_actually_getglobal(argtypes) return Future(abstract_eval_getglobal(interp, sv, si.saw_latestworld, argtypes)) elseif f === Core.isdefined && argtypes_are_actually_getglobal(argtypes) - exct = Bottom - if length(argtypes) == 4 - order = argtypes[4] - exct = global_order_exct(order, #=loading=#true, #=storing=#false) - if !(isa(order, Const) && get_atomic_order(order.val, #=loading=#true, #=storing=#false).x >= MEMORY_ORDER_UNORDERED.x) - exct = Union{exct, ConcurrencyViolationError} - end - end - return Future(merge_exct(CallMeta(abstract_eval_isdefined( - interp, - GlobalRef((argtypes[2]::Const).val::Module, - (argtypes[3]::Const).val::Symbol), - si.saw_latestworld, - sv), - NoCallInfo()), exct)) + return Future(abstract_eval_isdefinedglobal(interp, argtypes[2], argtypes[3], Const(true), + length(argtypes) == 4 ? argtypes[4] : Const(:unordered), + si.saw_latestworld, sv)) + elseif f === Core.isdefinedglobal && 3 <= length(argtypes) <= 5 + return Future(abstract_eval_isdefinedglobal(interp, argtypes[2], argtypes[3], + length(argtypes) >= 4 ? argtypes[4] : Const(true), + length(argtypes) >= 5 ? argtypes[5] : Const(:unordered), + si.saw_latestworld, sv)) elseif f === Core.get_binding_type return Future(abstract_eval_get_binding_type(interp, sv, argtypes)) end @@ -3203,21 +3196,73 @@ function abstract_eval_isdefined_expr(interp::AbstractInterpreter, e::Expr, ssta return abstract_eval_isdefined(interp, sym, sstate.saw_latestworld, sv) end -function abstract_eval_isdefined(interp::AbstractInterpreter, @nospecialize(sym), saw_latestworld::Bool, sv::AbsIntState) +const generic_isdefinedglobal_effects = Effects(EFFECTS_TOTAL, consistent=ALWAYS_FALSE, nothrow=false) +function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, mod::Module, sym::Symbol, allow_import::Union{Bool, Nothing}, saw_latestworld::Bool, sv::AbsIntState) rt = Bool + if saw_latestworld + return RTEffects(rt, Union{}, Effects(generic_isdefinedglobal_effects, nothrow=true)) + end + effects = EFFECTS_TOTAL - exct = Union{} - isa(sym, Symbol) && (sym = GlobalRef(frame_module(sv), sym)) - if isa(sym, GlobalRef) - rte = abstract_eval_globalref(interp, sym, saw_latestworld, sv) + partition = lookup_binding_partition!(interp, GlobalRef(mod, sym), sv) + if allow_import !== true && is_some_imported(binding_kind(partition)) + if allow_import === false + rt = Const(false) + else + effects = Effects(generic_isdefinedglobal_effects, nothrow=true) + end + else + partition = walk_binding_partition!(interp, partition, sv) + rte = abstract_eval_partition_load(interp, partition) if rte.exct == Union{} rt = Const(true) elseif rte.rt === Union{} && rte.exct === UndefVarError rt = Const(false) else - effects = Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE) + effects = Effects(generic_isdefinedglobal_effects, nothrow=true) + end + end + return RTEffects(rt, Union{}, effects) +end + +function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, @nospecialize(M), @nospecialize(s), @nospecialize(allow_import_arg), @nospecialize(order_arg), saw_latestworld::Bool, sv::AbsIntState) + exct = Bottom + allow_import = true + if allow_import_arg !== nothing + if !isa(allow_import_arg, Const) + allow_import = nothing + if widenconst(allow_import_arg) != Bool + exct = Union{exct, TypeError} + end + else + allow_import = allow_import_arg.val + end + end + if order_arg !== nothing + exct = global_order_exct(order_arg, #=loading=#true, #=storing=#false) + if !(isa(order_arg, Const) && get_atomic_order(order_arg.val, #=loading=#true, #=storing=#false).x >= MEMORY_ORDER_UNORDERED.x) + exct = Union{exct, ConcurrencyViolationError} + end + end + if M isa Const && s isa Const + M, s = M.val, s.val + if M isa Module && s isa Symbol + return merge_exct(CallMeta(abstract_eval_isdefinedglobal(interp, M, s, allow_import, saw_latestworld, sv), NoCallInfo()), exct) end - elseif isexpr(sym, :static_parameter) + return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo()) + elseif !hasintersect(widenconst(M), Module) || !hasintersect(widenconst(s), Symbol) + return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo()) + elseif M ⊑ Module && s ⊑ Symbol + return CallMeta(Bool, Union{exct, UndefVarError}, generic_isdefinedglobal_effects, NoCallInfo()) + end + return CallMeta(Bool, Union{exct, TypeError, UndefVarError}, generic_isdefinedglobal_effects, NoCallInfo()) +end + +function abstract_eval_isdefined(interp::AbstractInterpreter, @nospecialize(sym), saw_latestworld::Bool, sv::AbsIntState) + rt = Bool + effects = EFFECTS_TOTAL + exct = Union{} + if isexpr(sym, :static_parameter) n = sym.args[1]::Int if 1 <= n <= length(sv.sptypes) sp = sv.sptypes[n] @@ -3443,22 +3488,31 @@ function abstract_eval_globalref_type(g::GlobalRef, src::Union{CodeInfo, IRCode, return partition_restriction(partition) end -function abstract_eval_binding_partition!(interp::AbstractInterpreter, g::GlobalRef, sv::AbsIntState) +function lookup_binding_partition!(interp::AbstractInterpreter, g::GlobalRef, sv::AbsIntState) force_binding_resolution!(g) partition = lookup_binding_partition(get_inference_world(interp), g) update_valid_age!(sv, WorldRange(partition.min_world, partition.max_world)) + partition +end +function walk_binding_partition!(interp::AbstractInterpreter, partition::Core.BindingPartition, sv::AbsIntState) while is_some_imported(binding_kind(partition)) imported_binding = partition_restriction(partition)::Core.Binding partition = lookup_binding_partition(get_inference_world(interp), imported_binding) update_valid_age!(sv, WorldRange(partition.min_world, partition.max_world)) end + return partition +end +function abstract_eval_binding_partition!(interp::AbstractInterpreter, g::GlobalRef, sv::AbsIntState) + partition = lookup_binding_partition!(interp, g, sv) + partition = walk_binding_partition!(interp, partition, sv) return partition end function abstract_eval_partition_load(interp::AbstractInterpreter, partition::Core.BindingPartition) - if is_some_guard(binding_kind(partition)) + kind = binding_kind(partition) + if is_some_guard(kind) || kind == BINDING_KIND_UNDEF_CONST if InferenceParams(interp).assume_bindings_static return RTEffects(Union{}, UndefVarError, EFFECTS_THROWS) else @@ -3468,13 +3522,12 @@ function abstract_eval_partition_load(interp::AbstractInterpreter, partition::Co end end - if is_some_const_binding(binding_kind(partition)) + if is_defined_const_binding(kind) rt = Const(partition_restriction(partition)) return RTEffects(rt, Union{}, Effects(EFFECTS_TOTAL, inaccessiblememonly=is_mutation_free_argtype(rt) ? ALWAYS_TRUE : ALWAYS_FALSE)) end rt = partition_restriction(partition) - return RTEffects(rt, UndefVarError, generic_getglobal_effects) end diff --git a/Compiler/src/ssair/verify.jl b/Compiler/src/ssair/verify.jl index 072a564a31f78..12eb09be693f3 100644 --- a/Compiler/src/ssair/verify.jl +++ b/Compiler/src/ssair/verify.jl @@ -366,7 +366,7 @@ function verify_ir(ir::IRCode, print::Bool=true, @verify_error "Assignment should have been removed during SSA conversion" raise_error() elseif stmt.head === :isdefined - if length(stmt.args) > 2 || (length(stmt.args) == 2 && !isa(stmt.args[2], Bool)) + if length(stmt.args) > 2 @verify_error "malformed isdefined" raise_error() end @@ -382,7 +382,7 @@ function verify_ir(ir::IRCode, print::Bool=true, elseif stmt.head === :foreigncall isforeigncall = true elseif stmt.head === :isdefined && length(stmt.args) == 1 && - (stmt.args[1] isa GlobalRef || isexpr(stmt.args[1], :static_parameter)) + isexpr(stmt.args[1], :static_parameter) # a GlobalRef or static_parameter isdefined check does not evaluate its argument continue elseif stmt.head === :call diff --git a/base/boot.jl b/base/boot.jl index 05788844fde66..53e439d83ebe2 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -231,7 +231,7 @@ export fieldtype, getfield, setfield!, swapfield!, modifyfield!, replacefield!, setfieldonce!, nfields, throw, tuple, ===, isdefined, eval, # access to globals - getglobal, setglobal!, swapglobal!, modifyglobal!, replaceglobal!, setglobalonce!, + getglobal, setglobal!, swapglobal!, modifyglobal!, replaceglobal!, setglobalonce!, isdefinedglobal, # ifelse, sizeof # not exported, to avoid conflicting with Base # type reflection <:, typeof, isa, typeassert, diff --git a/base/docs/basedocs.jl b/base/docs/basedocs.jl index 16175010a20fa..88ed34de02b64 100644 --- a/base/docs/basedocs.jl +++ b/base/docs/basedocs.jl @@ -2754,6 +2754,9 @@ compatible with the stores to that location. Otherwise, if not declared as To test whether an array element is defined, use [`isassigned`](@ref) instead. +The global variable variant is supported for compatibility with older julia +releases. For new code, prefer [`isdefinedglobal`](@ref). + See also [`@isdefined`](@ref). # Examples @@ -2781,6 +2784,37 @@ false """ isdefined + +""" + isdefinedglobal(m::Module, s::Symbol, [allow_import::Bool=true, [order::Symbol=:unordered]]) + +Tests whether a global variable `s` is defined in module `m` (in the current world age). +A variable is considered defined if and only if a value may be read from this global variable +and an access will not throw. This includes both constants and global variables that have +a value set. + +If `allow_import` is `false`, the global variable must be defined inside `m` +and may not be imported from another module. + +See also [`@isdefined`](@ref). + +# Examples +```jldoctest +julia> isdefinedglobal(Base, :sum) +true + +julia> isdefinedglobal(Base, :NonExistentMethod) +false + +julia> isdefinedglobal(Base, :sum, false) +true + +julia> isdefinedglobal(Main, :sum, false) +false +``` +""" +isdefinedglobal + """ Memory{T}(undef, n) diff --git a/doc/src/base/base.md b/doc/src/base/base.md index 7181965d9aa81..e6c8ff554d494 100644 --- a/doc/src/base/base.md +++ b/doc/src/base/base.md @@ -166,6 +166,7 @@ Core.replacefield! Core.swapfield! Core.setfieldonce! Core.isdefined +Core.isdefinedglobal Base.@isdefined Base.convert Base.promote diff --git a/doc/src/devdocs/ast.md b/doc/src/devdocs/ast.md index d8db3ca677082..fe63dfe35edac 100644 --- a/doc/src/devdocs/ast.md +++ b/doc/src/devdocs/ast.md @@ -426,11 +426,8 @@ These symbols appear in the `head` field of [`Expr`](@ref)s in lowered form. * `isdefined` - `Expr(:isdefined, :x [, allow_import])` returns a Bool indicating whether `x` has - already been defined in the current scope. The optional second argument is a boolean - that specifies whether `x` should be considered defined by an import or if only constants - or globals in the current module count as being defined. If `x` is not a global, the argument - is ignored. + `Expr(:isdefined, :x)` returns a Bool indicating whether `x` has + already been defined in the current scope. * `the_exception` diff --git a/src/builtin_proto.h b/src/builtin_proto.h index 70ad67040991d..77463ae4884cb 100644 --- a/src/builtin_proto.h +++ b/src/builtin_proto.h @@ -45,6 +45,7 @@ DECLARE_BUILTIN(invoke); DECLARE_BUILTIN(is); DECLARE_BUILTIN(isa); DECLARE_BUILTIN(isdefined); +DECLARE_BUILTIN(isdefinedglobal); DECLARE_BUILTIN(issubtype); DECLARE_BUILTIN(memorynew); DECLARE_BUILTIN(memoryref); diff --git a/src/builtins.c b/src/builtins.c index c326e53ea968d..90d8a0d453e20 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1352,6 +1352,33 @@ JL_CALLABLE(jl_f_getglobal) return v; } +JL_CALLABLE(jl_f_isdefinedglobal) +{ + jl_module_t *m = NULL; + jl_sym_t *s = NULL; + JL_NARGS(isdefined, 2, 3); + int allow_import = 1; + enum jl_memory_order order = jl_memory_order_unspecified; + JL_TYPECHK(isdefined, module, args[0]); + JL_TYPECHK(isdefined, symbol, args[1]); + if (nargs == 3) { + JL_TYPECHK(isdefined, bool, args[2]); + allow_import = jl_unbox_bool(args[2]); + } + if (nargs == 4) { + JL_TYPECHK(isdefined, symbol, args[3]); + order = jl_get_atomic_order_checked((jl_sym_t*)args[2], 1, 0); + } + m = (jl_module_t*)args[0]; + s = (jl_sym_t*)args[1]; + if (order == jl_memory_order_unspecified) + order = jl_memory_order_unordered; + if (order < jl_memory_order_unordered) + jl_atomic_error("isdefined: module binding cannot be accessed non-atomically"); + int bound = jl_boundp(m, s, allow_import); // seq_cst always + return bound ? jl_true : jl_false; +} + JL_CALLABLE(jl_f_setglobal) { enum jl_memory_order order = jl_memory_order_release; @@ -2451,6 +2478,7 @@ void jl_init_primitives(void) JL_GC_DISABLED // module bindings jl_builtin_getglobal = add_builtin_func("getglobal", jl_f_getglobal); jl_builtin_setglobal = add_builtin_func("setglobal!", jl_f_setglobal); + jl_builtin_isdefinedglobal = add_builtin_func("isdefinedglobal", jl_f_isdefinedglobal); add_builtin_func("get_binding_type", jl_f_get_binding_type); jl_builtin_swapglobal = add_builtin_func("swapglobal!", jl_f_swapglobal); jl_builtin_replaceglobal = add_builtin_func("replaceglobal!", jl_f_replaceglobal); diff --git a/src/codegen.cpp b/src/codegen.cpp index 4b0f4ebd765fa..7bc14d2d0347f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4173,6 +4173,34 @@ static bool emit_f_opfield(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, return false; } +static jl_cgval_t emit_isdefinedglobal(jl_codectx_t &ctx, jl_module_t *modu, jl_sym_t *name, int allow_import, enum jl_memory_order order) +{ + Value *isnull = NULL; + jl_binding_t *bnd = allow_import ? jl_get_binding(modu, name) : jl_get_module_binding(modu, name, 0); + jl_binding_partition_t *bpart = jl_get_binding_partition_all(bnd, ctx.min_world, ctx.max_world); + jl_ptr_kind_union_t pku = bpart ? jl_atomic_load_relaxed(&bpart->restriction) : encode_restriction(NULL, BINDING_KIND_GUARD); + if (decode_restriction_kind(pku) == BINDING_KIND_GLOBAL || jl_bkind_is_some_constant(decode_restriction_kind(pku))) { + if (jl_get_binding_value_if_const(bnd)) + return mark_julia_const(ctx, jl_true); + Value *bp = julia_binding_gv(ctx, bnd); + bp = julia_binding_pvalue(ctx, bp); + LoadInst *v = ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, bp, Align(sizeof(void*))); + jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_binding); + ai.decorateInst(v); + v->setOrdering(get_llvm_atomic_order(order)); + isnull = ctx.builder.CreateICmpNE(v, Constant::getNullValue(ctx.types().T_prjlvalue)); + } + else { + Value *v = ctx.builder.CreateCall(prepare_call(jlboundp_func), { + literal_pointer_val(ctx, (jl_value_t*)modu), + literal_pointer_val(ctx, (jl_value_t*)name), + ConstantInt::get(getInt32Ty(ctx.builder.getContext()), allow_import) + }); + isnull = ctx.builder.CreateICmpNE(v, ConstantInt::get(getInt32Ty(ctx.builder.getContext()), 0)); + } + return mark_julia_type(ctx, isnull, false, jl_bool_type); +} + static bool emit_f_opmemory(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, ArrayRef argv, size_t nargs, const jl_cgval_t *modifyop) { @@ -5074,6 +5102,42 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } } + else if (f == jl_builtin_isdefinedglobal && (nargs == 2 || nargs == 3 || nargs == 4)) { + const jl_cgval_t &mod = argv[1]; + const jl_cgval_t &sym = argv[2]; + bool allow_import = true; + enum jl_memory_order order = jl_memory_order_unspecified; + + if (nargs >= 3) { + const jl_cgval_t &arg3 = argv[3]; + if (arg3.constant && jl_is_bool(arg3.constant)) + allow_import = jl_unbox_bool(arg3.constant); + else + return false; + } + + if (nargs == 4) { + const jl_cgval_t &arg4 = argv[4]; + if (arg4.constant && jl_is_symbol(arg4.constant)) + order = jl_get_atomic_order((jl_sym_t*)arg4.constant, true, false); + else + return false; + } + else + order = jl_memory_order_unordered; + + if (order < jl_memory_order_unordered) { + return false; + } + + if (!mod.constant || !sym.constant || !jl_is_symbol(sym.constant) || !jl_is_module(mod.constant)) { + return false; + } + + *ret = emit_isdefinedglobal(ctx, (jl_module_t*)mod.constant, (jl_sym_t*)sym.constant, allow_import, order); + return true; + } + else if (f == jl_builtin_isdefined && (nargs == 2 || nargs == 3)) { const jl_cgval_t &obj = argv[1]; const jl_cgval_t &fld = argv[2]; @@ -6074,39 +6138,7 @@ static jl_cgval_t emit_isdefined(jl_codectx_t &ctx, jl_value_t *sym, int allow_i isnull = ctx.builder.CreateICmpNE(emit_typeof(ctx, sp, false, true), emit_tagfrom(ctx, jl_tvar_type)); } else { - jl_module_t *modu; - jl_sym_t *name; - if (jl_is_globalref(sym)) { - modu = jl_globalref_mod(sym); - name = jl_globalref_name(sym); - } - else { - assert(jl_is_symbol(sym) && "malformed isdefined expression"); - modu = ctx.module; - name = (jl_sym_t*)sym; - } - jl_binding_t *bnd = allow_import ? jl_get_binding(modu, name) : jl_get_module_binding(modu, name, 0); - jl_binding_partition_t *bpart = jl_get_binding_partition_all(bnd, ctx.min_world, ctx.max_world); - jl_ptr_kind_union_t pku = bpart ? jl_atomic_load_relaxed(&bpart->restriction) : encode_restriction(NULL, BINDING_KIND_GUARD); - if (decode_restriction_kind(pku) == BINDING_KIND_GLOBAL || jl_bkind_is_some_constant(decode_restriction_kind(pku))) { - if (jl_get_binding_value_if_const(bnd)) - return mark_julia_const(ctx, jl_true); - Value *bp = julia_binding_gv(ctx, bnd); - bp = julia_binding_pvalue(ctx, bp); - LoadInst *v = ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, bp, Align(sizeof(void*))); - jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_binding); - ai.decorateInst(v); - v->setOrdering(AtomicOrdering::Unordered); - isnull = ctx.builder.CreateICmpNE(v, Constant::getNullValue(ctx.types().T_prjlvalue)); - } - else { - Value *v = ctx.builder.CreateCall(prepare_call(jlboundp_func), { - literal_pointer_val(ctx, (jl_value_t*)modu), - literal_pointer_val(ctx, (jl_value_t*)name), - ConstantInt::get(getInt32Ty(ctx.builder.getContext()), allow_import) - }); - isnull = ctx.builder.CreateICmpNE(v, ConstantInt::get(getInt32Ty(ctx.builder.getContext()), 0)); - } + assert(false && "malformed expression"); } return mark_julia_type(ctx, isnull, false, jl_bool_type); } diff --git a/src/interpreter.c b/src/interpreter.c index b9bd1997caa17..338853b56f692 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -251,22 +251,15 @@ static jl_value_t *eval_value(jl_value_t *e, interpreter_state *s) else if (head == jl_isdefined_sym) { jl_value_t *sym = args[0]; int defined = 0; - int allow_import = 1; - if (nargs == 2) { - assert(jl_is_bool(args[1]) && "malformed IR"); - allow_import = args[1] == jl_true; - } + assert(nargs == 1 && "malformed IR"); if (jl_is_slotnumber(sym) || jl_is_argument(sym)) { ssize_t n = jl_slot_number(sym); if (src == NULL || n > jl_source_nslots(src) || n < 1 || s->locals == NULL) jl_error("access to invalid slot number"); defined = s->locals[n - 1] != NULL; } - else if (jl_is_globalref(sym)) { - defined = jl_boundp(jl_globalref_mod(sym), jl_globalref_name(sym), allow_import); - } - else if (jl_is_symbol(sym)) { - defined = jl_boundp(s->module, (jl_sym_t*)sym, allow_import); + else if (jl_is_globalref(sym) || jl_is_symbol(sym)) { + jl_error("[Internal Error]: :isdefined on globalref should use `isdefinedglobal`"); } else if (jl_is_expr(sym) && ((jl_expr_t*)sym)->head == jl_static_parameter_sym) { ssize_t n = jl_unbox_long(jl_exprarg(sym, 0)); diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index c522a565f462a..007c3ce820820 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1022,7 +1022,7 @@ (call (core svec) ,@attrs) ,mut ,min-initialized)) (call (core _setsuper!) ,name ,super) - (if (isdefined (globalref (thismodule) ,name) (false)) + (if (call (core isdefinedglobal) (thismodule) (inert ,name) (false)) (block (= ,prev (globalref (thismodule) ,name)) (if (call (core _equiv_typedef) ,prev ,name) @@ -1084,7 +1084,7 @@ (= ,name (call (core _abstracttype) (thismodule) (inert ,name) (call (core svec) ,@params))) (call (core _setsuper!) ,name ,super) (call (core _typebody!) ,name) - (if (&& (isdefined (globalref (thismodule) ,name) (false)) + (if (&& (call (core isdefinedglobal) (thismodule) (inert ,name) (false)) (call (core _equiv_typedef) (globalref (thismodule) ,name) ,name)) (null) (const (globalref (thismodule) ,name) ,name)) @@ -1105,7 +1105,7 @@ (= ,name (call (core _primitivetype) (thismodule) (inert ,name) (call (core svec) ,@params) ,n)) (call (core _setsuper!) ,name ,super) (call (core _typebody!) ,name) - (if (&& (isdefined (globalref (thismodule) ,name) (false)) + (if (&& (call (core isdefinedglobal) (thismodule) (inert ,name) (false)) (call (core _equiv_typedef) (globalref (thismodule) ,name) ,name)) (null) (const (globalref (thismodule) ,name) ,name)) @@ -4064,7 +4064,9 @@ f(x) = yt(x) (if (and (vinfo:asgn vi) (vinfo:capt vi)) `(call (core isdefined) ,sym (inert contents)) e)) - (else e)))) + (else (if (globalref? sym) + `(call (core isdefinedglobal) ,(cadr sym) (inert ,(caddr sym))) + e))))) ((_opaque_closure) (let* ((isva (car (cddddr e))) (nargs (cadr (cddddr e))) diff --git a/src/staticdata.c b/src/staticdata.c index bdeecb911e3eb..4124d3b481bb3 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -101,7 +101,7 @@ extern "C" { // TODO: put WeakRefs on the weak_refs list during deserialization // TODO: handle finalizers -#define NUM_TAGS 195 +#define NUM_TAGS 196 // An array of references that need to be restored from the sysimg // This is a manually constructed dual of the gvars array, which would be produced by codegen for Julia code, for C. @@ -311,6 +311,7 @@ jl_value_t **const*const get_tags(void) { INSERT_TAG(jl_builtin_compilerbarrier); INSERT_TAG(jl_builtin_getglobal); INSERT_TAG(jl_builtin_setglobal); + INSERT_TAG(jl_builtin_isdefinedglobal); INSERT_TAG(jl_builtin_swapglobal); INSERT_TAG(jl_builtin_modifyglobal); INSERT_TAG(jl_builtin_replaceglobal); @@ -506,7 +507,7 @@ static htable_t bits_replace; static const jl_fptr_args_t id_to_fptrs[] = { &jl_f_throw, &jl_f_throw_methoderror, &jl_f_is, &jl_f_typeof, &jl_f_issubtype, &jl_f_isa, &jl_f_typeassert, &jl_f__apply_iterate, &jl_f__apply_pure, - &jl_f__call_latest, &jl_f__call_in_world, &jl_f__call_in_world_total, &jl_f_isdefined, + &jl_f__call_latest, &jl_f__call_in_world, &jl_f__call_in_world_total, &jl_f_isdefined, &jl_f_isdefinedglobal, &jl_f_tuple, &jl_f_svec, &jl_f_intrinsic_call, &jl_f_getfield, &jl_f_setfield, &jl_f_swapfield, &jl_f_modifyfield, &jl_f_setfieldonce, &jl_f_replacefield, &jl_f_fieldtype, &jl_f_nfields, &jl_f_apply_type, &jl_f_memorynew, diff --git a/test/meta.jl b/test/meta.jl index 2b235d3cc1b0d..e9e344bba2e22 100644 --- a/test/meta.jl +++ b/test/meta.jl @@ -274,7 +274,7 @@ ci = code_lowered(g, Tuple{Val{true}})[1] @eval isdefined_globalref(x) = $(Expr(:isdefined, GlobalRef(Base, :foo))) ci = code_lowered(isdefined_globalref, Tuple{Int})[1] @test Meta.partially_inline!(copy(ci.code), Any[isdefined_globalref, 1], Tuple{typeof(isdefined_globalref), Int}, - [], 0, 0, :propagate)[1] == Expr(:isdefined, GlobalRef(Base, :foo)) + [], 0, 0, :propagate)[1] == Expr(:call, GlobalRef(Core, :isdefinedglobal), Base, QuoteNode(:foo)) withunreachable(s::String) = sin(s) ci = code_lowered(withunreachable, Tuple{String})[1] diff --git a/test/syntax.jl b/test/syntax.jl index fca8b9e8ccdf5..9fd0204821eab 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -3919,28 +3919,28 @@ module ExtendedIsDefined import .Import.x4 @test x2 == 2 # Resolve the binding @eval begin - @test $(Expr(:isdefined, GlobalRef(@__MODULE__, :x1))) - @test $(Expr(:isdefined, GlobalRef(@__MODULE__, :x2))) - @test $(Expr(:isdefined, GlobalRef(@__MODULE__, :x3))) - @test $(Expr(:isdefined, GlobalRef(@__MODULE__, :x4))) + @test Core.isdefinedglobal(@__MODULE__, :x1) + @test Core.isdefinedglobal(@__MODULE__, :x2) + @test Core.isdefinedglobal(@__MODULE__, :x3) + @test Core.isdefinedglobal(@__MODULE__, :x4) - @test $(Expr(:isdefined, GlobalRef(@__MODULE__, :x1), false)) - @test !$(Expr(:isdefined, GlobalRef(@__MODULE__, :x2), false)) - @test !$(Expr(:isdefined, GlobalRef(@__MODULE__, :x3), false)) - @test !$(Expr(:isdefined, GlobalRef(@__MODULE__, :x4), false)) + @test Core.isdefinedglobal(@__MODULE__, :x1, false) + @test !Core.isdefinedglobal(@__MODULE__, :x2, false) + @test !Core.isdefinedglobal(@__MODULE__, :x3, false) + @test !Core.isdefinedglobal(@__MODULE__, :x4, false) end @eval begin @Base.Experimental.force_compile - @test $(Expr(:isdefined, GlobalRef(@__MODULE__, :x1))) - @test $(Expr(:isdefined, GlobalRef(@__MODULE__, :x2))) - @test $(Expr(:isdefined, GlobalRef(@__MODULE__, :x3))) - @test $(Expr(:isdefined, GlobalRef(@__MODULE__, :x4))) - - @test $(Expr(:isdefined, GlobalRef(@__MODULE__, :x1), false)) - @test !$(Expr(:isdefined, GlobalRef(@__MODULE__, :x2), false)) - @test !$(Expr(:isdefined, GlobalRef(@__MODULE__, :x3), false)) - @test !$(Expr(:isdefined, GlobalRef(@__MODULE__, :x4), false)) + @test Core.isdefinedglobal(@__MODULE__, :x1) + @test Core.isdefinedglobal(@__MODULE__, :x2) + @test Core.isdefinedglobal(@__MODULE__, :x3) + @test Core.isdefinedglobal(@__MODULE__, :x4) + + @test Core.isdefinedglobal(@__MODULE__, :x1, false) + @test !Core.isdefinedglobal(@__MODULE__, :x2, false) + @test !Core.isdefinedglobal(@__MODULE__, :x3, false) + @test !Core.isdefinedglobal(@__MODULE__, :x4, false) end end From b80dd58346a9644d18c52d1cf0e949c62d9e281b Mon Sep 17 00:00:00 2001 From: Michael Persico Date: Thu, 9 Jan 2025 21:24:04 -0500 Subject: [PATCH 171/342] Fix devcontainer definition (#57006) --- .devcontainer/Dockerfile | 3 --- .devcontainer/devcontainer.json | 16 ++++++++++------ 2 files changed, 10 insertions(+), 9 deletions(-) delete mode 100644 .devcontainer/Dockerfile diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index a688be130711c..0000000000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1,3 +0,0 @@ -FROM julia:latest - -RUN apt-get update && apt-get install -y build-essential libatomic1 python gfortran perl wget m4 cmake pkg-config git diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index a3747ca019694..455f8bea3e952 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,8 +1,12 @@ { - "extensions": [ - "julialang.language-julia", - "ms-vscode.cpptools" - ], - - "dockerFile": "Dockerfile" + "image": "docker.io/library/julia:latest", + "customizations": { + "vscode": { + "extensions": [ + "julialang.language-julia", + "ms-vscode.cpptools" + ] + } + }, + "onCreateCommand": "apt-get update && apt-get install -y build-essential libatomic1 python3 gfortran perl wget m4 cmake pkg-config git" } From 6ac351a9890272db959396a77254c8b4b807d69f Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Thu, 9 Jan 2025 23:24:49 -0300 Subject: [PATCH 172/342] Make write(IO, Char) actually return the amount of printed bytes instead of the attempted written bytes. (#56980) --- base/io.jl | 5 ++--- test/iobuffer.jl | 6 ++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/base/io.jl b/base/io.jl index 83a215d6359fc..46aec6ca393b7 100644 --- a/base/io.jl +++ b/base/io.jl @@ -864,11 +864,10 @@ end function write(io::IO, c::Char) u = bswap(reinterpret(UInt32, c)) - n = 1 + n = 0 while true - write(io, u % UInt8) + n += write(io, u % UInt8) (u >>= 8) == 0 && return n - n += 1 end end # write(io, ::AbstractChar) is not defined: implementations diff --git a/test/iobuffer.jl b/test/iobuffer.jl index 933662f7e41d1..a9d58f4b7871e 100644 --- a/test/iobuffer.jl +++ b/test/iobuffer.jl @@ -399,3 +399,9 @@ end io = IOBuffer(data) @test read(io) == data end + +@testset "Writing Char to full buffer" begin + io = IOBuffer(;maxsize=1) + write(io, 'a') + @test write(io, 'a') == 0 +end From d3964b600a5e596bd47cf04b3da4a1e78d4aecaf Mon Sep 17 00:00:00 2001 From: Neven Sajko <4944410+nsajko@users.noreply.github.com> Date: Fri, 10 Jan 2025 10:00:22 +0100 Subject: [PATCH 173/342] broadcast: align `ndims` implementation with intent behind code (#56999) The `N<:Integer` constraint was nonsensical, given that `(N === Any) || (N isa Int)`. N5N3 noticed this back in 2022: https://github.com/JuliaLang/julia/pull/44061#discussion_r883261337 Follow up on #44061. Also xref #45477. --- base/broadcast.jl | 9 +++++++-- test/broadcast.jl | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/base/broadcast.jl b/base/broadcast.jl index 7f278fc1ca66f..512b397352040 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -280,9 +280,14 @@ Base.@propagate_inbounds function Base.iterate(bc::Broadcasted, s) end Base.IteratorSize(::Type{T}) where {T<:Broadcasted} = Base.HasShape{ndims(T)}() -Base.ndims(BC::Type{<:Broadcasted{<:Any,Nothing}}) = _maxndims(fieldtype(BC, :args)) -Base.ndims(::Type{<:Broadcasted{<:AbstractArrayStyle{N},Nothing}}) where {N<:Integer} = N +Base.ndims(BC::Type{<:Broadcasted{<:Any,Nothing}}) = _maxndims_broadcasted(BC) +# the `AbstractArrayStyle` type parameter is required to be either equal to `Any` or be an `Int` value +Base.ndims(BC::Type{<:Broadcasted{<:AbstractArrayStyle{Any},Nothing}}) = _maxndims_broadcasted(BC) +Base.ndims(::Type{<:Broadcasted{<:AbstractArrayStyle{N},Nothing}}) where {N} = N::Int +function _maxndims_broadcasted(BC::Type{<:Broadcasted}) + _maxndims(fieldtype(BC, :args)) +end _maxndims(::Type{T}) where {T<:Tuple} = reduce(max, ntuple(n -> (F = fieldtype(T, n); F <: Tuple ? 1 : ndims(F)), Base._counttuple(T))) _maxndims(::Type{<:Tuple{T}}) where {T} = T <: Tuple ? 1 : ndims(T) function _maxndims(::Type{<:Tuple{T, S}}) where {T, S} diff --git a/test/broadcast.jl b/test/broadcast.jl index 57441de67c0ce..0f5bdf7a40bb1 100644 --- a/test/broadcast.jl +++ b/test/broadcast.jl @@ -930,6 +930,8 @@ let @test @inferred(Base.IteratorSize(Broadcast.broadcasted(+, (1,2,3), a1, zeros(3,3,3)))) === Base.HasShape{3}() + @test @inferred(Base.IteratorSize(Base.broadcasted(randn))) === Base.HasShape{0}() + # inference on nested bc = Base.broadcasted(+, AD1(randn(3)), AD1(randn(3))) bc_nest = Base.broadcasted(+, bc , bc) From 9211a932bb5e73adfa9c494d068bf0ad10e5f552 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 10 Jan 2025 18:44:21 +0100 Subject: [PATCH 174/342] Add edge kind for access to non-explicit partitioned bindings (#57009) Our binding partion invalidation code scans the original source for any GlobalRefs that need to be invalidated. However, this is not the only source of access to binding partitions. Various intrinsics (in particular the `*global` ones) also operate on bindings. Since these are not manifest in the source, we instead use the existing `edges` mechanism to give them forward edges. This PR only includes the basic info type, and validation in the replacement case. There's a bit more work to do there, but I'm waiting on #56499 for that part, precompilation in particular. --- Compiler/src/abstractinterpretation.jl | 86 ++++++++++++-------------- Compiler/src/stmtinfo.jl | 14 +++++ Compiler/src/typeinfer.jl | 3 + base/invalidation.jl | 41 ++++++++---- src/module.c | 8 +-- src/staticdata_utils.c | 8 +++ stdlib/REPL/src/REPLCompletions.jl | 6 +- sysimage.mk | 1 + test/rebinding.jl | 9 ++- 9 files changed, 110 insertions(+), 66 deletions(-) diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index 0c340a89d9878..3766907905aef 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -2395,7 +2395,8 @@ function abstract_eval_getglobal(interp::AbstractInterpreter, sv::AbsIntState, s if M isa Const && s isa Const M, s = M.val, s.val if M isa Module && s isa Symbol - return CallMeta(abstract_eval_globalref(interp, GlobalRef(M, s), saw_latestworld, sv), NoCallInfo()) + (ret, bpart) = abstract_eval_globalref(interp, GlobalRef(M, s), saw_latestworld, sv) + return CallMeta(ret, bpart === nothing ? NoCallInfo() : GlobalAccessInfo(bpart)) end return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo()) elseif !hasintersect(widenconst(M), Module) || !hasintersect(widenconst(s), Symbol) @@ -2473,8 +2474,8 @@ function abstract_eval_setglobal!(interp::AbstractInterpreter, sv::AbsIntState, if isa(M, Const) && isa(s, Const) M, s = M.val, s.val if M isa Module && s isa Symbol - rt, exct = global_assignment_rt_exct(interp, sv, saw_latestworld, GlobalRef(M, s), v) - return CallMeta(rt, exct, Effects(setglobal!_effects, nothrow=exct===Bottom), NoCallInfo()) + (rt, exct), partition = global_assignment_rt_exct(interp, sv, saw_latestworld, GlobalRef(M, s), v) + return CallMeta(rt, exct, Effects(setglobal!_effects, nothrow=exct===Bottom), GlobalAccessInfo(partition)) end return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo()) end @@ -2512,7 +2513,7 @@ function abstract_eval_swapglobal!(interp::AbstractInterpreter, sv::AbsIntState, scm = abstract_eval_setglobal!(interp, sv, saw_latestworld, M, s, v) scm.rt === Bottom && return scm gcm = abstract_eval_getglobal(interp, sv, saw_latestworld, M, s) - return CallMeta(gcm.rt, Union{scm.exct,gcm.exct}, merge_effects(scm.effects, gcm.effects), NoCallInfo()) + return CallMeta(gcm.rt, Union{scm.exct,gcm.exct}, merge_effects(scm.effects, gcm.effects), scm.info) end function abstract_eval_swapglobal!(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, @@ -2520,7 +2521,7 @@ function abstract_eval_swapglobal!(interp::AbstractInterpreter, sv::AbsIntState, scm = abstract_eval_setglobal!(interp, sv, saw_latestworld, M, s, v, order) scm.rt === Bottom && return scm gcm = abstract_eval_getglobal(interp, sv, saw_latestworld, M, s, order) - return CallMeta(gcm.rt, Union{scm.exct,gcm.exct}, merge_effects(scm.effects, gcm.effects), NoCallInfo()) + return CallMeta(gcm.rt, Union{scm.exct,gcm.exct}, merge_effects(scm.effects, gcm.effects), scm.info) end function abstract_eval_swapglobal!(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, argtypes::Vector{Any}) @@ -2569,7 +2570,7 @@ function abstract_eval_replaceglobal!(interp::AbstractInterpreter, sv::AbsIntSta end exct = Union{rte.exct, global_assignment_binding_rt_exct(interp, partition, v)[2]} effects = merge_effects(rte.effects, Effects(setglobal!_effects, nothrow=exct===Bottom)) - sg = CallMeta(Any, exct, effects, NoCallInfo()) + sg = CallMeta(Any, exct, effects, GlobalAccessInfo(partition)) else sg = abstract_eval_setglobal!(interp, sv, saw_latestworld, M, s, v) end @@ -2937,7 +2938,8 @@ function abstract_eval_special_value(interp::AbstractInterpreter, @nospecialize( return RTEffects(sv.ir.argtypes[e.n], Union{}, EFFECTS_TOTAL) # TODO frame_argtypes(sv)[e.n] and remove the assertion end elseif isa(e, GlobalRef) - return abstract_eval_globalref(interp, e, sstate.saw_latestworld, sv) + # No need for an edge since an explicit GlobalRef will be picked up by the source scan + return abstract_eval_globalref(interp, e, sstate.saw_latestworld, sv)[1] end if isa(e, QuoteNode) e = e.value @@ -3193,14 +3195,31 @@ function abstract_eval_isdefined_expr(interp::AbstractInterpreter, e::Expr, ssta end return RTEffects(rt, Union{}, EFFECTS_TOTAL) end - return abstract_eval_isdefined(interp, sym, sstate.saw_latestworld, sv) + rt = Bool + effects = EFFECTS_TOTAL + exct = Union{} + if isexpr(sym, :static_parameter) + n = sym.args[1]::Int + if 1 <= n <= length(sv.sptypes) + sp = sv.sptypes[n] + if !sp.undef + rt = Const(true) + elseif sp.typ === Bottom + rt = Const(false) + end + end + else + effects = EFFECTS_UNKNOWN + exct = Any + end + return RTEffects(rt, exct, effects) end const generic_isdefinedglobal_effects = Effects(EFFECTS_TOTAL, consistent=ALWAYS_FALSE, nothrow=false) function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, mod::Module, sym::Symbol, allow_import::Union{Bool, Nothing}, saw_latestworld::Bool, sv::AbsIntState) rt = Bool if saw_latestworld - return RTEffects(rt, Union{}, Effects(generic_isdefinedglobal_effects, nothrow=true)) + return CallMeta(RTEffects(rt, Union{}, Effects(generic_isdefinedglobal_effects, nothrow=true)), NoCallInfo()) end effects = EFFECTS_TOTAL @@ -3222,7 +3241,7 @@ function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, mod::Module, effects = Effects(generic_isdefinedglobal_effects, nothrow=true) end end - return RTEffects(rt, Union{}, effects) + return CallMeta(RTEffects(rt, Union{}, effects), GlobalAccessInfo(partition)) end function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, @nospecialize(M), @nospecialize(s), @nospecialize(allow_import_arg), @nospecialize(order_arg), saw_latestworld::Bool, sv::AbsIntState) @@ -3247,7 +3266,7 @@ function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, @nospecializ if M isa Const && s isa Const M, s = M.val, s.val if M isa Module && s isa Symbol - return merge_exct(CallMeta(abstract_eval_isdefinedglobal(interp, M, s, allow_import, saw_latestworld, sv), NoCallInfo()), exct) + return merge_exct(abstract_eval_isdefinedglobal(interp, M, s, allow_import, saw_latestworld, sv), exct) end return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo()) elseif !hasintersect(widenconst(M), Module) || !hasintersect(widenconst(s), Symbol) @@ -3258,26 +3277,6 @@ function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, @nospecializ return CallMeta(Bool, Union{exct, TypeError, UndefVarError}, generic_isdefinedglobal_effects, NoCallInfo()) end -function abstract_eval_isdefined(interp::AbstractInterpreter, @nospecialize(sym), saw_latestworld::Bool, sv::AbsIntState) - rt = Bool - effects = EFFECTS_TOTAL - exct = Union{} - if isexpr(sym, :static_parameter) - n = sym.args[1]::Int - if 1 <= n <= length(sv.sptypes) - sp = sv.sptypes[n] - if !sp.undef - rt = Const(true) - elseif sp.typ === Bottom - rt = Const(false) - end - end - else - effects = EFFECTS_UNKNOWN - end - return RTEffects(rt, exct, effects) -end - function abstract_eval_throw_undef_if_not(interp::AbstractInterpreter, e::Expr, sstate::StatementState, sv::AbsIntState) condt = abstract_eval_value(interp, e.args[2], sstate, sv) condval = maybe_extract_const_bool(condt) @@ -3533,26 +3532,29 @@ end function abstract_eval_globalref(interp::AbstractInterpreter, g::GlobalRef, saw_latestworld::Bool, sv::AbsIntState) if saw_latestworld - return RTEffects(Any, Any, generic_getglobal_effects) + return Pair{RTEffects, Union{Nothing, Core.BindingPartition}}(RTEffects(Any, Any, generic_getglobal_effects), nothing) end partition = abstract_eval_binding_partition!(interp, g, sv) ret = abstract_eval_partition_load(interp, partition) if ret.rt !== Union{} && ret.exct === UndefVarError && InferenceParams(interp).assume_bindings_static if isdefined(g, :binding) && isdefined(g.binding, :value) - return RTEffects(ret.rt, Union{}, Effects(generic_getglobal_effects, nothrow=true)) + ret = RTEffects(ret.rt, Union{}, Effects(generic_getglobal_effects, nothrow=true)) end # We do not assume in general that assigned global bindings remain assigned. # The existence of pkgimages allows them to revert in practice. end - return ret + return Pair{RTEffects, Union{Nothing, Core.BindingPartition}}(ret, partition) end function global_assignment_rt_exct(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, g::GlobalRef, @nospecialize(newty)) if saw_latestworld - return Pair{Any,Any}(newty, Union{ErrorException, TypeError}) + return Pair{Pair{Any,Any}, Union{Core.BindingPartition, Nothing}}( + Pair{Any,Any}(newty, Union{ErrorException, TypeError}), nothing) end partition = abstract_eval_binding_partition!(interp, g, sv) - return global_assignment_binding_rt_exct(interp, partition, newty) + return Pair{Pair{Any,Any}, Union{Core.BindingPartition, Nothing}}( + global_assignment_binding_rt_exct(interp, partition, newty), + partition) end function global_assignment_binding_rt_exct(interp::AbstractInterpreter, partition::Core.BindingPartition, @nospecialize(newty)) @@ -3573,18 +3575,6 @@ function global_assignment_binding_rt_exct(interp::AbstractInterpreter, partitio return Pair{Any,Any}(newty, Bottom) end -function handle_global_assignment!(interp::AbstractInterpreter, frame::InferenceState, saw_latestworld::Bool, lhs::GlobalRef, @nospecialize(newty)) - effect_free = ALWAYS_FALSE - nothrow = global_assignment_rt_exct(interp, frame, saw_latestworld, lhs, ignorelimited(newty))[2] === Union{} - inaccessiblememonly = ALWAYS_FALSE - if !nothrow - sub_curr_ssaflag!(frame, IR_FLAG_NOTHROW) - end - sub_curr_ssaflag!(frame, IR_FLAG_EFFECT_FREE) - merge_effects!(interp, frame, Effects(EFFECTS_TOTAL; effect_free, nothrow, inaccessiblememonly)) - return nothing -end - abstract_eval_ssavalue(s::SSAValue, sv::InferenceState) = abstract_eval_ssavalue(s, sv.ssavaluetypes) function abstract_eval_ssavalue(s::SSAValue, ssavaluetypes::Vector{Any}) diff --git a/Compiler/src/stmtinfo.jl b/Compiler/src/stmtinfo.jl index a42a9e47b328e..e3f8e2f56c86b 100644 --- a/Compiler/src/stmtinfo.jl +++ b/Compiler/src/stmtinfo.jl @@ -481,4 +481,18 @@ end add_edges_impl(edges::Vector{Any}, info::VirtualMethodMatchInfo) = _add_edges_impl(edges, info.info, #=mi_edge=#true) +""" + info::GlobalAccessInfo <: CallInfo + +Represents access to a global through runtime reflection, rather than as a manifest +`GlobalRef` in the source code. Used for builtins (getglobal/setglobal/etc.) that +perform such accesses. +""" +struct GlobalAccessInfo <: CallInfo + bpart::Core.BindingPartition +end +GlobalAccessInfo(::Nothing) = NoCallInfo() +add_edges_impl(edges::Vector{Any}, info::GlobalAccessInfo) = + push!(edges, info.bpart) + @specialize diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index 49cc711dc72df..ec1e62817106d 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -544,6 +544,9 @@ function store_backedges(caller::CodeInstance, edges::SimpleVector) # ignore `Method`-edges (from e.g. failed `abstract_call_method`) i += 1 continue + elseif isa(item, Core.BindingPartition) + i += 1 + continue end if isa(item, CodeInstance) item = item.def diff --git a/base/invalidation.jl b/base/invalidation.jl index 40a010ab7361c..5abb0b74ad884 100644 --- a/base/invalidation.jl +++ b/base/invalidation.jl @@ -9,7 +9,7 @@ globalrefs(mod::Module) = GlobalRefIterator(mod) function iterate(gri::GlobalRefIterator, i = 1) m = gri.mod table = ccall(:jl_module_get_bindings, Ref{SimpleVector}, (Any,), m) - i == length(table) && return nothing + i > length(table) && return nothing b = table[i] b === nothing && return iterate(gri, i+1) return ((b::Core.Binding).globalref, i+1) @@ -85,18 +85,33 @@ function should_invalidate_code_for_globalref(gr::GlobalRef, src::CodeInfo) return found_any end -function invalidate_code_for_globalref!(gr::GlobalRef, new_max_world::UInt) - valid_in_valuepos = false - foreach_reachable_mtable(new_max_world) do mt::Core.MethodTable - for method in MethodList(mt) - if isdefined(method, :source) - src = _uncompressed_ir(method) - old_stmts = src.code - if should_invalidate_code_for_globalref(gr, src) +function scan_edge_list(ci::Core.CodeInstance, bpart::Core.BindingPartition) + isdefined(ci, :edges) || return false + edges = ci.edges + i = 1 + while i <= length(edges) + if isassigned(edges, i) && edges[i] === bpart + return true + end + i += 1 + end + return false +end + +function invalidate_code_for_globalref!(gr::GlobalRef, invalidated_bpart::Core.BindingPartition, new_max_world::UInt) + try + valid_in_valuepos = false + foreach_reachable_mtable(new_max_world) do mt::Core.MethodTable + for method in MethodList(mt) + if isdefined(method, :source) + src = _uncompressed_ir(method) + old_stmts = src.code + invalidate_all = should_invalidate_code_for_globalref(gr, src) for mi in specializations(method) + isdefined(mi, :cache) || continue ci = mi.cache while true - if ci.max_world > new_max_world + if ci.max_world > new_max_world && (invalidate_all || scan_edge_list(ci, invalidated_bpart)) ccall(:jl_invalidate_code_instance, Cvoid, (Any, UInt), ci, new_max_world) end isdefined(ci, :next) || break @@ -105,7 +120,11 @@ function invalidate_code_for_globalref!(gr::GlobalRef, new_max_world::UInt) end end end + return true end - return true + catch err + bt = catch_backtrace() + invokelatest(Base.println, "Internal Error during invalidation:") + invokelatest(Base.display_error, err, bt) end end diff --git a/src/module.c b/src/module.c index 004371b9144b2..66049031f8790 100644 --- a/src/module.c +++ b/src/module.c @@ -1032,7 +1032,7 @@ JL_DLLEXPORT void jl_set_const(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var jl_gc_wb(bpart, val); } -void jl_invalidate_binding_refs(jl_globalref_t *ref, size_t new_world) +void jl_invalidate_binding_refs(jl_globalref_t *ref, jl_binding_partition_t *invalidated_bpart, size_t new_world) { static jl_value_t *invalidate_code_for_globalref = NULL; if (invalidate_code_for_globalref == NULL && jl_base_module != NULL) @@ -1043,7 +1043,7 @@ void jl_invalidate_binding_refs(jl_globalref_t *ref, size_t new_world) jl_error("Binding invalidation is not permitted during image generation."); jl_value_t *boxed_world = jl_box_ulong(new_world); JL_GC_PUSH1(&boxed_world); - jl_call2((jl_function_t*)invalidate_code_for_globalref, (jl_value_t*)ref, boxed_world); + jl_call3((jl_function_t*)invalidate_code_for_globalref, (jl_value_t*)ref, (jl_value_t*)invalidated_bpart, boxed_world); JL_GC_POP(); } @@ -1063,10 +1063,10 @@ JL_DLLEXPORT void jl_disable_binding(jl_globalref_t *gr) jl_task_t *ct = jl_current_task; size_t last_world = ct->world_age; size_t new_max_world = jl_atomic_load_acquire(&jl_world_counter); + jl_atomic_store_release(&bpart->max_world, new_max_world); ct->world_age = jl_typeinf_world; - jl_invalidate_binding_refs(gr, new_max_world); + jl_invalidate_binding_refs(gr, bpart, new_max_world); ct->world_age = last_world; - jl_atomic_store_release(&bpart->max_world, new_max_world); jl_atomic_store_release(&jl_world_counter, new_max_world + 1); JL_UNLOCK(&world_counter_lock); } diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index 5de85a8d6ec77..79d2909970d99 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -878,6 +878,10 @@ static int jl_verify_method(jl_code_instance_t *codeinst, size_t *minworld, size size_t min_valid2; size_t max_valid2; assert(!jl_is_method(edge)); // `Method`-edge isn't allowed for the optimized one-edge format + if (jl_is_binding_partition(edge)) { + j += 1; + continue; + } if (jl_is_code_instance(edge)) edge = (jl_value_t*)jl_get_ci_mi((jl_code_instance_t*)edge); if (jl_is_method_instance(edge)) { @@ -1051,6 +1055,10 @@ static void jl_insert_backedges(jl_array_t *edges, jl_array_t *ext_ci_list) j += 1; continue; } + else if (jl_is_binding_partition(edge)) { + j += 1; + continue; + } if (jl_is_code_instance(edge)) edge = (jl_value_t*)((jl_code_instance_t*)edge)->def; if (jl_is_method_instance(edge)) { diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index 2c03c6d563c1e..723a008b10f28 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -646,9 +646,11 @@ function CC.abstract_eval_globalref(interp::REPLInterpreter, g::GlobalRef, baile sv::CC.InferenceState) if (interp.limit_aggressive_inference ? is_repl_frame(sv) : is_call_graph_uncached(sv)) if isdefined_globalref(g) - return CC.RTEffects(Const(ccall(:jl_get_globalref_value, Any, (Any,), g)), Union{}, CC.EFFECTS_TOTAL) + return Pair{CC.RTEffects, Union{Nothing, Core.BindingPartition}}( + CC.RTEffects(Const(ccall(:jl_get_globalref_value, Any, (Any,), g)), Union{}, CC.EFFECTS_TOTAL), nothing) end - return CC.RTEffects(Union{}, UndefVarError, CC.EFFECTS_THROWS) + return Pair{CC.RTEffects, Union{Nothing, Core.BindingPartition}}( + CC.RTEffects(Union{}, UndefVarError, CC.EFFECTS_THROWS), nothing) end return @invoke CC.abstract_eval_globalref(interp::CC.AbstractInterpreter, g::GlobalRef, bailed::Bool, sv::CC.InferenceState) diff --git a/sysimage.mk b/sysimage.mk index a74aace4dd11c..571e2da003346 100644 --- a/sysimage.mk +++ b/sysimage.mk @@ -43,6 +43,7 @@ COMPILER_SRCS := $(addprefix $(JULIAHOME)/, \ base/int.jl \ base/indices.jl \ base/iterators.jl \ + base/invalidation.jl \ base/namedtuple.jl \ base/number.jl \ base/operators.jl \ diff --git a/test/rebinding.jl b/test/rebinding.jl index ad0ad1fc1643d..10da27ce3ad8f 100644 --- a/test/rebinding.jl +++ b/test/rebinding.jl @@ -31,7 +31,7 @@ module Rebinding # Tests for @world syntax @test Base.@world(Foo, defined_world_age) == typeof(x) - @test Base.@world(Rebinding.Foo, defined_world_age) == typeof(x) + nameof(@__MODULE__) === :Rebinding && @test Base.@world(Rebinding.Foo, defined_world_age) == typeof(x) @test Base.@world((@__MODULE__).Foo, defined_world_age) == typeof(x) # Test invalidation (const -> undefined) @@ -40,4 +40,11 @@ module Rebinding @test f_return_delete_me() == 1 Base.delete_binding(@__MODULE__, :delete_me) @test_throws UndefVarError f_return_delete_me() + + ## + via indirect access + const delete_me = 2 + f_return_delete_me_indirect() = getglobal(@__MODULE__, :delete_me) + @test f_return_delete_me_indirect() == 2 + Base.delete_binding(@__MODULE__, :delete_me) + @test_throws UndefVarError f_return_delete_me_indirect() end From 64706d789f4816230d595b03f527fc0e9d934a3e Mon Sep 17 00:00:00 2001 From: Oscar Smith Date: Fri, 10 Jan 2025 14:14:07 -0500 Subject: [PATCH 175/342] remove fence that GC change made unnecessary (#56986) @gbaraldi and I think that this fence can probably be removed now that https://github.com/JuliaLang/julia/pull/55223 is merged. This should slightly expand the set of cases where the Memory is removable. --- src/cgutils.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 295dd93e869ba..98c5627578b80 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -4463,8 +4463,6 @@ static void emit_memory_zeroinit_and_stores(jl_codectx_t &ctx, jl_datatype_t *ty auto len_store = ctx.builder.CreateAlignedStore(nel, len_field, Align(sizeof(void*))); auto aliasinfo = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_memorylen); aliasinfo.decorateInst(len_store); - //This avoids the length store from being deleted which is illegal - ctx.builder.CreateFence(AtomicOrdering::Release, SyncScope::SingleThread); // zeroinit pointers and unions if (zi) { Value *memory_ptr = ctx.builder.CreateStructGEP(ctx.types().T_jlgenericmemory, decay_alloc, 1); From db8cc484fd8e9b6120483acc6387d843de8f7fd4 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Fri, 10 Jan 2025 15:34:21 -0500 Subject: [PATCH 176/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?Pkg=20stdlib=20from=208d3cf02e5=20to=20bc9fb21b1=20(#57013)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: IanButterworth <1694067+IanButterworth@users.noreply.github.com> --- .../Pkg-8d3cf02e5e35913c89440c3b5c6678c1a806e975.tar.gz/md5 | 1 - .../Pkg-8d3cf02e5e35913c89440c3b5c6678c1a806e975.tar.gz/sha512 | 1 - .../Pkg-bc9fb21b1f2d72038491eff938673fc5fbc99445.tar.gz/md5 | 1 + .../Pkg-bc9fb21b1f2d72038491eff938673fc5fbc99445.tar.gz/sha512 | 1 + stdlib/Pkg.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/Pkg-8d3cf02e5e35913c89440c3b5c6678c1a806e975.tar.gz/md5 delete mode 100644 deps/checksums/Pkg-8d3cf02e5e35913c89440c3b5c6678c1a806e975.tar.gz/sha512 create mode 100644 deps/checksums/Pkg-bc9fb21b1f2d72038491eff938673fc5fbc99445.tar.gz/md5 create mode 100644 deps/checksums/Pkg-bc9fb21b1f2d72038491eff938673fc5fbc99445.tar.gz/sha512 diff --git a/deps/checksums/Pkg-8d3cf02e5e35913c89440c3b5c6678c1a806e975.tar.gz/md5 b/deps/checksums/Pkg-8d3cf02e5e35913c89440c3b5c6678c1a806e975.tar.gz/md5 deleted file mode 100644 index 0ec07e44a059d..0000000000000 --- a/deps/checksums/Pkg-8d3cf02e5e35913c89440c3b5c6678c1a806e975.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -30eed5409ab2f5e7791cac9f6583ccad diff --git a/deps/checksums/Pkg-8d3cf02e5e35913c89440c3b5c6678c1a806e975.tar.gz/sha512 b/deps/checksums/Pkg-8d3cf02e5e35913c89440c3b5c6678c1a806e975.tar.gz/sha512 deleted file mode 100644 index 37415fcac993c..0000000000000 --- a/deps/checksums/Pkg-8d3cf02e5e35913c89440c3b5c6678c1a806e975.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -bb995ff7bc047121e79162da8775cbf21a2874427af53ea46ccf9db2a01d5d3e864262d232e2988f41248e6b45a266a64467ada7e6a88f2306135ac4f1bb794f diff --git a/deps/checksums/Pkg-bc9fb21b1f2d72038491eff938673fc5fbc99445.tar.gz/md5 b/deps/checksums/Pkg-bc9fb21b1f2d72038491eff938673fc5fbc99445.tar.gz/md5 new file mode 100644 index 0000000000000..5180b5f916d1b --- /dev/null +++ b/deps/checksums/Pkg-bc9fb21b1f2d72038491eff938673fc5fbc99445.tar.gz/md5 @@ -0,0 +1 @@ +2332986e216728bc85e364994f2ed910 diff --git a/deps/checksums/Pkg-bc9fb21b1f2d72038491eff938673fc5fbc99445.tar.gz/sha512 b/deps/checksums/Pkg-bc9fb21b1f2d72038491eff938673fc5fbc99445.tar.gz/sha512 new file mode 100644 index 0000000000000..04bc79171c734 --- /dev/null +++ b/deps/checksums/Pkg-bc9fb21b1f2d72038491eff938673fc5fbc99445.tar.gz/sha512 @@ -0,0 +1 @@ +99bf03f921ae79767009dbd68a94a7119513b2454d5c9832b157bc1e092a35a6b90cb7a5d81346a7d927f9b0275328582098ca6b8b376b4a406ddf0b3167a280 diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 568a15dae1cc0..4240c77105583 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = master -PKG_SHA1 = 8d3cf02e5e35913c89440c3b5c6678c1a806e975 +PKG_SHA1 = bc9fb21b1f2d72038491eff938673fc5fbc99445 PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 From c1db3a419699a92c29ce2aff7547019eec3045a4 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Fri, 10 Jan 2025 16:29:48 -0500 Subject: [PATCH 177/342] Miscellaneous `Meta.partially_inline!` fixes (#56813) This fixes up a couple of conspicuous problems I noticed when reviewing #56787 I'm unsure we should have accepted this pass in Base to begin with... It should at least be re-written to error on unexpected IR elements (instead of performing an invalid transform silently), but the real problem is that this pass is out-of-pipeline and so it doesn't run on most user code and we have much worse coverage compared to passes in the main Compiler. --- base/meta.jl | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/base/meta.jl b/base/meta.jl index 85b54e8225d4e..36875b8e2c625 100644 --- a/base/meta.jl +++ b/base/meta.jl @@ -364,6 +364,19 @@ function _partially_inline!(@nospecialize(x), slot_replacements::Vector{Any}, x.edges .+= slot_offset return x end + if isa(x, Core.UpsilonNode) + if !isdefined(x, :val) + return x + end + return Core.UpsilonNode( + _partially_inline!(x.val, slot_replacements, type_signature, static_param_values, + slot_offset, statement_offset, boundscheck), + ) + end + if isa(x, Core.PhiCNode) + _partially_inline!(x.values, slot_replacements, type_signature, static_param_values, + slot_offset, statement_offset, boundscheck) + end if isa(x, Core.ReturnNode) # Unreachable doesn't have val defined if !isdefined(x, :val) @@ -383,6 +396,9 @@ function _partially_inline!(@nospecialize(x), slot_replacements::Vector{Any}, ) end if isa(x, Core.EnterNode) + if x.catch_dest == 0 + return x + end return Core.EnterNode(x, x.catch_dest + statement_offset) end if isa(x, Expr) From 49428e8fa2f787d8df894a4a8f538350ec0e54fe Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Fri, 10 Jan 2025 18:19:03 -0500 Subject: [PATCH 178/342] README.md: Update current stable version (#57016) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cfa2111600f22..021322336d286 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ and then use the command prompt to change into the resulting julia directory. By Julia. However, most users should use the [most recent stable version](https://github.com/JuliaLang/julia/releases) of Julia. You can get this version by running: - git checkout v1.11.1 + git checkout v1.11.2 To build the `julia` executable, run `make` from within the julia directory. From 71bfbb3b0134c05e1af49c385738b8f5d8f06e7c Mon Sep 17 00:00:00 2001 From: Alex Arslan Date: Fri, 10 Jan 2025 19:41:51 -0800 Subject: [PATCH 179/342] Update HelloWorldC in Artifacts tests and bump LazyArtifacts for the same change (#57000) This updates the version of HelloWorldC in `stdlib/Artifacts/test/Artifacts.toml` from 1.1.2 to 1.4.0, for which there are binaries for FreeBSD AArch64 and Linux RISC-V. The same change was made to LazyArtifacts, as it contains that same `Artifacts.toml` file in its tests, and the version of LazyArtifacts used here has been updated accordingly. No other changes have been made to LazyArtifacts since the previous version used here. --- .../md5 | 1 - .../sha512 | 1 - .../md5 | 1 + .../sha512 | 1 + stdlib/Artifacts/test/Artifacts.toml | 113 ++++++++++-------- stdlib/Artifacts/test/runtests.jl | 12 +- stdlib/LazyArtifacts.version | 2 +- 7 files changed, 74 insertions(+), 57 deletions(-) delete mode 100644 deps/checksums/LazyArtifacts-a719c0e3d68a95c6f3dc9571459428ca8761fa2c.tar.gz/md5 delete mode 100644 deps/checksums/LazyArtifacts-a719c0e3d68a95c6f3dc9571459428ca8761fa2c.tar.gz/sha512 create mode 100644 deps/checksums/LazyArtifacts-e4cfc39598c238f75bdfdbdb3f82c9329a5af59c.tar.gz/md5 create mode 100644 deps/checksums/LazyArtifacts-e4cfc39598c238f75bdfdbdb3f82c9329a5af59c.tar.gz/sha512 diff --git a/deps/checksums/LazyArtifacts-a719c0e3d68a95c6f3dc9571459428ca8761fa2c.tar.gz/md5 b/deps/checksums/LazyArtifacts-a719c0e3d68a95c6f3dc9571459428ca8761fa2c.tar.gz/md5 deleted file mode 100644 index 363c289573765..0000000000000 --- a/deps/checksums/LazyArtifacts-a719c0e3d68a95c6f3dc9571459428ca8761fa2c.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -ce3754f1d195e1533fc1f3c51e2a2d4c diff --git a/deps/checksums/LazyArtifacts-a719c0e3d68a95c6f3dc9571459428ca8761fa2c.tar.gz/sha512 b/deps/checksums/LazyArtifacts-a719c0e3d68a95c6f3dc9571459428ca8761fa2c.tar.gz/sha512 deleted file mode 100644 index 62227971fe7f7..0000000000000 --- a/deps/checksums/LazyArtifacts-a719c0e3d68a95c6f3dc9571459428ca8761fa2c.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -1e1beb6202f089b82f06c1f1fcb129a31d2b438df8a3a49c7367d3df4587d8b9b8fbcf74d3f5ff3c25c241314c71e5dfd72014338b822f01252890e2a14831d1 diff --git a/deps/checksums/LazyArtifacts-e4cfc39598c238f75bdfdbdb3f82c9329a5af59c.tar.gz/md5 b/deps/checksums/LazyArtifacts-e4cfc39598c238f75bdfdbdb3f82c9329a5af59c.tar.gz/md5 new file mode 100644 index 0000000000000..48bd7a8a7fa25 --- /dev/null +++ b/deps/checksums/LazyArtifacts-e4cfc39598c238f75bdfdbdb3f82c9329a5af59c.tar.gz/md5 @@ -0,0 +1 @@ +405faa2237105ff823e80e759b2df17a diff --git a/deps/checksums/LazyArtifacts-e4cfc39598c238f75bdfdbdb3f82c9329a5af59c.tar.gz/sha512 b/deps/checksums/LazyArtifacts-e4cfc39598c238f75bdfdbdb3f82c9329a5af59c.tar.gz/sha512 new file mode 100644 index 0000000000000..9fa6aec4d1939 --- /dev/null +++ b/deps/checksums/LazyArtifacts-e4cfc39598c238f75bdfdbdb3f82c9329a5af59c.tar.gz/sha512 @@ -0,0 +1 @@ +9bd2bdd5a83df28a26ebfb0d4e59b50584962e07b1364e6fd76bc7a6a7b109f1facaa04366beaa9f340192ea9efa540decde1393ddd50dc3efa13937deeb5d7f diff --git a/stdlib/Artifacts/test/Artifacts.toml b/stdlib/Artifacts/test/Artifacts.toml index 4b715b74c128b..5faf1012dec54 100644 --- a/stdlib/Artifacts/test/Artifacts.toml +++ b/stdlib/Artifacts/test/Artifacts.toml @@ -1,146 +1,163 @@ [[HelloWorldC]] arch = "aarch64" -git-tree-sha1 = "95fce80ec703eeb5f4270fef6821b38d51387499" +git-tree-sha1 = "0835a23111b12d2aa5e1f7a852ed71e0b92e3425" os = "macos" [[HelloWorldC.download]] - sha256 = "23f45918421881de8e9d2d471c70f6b99c26edd1dacd7803d2583ba93c8bbb28" - url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.1.2+0/HelloWorldC.v1.1.2.aarch64-apple-darwin.tar.gz" + sha256 = "4406a35689feaf532ff0347a11896449571e8a1c919e5550b01dfe10f2e64822" + url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.4.0+0/HelloWorldC.v1.4.0.aarch64-apple-darwin.tar.gz" [[HelloWorldC]] arch = "aarch64" -git-tree-sha1 = "1ccbaad776766366943fd5a66a8cbc9877ee8df9" +git-tree-sha1 = "c82465bd6d0aa1369ff2fd961b73884d1f5de49a" libc = "glibc" os = "linux" [[HelloWorldC.download]] - sha256 = "82bca07ff25a75875936116ca977285160a2afcc4f58dd160c7b1600f55da655" - url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.1.2+0/HelloWorldC.v1.1.2.aarch64-linux-gnu.tar.gz" + sha256 = "5bfa84332c7ee485ca8e2eee216ad9fa77b2c43d5f261baa823e301b7c789ec4" + url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.4.0+0/HelloWorldC.v1.4.0.aarch64-linux-gnu.tar.gz" [[HelloWorldC]] arch = "aarch64" -git-tree-sha1 = "dc43ab874611cfc26641741c31b8230276d7d664" +git-tree-sha1 = "cb4b8c88778c6cd93b6df38ec5b95a2678434f5d" libc = "musl" os = "linux" [[HelloWorldC.download]] - sha256 = "36b7c554f1cb04d5282b991c66a10b2100085ac8deb2156bf52b4f7c4e406c04" - url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.1.2+0/HelloWorldC.v1.1.2.aarch64-linux-musl.tar.gz" + sha256 = "924df1c2a386f79a2727a2f989393102649a24863214f2e88cb4a677d3d22e14" + url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.4.0+0/HelloWorldC.v1.4.0.aarch64-linux-musl.tar.gz" +[[HelloWorldC]] +arch = "aarch64" +git-tree-sha1 = "7db155cf8485fbeb23d30a305f76ece191db9dc4" +os = "freebsd" + + [[HelloWorldC.download]] + sha256 = "d86d992f428df1264d55d7ac886ccd0a0539fda82363bf5dda872d12ea742528" + url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.4.0+0/HelloWorldC.v1.4.0.aarch64-unknown-freebsd.tar.gz" [[HelloWorldC]] arch = "armv6l" call_abi = "eabihf" -git-tree-sha1 = "b7128521583d02d2dbe9c8de6fe156b79df781d9" +git-tree-sha1 = "20a32b71145b67e708f63fb5880a7243727aec0f" libc = "glibc" os = "linux" [[HelloWorldC.download]] - sha256 = "5e094b9c6e4c6a77ecc8dfc2b841ac1f2157f6a81f4c47f1e0d3e9a04eec7945" - url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.1.2+0/HelloWorldC.v1.1.2.armv6l-linux-gnueabihf.tar.gz" + sha256 = "6f0997b0aad387ba6e2402530642bb4ded85b0243460d2e4b13d94f2c8340a44" + url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.4.0+0/HelloWorldC.v1.4.0.armv6l-linux-gnueabihf.tar.gz" [[HelloWorldC]] arch = "armv6l" call_abi = "eabihf" -git-tree-sha1 = "edb3893a154519d6786234f5c83994c34e11feed" +git-tree-sha1 = "c1179604ea37fa66ee6d5d592c7bbfd1f20292c3" libc = "musl" os = "linux" [[HelloWorldC.download]] - sha256 = "0a2203f061ba2ef7ce4c452ec7874be3acc6db1efac8091f85d113c3404e6bb6" - url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.1.2+0/HelloWorldC.v1.1.2.armv6l-linux-musleabihf.tar.gz" + sha256 = "0aca47bce6f09c38a7939277a593deb988123fe59f7992225a1ede8e174f1b06" + url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.4.0+0/HelloWorldC.v1.4.0.armv6l-linux-musleabihf.tar.gz" [[HelloWorldC]] arch = "armv7l" call_abi = "eabihf" -git-tree-sha1 = "5a8288c8a30578c0d0f24a9cded29579517ce7a8" +git-tree-sha1 = "0a8e7b523ef6be31311aefe9983a488616e58201" libc = "glibc" os = "linux" [[HelloWorldC.download]] - sha256 = "a4392a4c8f834c97f9d8822ddfb1813d8674fa602eeaf04d6359c0a9e98478ec" - url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.1.2+0/HelloWorldC.v1.1.2.armv7l-linux-gnueabihf.tar.gz" + sha256 = "f29f4da556d2b4ee9eaff7740aa0f9436406b75b0f1ec428e881a47ab7b7477b" + url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.4.0+0/HelloWorldC.v1.4.0.armv7l-linux-gnueabihf.tar.gz" [[HelloWorldC]] arch = "armv7l" call_abi = "eabihf" -git-tree-sha1 = "169c261b321c4dc95894cdd2db9d0d0caa84677f" +git-tree-sha1 = "ca94b4d87f1a276066a2994733142e35046c41dd" libc = "musl" os = "linux" [[HelloWorldC.download]] - sha256 = "ed1aacbf197a6c78988725a39defad130ed31a2258f8e7846f73b459821f21d3" - url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.1.2+0/HelloWorldC.v1.1.2.armv7l-linux-musleabihf.tar.gz" + sha256 = "5fb4019d6d797e5e3860cfec90cab12f6865fa624e87b51c20220a44bb94846a" + url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.4.0+0/HelloWorldC.v1.4.0.armv7l-linux-musleabihf.tar.gz" [[HelloWorldC]] arch = "i686" -git-tree-sha1 = "fd35f9155dc424602d01fbf983eb76be3217a28f" +git-tree-sha1 = "91376c8b0bc90c47076cab4e55bf77e86bb59076" libc = "glibc" os = "linux" [[HelloWorldC.download]] - sha256 = "048fcff5ff47a3cc1e84a2688935fcd658ad1c7e7c52c0e81fe88ce6c3697aba" - url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.1.2+0/HelloWorldC.v1.1.2.i686-linux-gnu.tar.gz" + sha256 = "b775c985231cd0626afd0111902a764c75c9a8a123b12e1f386a1c2af3cef799" + url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.4.0+0/HelloWorldC.v1.4.0.i686-linux-gnu.tar.gz" [[HelloWorldC]] arch = "i686" -git-tree-sha1 = "8db14df0f1d2a3ed9c6a7b053a590ca6527eb95e" +git-tree-sha1 = "b50220be02e9c839749f91a70694ae68c2712c8e" libc = "musl" os = "linux" [[HelloWorldC.download]] - sha256 = "d521b4420392b8365de5ed0ef38a3b6c822665d7c257d3eef6f725c205bb3d78" - url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.1.2+0/HelloWorldC.v1.1.2.i686-linux-musl.tar.gz" + sha256 = "6aecc06cf803ad16703744610deb243a21b39e19ae1951a38977610881698f9e" + url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.4.0+0/HelloWorldC.v1.4.0.i686-linux-musl.tar.gz" [[HelloWorldC]] arch = "i686" -git-tree-sha1 = "56f82168947b8dc7bb98038f063209b9f864eaff" +git-tree-sha1 = "cc9cfa3272d4d3844d6fcf8b6b971bd68dbc792f" os = "windows" [[HelloWorldC.download]] - sha256 = "de578cf5ee2f457e9ff32089cbe17d03704a929980beddf4c41f4c0eb32f19c6" - url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.1.2+0/HelloWorldC.v1.1.2.i686-w64-mingw32.tar.gz" + sha256 = "bbf3276bcfc8223061c3b1cf8725425bfc33ac2929214ba57eecfd170d30f096" + url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.4.0+0/HelloWorldC.v1.4.0.i686-w64-mingw32.tar.gz" [[HelloWorldC]] arch = "powerpc64le" -git-tree-sha1 = "9c8902b62f5b1aaa7c2839c804bed7c3a0912c7b" +git-tree-sha1 = "5e9c87fc4e3372c27a77061a49d97fa5002df0e4" +libc = "glibc" +os = "linux" + + [[HelloWorldC.download]] + sha256 = "e2a728b29124fc7408d6e47cc6fc943d0336d1386e56a3775a0665b34528881b" + url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.4.0+0/HelloWorldC.v1.4.0.powerpc64le-linux-gnu.tar.gz" +[[HelloWorldC]] +arch = "riscv64" +git-tree-sha1 = "3c9b23e46b82ab59141bbbc042158af4037d846d" libc = "glibc" os = "linux" [[HelloWorldC.download]] - sha256 = "63ddbfbb6ea0cafef544cc25415e7ebee6ee0a69db0878d0d4e1ed27c0ae0ab5" - url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.1.2+0/HelloWorldC.v1.1.2.powerpc64le-linux-gnu.tar.gz" + sha256 = "59e2250eab04924eb7167d3232e4b0176c53097e4b21f2f3e3621f1e39f43107" + url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.4.0+0/HelloWorldC.v1.4.0.riscv64-linux-gnu.tar.gz" [[HelloWorldC]] arch = "x86_64" -git-tree-sha1 = "f8ab5a03697f9afc82210d8a2be1d94509aea8bc" +git-tree-sha1 = "2e1742c9c0addd693b0b025f7a1e7aa4c50a0e6c" os = "macos" [[HelloWorldC.download]] - sha256 = "f5043338613672b12546c59359c7997c5381a9a60b86aeb951dee74de428d5e3" - url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.1.2+0/HelloWorldC.v1.1.2.x86_64-apple-darwin.tar.gz" + sha256 = "c4f0c83ae4f72a039c33beb26ebb1d4c0fb739f34360102be79909a0dc17f47f" + url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.4.0+0/HelloWorldC.v1.4.0.x86_64-apple-darwin.tar.gz" [[HelloWorldC]] arch = "x86_64" -git-tree-sha1 = "1ed3d81088f16e3a1fa4e3d4c4c509b8c117fecf" +git-tree-sha1 = "8c8251b0c21615bce0701995eded26ac7697b5cc" libc = "glibc" os = "linux" [[HelloWorldC.download]] - sha256 = "a18212e7984b08b23bec06e8bf9286a89b9fa2e8ee0dd46af3b852fe22013a4f" - url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.1.2+0/HelloWorldC.v1.1.2.x86_64-linux-gnu.tar.gz" + sha256 = "974f7e1d1cdbebad149e51fed4f1b7c6a0b5ccfa350f7d252dfcf66c2dbf9f63" + url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.4.0+0/HelloWorldC.v1.4.0.x86_64-linux-gnu.tar.gz" [[HelloWorldC]] arch = "x86_64" -git-tree-sha1 = "c04ef757b8bb773d17a0fd0ea396e52db1c7c385" +git-tree-sha1 = "cfaaf0517421585561e3b30dd6f53f6c14b2835f" libc = "musl" os = "linux" [[HelloWorldC.download]] - sha256 = "7a3d1b09410989508774f00e073ea6268edefcaba7617fc5085255ec8e82555b" - url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.1.2+0/HelloWorldC.v1.1.2.x86_64-linux-musl.tar.gz" + sha256 = "25d3d6ecc753f4dbbcaab0db7b6c20b29b0a79b0c31f7a26a0cf18c365d27809" + url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.4.0+0/HelloWorldC.v1.4.0.x86_64-linux-musl.tar.gz" [[HelloWorldC]] arch = "x86_64" -git-tree-sha1 = "5f7e7abf7d545a1aaa368f22e3e01ea0268870b1" +git-tree-sha1 = "8e8a17876a9c1147bae6a53a175344b805ee72d4" os = "freebsd" [[HelloWorldC.download]] - sha256 = "56aedffe38fe20294e93cfc2eb0a193c8e2ddda5a697b302e77ff48ac1195198" - url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.1.2+0/HelloWorldC.v1.1.2.x86_64-unknown-freebsd.tar.gz" + sha256 = "61a3f945941adbf75c87c1c28f05e95b187959fedf29ecaa36519c5d1941bf23" + url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.4.0+0/HelloWorldC.v1.4.0.x86_64-unknown-freebsd.tar.gz" [[HelloWorldC]] arch = "x86_64" -git-tree-sha1 = "2f1a6d4f82cd1eea785a5141b992423c09491f1b" +git-tree-sha1 = "6e1eb164b0651aa44621eac4dfa340d6e60295ef" os = "windows" [[HelloWorldC.download]] - sha256 = "aad77a16cbc9752f6ec62549a28c7e9f3f7f57919f6fa9fb924e0c669b11f8c4" - url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.1.2+0/HelloWorldC.v1.1.2.x86_64-w64-mingw32.tar.gz" + sha256 = "1f10e46f7b073136f7f668de89096d631ae8bb8903547d588f6817f0b780b2fc" + url = "https://github.com/JuliaBinaryWrappers/HelloWorldC_jll.jl/releases/download/HelloWorldC-v1.4.0+0/HelloWorldC.v1.4.0.x86_64-w64-mingw32.tar.gz" [socrates] git-tree-sha1 = "43563e7631a7eafae1f9f8d9d332e3de44ad7239" diff --git a/stdlib/Artifacts/test/runtests.jl b/stdlib/Artifacts/test/runtests.jl index a09b3c7531996..cb81c16347abf 100644 --- a/stdlib/Artifacts/test/runtests.jl +++ b/stdlib/Artifacts/test/runtests.jl @@ -195,8 +195,8 @@ end with_artifacts_directory(artifacts_dir) do win64 = Platform("x86_64", "windows") mac64 = Platform("x86_64", "macos") - @test basename(@artifact_str("HelloWorldC", win64)) == "2f1a6d4f82cd1eea785a5141b992423c09491f1b" - @test basename(@artifact_str("HelloWorldC", mac64)) == "f8ab5a03697f9afc82210d8a2be1d94509aea8bc" + @test basename(@artifact_str("HelloWorldC", win64)) == "6e1eb164b0651aa44621eac4dfa340d6e60295ef" + @test basename(@artifact_str("HelloWorldC", mac64)) == "2e1742c9c0addd693b0b025f7a1e7aa4c50a0e6c" end end @@ -206,7 +206,7 @@ end # Check the first key in Artifacts.toml is hashed correctly @test artifact_hash("HelloWorldC", joinpath(@__DIR__, "Artifacts.toml"); platform=armv7l_linux) == - SHA1("5a8288c8a30578c0d0f24a9cded29579517ce7a8") + SHA1("0a8e7b523ef6be31311aefe9983a488616e58201") # Check the second key in Artifacts.toml is hashed correctly @test artifact_hash("socrates", joinpath(@__DIR__, "Artifacts.toml"); platform=armv7l_linux) == @@ -214,18 +214,18 @@ end # Check artifact_hash() works for any AbstractString @test artifact_hash(SubString("HelloWorldC0", 1, 11), joinpath(@__DIR__, "Artifacts.toml"); platform=armv7l_linux) == - SHA1("5a8288c8a30578c0d0f24a9cded29579517ce7a8") + SHA1("0a8e7b523ef6be31311aefe9983a488616e58201") end @testset "select_downloadable_artifacts()" begin armv7l_linux = Platform("armv7l", "linux") artifacts = select_downloadable_artifacts(joinpath(@__DIR__, "Artifacts.toml"); platform=armv7l_linux) @test length(keys(artifacts)) == 1 - @test artifacts["HelloWorldC"]["git-tree-sha1"] == "5a8288c8a30578c0d0f24a9cded29579517ce7a8" + @test artifacts["HelloWorldC"]["git-tree-sha1"] == "0a8e7b523ef6be31311aefe9983a488616e58201" artifacts = select_downloadable_artifacts(joinpath(@__DIR__, "Artifacts.toml"); platform=armv7l_linux, include_lazy=true) @test length(keys(artifacts)) == 2 - @test artifacts["HelloWorldC"]["git-tree-sha1"] == "5a8288c8a30578c0d0f24a9cded29579517ce7a8" + @test artifacts["HelloWorldC"]["git-tree-sha1"] == "0a8e7b523ef6be31311aefe9983a488616e58201" @test artifacts["socrates"]["git-tree-sha1"] == "43563e7631a7eafae1f9f8d9d332e3de44ad7239" end diff --git a/stdlib/LazyArtifacts.version b/stdlib/LazyArtifacts.version index f740516eb9953..8988e27bcb4ac 100644 --- a/stdlib/LazyArtifacts.version +++ b/stdlib/LazyArtifacts.version @@ -1,4 +1,4 @@ LAZYARTIFACTS_BRANCH = main -LAZYARTIFACTS_SHA1 = a719c0e3d68a95c6f3dc9571459428ca8761fa2c +LAZYARTIFACTS_SHA1 = e4cfc39598c238f75bdfdbdb3f82c9329a5af59c LAZYARTIFACTS_GIT_URL := https://github.com/JuliaPackaging/LazyArtifacts.jl.git LAZYARTIFACTS_TAR_URL = https://api.github.com/repos/JuliaPackaging/LazyArtifacts.jl/tarball/$1 From 056a69d1eb2a1f9525c44d89d7439714c78001ca Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Sun, 12 Jan 2025 18:03:34 +0100 Subject: [PATCH 180/342] Avoid promotion in `muladd` involving unitful `Furlong` (#56886) --- base/complex.jl | 2 +- test/testhelpers/Furlongs.jl | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/base/complex.jl b/base/complex.jl index 095c842795d38..5d9f9df6f2b78 100644 --- a/base/complex.jl +++ b/base/complex.jl @@ -342,7 +342,7 @@ end *(x::Real, z::Complex) = Complex(x * real(z), x * imag(z)) *(z::Complex, x::Real) = Complex(x * real(z), x * imag(z)) -muladd(x::Real, z::Complex, y::Number) = muladd(z, x, y) +muladd(x::Real, z::Complex, y::Union{Real,Complex}) = muladd(z, x, y) muladd(z::Complex, x::Real, y::Real) = Complex(muladd(real(z),x,y), imag(z)*x) muladd(z::Complex, x::Real, w::Complex) = Complex(muladd(real(z),x,real(w)), muladd(imag(z),x,imag(w))) diff --git a/test/testhelpers/Furlongs.jl b/test/testhelpers/Furlongs.jl index 6d52260bb20fd..3ddf42bf1a82c 100644 --- a/test/testhelpers/Furlongs.jl +++ b/test/testhelpers/Furlongs.jl @@ -100,5 +100,11 @@ for op in (:rem, :mod) end Base.sqrt(x::Furlong) = _div(sqrt(x.val), x, Val(2)) Base.muladd(x::Furlong, y::Furlong, z::Furlong) = x*y + z +Base.muladd(x::Furlong, y::Number, z::Number) = x*y + z +Base.muladd(x::Furlong, y::Furlong, z::Number) = x*y + z +Base.muladd(x::Number, y::Furlong, z::Number) = x*y + z +Base.muladd(x::Number, y::Number, z::Furlong) = x*y + z +Base.muladd(x::Number, y::Furlong, z::Furlong) = x*y + z +Base.muladd(x::Furlong, y::Number, z::Furlong) = x*y + z end From 37b8b61ee0bd4b8db1b210a5389cf794a1358ed1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= <765740+giordano@users.noreply.github.com> Date: Sun, 12 Jan 2025 18:12:35 +0000 Subject: [PATCH 181/342] [docs] Add RISC-V page to table of content (#57022) This was missed in #56105. --- doc/make.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/make.jl b/doc/make.jl index 5ef5fcf55b215..43d51e9936b58 100644 --- a/doc/make.jl +++ b/doc/make.jl @@ -248,6 +248,7 @@ DevDocs = [ "devdocs/build/windows.md", "devdocs/build/freebsd.md", "devdocs/build/arm.md", + "devdocs/build/riscv.md", "devdocs/build/distributing.md", ] ] From cac16d2e862a0b5719121b268c892f8abf38acef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= <765740+giordano@users.noreply.github.com> Date: Sun, 12 Jan 2025 23:52:21 +0000 Subject: [PATCH 182/342] [CompilerSupportLibraries_jll] Update to new build with GCC 14 (#57024) --- Make.inc | 2 +- deps/checksums/compilersupportlibraries | 194 +++++++++--------- deps/csl.mk | 11 +- .../CompilerSupportLibraries_jll/Project.toml | 2 +- 4 files changed, 106 insertions(+), 103 deletions(-) diff --git a/Make.inc b/Make.inc index 216fc6fd7adde..26b5ae7752555 100644 --- a/Make.inc +++ b/Make.inc @@ -1395,7 +1395,7 @@ LIBGFORTRAN_VERSION := $(subst libgfortran,,$(filter libgfortran%,$(subst -,$(SP # shipped with CSL. Although we do not depend on any of the symbols, it is entirely # possible that a user might choose to install a library which depends on symbols provided # by a newer libstdc++. Without runtime detection, those libraries would break. -CSL_NEXT_GLIBCXX_VERSION=GLIBCXX_3\.4\.33|GLIBCXX_3\.5\.|GLIBCXX_4\. +CSL_NEXT_GLIBCXX_VERSION=GLIBCXX_3\.4\.34|GLIBCXX_3\.5\.|GLIBCXX_4\. # This is the set of projects that BinaryBuilder dependencies are hooked up for. diff --git a/deps/checksums/compilersupportlibraries b/deps/checksums/compilersupportlibraries index a03ae8ee83f9a..08802ca1f4de3 100644 --- a/deps/checksums/compilersupportlibraries +++ b/deps/checksums/compilersupportlibraries @@ -1,96 +1,98 @@ -CompilerSupportLibraries.v1.2.0+0.aarch64-apple-darwin-libgfortran5.tar.gz/md5/20ebaad57850393b6ac9fa924e511fe4 -CompilerSupportLibraries.v1.2.0+0.aarch64-apple-darwin-libgfortran5.tar.gz/sha512/020de4d8b0ff6bedbadaa305ff8445e6849f12053762ea4aa68412d1ec763dbd86f479587a2fbb862487f1feb04d976c38099ddf3887817a3d32b3f029cf85b1 -CompilerSupportLibraries.v1.2.0+0.aarch64-linux-gnu-libgfortran3.tar.gz/md5/d641904255ee412c45b089d92c53262b -CompilerSupportLibraries.v1.2.0+0.aarch64-linux-gnu-libgfortran3.tar.gz/sha512/ace0383fe9bd64faeed1fb05a11bbec932bd56b8460d06d2b7c3e1b5f4f6e9a9b3345937088684e5cd1ca9a85ef1a5ff56a97a1f60449cd6e35247de1e123d81 -CompilerSupportLibraries.v1.2.0+0.aarch64-linux-gnu-libgfortran4.tar.gz/md5/2a71f320d8b9242ad26aabed74cbf404 -CompilerSupportLibraries.v1.2.0+0.aarch64-linux-gnu-libgfortran4.tar.gz/sha512/03e2a4482baaca2d6ce5cc207224d03bd7851486ebe8072c7317f5fcdd641395d945552d9462ab44a9f2e4b0ffaa3874a76f314d67bc0f75393a1151ab518611 -CompilerSupportLibraries.v1.2.0+0.aarch64-linux-gnu-libgfortran5.tar.gz/md5/1beec15ad689a5f572040ca2a7b6a880 -CompilerSupportLibraries.v1.2.0+0.aarch64-linux-gnu-libgfortran5.tar.gz/sha512/27bbe212a8d43e841cf8f3e9964b72bc220fea03cf5e65721b02d2f3aa5193acdce41e512578ed6be935b413cd0d2224a6bcd2e9624931f39092ba3cfc5cbcc0 -CompilerSupportLibraries.v1.2.0+0.aarch64-linux-musl-libgfortran3.tar.gz/md5/9e949c2efe48a7b2a62bff7e1ffdede0 -CompilerSupportLibraries.v1.2.0+0.aarch64-linux-musl-libgfortran3.tar.gz/sha512/2947acb250f8ff4936da5ed02ddbfa492fc38bc87baa588a36bb892ba68b6636a912cda976f8fff00cc7a710c3bfb185826b4cd4a726750ef5f161d5f1aa21a2 -CompilerSupportLibraries.v1.2.0+0.aarch64-linux-musl-libgfortran4.tar.gz/md5/7202764b1a89a748b07460d9c40a9279 -CompilerSupportLibraries.v1.2.0+0.aarch64-linux-musl-libgfortran4.tar.gz/sha512/63236225a9becdd166c4395ea5081c64f57bc51af89c2edb5abeb419d6eb8224a380a633afd861bb84a12435fd19c8554cbe5ffadf8324ff2c7f17021ed53e69 -CompilerSupportLibraries.v1.2.0+0.aarch64-linux-musl-libgfortran5.tar.gz/md5/f66c30d3cec8057ae47f05df022ead51 -CompilerSupportLibraries.v1.2.0+0.aarch64-linux-musl-libgfortran5.tar.gz/sha512/5329d9469bb0f47560e52b15eb21ab70e0e2da0275bdb2f8e6ed4feb132bc9989a6b44984329455104546c95d05a05f8fb4f1cf232856219ba005100f4b16dc3 -CompilerSupportLibraries.v1.2.0+0.aarch64-unknown-freebsd-libgfortran4.tar.gz/md5/1d8ae93fe000440d00c404ba5044f169 -CompilerSupportLibraries.v1.2.0+0.aarch64-unknown-freebsd-libgfortran4.tar.gz/sha512/6733bd456c389c7c2cd83c5e44aa575552aa7ab5549a5b3efefbc745a6129aa76d78bacb1441208fc77c58b36f1b0775aa3a44bb97e6769ff730744ecf5e8abc -CompilerSupportLibraries.v1.2.0+0.aarch64-unknown-freebsd-libgfortran5.tar.gz/md5/bf1a5a3320a0a38133f04861afab33b8 -CompilerSupportLibraries.v1.2.0+0.aarch64-unknown-freebsd-libgfortran5.tar.gz/sha512/221502795c075f64196dae687a35b83aa83a9a1ecf1ec3e9f51613bd7431c526015e412132a081e00ca13a5730d733330df79baad6fccc8758c17db9877e59dd -CompilerSupportLibraries.v1.2.0+0.armv6l-linux-gnueabihf-libgfortran3.tar.gz/md5/05ff63780f5b7c8c6c590c3626f32ac0 -CompilerSupportLibraries.v1.2.0+0.armv6l-linux-gnueabihf-libgfortran3.tar.gz/sha512/8d3c4149531f3782f5efbb6a6fbbb7080ba005298ba962b5bc5f66250ea9fde91b34836ed909c16f306d21d2e358f985360962e9362a8e807ccd4254da3bb19b -CompilerSupportLibraries.v1.2.0+0.armv6l-linux-gnueabihf-libgfortran4.tar.gz/md5/3ca2b6e8101d831e546c1b6ed2ca9a42 -CompilerSupportLibraries.v1.2.0+0.armv6l-linux-gnueabihf-libgfortran4.tar.gz/sha512/21a0b9c5acde96c0a91303f4f395e55f272d5585ad18f0365105188d129a3ca94ad66d4dd99b471abdf41a7a7262a3b258fd04b887110ad15255b284cd1612b0 -CompilerSupportLibraries.v1.2.0+0.armv6l-linux-gnueabihf-libgfortran5.tar.gz/md5/d4d560b8ecce0ff2cb4dbc88cb25942a -CompilerSupportLibraries.v1.2.0+0.armv6l-linux-gnueabihf-libgfortran5.tar.gz/sha512/d405f61525af1b2fe85107a70ed67b8a1eb767923487fa71539e0f49d6e70358c8a24f4ef1c224256cf677af99b54a2f8243f1e207350fcb14d426a7a6bb3915 -CompilerSupportLibraries.v1.2.0+0.armv6l-linux-musleabihf-libgfortran3.tar.gz/md5/8c6eddaa156fd0afee28ac5a154bc3f7 -CompilerSupportLibraries.v1.2.0+0.armv6l-linux-musleabihf-libgfortran3.tar.gz/sha512/b9fc86bb706ad98d61b63eb4cc8bfce6b2c67b58ba2cebecea7574f44790cce044bb1b4db1d20050b59538fa43b51cb352d752c77333a0f0621fde47c63a3596 -CompilerSupportLibraries.v1.2.0+0.armv6l-linux-musleabihf-libgfortran4.tar.gz/md5/0a54c16fea86c6dadb39eff65c465528 -CompilerSupportLibraries.v1.2.0+0.armv6l-linux-musleabihf-libgfortran4.tar.gz/sha512/c635c636384d3af5b4b078be7398fbc665a185eae69dd223279affb4836fb5c575d6ab296ae940ccbe73777bdb5e355f4f28a2fa27606ac143ff424641c60c65 -CompilerSupportLibraries.v1.2.0+0.armv6l-linux-musleabihf-libgfortran5.tar.gz/md5/892dfd91703f0f77d170a5371a1c25d4 -CompilerSupportLibraries.v1.2.0+0.armv6l-linux-musleabihf-libgfortran5.tar.gz/sha512/8ac59d00192c0e847168e61b3e93957f3909aab59ba8d05e47686a9f8b7226496f89b932151c42198ec966ccd47721cdf547a247ea4e5c61b22bfccce2ec591c -CompilerSupportLibraries.v1.2.0+0.armv7l-linux-gnueabihf-libgfortran3.tar.gz/md5/05ff63780f5b7c8c6c590c3626f32ac0 -CompilerSupportLibraries.v1.2.0+0.armv7l-linux-gnueabihf-libgfortran3.tar.gz/sha512/8d3c4149531f3782f5efbb6a6fbbb7080ba005298ba962b5bc5f66250ea9fde91b34836ed909c16f306d21d2e358f985360962e9362a8e807ccd4254da3bb19b -CompilerSupportLibraries.v1.2.0+0.armv7l-linux-gnueabihf-libgfortran4.tar.gz/md5/3ca2b6e8101d831e546c1b6ed2ca9a42 -CompilerSupportLibraries.v1.2.0+0.armv7l-linux-gnueabihf-libgfortran4.tar.gz/sha512/21a0b9c5acde96c0a91303f4f395e55f272d5585ad18f0365105188d129a3ca94ad66d4dd99b471abdf41a7a7262a3b258fd04b887110ad15255b284cd1612b0 -CompilerSupportLibraries.v1.2.0+0.armv7l-linux-gnueabihf-libgfortran5.tar.gz/md5/d4d560b8ecce0ff2cb4dbc88cb25942a -CompilerSupportLibraries.v1.2.0+0.armv7l-linux-gnueabihf-libgfortran5.tar.gz/sha512/d405f61525af1b2fe85107a70ed67b8a1eb767923487fa71539e0f49d6e70358c8a24f4ef1c224256cf677af99b54a2f8243f1e207350fcb14d426a7a6bb3915 -CompilerSupportLibraries.v1.2.0+0.armv7l-linux-musleabihf-libgfortran3.tar.gz/md5/8c6eddaa156fd0afee28ac5a154bc3f7 -CompilerSupportLibraries.v1.2.0+0.armv7l-linux-musleabihf-libgfortran3.tar.gz/sha512/b9fc86bb706ad98d61b63eb4cc8bfce6b2c67b58ba2cebecea7574f44790cce044bb1b4db1d20050b59538fa43b51cb352d752c77333a0f0621fde47c63a3596 -CompilerSupportLibraries.v1.2.0+0.armv7l-linux-musleabihf-libgfortran4.tar.gz/md5/0a54c16fea86c6dadb39eff65c465528 -CompilerSupportLibraries.v1.2.0+0.armv7l-linux-musleabihf-libgfortran4.tar.gz/sha512/c635c636384d3af5b4b078be7398fbc665a185eae69dd223279affb4836fb5c575d6ab296ae940ccbe73777bdb5e355f4f28a2fa27606ac143ff424641c60c65 -CompilerSupportLibraries.v1.2.0+0.armv7l-linux-musleabihf-libgfortran5.tar.gz/md5/892dfd91703f0f77d170a5371a1c25d4 -CompilerSupportLibraries.v1.2.0+0.armv7l-linux-musleabihf-libgfortran5.tar.gz/sha512/8ac59d00192c0e847168e61b3e93957f3909aab59ba8d05e47686a9f8b7226496f89b932151c42198ec966ccd47721cdf547a247ea4e5c61b22bfccce2ec591c -CompilerSupportLibraries.v1.2.0+0.i686-linux-gnu-libgfortran3.tar.gz/md5/3094705222b6b61fd6a10422a73e1149 -CompilerSupportLibraries.v1.2.0+0.i686-linux-gnu-libgfortran3.tar.gz/sha512/27f874cde357ffa45aaa10f2e620ec0f8ab4e5a8bf4607fc023a2ec42040bcc9a724f959237c340d67451f8621402fa05133c1420086b87135f40326c30b97af -CompilerSupportLibraries.v1.2.0+0.i686-linux-gnu-libgfortran4.tar.gz/md5/ba0acaff60648efa3915348a8a353df8 -CompilerSupportLibraries.v1.2.0+0.i686-linux-gnu-libgfortran4.tar.gz/sha512/0b6aaf75363cbe6133ca3aed351ab58ef1e441f61375f5baf702d8043813c459d48e8af17630f1a07dc22772ec9b02076af33726ed94e6314ae37d5a139d6dcc -CompilerSupportLibraries.v1.2.0+0.i686-linux-gnu-libgfortran5.tar.gz/md5/95f1d57cfc43677e40bfc121bce79274 -CompilerSupportLibraries.v1.2.0+0.i686-linux-gnu-libgfortran5.tar.gz/sha512/edacd9960e9de1236c91752e103cddfc018d697e87fabb3cceadf36153b4e97842ef284bd1532290a5620007234882b4c4cd4f36525b61763d97b2f608358262 -CompilerSupportLibraries.v1.2.0+0.i686-linux-musl-libgfortran3.tar.gz/md5/f37fe1818e1634476c44afae478611c8 -CompilerSupportLibraries.v1.2.0+0.i686-linux-musl-libgfortran3.tar.gz/sha512/6e4e3eb5ac9570bfdf5280f59167eb6c4a74f3aa152afb4c5d180b9a6cdbdca557e7dd13f0b5b76943b45a65e848fe77c5b3bbc6ddb0fd846d03fbc9fbedf7ce -CompilerSupportLibraries.v1.2.0+0.i686-linux-musl-libgfortran4.tar.gz/md5/b4ffd52179aa0006c56f279b87cb7556 -CompilerSupportLibraries.v1.2.0+0.i686-linux-musl-libgfortran4.tar.gz/sha512/a047ac7db204c31802f646351af51c55fe06498e851b2df58d7f93f75d9c0067f8736f247f108991ec01ac7f86f3026ecf58b5f2f3a76d7eab00130754e7f704 -CompilerSupportLibraries.v1.2.0+0.i686-linux-musl-libgfortran5.tar.gz/md5/2d38fc835f236f89f457fdf859ccb903 -CompilerSupportLibraries.v1.2.0+0.i686-linux-musl-libgfortran5.tar.gz/sha512/51fbe41efbce33b1cf3728df6fa59fd0e85a13308b3e868fe9f70f4d67857615f83542ba69be824a73e89959503dd7a11335d1c495704bd7d6cad6656d0c5d57 -CompilerSupportLibraries.v1.2.0+0.i686-w64-mingw32-libgfortran3.tar.gz/md5/9650002f6729c0964d33afcab334d77d -CompilerSupportLibraries.v1.2.0+0.i686-w64-mingw32-libgfortran3.tar.gz/sha512/0b7907811a13d09b7b33203c7e46888308c7d6fcf5d69790babafc39f640541551f784264247f159a552f15df1ddd061c421a93b983d838d3bd7f85ba6427f70 -CompilerSupportLibraries.v1.2.0+0.i686-w64-mingw32-libgfortran4.tar.gz/md5/47e9fb99906b9647e26e4126a913074e -CompilerSupportLibraries.v1.2.0+0.i686-w64-mingw32-libgfortran4.tar.gz/sha512/d7285691fbe1318e48e061d678e54890762cc16996652a34b190924cc1462d24ab0b08729945eb25f4bef60e60d50f3e78db57d4cda0302b8ba579db8a1311e1 -CompilerSupportLibraries.v1.2.0+0.i686-w64-mingw32-libgfortran5.tar.gz/md5/b588b2710f2b83d2c70c6104e585a3bd -CompilerSupportLibraries.v1.2.0+0.i686-w64-mingw32-libgfortran5.tar.gz/sha512/b62a63b0c8750f85fc265db88456307b794e912352a68997c7cce06444391307c03edbe5b901833f53c5bd55f5a1e61a586538b08487cc139a2d71fccdce1d31 -CompilerSupportLibraries.v1.2.0+0.powerpc64le-linux-gnu-libgfortran3.tar.gz/md5/7cce4f3dc057ebebaa677bf6f0d51e9e -CompilerSupportLibraries.v1.2.0+0.powerpc64le-linux-gnu-libgfortran3.tar.gz/sha512/a0dd93905f0ede4da5e2fbacf2579154db8ac8e9963c77fb62284489686f2aa372925b3341742d86430a839267421af55f6e1e413473d17f13a1a199e6a904a0 -CompilerSupportLibraries.v1.2.0+0.powerpc64le-linux-gnu-libgfortran4.tar.gz/md5/06ee6aaeca78b3e9005f53f1fa32731f -CompilerSupportLibraries.v1.2.0+0.powerpc64le-linux-gnu-libgfortran4.tar.gz/sha512/ff0e33ce9f93b3a867cf409b95e763efbc8f4dde65ed19107eb14d29460d084f253e03ebd6375f1da996182b3d96e1fda4abff06507258da9a89ece36663db84 -CompilerSupportLibraries.v1.2.0+0.powerpc64le-linux-gnu-libgfortran5.tar.gz/md5/483251d28076ee959dff131d13d7e53b -CompilerSupportLibraries.v1.2.0+0.powerpc64le-linux-gnu-libgfortran5.tar.gz/sha512/a7c9053a8c1b784cb6459762f26e0c2106a9758cbe2aefe8975a14aaaf61b8a08e51c465e733e44d01537beb59d467c57e536ebd8b27b7b68f46945174c469c7 -CompilerSupportLibraries.v1.2.0+0.x86_64-apple-darwin-libgfortran3.tar.gz/md5/a147bf3a6d6550c177b8a784b9b02e21 -CompilerSupportLibraries.v1.2.0+0.x86_64-apple-darwin-libgfortran3.tar.gz/sha512/c6f7a13f0195eae8f7ad980a4b24de9b155be69c4437522723411f9866a4aee3c5b350ee2f0c95f41f19aba43acaca78309881157e8498df0664c902d0c05a5d -CompilerSupportLibraries.v1.2.0+0.x86_64-apple-darwin-libgfortran4.tar.gz/md5/3f19c9d0e723a8d5591357ac3a9452a0 -CompilerSupportLibraries.v1.2.0+0.x86_64-apple-darwin-libgfortran4.tar.gz/sha512/5752bac310d80ed2dc1fc3d6580300d185787b9b933e31c8e0f572099abd0727d9483da8f9af858f706e96a183d2b10702c44381a080438cbb17d6459321ccfb -CompilerSupportLibraries.v1.2.0+0.x86_64-apple-darwin-libgfortran5.tar.gz/md5/ad0f0e2fe3e7d147a0a27271a2aba0fc -CompilerSupportLibraries.v1.2.0+0.x86_64-apple-darwin-libgfortran5.tar.gz/sha512/f42231adea3d0b6133c3b5bc5fbf765bc6a7ba8ef0f407fa1b8def36dd8a71d20ef39fb6e57b43208489c2795a96562cdbf15f3d20b3f3a09edb29b99d19a33a -CompilerSupportLibraries.v1.2.0+0.x86_64-linux-gnu-libgfortran3.tar.gz/md5/4c78d56dbbbff682c0a78d11fb9d1e70 -CompilerSupportLibraries.v1.2.0+0.x86_64-linux-gnu-libgfortran3.tar.gz/sha512/0e9d6dcc4b8fddaaa94a26a46e915d33fb474f8a8ee14edd4d1c7e774846c44c5c5d852649a4f70409c99ac0e1d458077b7f0eb7dc0b0326ee8b625644d7074d -CompilerSupportLibraries.v1.2.0+0.x86_64-linux-gnu-libgfortran4.tar.gz/md5/039d37f813b183c75feebadd21011eb6 -CompilerSupportLibraries.v1.2.0+0.x86_64-linux-gnu-libgfortran4.tar.gz/sha512/05e7291de1fd2520247402f0db9d348fdd7a02d8dd9133ac65701f88d237110a3cc6c6e2c5717364ab786b6e6063038ec10c9605e77bc4dbe1064a0e77617f5d -CompilerSupportLibraries.v1.2.0+0.x86_64-linux-gnu-libgfortran5.tar.gz/md5/a985f13a85eb14d1b6339ba4983dc372 -CompilerSupportLibraries.v1.2.0+0.x86_64-linux-gnu-libgfortran5.tar.gz/sha512/27468ccd5642e6e11bd5972684518a0fb883bf4835ac18f5279c3fce97b1779131c7d9e39d8de26a15c293c832946334e964919f51d7679cd0569ce82b938579 -CompilerSupportLibraries.v1.2.0+0.x86_64-linux-musl-libgfortran3.tar.gz/md5/9d86ce2fe481ea97a1fd098bd47d524c -CompilerSupportLibraries.v1.2.0+0.x86_64-linux-musl-libgfortran3.tar.gz/sha512/a865a4127bacaedd81b6c81279f6a44bc3497ab29a0401f66da1abfc0738ea459be9f158d06969c161a65925739665084bec5f8650a8cd1e8f0d08f1f44d729f -CompilerSupportLibraries.v1.2.0+0.x86_64-linux-musl-libgfortran4.tar.gz/md5/86d9db869a7af6c96dea39f5d9d90505 -CompilerSupportLibraries.v1.2.0+0.x86_64-linux-musl-libgfortran4.tar.gz/sha512/01e0c69b04138989200ded92eddae6ff1873d3a440d17273d08bee40d53b2929e35bfd14be051074fe78671cac34ac2dd7360c1571790ee52f94a5921de42a65 -CompilerSupportLibraries.v1.2.0+0.x86_64-linux-musl-libgfortran5.tar.gz/md5/e72d28df4bcb60ab2f3389046e7c83a8 -CompilerSupportLibraries.v1.2.0+0.x86_64-linux-musl-libgfortran5.tar.gz/sha512/cac193a26328ddeff5f7bcc3d7207101c574f9bdb1bff5c2b925315c5c2404a2fdb6591d1968f30931373fbfcae9bda784c72e65580ad3acc398448cd193f65d -CompilerSupportLibraries.v1.2.0+0.x86_64-unknown-freebsd-libgfortran3.tar.gz/md5/35642304a9a2f435cf5214b2715198fe -CompilerSupportLibraries.v1.2.0+0.x86_64-unknown-freebsd-libgfortran3.tar.gz/sha512/a67f41ba31c99a064f504f508711537f9e90089ca5352bfc2698c3fcd3e499ca716f07ffeac4fb1b88c2c934f7f380f262af8c863d3b16ac7e805d5c805ab358 -CompilerSupportLibraries.v1.2.0+0.x86_64-unknown-freebsd-libgfortran4.tar.gz/md5/01df0fbb265e5ff1a480a7a5e23b0835 -CompilerSupportLibraries.v1.2.0+0.x86_64-unknown-freebsd-libgfortran4.tar.gz/sha512/57a79f2b8e846c1514dcb18420f26ae2889962040f410b746836cab4395749155fa9cd9d00d4c25954c0ffa72f9f3823b1b50688a20ddf675301f64e0d4b5c7e -CompilerSupportLibraries.v1.2.0+0.x86_64-unknown-freebsd-libgfortran5.tar.gz/md5/1f1f6380ce8815cc9cedcea0b40860e7 -CompilerSupportLibraries.v1.2.0+0.x86_64-unknown-freebsd-libgfortran5.tar.gz/sha512/a88ea8af8c8df792861812bfdf7f1bcaae31582ab78ce78b47a0dc6fd57b93441c0471f529ce23877131ac9701c6eed72ce89241746e18271f3686fbd718138c -CompilerSupportLibraries.v1.2.0+0.x86_64-w64-mingw32-libgfortran3.tar.gz/md5/38fc8c445a1a610db40a7609155e22d6 -CompilerSupportLibraries.v1.2.0+0.x86_64-w64-mingw32-libgfortran3.tar.gz/sha512/085652c7ca583c3623611ca9262b70765c9936c9feb5f9034b2c6b6d6677a7a1d7d201b83d82d0d268f3190bd1a62eab0124e8fae3625407dee7f1df89d4106c -CompilerSupportLibraries.v1.2.0+0.x86_64-w64-mingw32-libgfortran4.tar.gz/md5/f3f89eb3c2e441fde6e6b9c1c1a61183 -CompilerSupportLibraries.v1.2.0+0.x86_64-w64-mingw32-libgfortran4.tar.gz/sha512/c53f79e20ad043ab099873f38ece98c6bed22950610ba88b9c178a4bd943039cc426473828d509deb8c65c93309da1de87bdf36fb3954b8f8047277c418fe2e0 -CompilerSupportLibraries.v1.2.0+0.x86_64-w64-mingw32-libgfortran5.tar.gz/md5/024f7133425db23e215dc55589bb9171 -CompilerSupportLibraries.v1.2.0+0.x86_64-w64-mingw32-libgfortran5.tar.gz/sha512/819945496ea48dd44d8c0f12a11a358b7d1ebf198d60fbad576d74ddee68cdea98070cdd11ca96567d0c772ec007c03cbc83ff5c7d2ad737cbd486fe0c9afcd5 +CompilerSupportLibraries.v1.3.0+1.aarch64-apple-darwin-libgfortran5.tar.gz/md5/20ebaad57850393b6ac9fa924e511fe4 +CompilerSupportLibraries.v1.3.0+1.aarch64-apple-darwin-libgfortran5.tar.gz/sha512/020de4d8b0ff6bedbadaa305ff8445e6849f12053762ea4aa68412d1ec763dbd86f479587a2fbb862487f1feb04d976c38099ddf3887817a3d32b3f029cf85b1 +CompilerSupportLibraries.v1.3.0+1.aarch64-linux-gnu-libgfortran3.tar.gz/md5/c679907ddce62f21bc30667cc40d8d52 +CompilerSupportLibraries.v1.3.0+1.aarch64-linux-gnu-libgfortran3.tar.gz/sha512/284b17b6634087f0b969d3e99b2e4152667ab5eb9e6b5813f9739bd14ae1c25dba01f15488e901ca5fcfd780b02bc02b6bff670fefed7d965dcb585e81b03782 +CompilerSupportLibraries.v1.3.0+1.aarch64-linux-gnu-libgfortran4.tar.gz/md5/1b4f6efeb83f5f3e27c42eddeafe993a +CompilerSupportLibraries.v1.3.0+1.aarch64-linux-gnu-libgfortran4.tar.gz/sha512/b1d5aa122b2bd25bcd1ce47e000f71785d617d77f44acda56f9f5ad77101a0c54f6c6a4c5560a7c12ffb8c89ae325d4f056bd92f893d219385c3d5c85aa457e9 +CompilerSupportLibraries.v1.3.0+1.aarch64-linux-gnu-libgfortran5.tar.gz/md5/834adb105f78ac1bb223ef309dbf7cdc +CompilerSupportLibraries.v1.3.0+1.aarch64-linux-gnu-libgfortran5.tar.gz/sha512/dd0440805145f1a8e8521633a955317567606bf2e3725a5a7eb90515128b077f2163832ab608022fab152526f2a55991f50256ab92104d5d62bbb8a740e25009 +CompilerSupportLibraries.v1.3.0+1.aarch64-linux-musl-libgfortran3.tar.gz/md5/d613881e48181bb8ac0bf34a456c9736 +CompilerSupportLibraries.v1.3.0+1.aarch64-linux-musl-libgfortran3.tar.gz/sha512/34214bca9f7c66e3c508b2f9d88cb296695721cfba0c001660e2edb0387a2efbb2fecb0360f8eb2b1d0ec502480fe63e802f350367498a342c455c0f58aadd82 +CompilerSupportLibraries.v1.3.0+1.aarch64-linux-musl-libgfortran4.tar.gz/md5/97e4ea4394df1d784ce4de3f75aed580 +CompilerSupportLibraries.v1.3.0+1.aarch64-linux-musl-libgfortran4.tar.gz/sha512/a072ceece6600b704dae5a7491f1ead9b4e11da3d4438b7056f2c71e59b0a37d3023fb812cbae205a4f1fcaf18a4b223a5ba2cea32131c5eda0d55b1f0649c23 +CompilerSupportLibraries.v1.3.0+1.aarch64-linux-musl-libgfortran5.tar.gz/md5/df09c5b33b2e307e0d9c2b39b450c0eb +CompilerSupportLibraries.v1.3.0+1.aarch64-linux-musl-libgfortran5.tar.gz/sha512/d0a8dc03ea1667d90bd58c2376b575a1090a54a4412bc53b311a3ea910c76dc698be5ca1078e6ca8341244f1fd6b84201ba10c10baba194c1d6c3ffb7e69563c +CompilerSupportLibraries.v1.3.0+1.aarch64-unknown-freebsd-libgfortran4.tar.gz/md5/4f9b257eabaf0a817755495cfbf75088 +CompilerSupportLibraries.v1.3.0+1.aarch64-unknown-freebsd-libgfortran4.tar.gz/sha512/876036a8b599008512ab7010f4bc5f11fbf963bb9b9f77499adcca21fcad89f94180f653dce3121e5c1206f4fd4ace717ef8f3b40d8009a71039a84ae7272588 +CompilerSupportLibraries.v1.3.0+1.aarch64-unknown-freebsd-libgfortran5.tar.gz/md5/0d296a080921b54d959a2a60884b7938 +CompilerSupportLibraries.v1.3.0+1.aarch64-unknown-freebsd-libgfortran5.tar.gz/sha512/d8232dd9131c2890ea2f5c90f62c646ea1dc93a0a6de4af0a98c7e69928c5ca5698e79ff9d23bdcf47de1f5670467c9e8fed5f01e82e009696641896f0658030 +CompilerSupportLibraries.v1.3.0+1.armv6l-linux-gnueabihf-libgfortran3.tar.gz/md5/3e0727a3813c699b6daa041e336d6e13 +CompilerSupportLibraries.v1.3.0+1.armv6l-linux-gnueabihf-libgfortran3.tar.gz/sha512/00cc2c34af7c4a5df06deaff27dff5b94b231ede4afe7a47b7b783a8d2e62158c0ba1b2062d40df949fdc0a21ac703f8c9011f998ab032bac265aef153cea012 +CompilerSupportLibraries.v1.3.0+1.armv6l-linux-gnueabihf-libgfortran4.tar.gz/md5/b7cb328b5e5fae5b5e456d058f5c18b7 +CompilerSupportLibraries.v1.3.0+1.armv6l-linux-gnueabihf-libgfortran4.tar.gz/sha512/ff191595bdf4dfb2cdd77d42e591adc0b27ca0e1055efa7fb25fc06784f26add83e6c5c7594405bdfd715f9c8e6ae3f2171a50ae218b4b691099da754fe9bedd +CompilerSupportLibraries.v1.3.0+1.armv6l-linux-gnueabihf-libgfortran5.tar.gz/md5/46a3fc18a65e223ba59d984f99d42979 +CompilerSupportLibraries.v1.3.0+1.armv6l-linux-gnueabihf-libgfortran5.tar.gz/sha512/cb470147f6695b101d497bf2d84caeb1f97d967bf23d1844ad70be47505588d981df096378136a98c35cda5aec090255d60cf7c1c8def9801233c72ca002b563 +CompilerSupportLibraries.v1.3.0+1.armv6l-linux-musleabihf-libgfortran3.tar.gz/md5/28e1bc0fb0ac1512a8598f26ee3f376a +CompilerSupportLibraries.v1.3.0+1.armv6l-linux-musleabihf-libgfortran3.tar.gz/sha512/7ec17859790cd08942929281906918e4c69d7f306a8302dcd591a4a67b3d95f7f72f7afbeea3a86a0d94ca5b608b3bda00ce43b594e9f173edb0228c0f79ba49 +CompilerSupportLibraries.v1.3.0+1.armv6l-linux-musleabihf-libgfortran4.tar.gz/md5/f9bff1a49d95fc0f3ad3d4a90b259c87 +CompilerSupportLibraries.v1.3.0+1.armv6l-linux-musleabihf-libgfortran4.tar.gz/sha512/8ad503a213b949f569c5b9eac28e33ed51cc55298bb66b147375dc12cb9ed90e60165aa2dca8e3d28f1a2c153894a9e4672bdb2ae3cfb3a67b1e06b345cb454f +CompilerSupportLibraries.v1.3.0+1.armv6l-linux-musleabihf-libgfortran5.tar.gz/md5/d550a4dac1b20606681a56acc00c01ad +CompilerSupportLibraries.v1.3.0+1.armv6l-linux-musleabihf-libgfortran5.tar.gz/sha512/14ca10ad8809dfd2434e300ad5280915f21cc1ba159a9f4aed7aa2164ae624687a2a7a9e6dd99abcfe95f40cb037c72292c992f4483fa1affcf8a9b5cf29c9bf +CompilerSupportLibraries.v1.3.0+1.armv7l-linux-gnueabihf-libgfortran3.tar.gz/md5/3e0727a3813c699b6daa041e336d6e13 +CompilerSupportLibraries.v1.3.0+1.armv7l-linux-gnueabihf-libgfortran3.tar.gz/sha512/00cc2c34af7c4a5df06deaff27dff5b94b231ede4afe7a47b7b783a8d2e62158c0ba1b2062d40df949fdc0a21ac703f8c9011f998ab032bac265aef153cea012 +CompilerSupportLibraries.v1.3.0+1.armv7l-linux-gnueabihf-libgfortran4.tar.gz/md5/b7cb328b5e5fae5b5e456d058f5c18b7 +CompilerSupportLibraries.v1.3.0+1.armv7l-linux-gnueabihf-libgfortran4.tar.gz/sha512/ff191595bdf4dfb2cdd77d42e591adc0b27ca0e1055efa7fb25fc06784f26add83e6c5c7594405bdfd715f9c8e6ae3f2171a50ae218b4b691099da754fe9bedd +CompilerSupportLibraries.v1.3.0+1.armv7l-linux-gnueabihf-libgfortran5.tar.gz/md5/46a3fc18a65e223ba59d984f99d42979 +CompilerSupportLibraries.v1.3.0+1.armv7l-linux-gnueabihf-libgfortran5.tar.gz/sha512/cb470147f6695b101d497bf2d84caeb1f97d967bf23d1844ad70be47505588d981df096378136a98c35cda5aec090255d60cf7c1c8def9801233c72ca002b563 +CompilerSupportLibraries.v1.3.0+1.armv7l-linux-musleabihf-libgfortran3.tar.gz/md5/28e1bc0fb0ac1512a8598f26ee3f376a +CompilerSupportLibraries.v1.3.0+1.armv7l-linux-musleabihf-libgfortran3.tar.gz/sha512/7ec17859790cd08942929281906918e4c69d7f306a8302dcd591a4a67b3d95f7f72f7afbeea3a86a0d94ca5b608b3bda00ce43b594e9f173edb0228c0f79ba49 +CompilerSupportLibraries.v1.3.0+1.armv7l-linux-musleabihf-libgfortran4.tar.gz/md5/f9bff1a49d95fc0f3ad3d4a90b259c87 +CompilerSupportLibraries.v1.3.0+1.armv7l-linux-musleabihf-libgfortran4.tar.gz/sha512/8ad503a213b949f569c5b9eac28e33ed51cc55298bb66b147375dc12cb9ed90e60165aa2dca8e3d28f1a2c153894a9e4672bdb2ae3cfb3a67b1e06b345cb454f +CompilerSupportLibraries.v1.3.0+1.armv7l-linux-musleabihf-libgfortran5.tar.gz/md5/d550a4dac1b20606681a56acc00c01ad +CompilerSupportLibraries.v1.3.0+1.armv7l-linux-musleabihf-libgfortran5.tar.gz/sha512/14ca10ad8809dfd2434e300ad5280915f21cc1ba159a9f4aed7aa2164ae624687a2a7a9e6dd99abcfe95f40cb037c72292c992f4483fa1affcf8a9b5cf29c9bf +CompilerSupportLibraries.v1.3.0+1.i686-linux-gnu-libgfortran3.tar.gz/md5/73e14b94dc74d17aca38a51ad402f836 +CompilerSupportLibraries.v1.3.0+1.i686-linux-gnu-libgfortran3.tar.gz/sha512/d37263a216fb3e9b94dd032642ed6bf5be154a5c66de3e4bd74e5e2059d9740958a673796eb652ca9ebea8ec09a7eec837d8906a50775913325899aa190808db +CompilerSupportLibraries.v1.3.0+1.i686-linux-gnu-libgfortran4.tar.gz/md5/23996e5c6690b35e7c36bff245f6f4d1 +CompilerSupportLibraries.v1.3.0+1.i686-linux-gnu-libgfortran4.tar.gz/sha512/660dc4866a13f9a1ae98424b605723b250218a034e02151d4160d58ca07bba4fa1390e99e7fe2f31eccdd518d1ac4c5f5454968ce52525e3a2d21918b6b5bba8 +CompilerSupportLibraries.v1.3.0+1.i686-linux-gnu-libgfortran5.tar.gz/md5/af836562cfaf76f0728be0d875d29ae1 +CompilerSupportLibraries.v1.3.0+1.i686-linux-gnu-libgfortran5.tar.gz/sha512/a2b10c2f72d1e84c7b496b7ad6d38629342c93cd6a7f691e5bbe96ce28ef40fd38509d382d22208e40cc4953e7b93d1c211bf59529db0ad1a77b684ba75bc68a +CompilerSupportLibraries.v1.3.0+1.i686-linux-musl-libgfortran3.tar.gz/md5/502f089e5ee03b3a290ee6e18577a22f +CompilerSupportLibraries.v1.3.0+1.i686-linux-musl-libgfortran3.tar.gz/sha512/13a97c2386f37aba2416ec35fe67b99a1eccb880b0254ff0a70f2ba01a01a15c80251606ec7eb0503d59a7723542b6b9778d6c9d9e4ba66ae5cce51e46a9cb40 +CompilerSupportLibraries.v1.3.0+1.i686-linux-musl-libgfortran4.tar.gz/md5/221aa40c278faee74ab6af46686d68d6 +CompilerSupportLibraries.v1.3.0+1.i686-linux-musl-libgfortran4.tar.gz/sha512/9e4e598c8acdecebc812555de9631f022f6158d679c329537e37f83c76c818f31476a5827924b5ac12978515d64a7e913f220ca75314f41d3227573e9a2ac9af +CompilerSupportLibraries.v1.3.0+1.i686-linux-musl-libgfortran5.tar.gz/md5/c364ec196e66dd5eadc3932b208a0385 +CompilerSupportLibraries.v1.3.0+1.i686-linux-musl-libgfortran5.tar.gz/sha512/3f7b80fb35a967d9354c2f4c40bb6d62751a0d791aeec09817cdc278393cacef089214f61d8338c0981f7a4ed3144d37bc9267cf0e7ce6c4cf651bc67c431b70 +CompilerSupportLibraries.v1.3.0+1.i686-w64-mingw32-libgfortran3.tar.gz/md5/4177f1ede00d81472bb69888f5b3e26f +CompilerSupportLibraries.v1.3.0+1.i686-w64-mingw32-libgfortran3.tar.gz/sha512/09ab710599d237ee35fca6a39b4d67b36bbadb7d127797724743026eae72319faa161755b03f4cb67c83f801aa4132968b561245487b2c2c0836d0ff867c0e83 +CompilerSupportLibraries.v1.3.0+1.i686-w64-mingw32-libgfortran4.tar.gz/md5/9402d280886784bc245096bdc838fbc6 +CompilerSupportLibraries.v1.3.0+1.i686-w64-mingw32-libgfortran4.tar.gz/sha512/60e72336efdd307b88b1e6db5234388ac1892504ac858b412d18f072a33ca1aeaf1b8621ccf43027508b7a4653150f0849a89c57164beb1e7f24ef32f7fb7f11 +CompilerSupportLibraries.v1.3.0+1.i686-w64-mingw32-libgfortran5.tar.gz/md5/310b163628e7defdfa6a293360b203db +CompilerSupportLibraries.v1.3.0+1.i686-w64-mingw32-libgfortran5.tar.gz/sha512/02e9a797246feb9c4b09b0c67c773dac5c3bb61568bdd48be147adeb2dc08fd2bd7151f2293e2756685d011e463e39dc5ca0f79593dda7501cacbc15adfc74e0 +CompilerSupportLibraries.v1.3.0+1.powerpc64le-linux-gnu-libgfortran3.tar.gz/md5/c139a9d54f39701e805d2af185a6f17c +CompilerSupportLibraries.v1.3.0+1.powerpc64le-linux-gnu-libgfortran3.tar.gz/sha512/0d1f29cb04b42b276edd7998a02f6166295f6b7a2a8ffdf6b2986145476385b19c2f93b012974835363ef57f2018bdb80814adef3b72b9378f0d2c6a8805c43e +CompilerSupportLibraries.v1.3.0+1.powerpc64le-linux-gnu-libgfortran4.tar.gz/md5/3ab360133835e1d0a6a24bb2de1dde02 +CompilerSupportLibraries.v1.3.0+1.powerpc64le-linux-gnu-libgfortran4.tar.gz/sha512/9c2f765b58a73b3705f787f68c995d8f2cbd211978c0ec8ac2adbfec6685f4b3a02aa63bf75b9dbf0a2a5c048e35536929d04b89c120671174d76132cbd2c7ed +CompilerSupportLibraries.v1.3.0+1.powerpc64le-linux-gnu-libgfortran5.tar.gz/md5/6ce9e27ab33b35900d8f81c2ad05eec2 +CompilerSupportLibraries.v1.3.0+1.powerpc64le-linux-gnu-libgfortran5.tar.gz/sha512/1d8af2664e68d18ef4f68b9fed28979af0acf3dd09c8064c4b25b3268808bc6901ce727b5b3ec3c27e37914a7c1f8c92e5ce35de093d66cb6a2e98ad59c2252b +CompilerSupportLibraries.v1.3.0+1.riscv64-linux-gnu-libgfortran5.tar.gz/md5/6c292cf98c6b4cbf10aeb4f0af383222 +CompilerSupportLibraries.v1.3.0+1.riscv64-linux-gnu-libgfortran5.tar.gz/sha512/1497789d918d633f319f89a04241678602d3b0f441ca6f8f6d756f6d1fba59d5eca54fd24183e39e9b956cd3c053afd747dc03a9a1e2d4819d26de3539c5eb07 +CompilerSupportLibraries.v1.3.0+1.x86_64-apple-darwin-libgfortran3.tar.gz/md5/0aae7ac19dade024e0228bb1a3565edf +CompilerSupportLibraries.v1.3.0+1.x86_64-apple-darwin-libgfortran3.tar.gz/sha512/b779badad7e6021875b5df04793445b4056d84cc217f389f9496d8ca61af71d98a667ec29b912131c83319be4d6e82c59e7c3f409f302cc3691899f0e77edd46 +CompilerSupportLibraries.v1.3.0+1.x86_64-apple-darwin-libgfortran4.tar.gz/md5/6fcb9749463a96504f1e23cd97695f60 +CompilerSupportLibraries.v1.3.0+1.x86_64-apple-darwin-libgfortran4.tar.gz/sha512/66d4cb8237859234f8fd49461b5976a7f155e02fb93c765208701c43c041dc8693f3f8b868ba74bd28614586c0f5109a5b5aa0d0d69ac38732ad6d84d2635e04 +CompilerSupportLibraries.v1.3.0+1.x86_64-apple-darwin-libgfortran5.tar.gz/md5/af01aefc789a0388df504abae68fc01f +CompilerSupportLibraries.v1.3.0+1.x86_64-apple-darwin-libgfortran5.tar.gz/sha512/444d1d54fb6ef95f2093894c685a4065e9708504b820bd9325bdf32619eac8b2972b1601e788ff8f1ee2759117b726c04c8bb395820359bdc737bdfdc3c4026b +CompilerSupportLibraries.v1.3.0+1.x86_64-linux-gnu-libgfortran3.tar.gz/md5/df1c55a47f9faebf09ea093d5d1ee344 +CompilerSupportLibraries.v1.3.0+1.x86_64-linux-gnu-libgfortran3.tar.gz/sha512/03477fdf14d8dfce204999e6825d9ad94c2c78686d59b251f39d1bb357b3c9d9a74339c4d5f5e97420870d44f7bc2fceca637fbf7b862d0d1cf04a19a2a0b036 +CompilerSupportLibraries.v1.3.0+1.x86_64-linux-gnu-libgfortran4.tar.gz/md5/8812418d84c2ac289d64a597d4968704 +CompilerSupportLibraries.v1.3.0+1.x86_64-linux-gnu-libgfortran4.tar.gz/sha512/4da50ea541c13a98ae05c6ff67b8021496b871a205f994605f0230a67eb6c58ede55aa3a471df8bbdd5618177d34914186cfae106664b80a7fef795e5fe97e8f +CompilerSupportLibraries.v1.3.0+1.x86_64-linux-gnu-libgfortran5.tar.gz/md5/55bd8dacbc4afff6196494542ea13eec +CompilerSupportLibraries.v1.3.0+1.x86_64-linux-gnu-libgfortran5.tar.gz/sha512/2bb63e68f56818c0a3bb988f395ebcbe99af2740f806e324c385c1dcd7a5dbb058afd286fb6d85a1621ca668aba962a8701bef96a4547b0d22f92d9e4f4b51cc +CompilerSupportLibraries.v1.3.0+1.x86_64-linux-musl-libgfortran3.tar.gz/md5/1e06592e53de4448b0712a79e61b9a51 +CompilerSupportLibraries.v1.3.0+1.x86_64-linux-musl-libgfortran3.tar.gz/sha512/cf92bbc217a51b9a18e07c5b5248ac5f59f92a7924c5fc566a1bd5b87a1acd36ec9c1d64871b273f80670596c05c1795cec91294f32f8dc1490633ea6d543037 +CompilerSupportLibraries.v1.3.0+1.x86_64-linux-musl-libgfortran4.tar.gz/md5/fa81135fc7e697eb8409baf3fcafdcb6 +CompilerSupportLibraries.v1.3.0+1.x86_64-linux-musl-libgfortran4.tar.gz/sha512/32ab98be0521f2451ce9b71c5ce7dfc70094583df80ed8db3990a2041594839f065abcf6c847fe6b8293eac3b3395da16ab3d24cf5e15c962aa320b28a6cd4be +CompilerSupportLibraries.v1.3.0+1.x86_64-linux-musl-libgfortran5.tar.gz/md5/d6f0a90da74eaf2f9bf4f7b884231a2a +CompilerSupportLibraries.v1.3.0+1.x86_64-linux-musl-libgfortran5.tar.gz/sha512/cbbbd0284799f78cf20a41f1b2d110651ee0460f0191d519d522a5034a31edaaf62ef130e7ef42c28882e224a4f997f0bead5b569254cdda7100b1f41e286b78 +CompilerSupportLibraries.v1.3.0+1.x86_64-unknown-freebsd-libgfortran3.tar.gz/md5/c525e70e726f0fc1c49deedd08ab6026 +CompilerSupportLibraries.v1.3.0+1.x86_64-unknown-freebsd-libgfortran3.tar.gz/sha512/eb50d1443e1d13b892c141ac579b2e807f346d98a75e2ce9a0a23494c754b7149d1900046f5c39e324b48bfeedc6bee590a7e2c182e6f0e3c07b9f816fcb9d6d +CompilerSupportLibraries.v1.3.0+1.x86_64-unknown-freebsd-libgfortran4.tar.gz/md5/9777c3216792efd8e8625f5f72442be6 +CompilerSupportLibraries.v1.3.0+1.x86_64-unknown-freebsd-libgfortran4.tar.gz/sha512/215398a9c893a5298101d98a3cf3df1e59e6dd4b0d66b3cdcd9decd8725541ae33c30d1e391fb51d7aaaa33dc5911511257f7ee7e3ea6350a8942ae70fcb3ada +CompilerSupportLibraries.v1.3.0+1.x86_64-unknown-freebsd-libgfortran5.tar.gz/md5/c7571567040d646935234b51c121745b +CompilerSupportLibraries.v1.3.0+1.x86_64-unknown-freebsd-libgfortran5.tar.gz/sha512/159900879d46eb2a2e45f0bfbf6eb7b03c1e28705d576ad712f67a3ae242e7e4642c08f3be181b9fbac659e1c76de6ca278ad3662fd15e8371adc7bf19e9e9b3 +CompilerSupportLibraries.v1.3.0+1.x86_64-w64-mingw32-libgfortran3.tar.gz/md5/63187354746bbcfd43c11b8047595d21 +CompilerSupportLibraries.v1.3.0+1.x86_64-w64-mingw32-libgfortran3.tar.gz/sha512/7c004e5ee255a9cc410b2f8f8836d0dffae8f4e35552c57a74a9c2eb8dadd6f0966ffceb296fd61c5c0ad7a0ea25c80ee2d7bd80ed3ccf1305f236b64e2dad5a +CompilerSupportLibraries.v1.3.0+1.x86_64-w64-mingw32-libgfortran4.tar.gz/md5/64f5d316b2d694dbdb2c96e557482de8 +CompilerSupportLibraries.v1.3.0+1.x86_64-w64-mingw32-libgfortran4.tar.gz/sha512/e1b3be2e6e9d4ccae55ec131f6cd51a7c4391639365057f7c8ecde539c9f5fa4d73942cbc2d06c62f43c2e1bca0469862a9ac6dc064536400ec09f37a20e2b1d +CompilerSupportLibraries.v1.3.0+1.x86_64-w64-mingw32-libgfortran5.tar.gz/md5/d10bb5d9facb9428c22f920798876f9b +CompilerSupportLibraries.v1.3.0+1.x86_64-w64-mingw32-libgfortran5.tar.gz/sha512/7671d0a7e1d965d0dfd56e3f037dbb47a2748cbff2656be26741e1b15687b3ba48bb44e7d43e005cd610257c94ffa8e71eb3e3ade772ee5c6f6aeee4535f04ce diff --git a/deps/csl.mk b/deps/csl.mk index a50a08fab8506..fef950aa41621 100644 --- a/deps/csl.mk +++ b/deps/csl.mk @@ -117,13 +117,14 @@ distclean-csl: clean-csl else $(eval $(call bb-install,csl,CSL,true)) ifeq ($(OS),WINNT) +GCC_VERSION = 14 install-csl: mkdir -p $(build_private_libdir)/ - cp -a $(build_libdir)/gcc/$(BB_TRIPLET)/13/libgcc_s.a $(build_private_libdir)/ - cp -a $(build_libdir)/gcc/$(BB_TRIPLET)/13/libgcc.a $(build_private_libdir)/ - cp -a $(build_libdir)/gcc/$(BB_TRIPLET)/13/libmsvcrt.a $(build_private_libdir)/ - cp -a $(build_libdir)/gcc/$(BB_TRIPLET)/13/libssp.dll.a $(build_private_libdir)/ - cp -a $(build_libdir)/gcc/$(BB_TRIPLET)/13/libssp.dll.a $(build_libdir)/ + cp -a $(build_libdir)/gcc/$(BB_TRIPLET)/$(GCC_VERSION)/libgcc_s.a $(build_private_libdir)/ + cp -a $(build_libdir)/gcc/$(BB_TRIPLET)/$(GCC_VERSION)/libgcc.a $(build_private_libdir)/ + cp -a $(build_libdir)/gcc/$(BB_TRIPLET)/$(GCC_VERSION)/libmsvcrt.a $(build_private_libdir)/ + cp -a $(build_libdir)/gcc/$(BB_TRIPLET)/$(GCC_VERSION)/libssp.dll.a $(build_private_libdir)/ + cp -a $(build_libdir)/gcc/$(BB_TRIPLET)/$(GCC_VERSION)/libssp.dll.a $(build_libdir)/ endif endif ifeq ($(OS),WINNT) diff --git a/stdlib/CompilerSupportLibraries_jll/Project.toml b/stdlib/CompilerSupportLibraries_jll/Project.toml index 12806e4bc427a..2f8143a77d740 100644 --- a/stdlib/CompilerSupportLibraries_jll/Project.toml +++ b/stdlib/CompilerSupportLibraries_jll/Project.toml @@ -4,7 +4,7 @@ uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" # NOTE: When updating this, also make sure to update the value # `CSL_NEXT_GLIBCXX_VERSION` in `Make.inc`, to properly disable # automatic usage of BB-built CSLs on extremely up-to-date systems! -version = "1.2.0+0" +version = "1.3.0+1" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" From b671c9dcdd715ea8c2ff7123b2905a0259873739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= <765740+giordano@users.noreply.github.com> Date: Mon, 13 Jan 2025 00:30:14 +0000 Subject: [PATCH 183/342] [OpenBLAS_jll] Upgrade to v0.3.29 (#57025) [OpenBLAS v0.3.29](https://github.com/OpenMathLib/OpenBLAS/releases) was released just 6 hours ago. Note that OpenBLAS 0.3.29 [doesn't support building for PowerPC with GCC before v11](https://github.com/OpenMathLib/OpenBLAS/issues/5068#issuecomment-2585836284), which means we can't support libgfortran3 and 4 anymore. --- deps/checksums/openblas | 194 +++++++++--------- deps/openblas.mk | 7 +- deps/openblas.version | 6 +- ...enblas-memory-buffer-multi-threading.patch | 49 ----- stdlib/OpenBLAS_jll/Project.toml | 2 +- 5 files changed, 101 insertions(+), 157 deletions(-) delete mode 100644 deps/patches/openblas-memory-buffer-multi-threading.patch diff --git a/deps/checksums/openblas b/deps/checksums/openblas index 74cdaa26c30b2..f1bcf3f322d8c 100644 --- a/deps/checksums/openblas +++ b/deps/checksums/openblas @@ -1,98 +1,96 @@ -OpenBLAS.v0.3.28+3.aarch64-apple-darwin-libgfortran5.tar.gz/md5/312aa603d089d680205dad7d5da58195 -OpenBLAS.v0.3.28+3.aarch64-apple-darwin-libgfortran5.tar.gz/sha512/ffb0069561f52f8ac2f8affe937a00592e0c5d75c6d64bb0d5c93d1c925c93a46b763638031c88818b9dcef4a7b149ee3f15792a812e87f57a8ad086604164c4 -OpenBLAS.v0.3.28+3.aarch64-linux-gnu-libgfortran3.tar.gz/md5/7c43d9e9ac07820130a3d5faefdef882 -OpenBLAS.v0.3.28+3.aarch64-linux-gnu-libgfortran3.tar.gz/sha512/3ade0f098796148c37b118f9c052bad4e40431b4792f001043f040f8b1e4b7c3bae512f56ea21e6c0111246b2200e7720fe720a56a19dd11d1fba789344f29e3 -OpenBLAS.v0.3.28+3.aarch64-linux-gnu-libgfortran4.tar.gz/md5/cd2fe87dac703c8bfa25406aa732b88a -OpenBLAS.v0.3.28+3.aarch64-linux-gnu-libgfortran4.tar.gz/sha512/2aea68bd8f1db2ac920951c8d9a47ce8c071f3736ee8aad8d185a09be25234a0ffd11b9f9640015b82770ba3b3fad9aa511cc43501c1bb5a3a44f1fb7ccd5692 -OpenBLAS.v0.3.28+3.aarch64-linux-gnu-libgfortran5.tar.gz/md5/e3db2bf2f1f38aeee8530c78f3ec049a -OpenBLAS.v0.3.28+3.aarch64-linux-gnu-libgfortran5.tar.gz/sha512/a0ccb92e818650ac3cbc292d5af1a000ee9b123953cc3eb16e2479e926af3f2be0ed9858e3c0c1075b1b9dd70ec1e51b9dce2c9d45b999d296aa050d257a3cb1 -OpenBLAS.v0.3.28+3.aarch64-linux-musl-libgfortran3.tar.gz/md5/5bb605738930037259e773ebdb4a7041 -OpenBLAS.v0.3.28+3.aarch64-linux-musl-libgfortran3.tar.gz/sha512/967e0f33be7b743d9617627a947a802286962a46c7c3b2418aaa1504cffc5f311b01e1702b35ded18ae3686b1914c6085213b03fa8a51e0a7ca16dc4cfee8504 -OpenBLAS.v0.3.28+3.aarch64-linux-musl-libgfortran4.tar.gz/md5/ce175e82b9c6597c546552e79a43f934 -OpenBLAS.v0.3.28+3.aarch64-linux-musl-libgfortran4.tar.gz/sha512/8ff5dff293d9786fc4f541b209b35afcbe325c13ddd0f9c8f9bfca8ba5c318c7890152260a5441b9e9088751ce03b1ff8f0f5d6fd4f142fae34bdb7390d1952c -OpenBLAS.v0.3.28+3.aarch64-linux-musl-libgfortran5.tar.gz/md5/cae6aabbdccf31fb78b234785b52d48a -OpenBLAS.v0.3.28+3.aarch64-linux-musl-libgfortran5.tar.gz/sha512/ac842023e5db243fcfada22adca051bd2ffa04fca496454539931eede159e5d0490d444c338684c2d178c3367b23b8f3d76c544e30f1897bbed181f56237619f -OpenBLAS.v0.3.28+3.aarch64-unknown-freebsd-libgfortran4.tar.gz/md5/875223f1a3867d1d77ca911da1f12e7d -OpenBLAS.v0.3.28+3.aarch64-unknown-freebsd-libgfortran4.tar.gz/sha512/a53eced30cd5d85bf13f17959f0d43127a1d967dfa3fc18fd931b8a0670d8f4fa7fa4e5360937ec301a195e8c4757d2454c8d1d189e6429b97fe3b322559c970 -OpenBLAS.v0.3.28+3.aarch64-unknown-freebsd-libgfortran5.tar.gz/md5/efc5b9b88bbb515b88b4cd84d280d6f2 -OpenBLAS.v0.3.28+3.aarch64-unknown-freebsd-libgfortran5.tar.gz/sha512/16581e2b61500c939f3be0d1e1aab3c103c2cdf56b9e5880368ff87bd2ecec89e6ee6ed00f2db90208ca26132c0b92f318084b0b2644ed93e72ca3c9706f951c -OpenBLAS.v0.3.28+3.armv6l-linux-gnueabihf-libgfortran3.tar.gz/md5/5d1f45f53dd1730051095fb8e027b14f -OpenBLAS.v0.3.28+3.armv6l-linux-gnueabihf-libgfortran3.tar.gz/sha512/0b1f91e86b5078b7cd6b64bc429a0e63bb5adf28df1baa336e67819fbd2c09f59b643c39e580f63e3bbccdc631c5d5e14c7d8afa6af94250453ce5286958f90f -OpenBLAS.v0.3.28+3.armv6l-linux-gnueabihf-libgfortran4.tar.gz/md5/8b3e3ea928975c575798d47466aafb82 -OpenBLAS.v0.3.28+3.armv6l-linux-gnueabihf-libgfortran4.tar.gz/sha512/ebac0f7047dd8b97d85e4251953a23824701af02754afd6808f13eb276326b30eb292c85fa717fbd2f21b929e6a9816a012b8ea378a0fa27e671f81435f5d3b9 -OpenBLAS.v0.3.28+3.armv6l-linux-gnueabihf-libgfortran5.tar.gz/md5/5aacfce96d5673b4d8341cb097d22c4a -OpenBLAS.v0.3.28+3.armv6l-linux-gnueabihf-libgfortran5.tar.gz/sha512/b84dc2b8cbe5453555182c3fcd8624d7a2b28fe3826d54fde3b77ad2c33e60309317d150f07554dd85e168b0ac1f91537a5c2c17fff9c02dd9216f01161e4965 -OpenBLAS.v0.3.28+3.armv6l-linux-musleabihf-libgfortran3.tar.gz/md5/dfeac22ee204868cf254dab5ae79382b -OpenBLAS.v0.3.28+3.armv6l-linux-musleabihf-libgfortran3.tar.gz/sha512/710117eb7400a0aacf69d6053730eb3b3ff4767f8d38defb2aaad94aebf1646a794489e78a8f46b469901159cdca73dd2b9460fff11e95daa4a2642cab721a25 -OpenBLAS.v0.3.28+3.armv6l-linux-musleabihf-libgfortran4.tar.gz/md5/13ff2a40bc55839bdef76b796db1eb76 -OpenBLAS.v0.3.28+3.armv6l-linux-musleabihf-libgfortran4.tar.gz/sha512/eb61fe6c0221e8f9d7a626b8d088ae1497155341dafb69835e7d53af76689ae212e1e4621e0729df5d896888c0b2d7354a24f7b57fe1d68f0b35c26bcf096699 -OpenBLAS.v0.3.28+3.armv6l-linux-musleabihf-libgfortran5.tar.gz/md5/aa7349724ba1d47256705777e755289a -OpenBLAS.v0.3.28+3.armv6l-linux-musleabihf-libgfortran5.tar.gz/sha512/25ab56c44b7d0d5de17344f39071e6894e878e89b5e35412a3c9fe345abd2eef76d7816cabb6407c7c521c3bf67a4741b37ad7e580962ead9275273e431f1fb3 -OpenBLAS.v0.3.28+3.armv7l-linux-gnueabihf-libgfortran3.tar.gz/md5/5d1f45f53dd1730051095fb8e027b14f -OpenBLAS.v0.3.28+3.armv7l-linux-gnueabihf-libgfortran3.tar.gz/sha512/0b1f91e86b5078b7cd6b64bc429a0e63bb5adf28df1baa336e67819fbd2c09f59b643c39e580f63e3bbccdc631c5d5e14c7d8afa6af94250453ce5286958f90f -OpenBLAS.v0.3.28+3.armv7l-linux-gnueabihf-libgfortran4.tar.gz/md5/8b3e3ea928975c575798d47466aafb82 -OpenBLAS.v0.3.28+3.armv7l-linux-gnueabihf-libgfortran4.tar.gz/sha512/ebac0f7047dd8b97d85e4251953a23824701af02754afd6808f13eb276326b30eb292c85fa717fbd2f21b929e6a9816a012b8ea378a0fa27e671f81435f5d3b9 -OpenBLAS.v0.3.28+3.armv7l-linux-gnueabihf-libgfortran5.tar.gz/md5/5aacfce96d5673b4d8341cb097d22c4a -OpenBLAS.v0.3.28+3.armv7l-linux-gnueabihf-libgfortran5.tar.gz/sha512/b84dc2b8cbe5453555182c3fcd8624d7a2b28fe3826d54fde3b77ad2c33e60309317d150f07554dd85e168b0ac1f91537a5c2c17fff9c02dd9216f01161e4965 -OpenBLAS.v0.3.28+3.armv7l-linux-musleabihf-libgfortran3.tar.gz/md5/dfeac22ee204868cf254dab5ae79382b -OpenBLAS.v0.3.28+3.armv7l-linux-musleabihf-libgfortran3.tar.gz/sha512/710117eb7400a0aacf69d6053730eb3b3ff4767f8d38defb2aaad94aebf1646a794489e78a8f46b469901159cdca73dd2b9460fff11e95daa4a2642cab721a25 -OpenBLAS.v0.3.28+3.armv7l-linux-musleabihf-libgfortran4.tar.gz/md5/13ff2a40bc55839bdef76b796db1eb76 -OpenBLAS.v0.3.28+3.armv7l-linux-musleabihf-libgfortran4.tar.gz/sha512/eb61fe6c0221e8f9d7a626b8d088ae1497155341dafb69835e7d53af76689ae212e1e4621e0729df5d896888c0b2d7354a24f7b57fe1d68f0b35c26bcf096699 -OpenBLAS.v0.3.28+3.armv7l-linux-musleabihf-libgfortran5.tar.gz/md5/aa7349724ba1d47256705777e755289a -OpenBLAS.v0.3.28+3.armv7l-linux-musleabihf-libgfortran5.tar.gz/sha512/25ab56c44b7d0d5de17344f39071e6894e878e89b5e35412a3c9fe345abd2eef76d7816cabb6407c7c521c3bf67a4741b37ad7e580962ead9275273e431f1fb3 -OpenBLAS.v0.3.28+3.i686-linux-gnu-libgfortran3.tar.gz/md5/53087cc770708c57d2654fd0095b64df -OpenBLAS.v0.3.28+3.i686-linux-gnu-libgfortran3.tar.gz/sha512/90961448ae40b0445bf881d0815aec54d2096ad235dc8e3db8d698a72961ef9a97e7fcd08f79c83cd1f7c5a341464f52a90351d927d5f1c3e9c8ee32b17970db -OpenBLAS.v0.3.28+3.i686-linux-gnu-libgfortran4.tar.gz/md5/ee910e19faa961bde11fdf90c211df9d -OpenBLAS.v0.3.28+3.i686-linux-gnu-libgfortran4.tar.gz/sha512/f5cfecfe965991cfd7843eff71efa71d6842058565bb63657e909b2942e58a8c7506aa66335308961e59f392da16e1177d79542ae509795566a14122f67a1782 -OpenBLAS.v0.3.28+3.i686-linux-gnu-libgfortran5.tar.gz/md5/fe52ba7ca8e16f37aa04b79248e0471d -OpenBLAS.v0.3.28+3.i686-linux-gnu-libgfortran5.tar.gz/sha512/79b5108886d60f12424709a841e359dc1cf23cef21bb0ee6d1a48043ac48a35dac1637e43c8ebf3f2e10dd34721993a7a12c5776f2975dd5bd7b6e29e1a9adc3 -OpenBLAS.v0.3.28+3.i686-linux-musl-libgfortran3.tar.gz/md5/88d8ff421d29456f1d7670ceaf8867ca -OpenBLAS.v0.3.28+3.i686-linux-musl-libgfortran3.tar.gz/sha512/91c1bd8142845d11fecba87a719315a14218e3863955ddd2ed82cecd4a2c177a48c660b6aac374ee9a11008245c0ced1bae70eaf5a1a6e3114db02e09a96396f -OpenBLAS.v0.3.28+3.i686-linux-musl-libgfortran4.tar.gz/md5/3035066a53032b551e49f56b323e941d -OpenBLAS.v0.3.28+3.i686-linux-musl-libgfortran4.tar.gz/sha512/f218e152a1c92bd374599814612add8010aedc78113cbe06465e8a1ee7f66892bb654cad687aa55555e74f3a65d74608692d41c9f0ce6c0bc63475ef62ab55b7 -OpenBLAS.v0.3.28+3.i686-linux-musl-libgfortran5.tar.gz/md5/f7cf36ac9a0cbb535952ec73f2e6c9ea -OpenBLAS.v0.3.28+3.i686-linux-musl-libgfortran5.tar.gz/sha512/00ab052d9fa4a72a640545782019f24ed6017b36aa89c5e659ce73b1e821817f560c09f71b26c027c0a05bd13567c71a6d7f5995d1c39ab233bec56cd3a7fd9e -OpenBLAS.v0.3.28+3.i686-w64-mingw32-libgfortran3.tar.gz/md5/b19d09297372e071805ba033afb55def -OpenBLAS.v0.3.28+3.i686-w64-mingw32-libgfortran3.tar.gz/sha512/eb1138578033167ececfe428db17fe28fad70631da3c25532edb4204fe733821156d6c619b6541fd47d53d335d6ab11b3d1ac1effb56031a2f782a5e8d863a89 -OpenBLAS.v0.3.28+3.i686-w64-mingw32-libgfortran4.tar.gz/md5/98ed2a8f2d3249438b913d5f35715a53 -OpenBLAS.v0.3.28+3.i686-w64-mingw32-libgfortran4.tar.gz/sha512/fbc32d81a4189ac170b18a029419bc98bb0655ee4d485f4bd165a394d223b80ba77f848d94a9ad96d926291de3db4a7602abd81c44fec55e4591dfe0aa91e29e -OpenBLAS.v0.3.28+3.i686-w64-mingw32-libgfortran5.tar.gz/md5/cb99d7d4944c5283a1a0142683e1d377 -OpenBLAS.v0.3.28+3.i686-w64-mingw32-libgfortran5.tar.gz/sha512/b77d3225e60f49506917bfff78c187df7157dbc834eccda2fa03d03eef8214b225682888a411a8b6e4b29a8d7e2b0ca625ea8c56b84ecc39e1f4f1012523c096 -OpenBLAS.v0.3.28+3.powerpc64le-linux-gnu-libgfortran3.tar.gz/md5/c6e5d4867a068e08b3f56f474e498b81 -OpenBLAS.v0.3.28+3.powerpc64le-linux-gnu-libgfortran3.tar.gz/sha512/de6249439758a501bfd27d3ef04ec04cc06edf64de73f0709a6a40a2eaf40bd3d5d77dfd54b7b19e2f6bf6c104b4416d3e225faa0cff4cb631785c08d90b8614 -OpenBLAS.v0.3.28+3.powerpc64le-linux-gnu-libgfortran4.tar.gz/md5/32e70466cfa3cfec65ab4cad3abc5f03 -OpenBLAS.v0.3.28+3.powerpc64le-linux-gnu-libgfortran4.tar.gz/sha512/2642385a5e9fc8e9c3839a5a44f9753b21b5078725f7d0c3e1ebe96b76129a3b8e2627d92629dee4f6fd7e8e51e86a7fbedc80cbe4d1a6812cea363559950da0 -OpenBLAS.v0.3.28+3.powerpc64le-linux-gnu-libgfortran5.tar.gz/md5/e2332831bd88d57132241697952819e7 -OpenBLAS.v0.3.28+3.powerpc64le-linux-gnu-libgfortran5.tar.gz/sha512/ad03edf9ac56bf6311f0ca70a1bc359242accfe82cba9e42f39f6cb1c3006226179ff9be8218847889cae10fac13bc33f60837e1e3249e309172da7fbc25400f -OpenBLAS.v0.3.28+3.x86_64-apple-darwin-libgfortran3.tar.gz/md5/27c24775af446a44a72a28ffd197696d -OpenBLAS.v0.3.28+3.x86_64-apple-darwin-libgfortran3.tar.gz/sha512/2af8caa33bee88efff84653f3932b04e8fd4aabb1bf16d49fa73657b0ec13c9457fde7ab3f953fc9b01da5c2841c3c9b588e3b0f559b89df0e6268468d1f7cc8 -OpenBLAS.v0.3.28+3.x86_64-apple-darwin-libgfortran4.tar.gz/md5/414e701d918d5fba08a12de6979db4b5 -OpenBLAS.v0.3.28+3.x86_64-apple-darwin-libgfortran4.tar.gz/sha512/949886d388b80e19b944d102852f2bb58ffa03c42e624986dd9dc076797c996634d4a8fc0f04544451d6848c2079969816979e1f68a999b2747e9dd5472be7a6 -OpenBLAS.v0.3.28+3.x86_64-apple-darwin-libgfortran5.tar.gz/md5/29fcf62c0280cc10f91d22189a2e8de8 -OpenBLAS.v0.3.28+3.x86_64-apple-darwin-libgfortran5.tar.gz/sha512/02e75d4ecf9cd922157a72c0ca2e713cf336b125df3982cd5f7cc4f2a04367ad4c2b1190ca2a0a9df8b639c7ebcfc9783066e99dd0b13acde7b02038391e8567 -OpenBLAS.v0.3.28+3.x86_64-linux-gnu-libgfortran3.tar.gz/md5/147d5e8eb2ec78fc8a31bdb091fab001 -OpenBLAS.v0.3.28+3.x86_64-linux-gnu-libgfortran3.tar.gz/sha512/2319eda568800c0b1f2d96a8a36c59b1bbd792c06de1d740aea3f1e49798242426ea8d10c100c42c3c281702e2b4f5b673b6ab5252b276d48542e875bcaa3094 -OpenBLAS.v0.3.28+3.x86_64-linux-gnu-libgfortran4.tar.gz/md5/448857d9c4b2e95afc12a14c75b24055 -OpenBLAS.v0.3.28+3.x86_64-linux-gnu-libgfortran4.tar.gz/sha512/3e7c8cd55e0b15a30992b1e0b48a6e2ae36fd9babf689fa5595c7de94aec401de1d7821d45a22bf14cd5c45c708bc8fa3511d34d732dadd4daaca3f49e200bdb -OpenBLAS.v0.3.28+3.x86_64-linux-gnu-libgfortran5.tar.gz/md5/3aaf417685b44e0e505208f7b31b981a -OpenBLAS.v0.3.28+3.x86_64-linux-gnu-libgfortran5.tar.gz/sha512/f7b1d123e48ede93fe624a79d9535a8915bfa3441d7a6f9c6643467027414c9f2538e299858ea98bbb49d4e6d385a6a491063cb1878ac3b0b3d6a8f7ff0a48df -OpenBLAS.v0.3.28+3.x86_64-linux-musl-libgfortran3.tar.gz/md5/5723136deaaf4b2e5960fb0774943288 -OpenBLAS.v0.3.28+3.x86_64-linux-musl-libgfortran3.tar.gz/sha512/127ea8b2b0d8d4586a23a2b8ecbf148d512efe68626e89b0688c3c9e29ed9420b45ae86755c1467313c565f9f3835762051d7086a815b813dbe6e9eb05fb4be1 -OpenBLAS.v0.3.28+3.x86_64-linux-musl-libgfortran4.tar.gz/md5/80b1b9cf5346916edda653174a987aa2 -OpenBLAS.v0.3.28+3.x86_64-linux-musl-libgfortran4.tar.gz/sha512/77e1387ec969bbed4945d2a598a1cd04d258265c4b2d5c43af92118eb32e0c69e40619a20ea1835f277febcfea068b241343d44932afef832bdcfd2e9f618f0a -OpenBLAS.v0.3.28+3.x86_64-linux-musl-libgfortran5.tar.gz/md5/44dcedf01c938d1a1c67dd3bc90ab61d -OpenBLAS.v0.3.28+3.x86_64-linux-musl-libgfortran5.tar.gz/sha512/e490d49b8d41d73ab3e71aca8c691ca58704f0fc6930cbfcc203f97b8db8d83144bad597a2c53ff0c0c4f7c40316d975a1b589a3603873d508f6beeb75970c5b -OpenBLAS.v0.3.28+3.x86_64-unknown-freebsd-libgfortran3.tar.gz/md5/0e8a7e88b54cb836292c289d1c456fa9 -OpenBLAS.v0.3.28+3.x86_64-unknown-freebsd-libgfortran3.tar.gz/sha512/0e9b3af6839b9c41c950bb4d8b739f0243a890af7092ef9f3a00e4931f2acc3820afb78e40c7bfef716dcd3230c1d0acc7b0b37f30eb47441b476bd7540745e6 -OpenBLAS.v0.3.28+3.x86_64-unknown-freebsd-libgfortran4.tar.gz/md5/5fc47ad55780c99ef9cab7ef1b26d9c0 -OpenBLAS.v0.3.28+3.x86_64-unknown-freebsd-libgfortran4.tar.gz/sha512/c531201e4abddd652efeb5801658f5c1e4891578f181e99d6e41fc0d3bc6347b82e5e928ff8a717ee1e75bb0a6a765260bf7c99fce44aa24c21f1c5a5e3c1e3b -OpenBLAS.v0.3.28+3.x86_64-unknown-freebsd-libgfortran5.tar.gz/md5/dc127f3ab984b5d47b325d5701ab73cd -OpenBLAS.v0.3.28+3.x86_64-unknown-freebsd-libgfortran5.tar.gz/sha512/50850911703320894a2e1e996c5de4613b5f9e3012f5cbf591f3677799599c45d9cc4c42cf310bdc6ba91ef550e52f6424bbbabdf47f96748d4669d94e6b46a4 -OpenBLAS.v0.3.28+3.x86_64-w64-mingw32-libgfortran3.tar.gz/md5/937847e2ad00539f3422d1ecb9d26d55 -OpenBLAS.v0.3.28+3.x86_64-w64-mingw32-libgfortran3.tar.gz/sha512/751d889661ddd46cd5718b49e34f826a4fb34b1b992251a5a975bc0af15b74a75d8a56f403e8fae570223477b2b8927d9cb36764e4b9e466045d5f317b8e7196 -OpenBLAS.v0.3.28+3.x86_64-w64-mingw32-libgfortran4.tar.gz/md5/180c54c50362d05696589b270693ee8f -OpenBLAS.v0.3.28+3.x86_64-w64-mingw32-libgfortran4.tar.gz/sha512/2e3b76be5b7c4a7dc45f07e17493abd7ef9185e92429d8fa4d38766e0da96dd0777b619a9e420d2e1142bdab2ae1f755f9bc9ad97ee9a7927741778f89b9135f -OpenBLAS.v0.3.28+3.x86_64-w64-mingw32-libgfortran5.tar.gz/md5/2f0fac7c96af66ea63fce26e409f4db6 -OpenBLAS.v0.3.28+3.x86_64-w64-mingw32-libgfortran5.tar.gz/sha512/141522971447c38b4908342f3ad09ffb18142d2e79b44f66fd80047b44c09216c9b94c39f776e3093f9ceb6bc4d6270cbbfb4209b2fc0debfe93e7145cb4dbff -openblas-5ef8b1964658f9cb6a6324a06f6a1a022609b0c5.tar.gz/md5/f7a1fe86cefbf7d4f2608843c7833ca7 -openblas-5ef8b1964658f9cb6a6324a06f6a1a022609b0c5.tar.gz/sha512/5f6020e958967a12a3c5b18bde13331f9c0602bd073563f35cd7cec848c92b45f30ca362819b12cd16989c0e4641ee3e63db8322d1092f61b31ba2e4068dd7a7 +OpenBLAS.v0.3.29+0.aarch64-apple-darwin-libgfortran5.tar.gz/md5/227fc95ef10e30698aade797ebd8b685 +OpenBLAS.v0.3.29+0.aarch64-apple-darwin-libgfortran5.tar.gz/sha512/49a932f0c1c2d1087d20a3de2940733ed6a944284e1cf2a384a7401c5ca6bd90a35e9679b4f19bac176923aa170427e7514a47fc16261413ee03a59bbb301bd0 +OpenBLAS.v0.3.29+0.aarch64-linux-gnu-libgfortran3.tar.gz/md5/77acdfde5dc6f05629f3fb68a95b78f8 +OpenBLAS.v0.3.29+0.aarch64-linux-gnu-libgfortran3.tar.gz/sha512/f28187213eac2d481bc12263fe13fcb35f4771084bacaa42b0b149ac15cf89d033910519ecc5cada77915a48c95a2de3ea4a476c0c6bc3f154e7f2ceb4bf3ffd +OpenBLAS.v0.3.29+0.aarch64-linux-gnu-libgfortran4.tar.gz/md5/4fb2bd80d3e4ad8ce04fa33c9a2aaa19 +OpenBLAS.v0.3.29+0.aarch64-linux-gnu-libgfortran4.tar.gz/sha512/8cc2aee3b351cc5c78e494efededdf98f65ce8942453bb3a55c90e0822ddcc07bc7716d0746bbc16701eca458b7a7aa933e9363f71bd56788c9fab36bd9bcf6d +OpenBLAS.v0.3.29+0.aarch64-linux-gnu-libgfortran5.tar.gz/md5/3a3ef97dc80dec3d0debade503ca2232 +OpenBLAS.v0.3.29+0.aarch64-linux-gnu-libgfortran5.tar.gz/sha512/53d707f9bf57c1a19279f0146e767d779280f922ef621b5f372cedc018efb2798adabbd762324819f342d0fd98ec17c68badc50da7b6e9aa3e57c3a3c045dab2 +OpenBLAS.v0.3.29+0.aarch64-linux-musl-libgfortran3.tar.gz/md5/463cb6b46091f4b4b4f2535b9f38f11d +OpenBLAS.v0.3.29+0.aarch64-linux-musl-libgfortran3.tar.gz/sha512/5a5a7d5a7ca5e619d5af9bcbab7cfffcb4b7954005cb4a2d03f4cd0ef29c95707e830ad0b0303d694cace557cb1e9973c0244ae1f635249a313fb9f9cdfaacd9 +OpenBLAS.v0.3.29+0.aarch64-linux-musl-libgfortran4.tar.gz/md5/699ca0247ec7cccec0d9d2801b5a35a7 +OpenBLAS.v0.3.29+0.aarch64-linux-musl-libgfortran4.tar.gz/sha512/3bb2926d2d2a43c280bb947063dd74b65194118edbd99df820bef56a546648ed903245e0947ebc31765ff43784b11349bf86cd592c78d143c0627d692162b344 +OpenBLAS.v0.3.29+0.aarch64-linux-musl-libgfortran5.tar.gz/md5/2ab069e5abd5014495b849bfbaabbd3a +OpenBLAS.v0.3.29+0.aarch64-linux-musl-libgfortran5.tar.gz/sha512/fd10e4ce326c524d97e69e50342ab63b8298c796faab8f4512772fbb9c4ae1ddc85d54643c868f3b2dc8084af974430e1f8751576bedfdc88af2ba0d2affba1a +OpenBLAS.v0.3.29+0.aarch64-unknown-freebsd-libgfortran4.tar.gz/md5/ce5d04e041e9447529ad8e043e45895c +OpenBLAS.v0.3.29+0.aarch64-unknown-freebsd-libgfortran4.tar.gz/sha512/eaf521d3957713e9d22b2c0b991f5eb846096891dc15bc42ad0817c32e6a1343617d28afe739dce0e39c185d022d3cdd44db2610635691990003b1b0a29f4657 +OpenBLAS.v0.3.29+0.aarch64-unknown-freebsd-libgfortran5.tar.gz/md5/00b3a4433f93a56fa8b0f17acc254865 +OpenBLAS.v0.3.29+0.aarch64-unknown-freebsd-libgfortran5.tar.gz/sha512/a9845380778ec15642d74a46dfa65f8a325929f8ec8d61915941f6e228bb1ed29310f86f20ec559fdc2d5dac98a780f71a1b3116676a34e18ee7c0cb86cb7124 +OpenBLAS.v0.3.29+0.armv6l-linux-gnueabihf-libgfortran3.tar.gz/md5/1be6fa7ef684733faab744fdec6c8dbd +OpenBLAS.v0.3.29+0.armv6l-linux-gnueabihf-libgfortran3.tar.gz/sha512/7c7803a0484b8c8e343ff5049e52fe81b76e43f0aaca7a5ad0134079147d2311cb5b159738486dcdd7ec69eb42cb0eea738741401179499a53fead2fbd8dba3b +OpenBLAS.v0.3.29+0.armv6l-linux-gnueabihf-libgfortran4.tar.gz/md5/451dad687dd26a299e4a44db37a8db2a +OpenBLAS.v0.3.29+0.armv6l-linux-gnueabihf-libgfortran4.tar.gz/sha512/ea73ee91896203566dd7510303c73d77189afec913ac1de3b7c7935dc2c460f87c83a8ddd272d9542b619e419b9392479f02540ef1c8d3daa528bf05aaf5c3f1 +OpenBLAS.v0.3.29+0.armv6l-linux-gnueabihf-libgfortran5.tar.gz/md5/07ca32f715981570f2e1a5ac6721e569 +OpenBLAS.v0.3.29+0.armv6l-linux-gnueabihf-libgfortran5.tar.gz/sha512/c6ece0dac375fd66a303ca6f503e46f78472a59dc13381e8462e3e9c29e133cbe87ee77f6144a80924ae286162620c4395f5217e4f9ba379a471409085950427 +OpenBLAS.v0.3.29+0.armv6l-linux-musleabihf-libgfortran3.tar.gz/md5/49ac07fcdf0d7ce221051d089b408e05 +OpenBLAS.v0.3.29+0.armv6l-linux-musleabihf-libgfortran3.tar.gz/sha512/6c9c379473f1bb5f202ca183c6ef4d43b442c867e67712e6ec2936790c282143c1edae0a1385e366f729c952e02fca13604f6b51d778dabb28ca7be0f359281e +OpenBLAS.v0.3.29+0.armv6l-linux-musleabihf-libgfortran4.tar.gz/md5/87e3dea9e115fbc9a0c7f64020c41f74 +OpenBLAS.v0.3.29+0.armv6l-linux-musleabihf-libgfortran4.tar.gz/sha512/63a37a9cc882562978460e1e0f603177921a64ece7d4050b0b7a584e05d80f58314e7f8e988ea5446945d7009620c4f746ce547fe7dcb77a0707d54fd830983e +OpenBLAS.v0.3.29+0.armv6l-linux-musleabihf-libgfortran5.tar.gz/md5/8c85e7ce9bd702438c548bdae54f5c32 +OpenBLAS.v0.3.29+0.armv6l-linux-musleabihf-libgfortran5.tar.gz/sha512/3dbaa326944d79688fa167c968a7e2660bf3b94c2e052755cc8b1ede853c02364edb7fa974880c37c60ee6e6f84c75848eb4d999c5c1e8881441191dbab056e2 +OpenBLAS.v0.3.29+0.armv7l-linux-gnueabihf-libgfortran3.tar.gz/md5/1be6fa7ef684733faab744fdec6c8dbd +OpenBLAS.v0.3.29+0.armv7l-linux-gnueabihf-libgfortran3.tar.gz/sha512/7c7803a0484b8c8e343ff5049e52fe81b76e43f0aaca7a5ad0134079147d2311cb5b159738486dcdd7ec69eb42cb0eea738741401179499a53fead2fbd8dba3b +OpenBLAS.v0.3.29+0.armv7l-linux-gnueabihf-libgfortran4.tar.gz/md5/451dad687dd26a299e4a44db37a8db2a +OpenBLAS.v0.3.29+0.armv7l-linux-gnueabihf-libgfortran4.tar.gz/sha512/ea73ee91896203566dd7510303c73d77189afec913ac1de3b7c7935dc2c460f87c83a8ddd272d9542b619e419b9392479f02540ef1c8d3daa528bf05aaf5c3f1 +OpenBLAS.v0.3.29+0.armv7l-linux-gnueabihf-libgfortran5.tar.gz/md5/07ca32f715981570f2e1a5ac6721e569 +OpenBLAS.v0.3.29+0.armv7l-linux-gnueabihf-libgfortran5.tar.gz/sha512/c6ece0dac375fd66a303ca6f503e46f78472a59dc13381e8462e3e9c29e133cbe87ee77f6144a80924ae286162620c4395f5217e4f9ba379a471409085950427 +OpenBLAS.v0.3.29+0.armv7l-linux-musleabihf-libgfortran3.tar.gz/md5/49ac07fcdf0d7ce221051d089b408e05 +OpenBLAS.v0.3.29+0.armv7l-linux-musleabihf-libgfortran3.tar.gz/sha512/6c9c379473f1bb5f202ca183c6ef4d43b442c867e67712e6ec2936790c282143c1edae0a1385e366f729c952e02fca13604f6b51d778dabb28ca7be0f359281e +OpenBLAS.v0.3.29+0.armv7l-linux-musleabihf-libgfortran4.tar.gz/md5/87e3dea9e115fbc9a0c7f64020c41f74 +OpenBLAS.v0.3.29+0.armv7l-linux-musleabihf-libgfortran4.tar.gz/sha512/63a37a9cc882562978460e1e0f603177921a64ece7d4050b0b7a584e05d80f58314e7f8e988ea5446945d7009620c4f746ce547fe7dcb77a0707d54fd830983e +OpenBLAS.v0.3.29+0.armv7l-linux-musleabihf-libgfortran5.tar.gz/md5/8c85e7ce9bd702438c548bdae54f5c32 +OpenBLAS.v0.3.29+0.armv7l-linux-musleabihf-libgfortran5.tar.gz/sha512/3dbaa326944d79688fa167c968a7e2660bf3b94c2e052755cc8b1ede853c02364edb7fa974880c37c60ee6e6f84c75848eb4d999c5c1e8881441191dbab056e2 +OpenBLAS.v0.3.29+0.i686-linux-gnu-libgfortran3.tar.gz/md5/86834236dee3db3affb38b8cdcf59681 +OpenBLAS.v0.3.29+0.i686-linux-gnu-libgfortran3.tar.gz/sha512/6731b4ea22a0f3d25f9d041e2baa6d66f1027dce49931a334a33711fc4c6de5da368274c9328618ed78158855c5d38524b917447d1aafb5c551934cf982505d2 +OpenBLAS.v0.3.29+0.i686-linux-gnu-libgfortran4.tar.gz/md5/c63c2fb1bda01456d99590e9aec3b45f +OpenBLAS.v0.3.29+0.i686-linux-gnu-libgfortran4.tar.gz/sha512/437c260499f4a28db9efb4bbdff31c0f675f3ccef1bd48fd2dfbb8c8897fc75608bd7247293bd3eae129b133cb05c3c8150dd19c243faa09b6506688f57c633a +OpenBLAS.v0.3.29+0.i686-linux-gnu-libgfortran5.tar.gz/md5/376567d56bf4314f8a4adcfc4d1baa66 +OpenBLAS.v0.3.29+0.i686-linux-gnu-libgfortran5.tar.gz/sha512/c4952874b19af4fd0d5541999d07094f7e7e983124964405a4756b9adf619172b7128e11557e64a80bc4eadaf76c783609a75f25ccfc44fc4f181886a0c8ca18 +OpenBLAS.v0.3.29+0.i686-linux-musl-libgfortran3.tar.gz/md5/8f7abbc6d5cefdbefb2b9499ec8874c9 +OpenBLAS.v0.3.29+0.i686-linux-musl-libgfortran3.tar.gz/sha512/b8c39674df9400efecbe4ac740f0c3ef11a04dd852f31774d63db3ca6583a21c8e0a0b80aa4e7b82be7a8fa3de38892d4fbca34244acef7fb49e8ffc0e1eed09 +OpenBLAS.v0.3.29+0.i686-linux-musl-libgfortran4.tar.gz/md5/6b0f0544fe45de9d2dea946c7f55cc40 +OpenBLAS.v0.3.29+0.i686-linux-musl-libgfortran4.tar.gz/sha512/8c21df39a8ee99614ef0880706c1497d032f68dfc332cc5ee111f69bfc818db4896115a964f16115ac49b01b31713037c905792d9586dd05471efdb21dd0be88 +OpenBLAS.v0.3.29+0.i686-linux-musl-libgfortran5.tar.gz/md5/aa343048c35c5227a4bcc37f25ddfacb +OpenBLAS.v0.3.29+0.i686-linux-musl-libgfortran5.tar.gz/sha512/af6c9d15d9d5a4901d228522d2e20da5276f1bf35d7f34648697ba7a39153a9152dc17f5f0d360593e733ef3e3317df29581cb86fdd9fe8d6e6093592a6240bb +OpenBLAS.v0.3.29+0.i686-w64-mingw32-libgfortran3.tar.gz/md5/8595dda5ee1f15b2070d8ac20077f389 +OpenBLAS.v0.3.29+0.i686-w64-mingw32-libgfortran3.tar.gz/sha512/df7d7ad68b47f8865d01f6edd6ba44587c6563ebc4a1900f92210b5117fc7c581e6145f95e10fe7a3db48eda9805330073c8cbeec7eb8a19978ec33f2528cef8 +OpenBLAS.v0.3.29+0.i686-w64-mingw32-libgfortran4.tar.gz/md5/4e67905ab599f24327e9726f70d261cf +OpenBLAS.v0.3.29+0.i686-w64-mingw32-libgfortran4.tar.gz/sha512/13ba78e98d7c2cda62a6ca9226365e90fa8a5404e4006ae5e49030b314b762a37d78977f14c72448c844e68a6b83ecd679c60362fde023c9052b9b8597d7775c +OpenBLAS.v0.3.29+0.i686-w64-mingw32-libgfortran5.tar.gz/md5/e78c5005d9ee57ab464fca86c6d6fff1 +OpenBLAS.v0.3.29+0.i686-w64-mingw32-libgfortran5.tar.gz/sha512/8ceb9527461136cd4f4d02f10c241f5e7070991f73c974389acedb1d9d7be4bade592bc021ba1001c5ac148ea580cf8355fb89c88438820bfa665bf3e72392fa +OpenBLAS.v0.3.29+0.powerpc64le-linux-gnu-libgfortran5.tar.gz/md5/421d93da4cfab0df79569e09dff1015b +OpenBLAS.v0.3.29+0.powerpc64le-linux-gnu-libgfortran5.tar.gz/sha512/351174d948626ad36daf40c45672cd1ac40bbe4af25c28332fbea62a7ba89188a7d33836d327d31ce99b9a9334c6053366d33b58f588355c2818e332e46b34d0 +OpenBLAS.v0.3.29+0.riscv64-linux-gnu-libgfortran5.tar.gz/md5/34cc0b3260d9471bc8fb32005e3c5043 +OpenBLAS.v0.3.29+0.riscv64-linux-gnu-libgfortran5.tar.gz/sha512/5eec279c5eead55d099d8db4a75dd4a3f2bcbc8bb22b33884a89d678e4eebf87c6dece1aa4c24374d0162b35f376648a473c2d6d7866583e61016e37f4262820 +OpenBLAS.v0.3.29+0.x86_64-apple-darwin-libgfortran3.tar.gz/md5/f921a0ad6ebf91f444cb8d927886e573 +OpenBLAS.v0.3.29+0.x86_64-apple-darwin-libgfortran3.tar.gz/sha512/5cc98edf9fa8ba8981ce78b2595fd27645c783561ff19d0fd25ecc927f63492437a4b9b80d5caf51ad619b7ca5d24cb43e153156921f9f03c64741014b686196 +OpenBLAS.v0.3.29+0.x86_64-apple-darwin-libgfortran4.tar.gz/md5/0126b52c134954e63ab8f9197afebd7a +OpenBLAS.v0.3.29+0.x86_64-apple-darwin-libgfortran4.tar.gz/sha512/6d1e37009e6831a26f25bfd3e95dbcc841ee50a3f84dc4355d7fd528cd74a400138955558306345e986a732d0d1ef9294c4f5be457d05119a8e1e5851cc8ca20 +OpenBLAS.v0.3.29+0.x86_64-apple-darwin-libgfortran5.tar.gz/md5/e8c7bd786672a9caf989dbe4fcef896a +OpenBLAS.v0.3.29+0.x86_64-apple-darwin-libgfortran5.tar.gz/sha512/2e708fddfa8e5821d2e44bbc00a86df83b09cdfc0054d7c2bbb2a8de52ed80c95973e6602048335a60b54be1baeb617121b605644daf50579b2044d0c5766063 +OpenBLAS.v0.3.29+0.x86_64-linux-gnu-libgfortran3.tar.gz/md5/b1efd957a2a63f814168bd318381812e +OpenBLAS.v0.3.29+0.x86_64-linux-gnu-libgfortran3.tar.gz/sha512/097a750b7f381089588498e52a2b07a67202bfd4bc2e38f5abbbeb372129e392fcd53beade2fa7cb60ef0038f2baf61d57fab40b5585806d3ddb1fcdad73bbe3 +OpenBLAS.v0.3.29+0.x86_64-linux-gnu-libgfortran4.tar.gz/md5/c3560828f503962c6ae94135c4f00ac5 +OpenBLAS.v0.3.29+0.x86_64-linux-gnu-libgfortran4.tar.gz/sha512/1ad514172e51a5d3eb6fea03182e3eb9c6db99d9d11c430e3d8542a9ce0f5d6967e623b9c0951535b683210ce0b02460358c67520b06363594f6063f8f012396 +OpenBLAS.v0.3.29+0.x86_64-linux-gnu-libgfortran5.tar.gz/md5/07a9c3050824bbc6a96efdb333fff0ea +OpenBLAS.v0.3.29+0.x86_64-linux-gnu-libgfortran5.tar.gz/sha512/b737ab1fc8c5ffd1494804c59f8fd3e5d3d8a063a89fbbc29cbd75d43af233ddf77f63d0e514059164517f408ea340ffe95c020a7c696af8c52be3a7259922ab +OpenBLAS.v0.3.29+0.x86_64-linux-musl-libgfortran3.tar.gz/md5/9a4a828a1b58737c79eb170c94021c52 +OpenBLAS.v0.3.29+0.x86_64-linux-musl-libgfortran3.tar.gz/sha512/785443a38cda87a63ee4268cdaa51bbc2c4662de27e0695cd7e21ffe55c3bddb1fa1a399edec39c3466f2ea0bd5ce727daca2eb381213059419c2e8371b5a733 +OpenBLAS.v0.3.29+0.x86_64-linux-musl-libgfortran4.tar.gz/md5/cd4afdd6f6ba06c7541e7124316802b3 +OpenBLAS.v0.3.29+0.x86_64-linux-musl-libgfortran4.tar.gz/sha512/55796fdb52e1ac92750dfc2233d3feb37b53920b12024be605bf6c7322153c4dbeb650f16d6def4f0fac685733a04a1c4cacb1fc4e562a27a00b4f44484a4715 +OpenBLAS.v0.3.29+0.x86_64-linux-musl-libgfortran5.tar.gz/md5/8cd55ac7a7f0a7bda80b44171793718e +OpenBLAS.v0.3.29+0.x86_64-linux-musl-libgfortran5.tar.gz/sha512/728991a4c39d691abebac3ebbb2dbe093f3a4acd2d3aefb5c7c08bccf0dc1fd5aaa24de6367961d278d448b76a4ddacab36b7be15128f7ccec5049eab83828da +OpenBLAS.v0.3.29+0.x86_64-unknown-freebsd-libgfortran3.tar.gz/md5/c2dda93a61e02812831b6a6e33f7d2ca +OpenBLAS.v0.3.29+0.x86_64-unknown-freebsd-libgfortran3.tar.gz/sha512/bd62e44f266b834c6dfab068841506a83eaf510eefbcf8896dfca36671321430293dc251885af108d94affc5b193919e0e29c965fef3ce6d994df37324aef013 +OpenBLAS.v0.3.29+0.x86_64-unknown-freebsd-libgfortran4.tar.gz/md5/8cbd64d2ce4e3944e702696839a4ad3a +OpenBLAS.v0.3.29+0.x86_64-unknown-freebsd-libgfortran4.tar.gz/sha512/3621dfa5cf8bca62bb8f2a049acdc0ed4e02cb2b5585758e6e1173e61b3a5f0e1655a10f2feb2f0e70a098b00181d0b24dcd61e1205324d436b712f58e58df5d +OpenBLAS.v0.3.29+0.x86_64-unknown-freebsd-libgfortran5.tar.gz/md5/476f1ebfb93baad6fac778fa00c4f99e +OpenBLAS.v0.3.29+0.x86_64-unknown-freebsd-libgfortran5.tar.gz/sha512/06aa18da572b0904e5d8ec0823626d0af02a29224aba98efd43d8fbf4636d2625ece9f88f9a86d2e493f016c106f2ae71422191afc16dda2b26bbc81eb09d901 +OpenBLAS.v0.3.29+0.x86_64-w64-mingw32-libgfortran3.tar.gz/md5/8c55d04d9def74f6bc2cc0d03b764975 +OpenBLAS.v0.3.29+0.x86_64-w64-mingw32-libgfortran3.tar.gz/sha512/d6196a339a263d80c05b94596ec5acfeff6e3ce93fafee348a864f760aa1239aa59ee294cab29fd730dcf7974ac6dcb230433184be093612bad3bc3edc067649 +OpenBLAS.v0.3.29+0.x86_64-w64-mingw32-libgfortran4.tar.gz/md5/8427f098a44457ba65b21a16439ee6c0 +OpenBLAS.v0.3.29+0.x86_64-w64-mingw32-libgfortran4.tar.gz/sha512/4855321b2a16d55e1c6e830e33d0a199286002798c0f33c7f594a55626b5a502df94c172de4fd0a38ab6ba92f384abbbc3ef06123c3115a3f290f50a9d43ae9d +OpenBLAS.v0.3.29+0.x86_64-w64-mingw32-libgfortran5.tar.gz/md5/9d1636bb7500d9ba15ed703231f8def2 +OpenBLAS.v0.3.29+0.x86_64-w64-mingw32-libgfortran5.tar.gz/sha512/0b3530fd95e01d58b85157d7bb75e44ee7b2f0c5a912920ff0763f404e1ab28d16a624463f3f20241c7baea57e00fca3f896d6e0befb6a1c9e5ece4264b87e35 +openblas-8795fc7985635de1ecf674b87e2008a15097ffab.tar.gz/md5/095d293409140dd8eee500eb92372eb7 +openblas-8795fc7985635de1ecf674b87e2008a15097ffab.tar.gz/sha512/7b10d4c2bef68159e0a88fb6d4fd0ecca17b4c6394479e8f838f5078d9d5acef24c6bd44777d43c03859c952d4612d76b57aa0bff367b197920ea16eb3839144 diff --git a/deps/openblas.mk b/deps/openblas.mk index 8cea044ca348f..e5a988ba84df2 100644 --- a/deps/openblas.mk +++ b/deps/openblas.mk @@ -90,12 +90,7 @@ $(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-winexit.patch-applied: $(BUILDDIR)/$(OP patch -p1 -f < $(SRCDIR)/patches/openblas-winexit.patch echo 1 > $@ -$(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-memory-buffer-multi-threading.patch-applied: $(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-winexit.patch-applied - cd $(BUILDDIR)/$(OPENBLAS_SRC_DIR) && \ - patch -p1 -f < $(SRCDIR)/patches/openblas-memory-buffer-multi-threading.patch - echo 1 > $@ - -$(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-ofast-power.patch-applied: $(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-memory-buffer-multi-threading.patch-applied +$(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-ofast-power.patch-applied: $(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-winexit.patch-applied cd $(BUILDDIR)/$(OPENBLAS_SRC_DIR) && \ patch -p1 -f < $(SRCDIR)/patches/openblas-ofast-power.patch echo 1 > $@ diff --git a/deps/openblas.version b/deps/openblas.version index 09dcdc45af1ef..f9729639c67ab 100644 --- a/deps/openblas.version +++ b/deps/openblas.version @@ -3,9 +3,9 @@ OPENBLAS_JLL_NAME := OpenBLAS ## source build -OPENBLAS_VER := 0.3.28 -OPENBLAS_BRANCH=v0.3.28 -OPENBLAS_SHA1=5ef8b1964658f9cb6a6324a06f6a1a022609b0c5 +OPENBLAS_VER := 0.3.29 +OPENBLAS_BRANCH=v0.3.29 +OPENBLAS_SHA1=8795fc7985635de1ecf674b87e2008a15097ffab # LAPACK, source-only LAPACK_VER := 3.9.0 diff --git a/deps/patches/openblas-memory-buffer-multi-threading.patch b/deps/patches/openblas-memory-buffer-multi-threading.patch deleted file mode 100644 index 9693b5cf61597..0000000000000 --- a/deps/patches/openblas-memory-buffer-multi-threading.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 23b5d66a86417a071bba9a96a0573192237981b6 Mon Sep 17 00:00:00 2001 -From: Martin Kroeker -Date: Wed, 14 Aug 2024 10:35:44 +0200 -Subject: [PATCH 1/2] Ensure a memory buffer has been allocated for each thread - before invoking it - ---- - driver/others/blas_server.c | 2 ++ - 1 file changed, 2 insertions(+) - -From d24b3cf39392a99e81ed47a5f093fbd074d4b39b Mon Sep 17 00:00:00 2001 -From: Martin Kroeker -Date: Thu, 15 Aug 2024 15:32:58 +0200 -Subject: [PATCH 2/2] properly fix buffer allocation and assignment - ---- - driver/others/blas_server.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) -diff --git a/driver/others/blas_server.c b/driver/others/blas_server.c -index 765511d8c7..b9a7674c17 100644 ---- a/driver/others/blas_server.c -+++ b/driver/others/blas_server.c -@@ -1076,6 +1076,8 @@ fprintf(STDERR, "Server[%2ld] Calculation started. Mode = 0x%03x M = %3ld N=%3l - main_status[cpu] = MAIN_RUNNING1; - #endif - -+if (buffer == NULL) blas_thread_buffer[cpu] = blas_memory_alloc(2); -+ - //For target LOONGSON3R5, applying an offset to the buffer is essential - //for minimizing cache conflicts and optimizing performance. - #if defined(ARCH_LOONGARCH64) && !defined(NO_AFFINITY) - -diff --git a/driver/others/blas_server.c b/driver/others/blas_server.c -index b9a7674c17..29f8a5e646 100644 ---- a/driver/others/blas_server.c -+++ b/driver/others/blas_server.c -@@ -1076,7 +1076,11 @@ fprintf(STDERR, "Server[%2ld] Calculation started. Mode = 0x%03x M = %3ld N=%3l - main_status[cpu] = MAIN_RUNNING1; - #endif - --if (buffer == NULL) blas_thread_buffer[cpu] = blas_memory_alloc(2); -+if (buffer == NULL) { -+ blas_thread_buffer[cpu] = blas_memory_alloc(2); -+ buffer = blas_thread_buffer[cpu]; -+} -+ - - //For target LOONGSON3R5, applying an offset to the buffer is essential - //for minimizing cache conflicts and optimizing performance. diff --git a/stdlib/OpenBLAS_jll/Project.toml b/stdlib/OpenBLAS_jll/Project.toml index 01e3af1d9467c..07a81d3c1d547 100644 --- a/stdlib/OpenBLAS_jll/Project.toml +++ b/stdlib/OpenBLAS_jll/Project.toml @@ -1,6 +1,6 @@ name = "OpenBLAS_jll" uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" -version = "0.3.28+3" +version = "0.3.29+0" [deps] # See note in `src/OpenBLAS_jll.jl` about this dependency. From de1dba2c96649d0dd30403cee1ae456ae19a2ac8 Mon Sep 17 00:00:00 2001 From: Jakob Nybo Nissen Date: Mon, 13 Jan 2025 04:56:14 +0100 Subject: [PATCH 184/342] Check channel state on iterate (#52981) --- base/channels.jl | 9 +++++++++ test/channels.jl | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/base/channels.jl b/base/channels.jl index 8882171095e7a..527c22b3d45fd 100644 --- a/base/channels.jl +++ b/base/channels.jl @@ -716,6 +716,15 @@ function iterate(c::Channel, state=nothing) end end else + # If the channel was closed with an exception, it needs to be thrown + if (@atomic :acquire c.state) === :closed + e = c.excp + if isa(e, InvalidStateException) && e.state === :closed + nothing + else + throw(e) + end + end return nothing end end diff --git a/test/channels.jl b/test/channels.jl index f3e5381a62e94..4acf6c94da1b6 100644 --- a/test/channels.jl +++ b/test/channels.jl @@ -499,12 +499,35 @@ end end end +struct CustomError <: Exception end + @testset "check_channel_state" begin c = Channel(1) close(c) @test !isopen(c) c.excp === nothing # to trigger the branch @test_throws InvalidStateException Base.check_channel_state(c) + + # Issue 52974 - closed channels with exceptions + # must be thrown on iteration, if channel is empty + c = Channel(2) + put!(c, 5) + close(c, CustomError()) + @test take!(c) == 5 + @test_throws CustomError iterate(c) + + c = Channel(Inf) + put!(c, 1) + close(c) + @test take!(c) == 1 + @test_throws InvalidStateException take!(c) + @test_throws InvalidStateException put!(c, 5) + + c = Channel(3) + put!(c, 1) + close(c) + @test first(iterate(c)) == 1 + @test isnothing(iterate(c)) end # PR #36641 From cea96c9046c6f8efaa01ae10880d9a67f4527073 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Mon, 13 Jan 2025 00:53:43 -0500 Subject: [PATCH 185/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?SparseArrays=20stdlib=20from=204fd3aad=20to=205f52721=20(#57027?= =?UTF-8?q?)?= 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: main Julia branch: master Old commit: 4fd3aad New commit: 5f52721 Julia version: 1.12.0-DEV SparseArrays version: 1.12.0 Bump invoked by: @ViralBShah Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaSparse/SparseArrays.jl/compare/4fd3aad5735e3b80eefe7b068f3407d7dd0c0924...5f527215c188ee99247cdce31ba8ce9e11f35055 ``` $ git log --oneline 4fd3aad..5f52721 5f52721 Update wrappers for SuiteSparse 7.8.3 (#593) c575811 Mention vectors in more docstrings (#591) ``` Co-authored-by: ViralBShah <744411+ViralBShah@users.noreply.github.com> --- .../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-4fd3aad5735e3b80eefe7b068f3407d7dd0c0924.tar.gz/md5 delete mode 100644 deps/checksums/SparseArrays-4fd3aad5735e3b80eefe7b068f3407d7dd0c0924.tar.gz/sha512 create mode 100644 deps/checksums/SparseArrays-5f527215c188ee99247cdce31ba8ce9e11f35055.tar.gz/md5 create mode 100644 deps/checksums/SparseArrays-5f527215c188ee99247cdce31ba8ce9e11f35055.tar.gz/sha512 diff --git a/deps/checksums/SparseArrays-4fd3aad5735e3b80eefe7b068f3407d7dd0c0924.tar.gz/md5 b/deps/checksums/SparseArrays-4fd3aad5735e3b80eefe7b068f3407d7dd0c0924.tar.gz/md5 deleted file mode 100644 index 4c75f5c1f619a..0000000000000 --- a/deps/checksums/SparseArrays-4fd3aad5735e3b80eefe7b068f3407d7dd0c0924.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -308e26cc6171656caaa7f6ba07e83d1c diff --git a/deps/checksums/SparseArrays-4fd3aad5735e3b80eefe7b068f3407d7dd0c0924.tar.gz/sha512 b/deps/checksums/SparseArrays-4fd3aad5735e3b80eefe7b068f3407d7dd0c0924.tar.gz/sha512 deleted file mode 100644 index ad389d6e42048..0000000000000 --- a/deps/checksums/SparseArrays-4fd3aad5735e3b80eefe7b068f3407d7dd0c0924.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -62b94ad0dca0d62e5753f50aef806ebdb5c8b56b241a285957190845be21fc6b8c8f93089b6f627795f6d7f2b1b01118bcff87c21102a3f3bae6d4c408362681 diff --git a/deps/checksums/SparseArrays-5f527215c188ee99247cdce31ba8ce9e11f35055.tar.gz/md5 b/deps/checksums/SparseArrays-5f527215c188ee99247cdce31ba8ce9e11f35055.tar.gz/md5 new file mode 100644 index 0000000000000..946bec189c1bd --- /dev/null +++ b/deps/checksums/SparseArrays-5f527215c188ee99247cdce31ba8ce9e11f35055.tar.gz/md5 @@ -0,0 +1 @@ +4b07db52a5a6d3cc6eeab380bd783a1e diff --git a/deps/checksums/SparseArrays-5f527215c188ee99247cdce31ba8ce9e11f35055.tar.gz/sha512 b/deps/checksums/SparseArrays-5f527215c188ee99247cdce31ba8ce9e11f35055.tar.gz/sha512 new file mode 100644 index 0000000000000..846867193d932 --- /dev/null +++ b/deps/checksums/SparseArrays-5f527215c188ee99247cdce31ba8ce9e11f35055.tar.gz/sha512 @@ -0,0 +1 @@ +4c631f1046ad0a6b972a4dce285c2092372ecbed269c83524c10b4be5124035670d703af53e1f8058d23230be20c06aa554097cc9bc7a12b3de3c039d3c545e8 diff --git a/stdlib/SparseArrays.version b/stdlib/SparseArrays.version index 0ff7a761bffa3..3f6ab5b878069 100644 --- a/stdlib/SparseArrays.version +++ b/stdlib/SparseArrays.version @@ -1,4 +1,4 @@ SPARSEARRAYS_BRANCH = main -SPARSEARRAYS_SHA1 = 4fd3aad5735e3b80eefe7b068f3407d7dd0c0924 +SPARSEARRAYS_SHA1 = 5f527215c188ee99247cdce31ba8ce9e11f35055 SPARSEARRAYS_GIT_URL := https://github.com/JuliaSparse/SparseArrays.jl.git SPARSEARRAYS_TAR_URL = https://api.github.com/repos/JuliaSparse/SparseArrays.jl/tarball/$1 From 3b629f1b95db6280cb67783ef6427cd6e71c6618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= <765740+giordano@users.noreply.github.com> Date: Mon, 13 Jan 2025 06:37:04 +0000 Subject: [PATCH 186/342] Update builds of MPFR_jll and OpenSSL_jll (#57026) --- deps/checksums/mpfr | 70 +++++++++++++++++---------------- deps/checksums/openssl | 70 +++++++++++++++++---------------- stdlib/MPFR_jll/Project.toml | 2 +- stdlib/OpenSSL_jll/Project.toml | 2 +- 4 files changed, 74 insertions(+), 70 deletions(-) diff --git a/deps/checksums/mpfr b/deps/checksums/mpfr index 4d029986663c9..7b3b57978bd01 100644 --- a/deps/checksums/mpfr +++ b/deps/checksums/mpfr @@ -1,36 +1,38 @@ -MPFR.v4.2.1+1.aarch64-apple-darwin.tar.gz/md5/816f9ff59070f21f1df2f310e2606c06 -MPFR.v4.2.1+1.aarch64-apple-darwin.tar.gz/sha512/dad9adba7a8867d1ce26d77efb5c33b602b920a2cdbec84ea58a054cfab3ab7df54d2bda101de72b71604e7844993f1e216b002ba092e69277d0764040216c81 -MPFR.v4.2.1+1.aarch64-linux-gnu.tar.gz/md5/c1e3c9619af6454d8adae9bcbd911dba -MPFR.v4.2.1+1.aarch64-linux-gnu.tar.gz/sha512/5d916492aa73d11e022a7ca3f31940ceb8f8667bdf878ba29d6256736a380a2f6a11ac90cd8de3f1d3454a79165db240a1b971b9794fd21692ed64502ec34b9a -MPFR.v4.2.1+1.aarch64-linux-musl.tar.gz/md5/8ada267e2d23eb0c65ab2d2df02362d5 -MPFR.v4.2.1+1.aarch64-linux-musl.tar.gz/sha512/0c7f18e6d0f3e2052541e3279dfa9a74eb34067ac4fea0b17ab805cd73010cc83f8d7cb4eda8f4a904da398268d1c0d638c35521a9f339f8c7c3b5f159f27277 -MPFR.v4.2.1+1.aarch64-unknown-freebsd.tar.gz/md5/8aa99bf9c6157b8bb2833d8987ce0806 -MPFR.v4.2.1+1.aarch64-unknown-freebsd.tar.gz/sha512/6e4f547596eb8dd8ee2e1d3aefd7c73eed744add401c1f93d9951a9187c96fa9fc39be14683723dcb43cdf6891ea0021dc3416e43a0e2ec2038b0d1cd7c8434e -MPFR.v4.2.1+1.armv6l-linux-gnueabihf.tar.gz/md5/42bdb78eee83f496d7da699ad9603913 -MPFR.v4.2.1+1.armv6l-linux-gnueabihf.tar.gz/sha512/edaa9ece1404a606d6b635406ad5e721c8d094ffa1c73ce19222afc2b4ea7b3b9e23e7c5589ae10fd9f4c4aefa265773bcfce6c510efbca57782115d43daeb13 -MPFR.v4.2.1+1.armv6l-linux-musleabihf.tar.gz/md5/2213207772b8a50de4768816fdc20e2f -MPFR.v4.2.1+1.armv6l-linux-musleabihf.tar.gz/sha512/d24debc38b8135ac5c10c4ea19de0c69126b6881940b4e182118e12cc2c7cf0aca2db065620f0cca636742da32eddec5bda3b4f449a035274f05120c977ed449 -MPFR.v4.2.1+1.armv7l-linux-gnueabihf.tar.gz/md5/a0d9fe20c9ff0027b6816ee0102b1f9a -MPFR.v4.2.1+1.armv7l-linux-gnueabihf.tar.gz/sha512/97ce02898dc0d29a616048fd7ecee3100a710f7a30a21f2276c01675749034a5241be88bd46dff3dbf9ea0adca98a4357bd16e43fa9520e7a02477494c2d072e -MPFR.v4.2.1+1.armv7l-linux-musleabihf.tar.gz/md5/7898b9047c914b290b5928af5df63030 -MPFR.v4.2.1+1.armv7l-linux-musleabihf.tar.gz/sha512/cbefa9588752c65751630832417c1c42e4819d49ff9a505f61c2567ef4271097e585542fa898efd61409a43e439d827bb79f693a0937d0a3a427b39535979588 -MPFR.v4.2.1+1.i686-linux-gnu.tar.gz/md5/ac5a9db4bef94e7062dac463b5f87346 -MPFR.v4.2.1+1.i686-linux-gnu.tar.gz/sha512/2b5f3656e25065bfd83c81ee75999e6162c6e5436fcb0e3e3a767e2d941a556b4ebd3bebab78c63e8165105f81576959d8ad6e6d9cef1052751e39849e85df73 -MPFR.v4.2.1+1.i686-linux-musl.tar.gz/md5/6dc6a00d3ea22e2c60374d49926598d6 -MPFR.v4.2.1+1.i686-linux-musl.tar.gz/sha512/4a90356091b53d7238dda59f6e9c5c420614f16460dc67310e581611ad46a2dd3324d6164cfecf1bcd660b8f2e473f0afe137aac954c608b11be3acbda648e14 -MPFR.v4.2.1+1.i686-w64-mingw32.tar.gz/md5/7f7158a28ce8f262b897b38218f57958 -MPFR.v4.2.1+1.i686-w64-mingw32.tar.gz/sha512/8fbae0f1dd36534d4b9c63192c6e5cb1e531732d8eb1ab36783a6c71182f24ef80245b31a03460fd2f412fd0acaf1c4b9c8b574725271391217a3977b9ae4c79 -MPFR.v4.2.1+1.powerpc64le-linux-gnu.tar.gz/md5/ac70f716bddd5323b4add663b473b52d -MPFR.v4.2.1+1.powerpc64le-linux-gnu.tar.gz/sha512/ebb0f5ea76c892b7a4e4636706e71f476aaea58bb88e1734a7966c44495fda8c81318e0e8629e208185f0fc8d0c73b6f3463034cd831dfb5fbbd493a0689bc06 -MPFR.v4.2.1+1.x86_64-apple-darwin.tar.gz/md5/ff13e865e3be717b0fffc16296cb2f56 -MPFR.v4.2.1+1.x86_64-apple-darwin.tar.gz/sha512/98479210910945714da0285a40803674242581894a731ba4709c70dc1341849e736a88aa4914df0ff536c15f8848c417e712ff6abeb25047d300f8b215fd131f -MPFR.v4.2.1+1.x86_64-linux-gnu.tar.gz/md5/ca582be47601b8e6edb9d39f2881f44a -MPFR.v4.2.1+1.x86_64-linux-gnu.tar.gz/sha512/44a2e6158fde9fa8eaa6fac513dd5a8cae25a4b8879e5bb752a3f6af53d750c3a8e79be669ad87925b10c559cf9518fae431a607a342c48c00a390555e7e7b1f -MPFR.v4.2.1+1.x86_64-linux-musl.tar.gz/md5/0babbb823964ccebf63b42fd07f08936 -MPFR.v4.2.1+1.x86_64-linux-musl.tar.gz/sha512/880b685d9b456fa2bf78e707273783423f9ff00791b529eba00c5e1b94ff96f4ba01e680152a4d6b45b695e3c1169d07f793db42c5a4120861813d5458dfc828 -MPFR.v4.2.1+1.x86_64-unknown-freebsd.tar.gz/md5/f11d634e5a19177fe36b2b2f6f5727ca -MPFR.v4.2.1+1.x86_64-unknown-freebsd.tar.gz/sha512/291245c06edf31b2e39b6774359ebd4f95b924f19d2a7e8581822a5bf908426d00f0452c061a027da0d7d4bb2fa1bb7ef8ab6d8e49bc848d6d7450a8d5c8a9c4 -MPFR.v4.2.1+1.x86_64-w64-mingw32.tar.gz/md5/dcfad84470f15484443734feccbf8bf6 -MPFR.v4.2.1+1.x86_64-w64-mingw32.tar.gz/sha512/ceba1814fa671c2ba3e1ffeb6c736776981052e14111112fe963b5c11fd070136f8f022c5c21895f1f4f5084a5612fa673dddbb6b9622d7cade9b62eefcc8a14 +MPFR.v4.2.1+2.aarch64-apple-darwin.tar.gz/md5/1f5bba3e8e540720e239da75e5ae79eb +MPFR.v4.2.1+2.aarch64-apple-darwin.tar.gz/sha512/7de26c625e540a5b88e280ec2cb8712d4514732d80a0c6342d2b2cabc6bc17c05f6c614b8e38800c93a4af5438c554733d3fa2002ef70072dfb44c08d3f03d26 +MPFR.v4.2.1+2.aarch64-linux-gnu.tar.gz/md5/112ddd4e5cddf36b005394f9cd81b8e5 +MPFR.v4.2.1+2.aarch64-linux-gnu.tar.gz/sha512/dc125f625e8c74ce18c052ef759ccbcfc2f3a932f2810a306bdddf70d5f37f3546200690fd08fb76742022322a7c1b9aa907b4aec6edb318060f0648ff426cbc +MPFR.v4.2.1+2.aarch64-linux-musl.tar.gz/md5/a0919ef7cc35bb663d05e27da2bcb9a7 +MPFR.v4.2.1+2.aarch64-linux-musl.tar.gz/sha512/8acbaaca766c2ce225ac8df88c103a57fc52119d1fd54e9fc7d1f9d725c4ca9f74a0090e86eea0c140482a1abaf5b6086c453824a7516e9aef3ede5058f1767c +MPFR.v4.2.1+2.aarch64-unknown-freebsd.tar.gz/md5/61e1dcc7e323b976854a4e8164316d37 +MPFR.v4.2.1+2.aarch64-unknown-freebsd.tar.gz/sha512/f3a5493f88b290d15aff9bf79b15158d19bea05af7210b2967368e0b2f98cd291f77e62f39ee0c7ad4e9d2ef6ebdba4bf2fea24c723791f71f7b9b1ef989a67d +MPFR.v4.2.1+2.armv6l-linux-gnueabihf.tar.gz/md5/629aad4ac45ba23becd8a26df188638c +MPFR.v4.2.1+2.armv6l-linux-gnueabihf.tar.gz/sha512/bb05a8bf127eb16608a82037546f48462cb6168e1adcdb2c60dc3bd08f62cff30cf603abcab87bb336305d37dbb7b0480ea8f6664191879bdcd487738a33dd99 +MPFR.v4.2.1+2.armv6l-linux-musleabihf.tar.gz/md5/0c3c026051b096d98c8d476dd44db334 +MPFR.v4.2.1+2.armv6l-linux-musleabihf.tar.gz/sha512/9e791fe9748c87068c167517883cc905fe51ea38d2db89562a7a0959cfd83b268eed2897e5eaaf90c0b0b08a4efd8039bdeece64e83b17bf1d676570d13c2b98 +MPFR.v4.2.1+2.armv7l-linux-gnueabihf.tar.gz/md5/a2433a717e49ad95c3e430a538d01134 +MPFR.v4.2.1+2.armv7l-linux-gnueabihf.tar.gz/sha512/abde21a943d4af312e0d44b1ff1d4aefa10b2f38c74ff0e04c0c2b8561750ef5d164679564ffe1b551821d83ebcafbe99467230b37fe4591c593a24dfb070c6a +MPFR.v4.2.1+2.armv7l-linux-musleabihf.tar.gz/md5/4c892b4cbf1926d5d2b6a88330015c8f +MPFR.v4.2.1+2.armv7l-linux-musleabihf.tar.gz/sha512/24825bb1268ef2ea42894ec9ff6589308abae430dd8e43a2ca0d368f1e718fd3cdf6d9bc4bc383346970ba845d2ef1721c4848ee0c783d09addc5505131db3e6 +MPFR.v4.2.1+2.i686-linux-gnu.tar.gz/md5/0b1e0268dcaeb3aa0f7f0a6451c6b841 +MPFR.v4.2.1+2.i686-linux-gnu.tar.gz/sha512/f0ef142c7b86e8f92b78a7ff0607da70bf8f3970b118fa77438cbb0acbea604dc0c7566b52ff1f85b179aac7661b31e4aee049f2c5ff799c95b385ba9cde2a25 +MPFR.v4.2.1+2.i686-linux-musl.tar.gz/md5/2fc9a938e76e7bdc0b73d7e8bfc8b8ee +MPFR.v4.2.1+2.i686-linux-musl.tar.gz/sha512/4aed3884ad569b7695b9383db9d9dbb279ffe5349f7757b867ff860fa600b47faa4c169f4a60409666ce45fc6e6f269c18cef2df6fa0585f056d7e07e55005b8 +MPFR.v4.2.1+2.i686-w64-mingw32.tar.gz/md5/d13c44bb28d721107639c8555db5e157 +MPFR.v4.2.1+2.i686-w64-mingw32.tar.gz/sha512/1b5562d2df322c28bd06bb4ba8c9039cf90ed62affcf7f2b0d7ae8925d503c76a0d3d2f9b65c8c55575f245a4df8fbc4c7c63e93e7b973188f203a7fbda4eac5 +MPFR.v4.2.1+2.powerpc64le-linux-gnu.tar.gz/md5/52b3912b2c5f59ab3dcd7c3e06ca41b5 +MPFR.v4.2.1+2.powerpc64le-linux-gnu.tar.gz/sha512/533cf1f93c4464b4bed1d56ea79946fc2d20f3a7825d6b0383ed98cec99f85713e7bca549fd8948adb69aedc14e5d14a54238b3e67ef103e1b049b0cfb6cc1c9 +MPFR.v4.2.1+2.riscv64-linux-gnu.tar.gz/md5/aef7709c8457ee2db2622c39f1da16b7 +MPFR.v4.2.1+2.riscv64-linux-gnu.tar.gz/sha512/7a9c88563e3e7ab22a3aaa45690ed89c3e7eb22333a3d45c5e04ad2660c91ad2c97f10cd6c1aa1ccfdbf97186f9fd7f92330a41ec0be026e2ff84c5ba91f2652 +MPFR.v4.2.1+2.x86_64-apple-darwin.tar.gz/md5/12afc9778e39a5b6d9ea0161e2c80a95 +MPFR.v4.2.1+2.x86_64-apple-darwin.tar.gz/sha512/a9070423a898fa865740753ae7513d3cc0b500bd9b6b5c6aa672833dcac429efd806eff48501b51afcba5db0d31e79dac243b11b2f8847a1551576c6131506f5 +MPFR.v4.2.1+2.x86_64-linux-gnu.tar.gz/md5/46c6a5f40243795bdff51bd68a89c82e +MPFR.v4.2.1+2.x86_64-linux-gnu.tar.gz/sha512/df8209d69ae55dd54491055078f113f4ac8be7bc68e1c0eb62944e6c9c04ed3e9a55c4a5f28ec68eb69f558d9f4d1b975f36de572fbd0ef7720568efc8042327 +MPFR.v4.2.1+2.x86_64-linux-musl.tar.gz/md5/045236ee0d558d2eda42df76c3397f69 +MPFR.v4.2.1+2.x86_64-linux-musl.tar.gz/sha512/52b68a673160af7cd09b191f3c28e17d5af7516b5baa86c0df9cb63a116772a15b5358f3db5f0b254b5752c652f8959454667cc1726ea4ff30946e3bbdb90ab4 +MPFR.v4.2.1+2.x86_64-unknown-freebsd.tar.gz/md5/da3da71bc7572eca5bc3d3895abf73c2 +MPFR.v4.2.1+2.x86_64-unknown-freebsd.tar.gz/sha512/4270b83ebe72d431f8fd9127b2b8d3bd75c2e52c563d390a4ca8d40c0514f5996fce57746d07b7d3bcbf93bfe78d420f815fde5eda4d84a5bcb7b7cf0e092504 +MPFR.v4.2.1+2.x86_64-w64-mingw32.tar.gz/md5/2a6f5ccb8d45591a845ad43916beb85a +MPFR.v4.2.1+2.x86_64-w64-mingw32.tar.gz/sha512/db9ecc9d8247fe4421c4cc9c6ab540e17a7445056b7a1062d4e334b353783a1c067062fd8e6f0517d8bd8782c9bb75abcce8ab8247be707ba066dc90b7fc12ff mpfr-4.2.1.tar.bz2/md5/7765afa036e4ce7fb0e02bce0fef894b mpfr-4.2.1.tar.bz2/sha512/c81842532ecc663348deb7400d911ad71933d3b525a2f9e5adcd04265c9c0fdd1f22eca229f482703ac7f222ef209fc9e339dd1fa47d72ae57f7f70b2336a76f diff --git a/deps/checksums/openssl b/deps/checksums/openssl index 4d56641b34c80..c973f592861f3 100644 --- a/deps/checksums/openssl +++ b/deps/checksums/openssl @@ -1,36 +1,38 @@ -OpenSSL.v3.0.15+1.aarch64-apple-darwin.tar.gz/md5/8495727a34f178bc474c970855b88e8d -OpenSSL.v3.0.15+1.aarch64-apple-darwin.tar.gz/sha512/2beb6003e0431d56fd4161a7739d0ea2e2238181b2a064f552d5083b59e7724904e8a991e5d0ecaeb05e21d17b56ca44f321c71ac477db4ddaa05d792cb61c9b -OpenSSL.v3.0.15+1.aarch64-linux-gnu.tar.gz/md5/652845c276f3403e8374111fd6654aa0 -OpenSSL.v3.0.15+1.aarch64-linux-gnu.tar.gz/sha512/5d7a20836fffd253eaf574eb461eb10dcbb3fcf0d4f3d763539ef02a922af944e4ff29e8f20cec210ed798a48c742684ea713d511c58c784f33793e167a98469 -OpenSSL.v3.0.15+1.aarch64-linux-musl.tar.gz/md5/52397b6264c156815cdf9de5709533ef -OpenSSL.v3.0.15+1.aarch64-linux-musl.tar.gz/sha512/f1e8c0a3a7bac3c8b78d68fce551c29e5d537f7289f51c297e75c5c7bc3678747dc19ed579387021def041f02bf08d0e7938c5498b4493438efeb4685e01a191 -OpenSSL.v3.0.15+1.aarch64-unknown-freebsd.tar.gz/md5/bbdbea23761b13821d99f9eb4ba5d198 -OpenSSL.v3.0.15+1.aarch64-unknown-freebsd.tar.gz/sha512/a1c3985658eaf38a901bc7de1e782101ab41638d4641fea3115c5020b229d3f6fba3e3709c5568b3395986f396d82feb32b804d343dfd05c2fa1e6eefe120e96 -OpenSSL.v3.0.15+1.armv6l-linux-gnueabihf.tar.gz/md5/ceeb288e5c8da5831047dc4b1c2a983e -OpenSSL.v3.0.15+1.armv6l-linux-gnueabihf.tar.gz/sha512/961c4ec351b69aaf42082b462623afd7315b6606c2a5fb98142ca1bc6ce0494c388f5020474eff5081e850fd34aed8b3ef2f881304872255236fcae0b0b641e4 -OpenSSL.v3.0.15+1.armv6l-linux-musleabihf.tar.gz/md5/e75d83ecf3876a595cfe36cf81853489 -OpenSSL.v3.0.15+1.armv6l-linux-musleabihf.tar.gz/sha512/3e113a275233f434df685b114342f2a59634282a9b68606d4c16da51e5173cbed26498512b22f84017100a18415cc1bb2d269f1ba0d44941d51b8d05c73950cc -OpenSSL.v3.0.15+1.armv7l-linux-gnueabihf.tar.gz/md5/fbe3bf8921cf9b679b60ea12e2d19458 -OpenSSL.v3.0.15+1.armv7l-linux-gnueabihf.tar.gz/sha512/294c91308eede14b8db255ff1b47fe5dba3b6441318e38e284446f276355b93d97b88e6c78d9ed6bb6623623c47be5c65ce6b2fa5ce5ea087a8bfaeb94830627 -OpenSSL.v3.0.15+1.armv7l-linux-musleabihf.tar.gz/md5/ab35b5d4f79e349d558742c69c775d34 -OpenSSL.v3.0.15+1.armv7l-linux-musleabihf.tar.gz/sha512/6a5c85e36ed609ad33d0d2466fa1732a47072af37226052456172d7b049b9d943ad48d94b444600ed1f859a4c016226fc1952fda7381f3aaa6229bcd15c72f78 -OpenSSL.v3.0.15+1.i686-linux-gnu.tar.gz/md5/99e76e6c5d50fd0a4e6218bb807f1062 -OpenSSL.v3.0.15+1.i686-linux-gnu.tar.gz/sha512/30235842672e3b854d38ffd3ba1812a9e81b1f9fcf285ed12d07622d386a5355b79f2264be3d0e84d0bec0e57a9f3e1ac6de898463c43f6d2e3290854205cb30 -OpenSSL.v3.0.15+1.i686-linux-musl.tar.gz/md5/adb2ed9a8ef34294643f7762de1c7842 -OpenSSL.v3.0.15+1.i686-linux-musl.tar.gz/sha512/56d56eb89ea0dcadafbfc92a3bd2032b6c934d217882f56ba47086783b7a5134816f43d391a569963fa978ab708bf695af5abf03cac11c709930752882c761b7 -OpenSSL.v3.0.15+1.i686-w64-mingw32.tar.gz/md5/4596a947bb22aab728ba585d2727053a -OpenSSL.v3.0.15+1.i686-w64-mingw32.tar.gz/sha512/6a1479036c7ccb170daf42ed7d6054d2c7f3a4115dbb01fe34e518efdf0a60929eb89771d5f7fdcb3d055ebf05351cbc82397606d49ea4bde44c465cdb60274e -OpenSSL.v3.0.15+1.powerpc64le-linux-gnu.tar.gz/md5/f36402387dde259a64b0bed2a0d2a3c9 -OpenSSL.v3.0.15+1.powerpc64le-linux-gnu.tar.gz/sha512/3011eec16c1abcbf3c452a2d8e4e7c5a3c280981ea57374a938e3f8843f25022e9b0beaa6a87a1e5f7547ae4abd614221cc2a0a51495869fe99a03f6b3f46d8e -OpenSSL.v3.0.15+1.x86_64-apple-darwin.tar.gz/md5/f4c82b74f80a3cda4ae409e4623b6615 -OpenSSL.v3.0.15+1.x86_64-apple-darwin.tar.gz/sha512/d4a08a914533e603f06e584b8d7e69f4fca9671635fe24e1a896a362bfd388eea2397b9b66b82aecc0ba751e72dfcfbd8b46c5a148349f5aaeb9c37bc257ed37 -OpenSSL.v3.0.15+1.x86_64-linux-gnu.tar.gz/md5/9868c286c6275581a5891167540def7d -OpenSSL.v3.0.15+1.x86_64-linux-gnu.tar.gz/sha512/5631aa288e0e174bd05d520d90a29423c743576eb2385e97a58ed45361e94e59daa3b3193e81ce649bfed21d07fd508c135a38b486b34120afc3af1b4f92451d -OpenSSL.v3.0.15+1.x86_64-linux-musl.tar.gz/md5/e118f2b842a3a1be539208aff17281ec -OpenSSL.v3.0.15+1.x86_64-linux-musl.tar.gz/sha512/1c6fa866bebf5c0c6cc5ea8a423d2a522b186e7f2590146e464813be22d66de0a9bc797449508fa5508d296309348b8dd3a881c0099e6fb77b8d28ff270fab35 -OpenSSL.v3.0.15+1.x86_64-unknown-freebsd.tar.gz/md5/03830b4a8735a7e704df444e9a4353ab -OpenSSL.v3.0.15+1.x86_64-unknown-freebsd.tar.gz/sha512/bfc9e4ca160a9e3d4232117d819ea37f3997d4c433cfc85a4055ced60e8c65e7df6009d58f6b94f6f2aa1b436a8ee9f08dcf5a21faf7106bfdb50ca9a05322c6 -OpenSSL.v3.0.15+1.x86_64-w64-mingw32.tar.gz/md5/5b2c640cb72115f417cdd7ec82a8336f -OpenSSL.v3.0.15+1.x86_64-w64-mingw32.tar.gz/sha512/d2224dd37205c7781be93f1581a08c4008f4c35cb3f457f3b4455a00805c1a20be7f7e29188a55164364c42a926ffa12527af379d1bc8d11f4351b07d8a5928b +OpenSSL.v3.0.15+2.aarch64-apple-darwin.tar.gz/md5/d11d92e6530705e3d93925bbb4dfccff +OpenSSL.v3.0.15+2.aarch64-apple-darwin.tar.gz/sha512/e30d763d956f930c3dab961ef1b382385b78cbb2324ae7f5e943420b9178bc2b086d9877c2d2b41b30a92ca109d7832a2ae50f70547fcc9788e25889d8252ffc +OpenSSL.v3.0.15+2.aarch64-linux-gnu.tar.gz/md5/d29f0d3a35d592488ba3a8bbb0dc8d0e +OpenSSL.v3.0.15+2.aarch64-linux-gnu.tar.gz/sha512/67c527c1930b903d2fbb55df1bd3fc1b8394bc4fadd15dd8fb84e776bae8c448487c117492e22b9b014f823cc7fe709695f4064639066b10427b06355540e997 +OpenSSL.v3.0.15+2.aarch64-linux-musl.tar.gz/md5/4f5313f1f18e29585951e95372a7a0fe +OpenSSL.v3.0.15+2.aarch64-linux-musl.tar.gz/sha512/48007a1f6667d6aeb87cc7287723ed00e39fe2bc9c353ff33348442516f1a28961985cc4a29a2a8f76b3a7049bd955973562d7c6c4af43af884596def636f7f8 +OpenSSL.v3.0.15+2.aarch64-unknown-freebsd.tar.gz/md5/5b6041353197bb8f75b39ed8f58cf4e9 +OpenSSL.v3.0.15+2.aarch64-unknown-freebsd.tar.gz/sha512/9be617d51fdc167085887380e720e6baf8e1e180f455b297f44d0bc0862fd490f015b5292d952d4ad095750cde796cc7dac4f901389b73135cb399b3a9d378c1 +OpenSSL.v3.0.15+2.armv6l-linux-gnueabihf.tar.gz/md5/858f548a28e289153842226473138a3e +OpenSSL.v3.0.15+2.armv6l-linux-gnueabihf.tar.gz/sha512/f9385678fca65d1fb8d96756442518b16607a57a9b6d76991414b37dfc4e30a7e1eebe5f3977b088b491216af4a34f958b64fe95062ee9ae23a9212f46c4e923 +OpenSSL.v3.0.15+2.armv6l-linux-musleabihf.tar.gz/md5/c4e52ecb4f9e24d948724424f1070071 +OpenSSL.v3.0.15+2.armv6l-linux-musleabihf.tar.gz/sha512/12f9276c68049026f2741c7d97e62d24525e5e832911546e1ea3868362034e6384304d749730122edf828b8c5573084055d59cc0bd75bda32f000ce630837c2b +OpenSSL.v3.0.15+2.armv7l-linux-gnueabihf.tar.gz/md5/767d3f3047366ccd6e2aa275f80d9f6c +OpenSSL.v3.0.15+2.armv7l-linux-gnueabihf.tar.gz/sha512/17700fd33c221070a7dd2db79d045e102591b85e16b3d4099356fb6a8635aea297b5fcef91740f75c55344a12ed356772b3b85c0cc68627856093ceb53ea8eb3 +OpenSSL.v3.0.15+2.armv7l-linux-musleabihf.tar.gz/md5/3ef2385cb1fec9e2d3af2ba9385ac733 +OpenSSL.v3.0.15+2.armv7l-linux-musleabihf.tar.gz/sha512/6156e9431fa8269b8d037149271be6cca0b119be67be01cfd958dabf59cdd468ef2a5ebf885e5835585006efdedd29afc308076283d070d4ae743146b57cd2b1 +OpenSSL.v3.0.15+2.i686-linux-gnu.tar.gz/md5/e62992d214cec6b1970f9fbd04cb8ecd +OpenSSL.v3.0.15+2.i686-linux-gnu.tar.gz/sha512/dfdb3d2d1d5fed7bf1c322899d6138c81f0653350f4b918858dd51bf7bcc86d2d04de824533925fa5f8d366a5c18ee33ade883f50a538b657717f8a428be8c60 +OpenSSL.v3.0.15+2.i686-linux-musl.tar.gz/md5/186a6bb8055ce089ac0c9897bd2cd697 +OpenSSL.v3.0.15+2.i686-linux-musl.tar.gz/sha512/f3c8d608113e9b0e91dd6af697172a46892d4a66572e35e13ad394397291dded3042667c1ec4fafe051778e71ff56a876dc3e848a2b85cef9f925ef3969ab950 +OpenSSL.v3.0.15+2.i686-w64-mingw32.tar.gz/md5/b72b8e4883337e4bc90094dce86c8b8b +OpenSSL.v3.0.15+2.i686-w64-mingw32.tar.gz/sha512/3b5ddef15ca1463ab92ef5b88df36f8418c8c44ffb123a0922e55718ab317b5fe379994aba9a5e8ca112475043d5cf99b1574702cdb30de438f458ee06ac80ea +OpenSSL.v3.0.15+2.powerpc64le-linux-gnu.tar.gz/md5/da194ce6f37f34cc19cc78d25c9af5e2 +OpenSSL.v3.0.15+2.powerpc64le-linux-gnu.tar.gz/sha512/e256a9d9a0af8764de730419281aa4d3ee9f6146692ec9105a318d8301d8fda5cca82c6ef4d0d7b70d721992361771724b237ce26ef81f92c295f6056d5a7cdd +OpenSSL.v3.0.15+2.riscv64-linux-gnu.tar.gz/md5/86825ee5f83ec0c827d5c051fe1a3d41 +OpenSSL.v3.0.15+2.riscv64-linux-gnu.tar.gz/sha512/7db4ae2f0a9491ae484da5b8b0c3698d970ada91c83f9783c9e5bd92006f52dffa1a4c7fb282b63e34760199a97c52793040dc306ad0986970cfa233e29cb195 +OpenSSL.v3.0.15+2.x86_64-apple-darwin.tar.gz/md5/271cc359f5bc4718659044ad5ac7631d +OpenSSL.v3.0.15+2.x86_64-apple-darwin.tar.gz/sha512/10e7575dc4cce6c617c96e6f94dbfe3058aad696292d3fac4bde7c92623f2a849b7d10e35b156b7582294b3cf103d61b3ea73605f958ee4c9f8ff05b647939a7 +OpenSSL.v3.0.15+2.x86_64-linux-gnu.tar.gz/md5/5d045d93d632af9914bff551f67eed9b +OpenSSL.v3.0.15+2.x86_64-linux-gnu.tar.gz/sha512/240791382d9549be029e2d404bc0e962f9876ab0597bf20cf34c87fcfafc3d75ba9f223641287895f9aee8519a5a33293910ed6d67bc1424ff3513eedaa8b699 +OpenSSL.v3.0.15+2.x86_64-linux-musl.tar.gz/md5/bb2637babf3730ed1117f89cb8aab34a +OpenSSL.v3.0.15+2.x86_64-linux-musl.tar.gz/sha512/b847539acc00870f77b242eeccfcf16f590493b7deb0089fa3654026f4016d40f9595d3bbb21ab981e9decfde4321da71f162beb1837a158fd3a884375a86fee +OpenSSL.v3.0.15+2.x86_64-unknown-freebsd.tar.gz/md5/23b69e0256e6c86e026be3ade20aed5c +OpenSSL.v3.0.15+2.x86_64-unknown-freebsd.tar.gz/sha512/1b7da1e13d325c7776b8e1a63aaa334bd633bb10604f8bed5f5f6a81955268b3d11ad221a5dd181dbdc7ad27c35d5754e6875d36226003c2fd7da6cd91854de1 +OpenSSL.v3.0.15+2.x86_64-w64-mingw32.tar.gz/md5/73cf4138ab403b7c9f91368a030590f9 +OpenSSL.v3.0.15+2.x86_64-w64-mingw32.tar.gz/sha512/052bb52837c29b4b18a97df71a80ad77486bd6ccef6e2e57dfa68a02754180976dc0302a158886393ef13fe91904f963119b17429a4ecc6f8b6c80ff878df05d openssl-3.0.15.tar.gz/md5/08f458c00fff496a52ef931c481045cd openssl-3.0.15.tar.gz/sha512/acd80f2f7924d90c1416946a5c61eff461926ad60f4821bb6b08845ea18f8452fd5e88a2c2c5bd0d7590a792cb8341a3f3be042fd0a5b6c9c1b84a497c347bbf diff --git a/stdlib/MPFR_jll/Project.toml b/stdlib/MPFR_jll/Project.toml index a9987ccfa38f6..50de38f169ff0 100644 --- a/stdlib/MPFR_jll/Project.toml +++ b/stdlib/MPFR_jll/Project.toml @@ -1,6 +1,6 @@ name = "MPFR_jll" uuid = "3a97d323-0669-5f0c-9066-3539efd106a3" -version = "4.2.1+1" +version = "4.2.1+2" [deps] GMP_jll = "781609d7-10c4-51f6-84f2-b8444358ff6d" diff --git a/stdlib/OpenSSL_jll/Project.toml b/stdlib/OpenSSL_jll/Project.toml index df00f99b205c9..0773311e11043 100644 --- a/stdlib/OpenSSL_jll/Project.toml +++ b/stdlib/OpenSSL_jll/Project.toml @@ -1,6 +1,6 @@ name = "OpenSSL_jll" uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" -version = "3.0.15+1" +version = "3.0.15+2" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" From f135f3a2dc89d8aa6b885795f27ae989dadc6c3f Mon Sep 17 00:00:00 2001 From: Nicholas Bauer Date: Mon, 13 Jan 2025 14:51:46 -0500 Subject: [PATCH 187/342] More efficient hvcat of scalars and arrays of numbers (#39729) First attempt to address #39713 Original: ``` const a, b, c, d = zeros(Int, 2, 2), [3 4], [2 ; 4], 5 using BenchmarkTools @btime [a c ; b d] # 31 allocations and 1.25 kb ``` New: ``` @btime [a c ; b d] # 15 allocations and 656 bytes ``` Others unchanged, as expected. ~~Though if different types of numbers are mixed, it still takes the longer path. I tried expanding the definition but there's some weird stuff going on that increases allocations in the other situations I posted in that issue.~~ Works for any Number element type. Fixes #39713 --- base/abstractarray.jl | 59 ++++--------------------------------------- 1 file changed, 5 insertions(+), 54 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index a370b79976ab0..1ab78a55c93b5 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -2189,48 +2189,8 @@ true hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractArray...) = typed_hvcat(promote_eltype(xs...), rows, xs...) hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractArray{T}...) where {T} = typed_hvcat(T, rows, xs...) -function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as::AbstractVecOrMat...) where T - nbr = length(rows) # number of block rows - - nc = 0 - for i=1:rows[1] - nc += size(as[i],2) - end - - nr = 0 - a = 1 - for i = 1:nbr - nr += size(as[a],1) - a += rows[i] - end - - out = similar(as[1], T, nr, nc) - - a = 1 - r = 1 - for i = 1:nbr - c = 1 - szi = size(as[a],1) - for j = 1:rows[i] - Aj = as[a+j-1] - szj = size(Aj,2) - if size(Aj,1) != szi - throw(DimensionMismatch("mismatched height in block row $(i) (expected $szi, got $(size(Aj,1)))")) - end - if c-1+szj > nc - throw(DimensionMismatch("block row $(i) has mismatched number of columns (expected $nc, got $(c-1+szj))")) - end - out[r:r-1+szi, c:c-1+szj] = Aj - c += szj - end - if c != nc+1 - throw(DimensionMismatch("block row $(i) has mismatched number of columns (expected $nc, got $(c-1))")) - end - r += szi - a += rows[i] - end - out -end +rows_to_dimshape(rows::Tuple{Vararg{Int}}) = all(==(rows[1]), rows) ? (length(rows), rows[1]) : (rows, (sum(rows),)) +typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as::AbstractVecOrMat...) where T = typed_hvncat(T, rows_to_dimshape(rows), true, as...) hvcat(rows::Tuple{Vararg{Int}}) = [] typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}) where {T} = Vector{T}() @@ -2288,16 +2248,7 @@ function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, xs::Number...) where T hvcat_fill!(Matrix{T}(undef, nr, nc), xs) end -function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as...) where T - nbr = length(rows) # number of block rows - rs = Vector{Any}(undef, nbr) - a = 1 - for i = 1:nbr - rs[i] = typed_hcat(T, as[a:a-1+rows[i]]...) - a += rows[i] - end - T[rs...;] -end +typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as...) where T = typed_hvncat(T, rows_to_dimshape(rows), true, as...) ## N-dimensional concatenation ## @@ -2645,7 +2596,7 @@ function _typed_hvncat_dims(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, as throw(DimensionMismatch("mismatched number of elements; expected $(outlen), got $(elementcount)")) # copy into final array - A = cat_similar(as[1], T, outdims) + A = cat_similar(as[1], T, ntuple(i -> outdims[i], N)) # @assert all(==(0), currentdims) outdims .= 0 hvncat_fill!(A, currentdims, outdims, d1, d2, as) @@ -2739,7 +2690,7 @@ function _typed_hvncat_shape(::Type{T}, shape::NTuple{N, Tuple}, row_first, as:: # @assert all(==(0), blockcounts) # copy into final array - A = cat_similar(as[1], T, outdims) + A = cat_similar(as[1], T, ntuple(i -> outdims[i], nd)) hvncat_fill!(A, currentdims, blockcounts, d1, d2, as) return A end From 664528adac261df806f291493593f63b66ff169c Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Tue, 14 Jan 2025 05:26:23 +0900 Subject: [PATCH 188/342] make `datatype_min_ninitialized` robust against non `DataType` input (#57033) By unwrapping the input type in `datatype_min_ninitialized`, and guard against non `DataType` input by returning the most conservative value `0` in such cases. Fixes #56997 --- Compiler/src/abstractinterpretation.jl | 2 +- Compiler/src/typelimits.jl | 2 +- Compiler/src/typeutils.jl | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index 3766907905aef..59510dbfbb65a 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -3708,7 +3708,7 @@ end if isa(rt, PartialStruct) fields = copy(rt.fields) anyrefine = !isvarargtype(rt.fields[end]) && - length(rt.fields) > datatype_min_ninitialized(unwrap_unionall(rt.typ)) + length(rt.fields) > datatype_min_ninitialized(rt.typ) 𝕃 = typeinf_lattice(info.interp) ⊏ = strictpartialorder(𝕃) for i in 1:length(fields) diff --git a/Compiler/src/typelimits.jl b/Compiler/src/typelimits.jl index 11245fbaee9b0..536b5fb34d1b1 100644 --- a/Compiler/src/typelimits.jl +++ b/Compiler/src/typelimits.jl @@ -601,7 +601,7 @@ end end nflds == 0 && return nothing fields = Vector{Any}(undef, nflds) - anyrefine = nflds > datatype_min_ninitialized(unwrap_unionall(aty)) + anyrefine = nflds > datatype_min_ninitialized(aty) for i = 1:nflds ai = getfield_tfunc(𝕃, typea, Const(i)) bi = getfield_tfunc(𝕃, typeb, Const(i)) diff --git a/Compiler/src/typeutils.jl b/Compiler/src/typeutils.jl index 4af8fed0e40c3..5175e00612270 100644 --- a/Compiler/src/typeutils.jl +++ b/Compiler/src/typeutils.jl @@ -64,7 +64,9 @@ end # Compute the minimum number of initialized fields for a particular datatype # (therefore also a lower bound on the number of fields) -function datatype_min_ninitialized(t::DataType) +function datatype_min_ninitialized(@nospecialize t0) + t = unwrap_unionall(t0) + t isa DataType || return 0 isabstracttype(t) && return 0 if t.name === _NAMEDTUPLE_NAME names, types = t.parameters[1], t.parameters[2] From a861a551b764062d47ab3c2a3748bcf540221bae Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Tue, 14 Jan 2025 01:14:56 -0300 Subject: [PATCH 189/342] Move all platforms to use llvm.minimum/llvm.maximum for fmin/fmax (#56371) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This used to not work but LLVM now has support for this on all platforms we care about. Maybe this should be a builtin. This allows for more vectorization opportunities since llvm understands the code better Fix #48487. --------- Co-authored-by: Mosè Giordano <765740+giordano@users.noreply.github.com> Co-authored-by: oscarddssmith --- Compiler/src/tfuncs.jl | 4 ++++ base/fastmath.jl | 10 ++++----- base/math.jl | 45 +++++----------------------------------- src/intrinsics.cpp | 32 ++++++++++++++++++++++++++++ src/intrinsics.h | 4 ++++ src/julia_internal.h | 2 ++ src/runtime_intrinsics.c | 39 +++++++++++++++++++++++++++++++++- 7 files changed, 89 insertions(+), 47 deletions(-) diff --git a/Compiler/src/tfuncs.jl b/Compiler/src/tfuncs.jl index f0c793a4ae3b7..cfb865b06e9e5 100644 --- a/Compiler/src/tfuncs.jl +++ b/Compiler/src/tfuncs.jl @@ -189,6 +189,8 @@ add_tfunc(add_float, 2, 2, math_tfunc, 2) add_tfunc(sub_float, 2, 2, math_tfunc, 2) add_tfunc(mul_float, 2, 2, math_tfunc, 8) add_tfunc(div_float, 2, 2, math_tfunc, 10) +add_tfunc(min_float, 2, 2, math_tfunc, 1) +add_tfunc(max_float, 2, 2, math_tfunc, 1) add_tfunc(fma_float, 3, 3, math_tfunc, 8) add_tfunc(muladd_float, 3, 3, math_tfunc, 8) @@ -198,6 +200,8 @@ add_tfunc(add_float_fast, 2, 2, math_tfunc, 2) add_tfunc(sub_float_fast, 2, 2, math_tfunc, 2) add_tfunc(mul_float_fast, 2, 2, math_tfunc, 8) add_tfunc(div_float_fast, 2, 2, math_tfunc, 10) +add_tfunc(min_float_fast, 2, 2, math_tfunc, 1) +add_tfunc(max_float_fast, 2, 2, math_tfunc, 1) # bitwise operators # ----------------- diff --git a/base/fastmath.jl b/base/fastmath.jl index b82d613f1fc76..f2f60519b99ac 100644 --- a/base/fastmath.jl +++ b/base/fastmath.jl @@ -28,7 +28,7 @@ module FastMath export @fastmath import Core.Intrinsics: sqrt_llvm_fast, neg_float_fast, - add_float_fast, sub_float_fast, mul_float_fast, div_float_fast, + add_float_fast, sub_float_fast, mul_float_fast, div_float_fast, min_float_fast, max_float_fast, eq_float_fast, ne_float_fast, lt_float_fast, le_float_fast import Base: afoldl @@ -168,6 +168,9 @@ add_fast(x::T, y::T) where {T<:FloatTypes} = add_float_fast(x, y) sub_fast(x::T, y::T) where {T<:FloatTypes} = sub_float_fast(x, y) mul_fast(x::T, y::T) where {T<:FloatTypes} = mul_float_fast(x, y) div_fast(x::T, y::T) where {T<:FloatTypes} = div_float_fast(x, y) +max_fast(x::T, y::T) where {T<:FloatTypes} = max_float_fast(x, y) +min_fast(x::T, y::T) where {T<:FloatTypes} = min_float_fast(x, y) +minmax_fast(x::T, y::T) where {T<:FloatTypes} = (min_fast(x, y), max_fast(x, y)) @fastmath begin cmp_fast(x::T, y::T) where {T<:FloatTypes} = ifelse(x==y, 0, ifelse(x x, y, x) - min_fast(x::T, y::T) where {T<:FloatTypes} = ifelse(y > x, x, y) - minmax_fast(x::T, y::T) where {T<:FloatTypes} = ifelse(y > x, (x,y), (y,x)) end # fall-back implementations and type promotion diff --git a/base/math.jl b/base/math.jl index 16a8a547e8de1..650fc6bc0cef0 100644 --- a/base/math.jl +++ b/base/math.jl @@ -25,7 +25,7 @@ using .Base: sign_mask, exponent_mask, exponent_one, significand_bits, exponent_bits, exponent_bias, exponent_max, exponent_raw_max, clamp, clamp! -using Core.Intrinsics: sqrt_llvm +using Core.Intrinsics: sqrt_llvm, min_float, max_float using .Base: IEEEFloat @@ -831,47 +831,12 @@ min(x::T, y::T) where {T<:AbstractFloat} = isnan(x) || ~isnan(y) && _isless(x, y max(x::T, y::T) where {T<:AbstractFloat} = isnan(x) || ~isnan(y) && _isless(y, x) ? x : y minmax(x::T, y::T) where {T<:AbstractFloat} = min(x, y), max(x, y) -_isless(x::Float16, y::Float16) = signbit(widen(x) - widen(y)) - -const has_native_fminmax = Sys.ARCH === :aarch64 -@static if has_native_fminmax - @eval begin - Base.@assume_effects :total @inline llvm_min(x::Float64, y::Float64) = ccall("llvm.minimum.f64", llvmcall, Float64, (Float64, Float64), x, y) - Base.@assume_effects :total @inline llvm_min(x::Float32, y::Float32) = ccall("llvm.minimum.f32", llvmcall, Float32, (Float32, Float32), x, y) - Base.@assume_effects :total @inline llvm_max(x::Float64, y::Float64) = ccall("llvm.maximum.f64", llvmcall, Float64, (Float64, Float64), x, y) - Base.@assume_effects :total @inline llvm_max(x::Float32, y::Float32) = ccall("llvm.maximum.f32", llvmcall, Float32, (Float32, Float32), x, y) - end -end - -function min(x::T, y::T) where {T<:Union{Float32,Float64}} - @static if has_native_fminmax - return llvm_min(x,y) - end - diff = x - y - argmin = ifelse(signbit(diff), x, y) - anynan = isnan(x)|isnan(y) - return ifelse(anynan, diff, argmin) +function min(x::T, y::T) where {T<:IEEEFloat} + return min_float(x, y) end -function max(x::T, y::T) where {T<:Union{Float32,Float64}} - @static if has_native_fminmax - return llvm_max(x,y) - end - diff = x - y - argmax = ifelse(signbit(diff), y, x) - anynan = isnan(x)|isnan(y) - return ifelse(anynan, diff, argmax) -end - -function minmax(x::T, y::T) where {T<:Union{Float32,Float64}} - @static if has_native_fminmax - return llvm_min(x, y), llvm_max(x, y) - end - diff = x - y - sdiff = signbit(diff) - min, max = ifelse(sdiff, x, y), ifelse(sdiff, y, x) - anynan = isnan(x)|isnan(y) - return ifelse(anynan, diff, min), ifelse(anynan, diff, max) +function max(x::T, y::T) where {T<:IEEEFloat} + return max_float(x, y) end """ diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 09916297e16ff..7b5aa7c397129 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -83,10 +83,14 @@ const auto &float_func() { float_func[sub_float] = true; float_func[mul_float] = true; float_func[div_float] = true; + float_func[min_float] = true; + float_func[max_float] = true; float_func[add_float_fast] = true; float_func[sub_float_fast] = true; float_func[mul_float_fast] = true; float_func[div_float_fast] = true; + float_func[min_float_fast] = true; + float_func[max_float_fast] = true; float_func[fma_float] = true; float_func[muladd_float] = true; float_func[eq_float] = true; @@ -1490,6 +1494,34 @@ static Value *emit_untyped_intrinsic(jl_codectx_t &ctx, intrinsic f, ArrayRefgetType() == y->getType()); + FunctionCallee minintr = Intrinsic::getDeclaration(jl_Module, Intrinsic::minimum, ArrayRef(t)); + return ctx.builder.CreateCall(minintr, {x, y}); + } + case max_float: { + assert(x->getType() == y->getType()); + FunctionCallee maxintr = Intrinsic::getDeclaration(jl_Module, Intrinsic::maximum, ArrayRef(t)); + return ctx.builder.CreateCall(maxintr, {x, y}); + } + case min_float_fast: { + assert(x->getType() == y->getType()); + FunctionCallee minintr = Intrinsic::getDeclaration(jl_Module, Intrinsic::minimum, ArrayRef(t)); + auto call = ctx.builder.CreateCall(minintr, {x, y}); + auto fmf = call->getFastMathFlags(); + fmf.setFast(); + call->copyFastMathFlags(fmf); + return call; + } + case max_float_fast: { + assert(x->getType() == y->getType()); + FunctionCallee maxintr = Intrinsic::getDeclaration(jl_Module, Intrinsic::maximum, ArrayRef(t)); + auto call = ctx.builder.CreateCall(maxintr, {x, y}); + auto fmf = call->getFastMathFlags(); + fmf.setFast(); + call->copyFastMathFlags(fmf); + return call; + } case add_float_fast: return math_builder(ctx, true)().CreateFAdd(x, y); case sub_float_fast: return math_builder(ctx, true)().CreateFSub(x, y); case mul_float_fast: return math_builder(ctx, true)().CreateFMul(x, y); diff --git a/src/intrinsics.h b/src/intrinsics.h index 5b463e3bafe28..5765e3e671bc6 100644 --- a/src/intrinsics.h +++ b/src/intrinsics.h @@ -17,6 +17,8 @@ ADD_I(sub_float, 2) \ ADD_I(mul_float, 2) \ ADD_I(div_float, 2) \ + ADD_I(min_float, 2) \ + ADD_I(max_float, 2) \ ADD_I(fma_float, 3) \ ADD_I(muladd_float, 3) \ /* fast arithmetic */ \ @@ -25,6 +27,8 @@ ALIAS(sub_float_fast, sub_float) \ ALIAS(mul_float_fast, mul_float) \ ALIAS(div_float_fast, div_float) \ + ALIAS(min_float_fast, min_float) \ + ALIAS(max_float_fast, max_float) \ /* same-type comparisons */ \ ADD_I(eq_int, 2) \ ADD_I(ne_int, 2) \ diff --git a/src/julia_internal.h b/src/julia_internal.h index f8dd49eab65a3..81e9ebb537667 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -1595,6 +1595,8 @@ JL_DLLEXPORT jl_value_t *jl_add_float(jl_value_t *a, jl_value_t *b); JL_DLLEXPORT jl_value_t *jl_sub_float(jl_value_t *a, jl_value_t *b); JL_DLLEXPORT jl_value_t *jl_mul_float(jl_value_t *a, jl_value_t *b); JL_DLLEXPORT jl_value_t *jl_div_float(jl_value_t *a, jl_value_t *b); +JL_DLLEXPORT jl_value_t *jl_min_float(jl_value_t *a, jl_value_t *b); +JL_DLLEXPORT jl_value_t *jl_max_float(jl_value_t *a, jl_value_t *b); JL_DLLEXPORT jl_value_t *jl_fma_float(jl_value_t *a, jl_value_t *b, jl_value_t *c); JL_DLLEXPORT jl_value_t *jl_muladd_float(jl_value_t *a, jl_value_t *b, jl_value_t *c); diff --git a/src/runtime_intrinsics.c b/src/runtime_intrinsics.c index 80281b733bf44..1790b9bd8d106 100644 --- a/src/runtime_intrinsics.c +++ b/src/runtime_intrinsics.c @@ -1398,13 +1398,50 @@ bi_iintrinsic_fast(LLVMURem, rem, urem_int, u) bi_iintrinsic_fast(jl_LLVMSMod, smod, smod_int, ) #define frem(a, b) \ fp_select2(a, b, fmod) - un_fintrinsic(neg_float,neg_float) bi_fintrinsic(add,add_float) bi_fintrinsic(sub,sub_float) bi_fintrinsic(mul,mul_float) bi_fintrinsic(div,div_float) +float min_float(float x, float y) JL_NOTSAFEPOINT +{ + float diff = x - y; + float argmin = signbit(diff) ? x : y; + int is_nan = isnan(x) || isnan(y); + return is_nan ? diff : argmin; +} + +double min_double(double x, double y) JL_NOTSAFEPOINT +{ + double diff = x - y; + double argmin = signbit(diff) ? x : y; + int is_nan = isnan(x) || isnan(y); + return is_nan ? diff : argmin; +} + +#define _min(a, b) sizeof(a) == sizeof(float) ? min_float(a, b) : min_double(a, b) +bi_fintrinsic(_min, min_float) + +float max_float(float x, float y) JL_NOTSAFEPOINT +{ + float diff = x - y; + float argmin = signbit(diff) ? y : x; + int is_nan = isnan(x) || isnan(y); + return is_nan ? diff : argmin; +} + +double max_double(double x, double y) JL_NOTSAFEPOINT +{ + double diff = x - y; + double argmin = signbit(diff) ? x : y; + int is_nan = isnan(x) || isnan(y); + return is_nan ? diff : argmin; +} + +#define _max(a, b) sizeof(a) == sizeof(float) ? max_float(a, b) : max_double(a, b) +bi_fintrinsic(_max, max_float) + // ternary operators // // runtime fma is broken on windows, define julia_fma(f) ourself with fma_emulated as reference. #if defined(_OS_WINDOWS_) From 9b1ea1a880e1c47ebdc549a12fca288b5cc60013 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Tue, 14 Jan 2025 15:37:18 +0900 Subject: [PATCH 190/342] publish Compiler.jl v0.0.3 (#57032) Cthulhu.jl requires this (as the signature of `jl_update_codeinst` has been updated). --- Compiler/Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Compiler/Project.toml b/Compiler/Project.toml index 046d672c4877c..994634f5a8b78 100644 --- a/Compiler/Project.toml +++ b/Compiler/Project.toml @@ -1,6 +1,6 @@ name = "Compiler" uuid = "807dbc54-b67e-4c79-8afb-eafe4df6f2e1" -version = "0.0.2" +version = "0.0.3" [compat] julia = "1.10" From 3ba504a5484c48720aa3f19e7ef51a5a32c3a7db Mon Sep 17 00:00:00 2001 From: Yi Lin Date: Wed, 15 Jan 2025 00:39:11 +1300 Subject: [PATCH 191/342] Fix getall failure with MMTk dependency (#57038) This PR fixes https://github.com/JuliaLang/julia/issues/57002. The current makefile checks if `MMTK_JULIA_DIR` points to `$(BUILDROOT)/usr/lib/mmtk_julia` and defines the rule `get-mmtk_julia` if the condition is met. For non-mmtk builds (e.g. `make -C deps getall`), `MMTK_JULIA_DIR` is not defined, thus `get-mmtk_julia` is not defined. This PR moves the rule `get-mmtk_julia` outside the condition so it always exists. --- deps/mmtk_julia.mk | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/deps/mmtk_julia.mk b/deps/mmtk_julia.mk index ccf638e9211bb..7ec55426821c3 100644 --- a/deps/mmtk_julia.mk +++ b/deps/mmtk_julia.mk @@ -6,9 +6,11 @@ MMTK_MOVING := 0 MMTK_VARS := MMTK_PLAN=$(MMTK_PLAN) MMTK_MOVING=$(MMTK_MOVING) +$(eval $(call git-external,mmtk_julia,MMTK_JULIA,,,$(BUILDDIR))) +get-mmtk_julia: $(MMTK_JULIA_SRC_FILE) + # Download the binding, build it from source ifeq (${MMTK_JULIA_DIR},$(BUILDROOT)/usr/lib/mmtk_julia) -$(eval $(call git-external,mmtk_julia,MMTK_JULIA,,,$(BUILDDIR))) MMTK_JULIA_DIR=$(BUILDROOT)/deps/$(BUILDDIR)/$(MMTK_JULIA_SRC_DIR) MMTK_JULIA_LIB_PATH=$(MMTK_JULIA_DIR)/mmtk/target/$(MMTK_BUILD) @@ -24,7 +26,6 @@ $(BUILDROOT)/usr/lib/libmmtk_julia.so: $(MMTK_JULIA_LIB_PATH)/libmmtk_julia.so $(MMTK_JULIA_LIB_PATH)/libmmtk_julia.so: $(BUILDDIR)/$(MMTK_JULIA_SRC_DIR)/source-extracted @$(PROJECT_DIRS) $(MMTK_VARS) $(MAKE) -C $(MMTK_JULIA_DIR) $(MMTK_BUILD) -get-mmtk_julia: $(MMTK_JULIA_SRC_FILE) extract-mmtk_julia: $(BUILDDIR)/$(MMTK_JULIA_SRC_DIR)/source-extracted configure-mmtk_julia: extract-mmtk_julia compile-mmtk_julia: $(BUILDROOT)/usr/lib/libmmtk_julia.so From b23f557e80cabac1624fc98abacfba152156ef8f Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Tue, 14 Jan 2025 16:28:34 +0100 Subject: [PATCH 192/342] Revert "Avoid allocations in views of views (#53231)" (#57044) This reverts commit 2bd4cf8090f2c651543f562a4c469d73e4b15bd6. (#53231) The reason for this revert is that it caused exponential blowup of types in iterated views causing some packages to simply freeze when doing something that worked ok in 1.10. In my opinion, the perf gain from the PR is not outweighed by the "risk" of hitting this compilation blowup case. Fixes https://github.com/JuliaLang/julia/issues/56760. Co-authored-by: KristofferC --- base/subarray.jl | 6 +++--- test/subarray.jl | 25 ------------------------- 2 files changed, 3 insertions(+), 28 deletions(-) diff --git a/base/subarray.jl b/base/subarray.jl index d6ddf7786f7ec..eacaddc068f1f 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -291,18 +291,18 @@ reindex(idxs::Tuple{Slice, Vararg{Any}}, subidxs::Tuple{Any, Vararg{Any}}) = # Re-index into parent vectors with one subindex reindex(idxs::Tuple{AbstractVector, Vararg{Any}}, subidxs::Tuple{Any, Vararg{Any}}) = - (@_propagate_inbounds_meta; (maybeview(idxs[1], subidxs[1]), reindex(tail(idxs), tail(subidxs))...)) + (@_propagate_inbounds_meta; (idxs[1][subidxs[1]], reindex(tail(idxs), tail(subidxs))...)) # Parent matrices are re-indexed with two sub-indices reindex(idxs::Tuple{AbstractMatrix, Vararg{Any}}, subidxs::Tuple{Any, Any, Vararg{Any}}) = - (@_propagate_inbounds_meta; (maybeview(idxs[1], subidxs[1], subidxs[2]), reindex(tail(idxs), tail(tail(subidxs)))...)) + (@_propagate_inbounds_meta; (idxs[1][subidxs[1], subidxs[2]], reindex(tail(idxs), tail(tail(subidxs)))...)) # In general, we index N-dimensional parent arrays with N indices @generated function reindex(idxs::Tuple{AbstractArray{T,N}, Vararg{Any}}, subidxs::Tuple{Vararg{Any}}) where {T,N} if length(subidxs.parameters) >= N subs = [:(subidxs[$d]) for d in 1:N] tail = [:(subidxs[$d]) for d in N+1:length(subidxs.parameters)] - :(@_propagate_inbounds_meta; (maybeview(idxs[1], $(subs...)), reindex(tail(idxs), ($(tail...),))...)) + :(@_propagate_inbounds_meta; (idxs[1][$(subs...)], reindex(tail(idxs), ($(tail...),))...)) else :(throw(ArgumentError("cannot re-index SubArray with fewer indices than dimensions\nThis should not occur; please submit a bug report."))) end diff --git a/test/subarray.jl b/test/subarray.jl index 818365730f079..a462224e7643a 100644 --- a/test/subarray.jl +++ b/test/subarray.jl @@ -1027,31 +1027,6 @@ catch err err isa ErrorException && startswith(err.msg, "syntax:") end - -@testset "avoid allocating in reindex" begin - a = reshape(1:16, 4, 4) - inds = ([2,3], [3,4]) - av = view(a, inds...) - av2 = view(av, 1, 1) - @test parentindices(av2) === (2,3) - av2 = view(av, 2:2, 2:2) - @test parentindices(av2) === (view(inds[1], 2:2), view(inds[2], 2:2)) - - inds = (reshape([eachindex(a);], size(a)),) - av = view(a, inds...) - av2 = view(av, 1, 1) - @test parentindices(av2) === (1,) - av2 = view(av, 2:2, 2:2) - @test parentindices(av2) === (view(inds[1], 2:2, 2:2),) - - inds = (reshape([eachindex(a);], size(a)..., 1),) - av = view(a, inds...) - av2 = view(av, 1, 1, 1) - @test parentindices(av2) === (1,) - av2 = view(av, 2:2, 2:2, 1:1) - @test parentindices(av2) === (view(inds[1], 2:2, 2:2, 1:1),) -end - @testset "isassigned" begin a = Vector{BigFloat}(undef, 5) a[2] = 0 From 1b0fba7ffd455d919f1c4f6bb8f31d7c4fae0cc0 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 14 Jan 2025 10:31:17 -0500 Subject: [PATCH 193/342] debuginfo: fix GC error in OC debuginfo (#57036) Also add some extra annotations that seemed to be required locally, though unrelated to the primary change. Observed on CI: https://buildkite.com/julialang/julia-master/builds/43693#01946057-7150-4741-a756-79e7d59a7717 Fixes #57042 --- src/aotcompile.cpp | 112 +++++++++++++++++++++++---------------------- src/debuginfo.cpp | 8 +++- src/jitlayers.cpp | 2 +- src/jitlayers.h | 11 +++-- 4 files changed, 72 insertions(+), 61 deletions(-) diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index b839ced8336da..0235758979cd1 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -2209,65 +2209,67 @@ void jl_get_llvmf_defn_impl(jl_llvmf_dump_t* dump, jl_method_instance_t *mi, jl_ if (src && jl_is_code_info(src)) { auto ctx = jl_ExecutionEngine->makeContext(); orc::ThreadSafeModule m = jl_create_ts_module(name_from_method_instance(mi), ctx); - uint64_t compiler_start_time = 0; - uint8_t measure_compile_time_enabled = jl_atomic_load_relaxed(&jl_measure_compile_time_enabled); - if (measure_compile_time_enabled) - compiler_start_time = jl_hrtime(); - auto target_info = m.withModuleDo([&](Module &M) { - return std::make_pair(M.getDataLayout(), Triple(M.getTargetTriple())); - }); - jl_codegen_params_t output(ctx, std::move(target_info.first), std::move(target_info.second)); - output.params = ¶ms; - output.imaging_mode = jl_options.image_codegen; - output.temporary_roots = jl_alloc_array_1d(jl_array_any_type, 0); - JL_GC_PUSH1(&output.temporary_roots); - auto decls = jl_emit_code(m, mi, src, NULL, output); - output.temporary_roots = nullptr; - JL_GC_POP(); // GC the global_targets array contents now since reflection doesn't need it - - Function *F = NULL; - if (m) { - // if compilation succeeded, prepare to return the result - // Similar to jl_link_global from jitlayers.cpp, - // so that code_llvm shows similar codegen to the jit - for (auto &global : output.global_targets) { - if (jl_options.image_codegen) { - global.second->setLinkage(GlobalValue::ExternalLinkage); + Function *F = nullptr; + { + uint64_t compiler_start_time = 0; + uint8_t measure_compile_time_enabled = jl_atomic_load_relaxed(&jl_measure_compile_time_enabled); + if (measure_compile_time_enabled) + compiler_start_time = jl_hrtime(); + auto target_info = m.withModuleDo([&](Module &M) { + return std::make_pair(M.getDataLayout(), Triple(M.getTargetTriple())); + }); + jl_codegen_params_t output(ctx, std::move(target_info.first), std::move(target_info.second)); + output.params = ¶ms; + output.imaging_mode = jl_options.image_codegen; + output.temporary_roots = jl_alloc_array_1d(jl_array_any_type, 0); + JL_GC_PUSH1(&output.temporary_roots); + auto decls = jl_emit_code(m, mi, src, NULL, output); + output.temporary_roots = nullptr; + JL_GC_POP(); // GC the global_targets array contents now since reflection doesn't need it + + if (m) { + // if compilation succeeded, prepare to return the result + // Similar to jl_link_global from jitlayers.cpp, + // so that code_llvm shows similar codegen to the jit + for (auto &global : output.global_targets) { + if (jl_options.image_codegen) { + global.second->setLinkage(GlobalValue::ExternalLinkage); + } + else { + auto p = literal_static_pointer_val(global.first, global.second->getValueType()); + Type *elty = PointerType::get(output.getContext(), 0); + // For pretty printing, when LLVM inlines the global initializer into its loads + auto alias = GlobalAlias::create(elty, 0, GlobalValue::PrivateLinkage, global.second->getName() + ".jit", p, global.second->getParent()); + global.second->setInitializer(ConstantExpr::getBitCast(alias, global.second->getValueType())); + global.second->setConstant(true); + global.second->setLinkage(GlobalValue::PrivateLinkage); + global.second->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); + global.second->setVisibility(GlobalValue::DefaultVisibility); + } } - else { - auto p = literal_static_pointer_val(global.first, global.second->getValueType()); - Type *elty = PointerType::get(output.getContext(), 0); - // For pretty printing, when LLVM inlines the global initializer into its loads - auto alias = GlobalAlias::create(elty, 0, GlobalValue::PrivateLinkage, global.second->getName() + ".jit", p, global.second->getParent()); - global.second->setInitializer(ConstantExpr::getBitCast(alias, global.second->getValueType())); - global.second->setConstant(true); - global.second->setLinkage(GlobalValue::PrivateLinkage); - global.second->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); - global.second->setVisibility(GlobalValue::DefaultVisibility); + if (!jl_options.image_codegen) { + optimizeDLSyms(*m.getModuleUnlocked()); } - } - if (!jl_options.image_codegen) { - optimizeDLSyms(*m.getModuleUnlocked()); - } - assert(!verifyLLVMIR(*m.getModuleUnlocked())); - if (optimize) { - NewPM PM{jl_ExecutionEngine->cloneTargetMachine(), getOptLevel(jl_options.opt_level)}; - //Safe b/c context lock is held by output - PM.run(*m.getModuleUnlocked()); assert(!verifyLLVMIR(*m.getModuleUnlocked())); + if (optimize) { + NewPM PM{jl_ExecutionEngine->cloneTargetMachine(), getOptLevel(jl_options.opt_level)}; + //Safe b/c context lock is held by output + PM.run(*m.getModuleUnlocked()); + assert(!verifyLLVMIR(*m.getModuleUnlocked())); + } + const std::string *fname; + if (decls.functionObject == "jl_fptr_args" || decls.functionObject == "jl_fptr_sparam") + getwrapper = false; + if (!getwrapper) + fname = &decls.specFunctionObject; + else + fname = &decls.functionObject; + F = cast(m.getModuleUnlocked()->getNamedValue(*fname)); + } + if (measure_compile_time_enabled) { + auto end = jl_hrtime(); + jl_atomic_fetch_add_relaxed(&jl_cumulative_compile_time, end - compiler_start_time); } - const std::string *fname; - if (decls.functionObject == "jl_fptr_args" || decls.functionObject == "jl_fptr_sparam") - getwrapper = false; - if (!getwrapper) - fname = &decls.specFunctionObject; - else - fname = &decls.functionObject; - F = cast(m.getModuleUnlocked()->getNamedValue(*fname)); - } - if (measure_compile_time_enabled) { - auto end = jl_hrtime(); - jl_atomic_fetch_add_relaxed(&jl_cumulative_compile_time, end - compiler_start_time); } if (F) { dump->TSM = wrap(new orc::ThreadSafeModule(std::move(m))); diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index c16fb559a6516..17e093cecb89a 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -162,14 +162,18 @@ static void jl_profile_atomic(T f) JL_NOTSAFEPOINT // --- storing and accessing source location metadata --- -void jl_add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL) +void jl_add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL) JL_NOTSAFEPOINT_LEAVE JL_NOTSAFEPOINT_ENTER { // Non-opaque-closure MethodInstances are considered globally rooted // through their methods, but for OC, we need to create a global root // here. jl_method_instance_t *mi = jl_get_ci_mi(codeinst); - if (jl_is_method(mi->def.value) && mi->def.method->is_for_opaque_closure) + if (jl_is_method(mi->def.value) && mi->def.method->is_for_opaque_closure) { + jl_task_t *ct = jl_current_task; + int8_t gc_state = jl_gc_unsafe_enter(ct->ptls); jl_as_global_root((jl_value_t*)mi, 1); + jl_gc_unsafe_leave(ct->ptls, gc_state); + } getJITDebugRegistry().add_code_in_flight(name, codeinst, DL); } diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 396a42505188a..0acb7beaca9ab 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -699,7 +699,7 @@ static void jl_compile_codeinst_now(jl_code_instance_t *codeinst) } } -void jl_add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL); +void jl_add_code_in_flight(StringRef name, jl_code_instance_t *codeinst, const DataLayout &DL) JL_NOTSAFEPOINT_LEAVE JL_NOTSAFEPOINT_ENTER; extern "C" JL_DLLEXPORT_CODEGEN void jl_emit_codeinst_to_jit_impl( diff --git a/src/jitlayers.h b/src/jitlayers.h index b41f2e38bc470..7198c9b2f0210 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -178,10 +178,15 @@ struct jl_locked_stream { } }; -typedef struct _jl_llvm_functions_t { +struct jl_llvm_functions_t { std::string functionObject; // jlcall llvm Function name std::string specFunctionObject; // specialized llvm Function name -} jl_llvm_functions_t; + jl_llvm_functions_t() JL_NOTSAFEPOINT = default; + jl_llvm_functions_t &operator=(const jl_llvm_functions_t&) JL_NOTSAFEPOINT = default; + jl_llvm_functions_t(const jl_llvm_functions_t &) JL_NOTSAFEPOINT = default; + jl_llvm_functions_t(jl_llvm_functions_t &&) JL_NOTSAFEPOINT = default; + ~jl_llvm_functions_t() JL_NOTSAFEPOINT = default; +}; struct jl_returninfo_t { llvm::FunctionCallee decl; @@ -642,7 +647,7 @@ Module &jl_codegen_params_t::shared_module() JL_NOTSAFEPOINT { } void fixupTM(TargetMachine &TM) JL_NOTSAFEPOINT; -void optimizeDLSyms(Module &M); +void optimizeDLSyms(Module &M) JL_NOTSAFEPOINT_LEAVE JL_NOTSAFEPOINT_ENTER; // NewPM #include "passes.h" From 1f05953fab1e14e1e881a224d8719d2c7d637da3 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 14 Jan 2025 10:33:09 -0500 Subject: [PATCH 194/342] linux: workaround to avoid deadlock inside dl_iterate_phdr in glibc (#57035) Extend the fix for #43578 on Darwin to also cover the same bug in Glibc (and just assume other libc have the same bug). We cannot use the same atfork trick, since the atfork implementation of this in Glibc makes this unsafe to use this after fork, just like Darwin (though for different basic concurrency mistakes in each of their respective codes). Fix #57017 --- src/julia_internal.h | 3 +- src/signals-mach.c | 9 +-- src/signals-unix.c | 186 +++++++++++++++++++++++-------------------- src/signals-win.c | 19 +++-- src/stackwalk.c | 18 ++++- 5 files changed, 130 insertions(+), 105 deletions(-) diff --git a/src/julia_internal.h b/src/julia_internal.h index 81e9ebb537667..a464025edf856 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -208,8 +208,7 @@ JL_DLLEXPORT void jl_lock_profile(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER; JL_DLLEXPORT void jl_unlock_profile(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE; JL_DLLEXPORT void jl_lock_profile_wr(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER; JL_DLLEXPORT void jl_unlock_profile_wr(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE; -int jl_lock_stackwalk(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER; -void jl_unlock_stackwalk(int lockret) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE; +void jl_with_stackwalk_lock(void (*f)(void*) JL_NOTSAFEPOINT, void *ctx) JL_NOTSAFEPOINT; arraylist_t *jl_get_all_tasks_arraylist(void) JL_NOTSAFEPOINT; typedef struct { diff --git a/src/signals-mach.c b/src/signals-mach.c index 24508a8902d5e..1c4af2cf9d033 100644 --- a/src/signals-mach.c +++ b/src/signals-mach.c @@ -714,13 +714,10 @@ static void jl_unlock_profile_mach(int dlsymlock, int keymgr_locked) jl_unlock_profile(); } -int jl_lock_stackwalk(void) -{ - return jl_lock_profile_mach(1); -} - -void jl_unlock_stackwalk(int lockret) +void jl_with_stackwalk_lock(void (*f)(void*), void *ctx) { + int lockret = jl_lock_profile_mach(1); + f(ctx); jl_unlock_profile_mach(1, lockret); } diff --git a/src/signals-unix.c b/src/signals-unix.c index 394c4a108b647..91d3378068f84 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -308,20 +308,27 @@ int exc_reg_is_write_fault(uintptr_t esr) { #else #include #include +#include -int jl_lock_stackwalk(void) +typedef struct { + void (*f)(void*) JL_NOTSAFEPOINT; + void *ctx; +} callback_t; +static int with_dl_iterate_phdr_lock(struct dl_phdr_info *info, size_t size, void *data) { jl_lock_profile(); - return 0; + callback_t *callback = (callback_t*)data; + callback->f(callback->ctx); + jl_unlock_profile(); + return 1; // only call this once } -void jl_unlock_stackwalk(int lockret) +void jl_with_stackwalk_lock(void (*f)(void*), void *ctx) { - (void)lockret; - jl_unlock_profile(); + callback_t callback = {f, ctx}; + dl_iterate_phdr(with_dl_iterate_phdr_lock, &callback); } - #if defined(_OS_LINUX_) && (defined(_CPU_X86_64_) || defined(_CPU_X86_)) int is_write_fault(void *context) { ucontext_t *ctx = (ucontext_t*)context; @@ -435,7 +442,7 @@ JL_NO_ASAN static void segv_handler(int sig, siginfo_t *info, void *context) } pthread_mutex_t in_signal_lock; // shared with jl_delete_thread -static bt_context_t *signal_context; // protected by in_signal_lock +static bt_context_t *usr2_signal_context; // protected by in_signal_lock static int exit_signal_cond = -1; static int signal_caught_cond = -1; static int signals_inflight = 0; @@ -507,7 +514,7 @@ int jl_thread_suspend_and_get_state(int tid, int timeout, bt_context_t *ctx) request = jl_atomic_load_acquire(&ptls2->signal_request); assert(request == 0 || request == -1); (void) request; jl_atomic_store_release(&ptls2->signal_request, 4); // prepare to resume normally, but later code may change this - *ctx = *signal_context; + *ctx = *usr2_signal_context; return 1; } @@ -587,8 +594,8 @@ void usr2_handler(int sig, siginfo_t *info, void *ctx) if (!jl_atomic_cmpswap(&ptls->signal_request, &request, -1)) return; if (request == 1) { - signal_context = jl_to_bt_context(ctx); - // acknowledge that we saw the signal_request and set signal_context + usr2_signal_context = jl_to_bt_context(ctx); + // acknowledge that we saw the signal_request and set usr2_signal_context int err; eventfd_t got = 1; err = write(signal_caught_cond, &got, sizeof(eventfd_t)); @@ -602,7 +609,7 @@ void usr2_handler(int sig, siginfo_t *info, void *ctx) if (err != sizeof(eventfd_t)) abort(); assert(got == 1); request = jl_atomic_exchange(&ptls->signal_request, -1); - signal_context = NULL; + usr2_signal_context = NULL; assert(request == 2 || request == 3 || request == 4); } int err; @@ -806,7 +813,7 @@ void trigger_profile_peek(void) jl_safe_printf("\n======================================================================================\n"); jl_safe_printf("Information request received. A stacktrace will print followed by a %.1f second profile\n", profile_peek_duration); jl_safe_printf("======================================================================================\n"); - if (profile_bt_size_max == 0){ + if (profile_bt_size_max == 0) { // If the buffer hasn't been initialized, initialize with default size // Keep these values synchronized with Profile.default_init() if (jl_profile_init(10000000, 1000000) == -1) { @@ -821,59 +828,93 @@ void trigger_profile_peek(void) profile_autostop_time = jl_hrtime() + (profile_peek_duration * 1e9); } -// assumes holding `jl_lock_stackwalk` -void jl_profile_thread_unix(int tid, bt_context_t *signal_context) +#if !defined(JL_DISABLE_LIBUNWIND) + +static jl_bt_element_t signal_bt_data[JL_MAX_BT_SIZE + 1]; +static size_t signal_bt_size = 0; +static void do_critical_profile(void *ctx) { - if (jl_profile_is_buffer_full()) { - // Buffer full: Delete the timer - jl_profile_stop_timer(); - return; - } - // notify thread to stop - if (!jl_thread_suspend_and_get_state(tid, 1, signal_context)) - return; - // unwinding can fail, so keep track of the current state - // and restore from the SEGV handler if anything happens. - jl_jmp_buf *old_buf = jl_get_safe_restore(); - jl_jmp_buf buf; - - jl_set_safe_restore(&buf); - if (jl_setjmp(buf, 0)) { - jl_safe_printf("WARNING: profiler attempt to access an invalid memory location\n"); - } else { - // Get backtrace data - profile_bt_size_cur += rec_backtrace_ctx((jl_bt_element_t*)profile_bt_data_prof + profile_bt_size_cur, - profile_bt_size_max - profile_bt_size_cur - 1, signal_context, NULL); + bt_context_t signal_context; + // sample each thread, round-robin style in reverse order + // (so that thread zero gets notified last) + int nthreads = jl_atomic_load_acquire(&jl_n_threads); + for (int i = nthreads; i-- > 0; ) { + // notify thread to stop + if (!jl_thread_suspend_and_get_state(i, 1, &signal_context)) + continue; + + // do backtrace on thread contexts for critical signals + // this part must be signal-handler safe + signal_bt_size += rec_backtrace_ctx(signal_bt_data + signal_bt_size, + JL_MAX_BT_SIZE / nthreads - 1, + &signal_context, NULL); + signal_bt_data[signal_bt_size++].uintptr = 0; + jl_thread_resume(i); } - jl_set_safe_restore(old_buf); +} - jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[tid]; +static void do_profile(void *ctx) +{ + bt_context_t signal_context; + int nthreads = jl_atomic_load_acquire(&jl_n_threads); + int *randperm = profile_get_randperm(nthreads); + for (int idx = nthreads; idx-- > 0; ) { + // Stop the threads in the random order. + int tid = randperm[idx]; + // do backtrace for profiler + if (!profile_running) + return; + if (jl_profile_is_buffer_full()) { + // Buffer full: Delete the timer + jl_profile_stop_timer(); + return; + } + // notify thread to stop + if (!jl_thread_suspend_and_get_state(tid, 1, &signal_context)) + return; + // unwinding can fail, so keep track of the current state + // and restore from the SEGV handler if anything happens. + jl_jmp_buf *old_buf = jl_get_safe_restore(); + jl_jmp_buf buf; + + jl_set_safe_restore(&buf); + if (jl_setjmp(buf, 0)) { + jl_safe_printf("WARNING: profiler attempt to access an invalid memory location\n"); + } + else { + // Get backtrace data + profile_bt_size_cur += rec_backtrace_ctx((jl_bt_element_t*)profile_bt_data_prof + profile_bt_size_cur, + profile_bt_size_max - profile_bt_size_cur - 1, &signal_context, NULL); + } + jl_set_safe_restore(old_buf); - // store threadid but add 1 as 0 is preserved to indicate end of block - profile_bt_data_prof[profile_bt_size_cur++].uintptr = ptls2->tid + 1; + jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[tid]; - // store task id (never null) - profile_bt_data_prof[profile_bt_size_cur++].jlvalue = (jl_value_t*)jl_atomic_load_relaxed(&ptls2->current_task); + // store threadid but add 1 as 0 is preserved to indicate end of block + profile_bt_data_prof[profile_bt_size_cur++].uintptr = ptls2->tid + 1; - // store cpu cycle clock - profile_bt_data_prof[profile_bt_size_cur++].uintptr = cycleclock(); + // store task id (never null) + profile_bt_data_prof[profile_bt_size_cur++].jlvalue = (jl_value_t*)jl_atomic_load_relaxed(&ptls2->current_task); - // store whether thread is sleeping (don't ever encode a state as `0` since is preserved to indicate end of block) - int state = jl_atomic_load_relaxed(&ptls2->sleep_check_state) == 0 ? PROFILE_STATE_THREAD_NOT_SLEEPING : PROFILE_STATE_THREAD_SLEEPING; - profile_bt_data_prof[profile_bt_size_cur++].uintptr = state; + // store cpu cycle clock + profile_bt_data_prof[profile_bt_size_cur++].uintptr = cycleclock(); - // Mark the end of this block with two 0's - profile_bt_data_prof[profile_bt_size_cur++].uintptr = 0; - profile_bt_data_prof[profile_bt_size_cur++].uintptr = 0; + // store whether thread is sleeping (don't ever encode a state as `0` since is preserved to indicate end of block) + int state = jl_atomic_load_relaxed(&ptls2->sleep_check_state) == 0 ? PROFILE_STATE_THREAD_NOT_SLEEPING : PROFILE_STATE_THREAD_SLEEPING; + profile_bt_data_prof[profile_bt_size_cur++].uintptr = state; - // notify thread to resume - jl_thread_resume(tid); + // Mark the end of this block with two 0's + profile_bt_data_prof[profile_bt_size_cur++].uintptr = 0; + profile_bt_data_prof[profile_bt_size_cur++].uintptr = 0; + + // notify thread to resume + jl_thread_resume(tid); + } } +#endif static void *signal_listener(void *arg) { - static jl_bt_element_t bt_data[JL_MAX_BT_SIZE + 1]; - static size_t bt_size = 0; sigset_t sset; int sig, critical, profile; jl_sigsetset(&sset); @@ -1005,28 +1046,10 @@ static void *signal_listener(void *arg) } } - int nthreads = jl_atomic_load_acquire(&jl_n_threads); - bt_size = 0; + signal_bt_size = 0; #if !defined(JL_DISABLE_LIBUNWIND) - bt_context_t signal_context; if (critical) { - int lockret = jl_lock_stackwalk(); - // sample each thread, round-robin style in reverse order - // (so that thread zero gets notified last) - for (int i = nthreads; i-- > 0; ) { - // notify thread to stop - if (!jl_thread_suspend_and_get_state(i, 1, &signal_context)) - continue; - - // do backtrace on thread contexts for critical signals - // this part must be signal-handler safe - bt_size += rec_backtrace_ctx(bt_data + bt_size, - JL_MAX_BT_SIZE / nthreads - 1, - &signal_context, NULL); - bt_data[bt_size++].uintptr = 0; - jl_thread_resume(i); - } - jl_unlock_stackwalk(lockret); + jl_with_stackwalk_lock(do_critical_profile, NULL); } else if (profile) { if (profile_all_tasks) { @@ -1034,17 +1057,7 @@ static void *signal_listener(void *arg) jl_profile_task(); } else { - int lockret = jl_lock_stackwalk(); - int *randperm = profile_get_randperm(nthreads); - for (int idx = nthreads; idx-- > 0; ) { - // Stop the threads in the random order. - int i = randperm[idx]; - // do backtrace for profiler - if (profile_running) { - jl_profile_thread_unix(i, &signal_context); - } - } - jl_unlock_stackwalk(lockret); + jl_with_stackwalk_lock(do_profile, NULL); } } #ifndef HAVE_MACH @@ -1065,11 +1078,12 @@ static void *signal_listener(void *arg) //#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L && !HAVE_KEVENT // si_code = info.si_code; //#endif - jl_exit_thread0(sig, bt_data, bt_size); + jl_exit_thread0(sig, signal_bt_data, signal_bt_size); } else if (critical) { // critical in this case actually means SIGINFO request #ifndef SIGINFO // SIGINFO already prints something similar automatically + int nthreads = jl_atomic_load_acquire(&jl_n_threads); int n_threads_running = 0; for (int idx = nthreads; idx-- > 0; ) { jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[idx]; @@ -1080,8 +1094,8 @@ static void *signal_listener(void *arg) jl_safe_printf("\nsignal (%d): %s\n", sig, strsignal(sig)); 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); + 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); } } } diff --git a/src/signals-win.c b/src/signals-win.c index dbf95fdb19791..c8ae74f52dba4 100644 --- a/src/signals-win.c +++ b/src/signals-win.c @@ -383,20 +383,25 @@ void jl_thread_resume(int tid) } } -int jl_lock_stackwalk(void) +void jl_lock_stackwalk(void) { uv_mutex_lock(&jl_in_stackwalk); jl_lock_profile(); - return 0; } -void jl_unlock_stackwalk(int lockret) +void jl_unlock_stackwalk(void) { - (void)lockret; jl_unlock_profile(); uv_mutex_unlock(&jl_in_stackwalk); } +void jl_with_stackwalk_lock(void (*f)(void*), void *ctx) +{ + jl_lock_stackwalk(); + f(ctx); + jl_unlock_stackwalk(); +} + static DWORD WINAPI profile_bt( LPVOID lparam ) { @@ -416,10 +421,10 @@ static DWORD WINAPI profile_bt( LPVOID lparam ) } else { // TODO: bring this up to parity with other OS by adding loop over tid here - int lockret = jl_lock_stackwalk(); + jl_lock_stackwalk(); CONTEXT ctxThread; if (!jl_thread_suspend_and_get_state(0, 0, &ctxThread)) { - jl_unlock_stackwalk(lockret); + jl_unlock_stackwalk(); fputs("failed to suspend main thread. aborting profiling.", stderr); jl_profile_stop_timer(); break; @@ -446,7 +451,7 @@ static DWORD WINAPI profile_bt( LPVOID lparam ) // Mark the end of this block with two 0's profile_bt_data_prof[profile_bt_size_cur++].uintptr = 0; profile_bt_data_prof[profile_bt_size_cur++].uintptr = 0; - jl_unlock_stackwalk(lockret); + jl_unlock_stackwalk(); jl_thread_resume(0); jl_check_profile_autostop(); } diff --git a/src/stackwalk.c b/src/stackwalk.c index 28adef030395e..f1d807908cf42 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -1249,6 +1249,17 @@ return 0; #endif } +typedef struct { + int16_t old; + bt_context_t *c; + int success; +} suspend_t; +static void suspend(void *ctx) +{ + suspend_t *suspenddata = (suspend_t*)ctx; + suspenddata->success = jl_thread_suspend_and_get_state(suspenddata->old, 1, suspenddata->c); +} + JL_DLLEXPORT jl_record_backtrace_result_t jl_record_backtrace(jl_task_t *t, jl_bt_element_t *bt_data, size_t max_bt_size, int all_tasks_profiler) JL_NOTSAFEPOINT { int16_t tid = INT16_MAX; @@ -1270,15 +1281,14 @@ JL_DLLEXPORT jl_record_backtrace_result_t jl_record_backtrace(jl_task_t *t, jl_b bt_context_t c; int16_t old; for (old = -1; !jl_atomic_cmpswap(&t->tid, &old, tid) && old != tid; old = -1) { - int lockret = jl_lock_stackwalk(); // if this task is already running somewhere, we need to stop the thread it is running on and query its state - if (!jl_thread_suspend_and_get_state(old, 1, &c)) { - jl_unlock_stackwalk(lockret); + suspend_t suspenddata = {old, &c}; + jl_with_stackwalk_lock(suspend, &suspenddata); + if (!suspenddata.success) { if (jl_atomic_load_relaxed(&t->tid) != old) continue; return result; } - jl_unlock_stackwalk(lockret); if (jl_atomic_load_relaxed(&t->tid) == old) { jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[old]; if (ptls2->previous_task == t || // we might print the wrong stack here, since we can't know whether we executed the swapcontext yet or not, but it at least avoids trying to access the state inside uc_mcontext which might not be set yet From 723c3e603c8b19e471b2f773047c9432471f0e68 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Wed, 15 Jan 2025 03:52:45 +0900 Subject: [PATCH 195/342] improve pcre.jl code a bit (#57031) - `PCRE._mth()` now uses `Base._maxthreadid` instead of manual inlining of `Threads.maxthreadid()` - `PCRE_COMPILE_LOCK` is now typed global --- base/Base.jl | 12 ++++++------ base/pcre.jl | 8 ++++---- base/regex.jl | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/base/Base.jl b/base/Base.jl index 1f737452fa17a..9119b3a482242 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -91,6 +91,12 @@ include("osutils.jl") include("io.jl") include("iobuffer.jl") +# Concurrency (part 1) +include("linked_list.jl") +include("condition.jl") +include("threads.jl") +include("lock.jl") + # strings & printing include("intfuncs.jl") include("strings/strings.jl") @@ -117,12 +123,6 @@ include("missing.jl") # version include("version.jl") -# Concurrency (part 1) -include("linked_list.jl") -include("condition.jl") -include("threads.jl") -include("lock.jl") - # system & environment include("sysinfo.jl") include("libc.jl") diff --git a/base/pcre.jl b/base/pcre.jl index b357bbc8f3bf9..e4567fe03e8f8 100644 --- a/base/pcre.jl +++ b/base/pcre.jl @@ -24,19 +24,19 @@ function create_match_context() return ctx end -THREAD_MATCH_CONTEXTS::Vector{Ptr{Cvoid}} = [C_NULL] +global THREAD_MATCH_CONTEXTS::Vector{Ptr{Cvoid}} = [C_NULL] -PCRE_COMPILE_LOCK = nothing +global PCRE_COMPILE_LOCK::Threads.SpinLock _tid() = Int(ccall(:jl_threadid, Int16, ())) + 1 -_mth() = Int(Core.Intrinsics.atomic_pointerref(cglobal(:jl_n_threads, Cint), :acquire)) +_mth() = Threads.maxthreadid() function get_local_match_context() tid = _tid() ctxs = THREAD_MATCH_CONTEXTS if length(ctxs) < tid # slow path to allocate it - l = PCRE_COMPILE_LOCK::Threads.SpinLock + l = PCRE_COMPILE_LOCK lock(l) try ctxs = THREAD_MATCH_CONTEXTS diff --git a/base/regex.jl b/base/regex.jl index 9444c9a9fb63e..09922b8a25111 100644 --- a/base/regex.jl +++ b/base/regex.jl @@ -69,11 +69,11 @@ Regex(pattern::AbstractString) = Regex(pattern, DEFAULT_COMPILER_OPTS, DEFAULT_M function compile(regex::Regex) if regex.regex == C_NULL - if PCRE.PCRE_COMPILE_LOCK === nothing + if !isdefinedglobal(PCRE, :PCRE_COMPILE_LOCK) regex.regex = PCRE.compile(regex.pattern, regex.compile_options) PCRE.jit_compile(regex.regex) else - l = PCRE.PCRE_COMPILE_LOCK::Threads.SpinLock + l = PCRE.PCRE_COMPILE_LOCK lock(l) try if regex.regex == C_NULL From 2cc296c8fd3cba6b7caa872d5fb13c947b190780 Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Tue, 14 Jan 2025 17:13:24 -0500 Subject: [PATCH 196/342] MozillaCACerts_jll: Update to 2024.12.31 (#57039) --- deps/checksums/cacert-2024-11-26.pem/md5 | 1 - deps/checksums/cacert-2024-11-26.pem/sha512 | 1 - deps/checksums/cacert-2024-12-31.pem/md5 | 1 + deps/checksums/cacert-2024-12-31.pem/sha512 | 1 + deps/libgit2.version | 2 +- stdlib/MozillaCACerts_jll/Project.toml | 2 +- 6 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 deps/checksums/cacert-2024-11-26.pem/md5 delete mode 100644 deps/checksums/cacert-2024-11-26.pem/sha512 create mode 100644 deps/checksums/cacert-2024-12-31.pem/md5 create mode 100644 deps/checksums/cacert-2024-12-31.pem/sha512 diff --git a/deps/checksums/cacert-2024-11-26.pem/md5 b/deps/checksums/cacert-2024-11-26.pem/md5 deleted file mode 100644 index 865c6abf3e77a..0000000000000 --- a/deps/checksums/cacert-2024-11-26.pem/md5 +++ /dev/null @@ -1 +0,0 @@ -92c13373d7dbe43bdc167479274a43e2 diff --git a/deps/checksums/cacert-2024-11-26.pem/sha512 b/deps/checksums/cacert-2024-11-26.pem/sha512 deleted file mode 100644 index d51605348faf4..0000000000000 --- a/deps/checksums/cacert-2024-11-26.pem/sha512 +++ /dev/null @@ -1 +0,0 @@ -26c6fa1ac7bcfd523f9ab9e6c2d971103ccfc610ad0df504d4e9b064dad74576d77240c052b808f4c37c9240302a7e973a20f79ee39ac7bf3201a6fa9f0dfa96 diff --git a/deps/checksums/cacert-2024-12-31.pem/md5 b/deps/checksums/cacert-2024-12-31.pem/md5 new file mode 100644 index 0000000000000..b01bf68ddc247 --- /dev/null +++ b/deps/checksums/cacert-2024-12-31.pem/md5 @@ -0,0 +1 @@ +d9178b626f8b87f51b47987418d012bf diff --git a/deps/checksums/cacert-2024-12-31.pem/sha512 b/deps/checksums/cacert-2024-12-31.pem/sha512 new file mode 100644 index 0000000000000..c12b8215a7855 --- /dev/null +++ b/deps/checksums/cacert-2024-12-31.pem/sha512 @@ -0,0 +1 @@ +bf578937d7826106bae1ebe74a70bfbc439387445a1f41ef57430de9d9aea6fcfa1884381bf0ef14632f6b89e9543642c9b774fcca93837efffdc557c4958dbd diff --git a/deps/libgit2.version b/deps/libgit2.version index 57744b6c96d8e..6bfb6106e67d2 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 := 2024-11-26 +MOZILLA_CACERT_VERSION := 2024-12-31 diff --git a/stdlib/MozillaCACerts_jll/Project.toml b/stdlib/MozillaCACerts_jll/Project.toml index 5df9bd5949972..2f9bf67e22a74 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 = "2024.11.26" +version = "2024.12.31" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" From ef0405584dd3280f8e23906d9eef8f8799a236f9 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Wed, 15 Jan 2025 18:13:44 +0900 Subject: [PATCH 197/342] aot: move `jl_insert_backedges` to Julia side (#56499) With JuliaLang/julia#56447, the dependency between `jl_insert_backedges` and method insertion has been eliminated, allowing `jl_insert_backedges` to be performed after loading. As a result, it is now possible to move `jl_insert_backedges` to the Julia side. Currently this commit simply moves the implementation without adding any new features. --------- Co-authored-by: Jameson Nash --- Compiler/src/typeinfer.jl | 5 +- base/Base.jl | 1 + base/loading.jl | 17 +- base/staticdata.jl | 296 +++++++++++++++++++++++++++++++ src/staticdata.c | 14 +- src/staticdata_utils.c | 362 -------------------------------------- test/precompile.jl | 12 +- 7 files changed, 323 insertions(+), 384 deletions(-) create mode 100644 base/staticdata.jl diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index ec1e62817106d..e3896870d82b8 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -560,12 +560,11 @@ function store_backedges(caller::CodeInstance, edges::SimpleVector) ccall(:jl_method_table_add_backedge, Cvoid, (Any, Any, Any), callee, item, caller) i += 2 continue - end - # `invoke` edge - if isa(callee, Method) + elseif isa(callee, Method) # ignore `Method`-edges (from e.g. failed `abstract_call_method`) i += 2 continue + # `invoke` edge elseif isa(callee, CodeInstance) callee = get_ci_mi(callee) end diff --git a/base/Base.jl b/base/Base.jl index 9119b3a482242..20b1636c29a8d 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -262,6 +262,7 @@ include("uuid.jl") include("pkgid.jl") include("toml_parser.jl") include("linking.jl") +include("staticdata.jl") include("loading.jl") # misc useful functions & macros diff --git a/base/loading.jl b/base/loading.jl index 024c4ceb356fd..4193aae13b96a 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -1280,17 +1280,20 @@ function _include_from_serialized(pkg::PkgId, path::String, ocachepath::Union{No sv = try if ocachepath !== nothing @debug "Loading object cache file $ocachepath for $(repr("text/plain", pkg))" - ccall(:jl_restore_package_image_from_file, Any, (Cstring, Any, Cint, Cstring, Cint), ocachepath, depmods, false, pkg.name, ignore_native) + ccall(:jl_restore_package_image_from_file, Ref{SimpleVector}, (Cstring, Any, Cint, Cstring, Cint), + ocachepath, depmods, #=completeinfo=#false, pkg.name, ignore_native) else @debug "Loading cache file $path for $(repr("text/plain", pkg))" - ccall(:jl_restore_incremental, Any, (Cstring, Any, Cint, Cstring), path, depmods, false, pkg.name) + ccall(:jl_restore_incremental, Ref{SimpleVector}, (Cstring, Any, Cint, Cstring), + path, depmods, #=completeinfo=#false, pkg.name) end finally lock(require_lock) end - if isa(sv, Exception) - return sv - end + + edges = sv[3]::Vector{Any} + ext_edges = sv[4]::Union{Nothing,Vector{Any}} + StaticData.insert_backedges(edges, ext_edges) restored = register_restored_modules(sv, pkg, path) @@ -4198,7 +4201,7 @@ function precompile(@nospecialize(argt::Type)) end # Variants that work for `invoke`d calls for which the signature may not be sufficient -precompile(mi::Core.MethodInstance, world::UInt=get_world_counter()) = +precompile(mi::MethodInstance, world::UInt=get_world_counter()) = (ccall(:jl_compile_method_instance, Cvoid, (Any, Ptr{Cvoid}, UInt), mi, C_NULL, world); return true) """ @@ -4214,7 +4217,7 @@ end function precompile(@nospecialize(argt::Type), m::Method) atype, sparams = ccall(:jl_type_intersection_with_env, Any, (Any, Any), argt, m.sig)::SimpleVector - mi = Core.Compiler.specialize_method(m, atype, sparams) + mi = Base.Compiler.specialize_method(m, atype, sparams) return precompile(mi) end diff --git a/base/staticdata.jl b/base/staticdata.jl new file mode 100644 index 0000000000000..79d81788cc16a --- /dev/null +++ b/base/staticdata.jl @@ -0,0 +1,296 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +module StaticData + +using Core: CodeInstance, MethodInstance +using Base: get_world_counter + +const WORLD_AGE_REVALIDATION_SENTINEL::UInt = 1 +const _jl_debug_method_invalidation = Ref{Union{Nothing,Vector{Any}}}(nothing) +debug_method_invalidation(onoff::Bool) = + _jl_debug_method_invalidation[] = onoff ? Any[] : nothing + +function get_ci_mi(codeinst::CodeInstance) + def = codeinst.def + if def isa Core.ABIOverride + return def.def + else + return def::MethodInstance + end +end + +# Restore backedges to external targets +# `edges` = [caller1, ...], the list of worklist-owned code instances internally +# `ext_ci_list` = [caller1, ...], the list of worklist-owned code instances externally +function insert_backedges(edges::Vector{Any}, ext_ci_list::Union{Nothing,Vector{Any}}) + # determine which CodeInstance objects are still valid in our image + # to enable any applicable new codes + stack = CodeInstance[] + visiting = IdDict{CodeInstance,Int}() + _insert_backedges(edges, stack, visiting) + if ext_ci_list !== nothing + _insert_backedges(ext_ci_list, stack, visiting, #=external=#true) + end +end + +function _insert_backedges(edges::Vector{Any}, stack::Vector{CodeInstance}, visiting::IdDict{CodeInstance,Int}, external::Bool=false) + for i = 1:length(edges) + codeinst = edges[i]::CodeInstance + verify_method_graph(codeinst, stack, visiting) + minvalid = codeinst.min_world + maxvalid = codeinst.max_world + if maxvalid ≥ minvalid + if get_world_counter() == maxvalid + # if this callee is still valid, add all the backedges + Base.Compiler.store_backedges(codeinst, codeinst.edges) + end + if get_world_counter() == maxvalid + maxvalid = typemax(UInt) + @atomic :monotonic codeinst.max_world = maxvalid + end + if external + caller = get_ci_mi(codeinst) + @assert isdefined(codeinst, :inferred) # See #53586, #53109 + inferred = @ccall jl_rettype_inferred( + codeinst.owner::Any, caller::Any, minvalid::UInt, maxvalid::UInt)::Any + if inferred !== nothing + # We already got a code instance for this world age range from + # somewhere else - we don't need this one. + else + @ccall jl_mi_cache_insert(caller::Any, codeinst::Any)::Cvoid + end + end + end + end +end + +function verify_method_graph(codeinst::CodeInstance, stack::Vector{CodeInstance}, visiting::IdDict{CodeInstance,Int}) + @assert isempty(stack); @assert isempty(visiting); + child_cycle, minworld, maxworld = verify_method(codeinst, stack, visiting) + @assert child_cycle == 0 + @assert isempty(stack); @assert isempty(visiting); + nothing +end + +# Test all edges relevant to a method: +# - Visit the entire call graph, starting from edges[idx] to determine if that method is valid +# - Implements Tarjan's SCC (strongly connected components) algorithm, simplified to remove the count variable +# and slightly modified with an early termination option once the computation reaches its minimum +function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visiting::IdDict{CodeInstance,Int}) + world = codeinst.min_world + let max_valid2 = codeinst.max_world + if max_valid2 ≠ WORLD_AGE_REVALIDATION_SENTINEL + return 0, world, max_valid2 + end + end + current_world = get_world_counter() + local minworld::UInt, maxworld::UInt = 1, current_world + @assert get_ci_mi(codeinst).def isa Method + if haskey(visiting, codeinst) + return visiting[codeinst], minworld, maxworld + end + push!(stack, codeinst) + depth = length(stack) + visiting[codeinst] = depth + # TODO JL_TIMING(VERIFY_IMAGE, VERIFY_Methods) + callees = codeinst.edges + # verify current edges + if isempty(callees) + # quick return: no edges to verify (though we probably shouldn't have gotten here from WORLD_AGE_REVALIDATION_SENTINEL) + elseif maxworld == unsafe_load(cglobal(:jl_require_world, UInt)) + # if no new worlds were allocated since serializing the base module, then no new validation is worth doing right now either + minworld = maxworld + else + j = 1 + while j ≤ length(callees) + local min_valid2::UInt, max_valid2::UInt + edge = callees[j] + @assert !(edge isa Method) # `Method`-edge isn't allowed for the optimized one-edge format + if edge isa Core.BindingPartition + j += 1 + continue + end + if edge isa CodeInstance + edge = get_ci_mi(edge) + end + if edge isa MethodInstance + sig = typeintersect((edge.def::Method).sig, edge.specTypes) # TODO?? + min_valid2, max_valid2, matches = verify_call(sig, callees, j, 1, world) + j += 1 + elseif edge isa Int + sig = callees[j+1] + min_valid2, max_valid2, matches = verify_call(sig, callees, j+2, edge, world) + j += 2 + edge + edge = sig + else + callee = callees[j+1] + if callee isa Core.MethodTable # skip the legacy edge (missing backedge) + j += 2 + continue + end + if callee isa CodeInstance + callee = get_ci_mi(callee) + end + if callee isa MethodInstance + meth = callee.def::Method + else + meth = callee::Method + end + min_valid2, max_valid2 = verify_invokesig(edge, meth, world) + matches = nothing + j += 2 + end + if minworld < min_valid2 + minworld = min_valid2 + end + if maxworld > max_valid2 + maxworld = max_valid2 + end + invalidations = _jl_debug_method_invalidation[] + if max_valid2 ≠ typemax(UInt) && invalidations !== nothing + push!(invalidations, edge, "insert_backedges_callee", codeinst, matches) + end + if max_valid2 == 0 && invalidations === nothing + break + end + end + end + # verify recursive edges (if valid, or debugging) + cycle = depth + cause = codeinst + if maxworld ≠ 0 || _jl_debug_method_invalidation[] !== nothing + for j = 1:length(callees) + edge = callees[j] + if !(edge isa CodeInstance) + continue + end + callee = edge + local min_valid2::UInt, max_valid2::UInt + child_cycle, min_valid2, max_valid2 = verify_method(callee, stack, visiting) + if minworld < min_valid2 + minworld = min_valid2 + end + if minworld > max_valid2 + max_valid2 = 0 + end + if maxworld > max_valid2 + cause = callee + maxworld = max_valid2 + end + if max_valid2 == 0 + # found what we were looking for, so terminate early + break + elseif child_cycle ≠ 0 && child_cycle < cycle + # record the cycle will resolve at depth "cycle" + cycle = child_cycle + end + end + end + if maxworld ≠ 0 && cycle ≠ depth + return cycle, minworld, maxworld + end + # If we are the top of the current cycle, now mark all other parts of + # our cycle with what we found. + # Or if we found a failed edge, also mark all of the other parts of the + # cycle as also having a failed edge. + while length(stack) ≥ depth + child = pop!(stack) + if maxworld ≠ 0 + @atomic :monotonic child.min_world = minworld + end + @atomic :monotonic child.max_world = maxworld + @assert visiting[child] == length(stack) + 1 + delete!(visiting, child) + invalidations = _jl_debug_method_invalidation[] + if invalidations !== nothing && maxworld < current_world + push!(invalidations, child, "verify_methods", cause) + end + end + return 0, minworld, maxworld +end + +function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n::Int, world::UInt) + # verify that these edges intersect with the same methods as before + lim = _jl_debug_method_invalidation[] !== nothing ? Int(typemax(Int32)) : n + minworld = Ref{UInt}(1) + maxworld = Ref{UInt}(typemax(UInt)) + has_ambig = Ref{Int32}(0) + result = Base._methods_by_ftype(sig, nothing, lim, world, #=ambig=#false, minworld, maxworld, has_ambig) + if result === nothing + maxworld[] = 0 + else + # setdiff!(result, expected) + if length(result) ≠ n + maxworld[] = 0 + end + ins = 0 + for k = 1:length(result) + match = result[k]::Core.MethodMatch + local found = false + for j = 1:n + t = expecteds[i+j-1] + if t isa Method + meth = t + else + if t isa CodeInstance + t = get_ci_mi(t) + else + t = t::MethodInstance + end + meth = t.def::Method + end + if match.method == meth + found = true + break + end + end + if !found + # intersection has a new method or a method was + # deleted--this is now probably no good, just invalidate + # everything about it now + maxworld[] = 0 + if _jl_debug_method_invalidation[] === nothing + break + end + ins += 1 + result[ins] = match.method + end + end + if maxworld[] ≠ typemax(UInt) && _jl_debug_method_invalidation[] !== nothing + resize!(result, ins) + end + end + return minworld[], maxworld[], result +end + +function verify_invokesig(@nospecialize(invokesig), expected::Method, world::UInt) + @assert invokesig isa Type + local minworld::UInt, maxworld::UInt + if invokesig === expected.sig + # the invoke match is `expected` for `expected->sig`, unless `expected` is invalid + minworld = expected.primary_world + maxworld = expected.deleted_world + @assert minworld ≤ world + if maxworld < world + maxworld = 0 + end + else + minworld = 1 + maxworld = typemax(UInt) + mt = Base.get_methodtable(expected) + if mt === nothing + maxworld = 0 + else + matched, valid_worlds = Base.Compiler._findsup(invokesig, mt, world) + minworld, maxworld = valid_worlds.min_world, valid_worlds.max_world + if matched === nothing + maxworld = 0 + elseif matched.method != expected + maxworld = 0 + end + end + end + return minworld, maxworld +end + +end # module StaticData diff --git a/src/staticdata.c b/src/staticdata.c index 4124d3b481bb3..7fad87652b26a 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -89,7 +89,7 @@ External links: #include "julia_assert.h" static const size_t WORLD_AGE_REVALIDATION_SENTINEL = 0x1; -size_t jl_require_world = ~(size_t)0; +JL_DLLEXPORT size_t jl_require_world = ~(size_t)0; #include "staticdata_utils.c" #include "precompile_utils.c" @@ -4110,12 +4110,13 @@ static jl_value_t *jl_restore_package_image_from_stream(void* pkgimage_handle, i jl_atomic_store_release(&jl_world_counter, world); // now permit more methods to be added again JL_UNLOCK(&world_counter_lock); - // but one of those immediate users is going to be our cache insertions - jl_insert_backedges((jl_array_t*)edges, (jl_array_t*)new_ext_cis); // restore existing caches (needs to be last) + // reinit ccallables jl_reinit_ccallable(&ccallable_list, base, pkgimage_handle); arraylist_free(&ccallable_list); + jl_value_t *ext_edges = new_ext_cis ? (jl_value_t*)new_ext_cis : jl_nothing; + if (completeinfo) { cachesizes_sv = jl_alloc_svec(7); jl_svecset(cachesizes_sv, 0, jl_box_long(cachesizes.sysdata)); @@ -4125,12 +4126,11 @@ static jl_value_t *jl_restore_package_image_from_stream(void* pkgimage_handle, i jl_svecset(cachesizes_sv, 4, jl_box_long(cachesizes.reloclist)); jl_svecset(cachesizes_sv, 5, jl_box_long(cachesizes.gvarlist)); jl_svecset(cachesizes_sv, 6, jl_box_long(cachesizes.fptrlist)); - restored = (jl_value_t*)jl_svec(7, restored, init_order, extext_methods, - new_ext_cis ? (jl_value_t*)new_ext_cis : jl_nothing, - method_roots_list, edges, cachesizes_sv); + restored = (jl_value_t*)jl_svec(7, restored, init_order, edges, ext_edges, + extext_methods, method_roots_list, cachesizes_sv); } else { - restored = (jl_value_t*)jl_svec(2, restored, init_order); + restored = (jl_value_t*)jl_svec(4, restored, init_order, edges, ext_edges); } } } diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index 79d2909970d99..1985357321a3a 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -750,368 +750,6 @@ static void jl_copy_roots(jl_array_t *method_roots_list, uint64_t key) } } -static void verify_invokesig(jl_value_t *invokesig, jl_method_t *expected, size_t world, size_t *minworld, size_t *maxworld) -{ - assert(jl_is_type(invokesig)); - assert(jl_is_method(expected)); - if (jl_egal(invokesig, expected->sig)) { - // the invoke match is `expected` for `expected->sig`, unless `expected` is invalid - *minworld = jl_atomic_load_relaxed(&expected->primary_world); - *maxworld = jl_atomic_load_relaxed(&expected->deleted_world); - assert(*minworld <= world); - if (*maxworld < world) - *maxworld = 0; - } - else { - *minworld = 1; - *maxworld = ~(size_t)0; - jl_methtable_t *mt = jl_method_get_table(expected); - if ((jl_value_t*)mt == jl_nothing) { - *maxworld = 0; - } - else { - jl_value_t *matches = jl_gf_invoke_lookup_worlds(invokesig, (jl_value_t*)mt, world, minworld, maxworld); - if (matches == jl_nothing) { - *maxworld = 0; - } - else { - if (((jl_method_match_t*)matches)->method != expected) { - *maxworld = 0; - } - } - } - } -} - -static void verify_call(jl_value_t *sig, jl_svec_t *expecteds, size_t i, size_t n, size_t world, size_t *minworld, size_t *maxworld, jl_value_t **matches JL_REQUIRE_ROOTED_SLOT) -{ - // verify that these edges intersect with the same methods as before - *minworld = 1; - *maxworld = ~(size_t)0; - int ambig = 0; - // TODO: possibly need to included ambiguities too (for the optimizer correctness)? - jl_value_t *result = jl_matching_methods((jl_tupletype_t*)sig, jl_nothing, - _jl_debug_method_invalidation ? INT32_MAX : n, - 0, world, minworld, maxworld, &ambig); - *matches = result; - if (result == jl_nothing) { - *maxworld = 0; - } - else { - // setdiff!(result, expected) - size_t j, k, ins = 0; - if (jl_array_nrows(result) != n) { - *maxworld = 0; - } - for (k = 0; k < jl_array_nrows(result); k++) { - jl_method_t *match = ((jl_method_match_t*)jl_array_ptr_ref(result, k))->method; - for (j = 0; j < n; j++) { - jl_value_t *t = jl_svecref(expecteds, j + i); - if (jl_is_code_instance(t)) - t = (jl_value_t*)((jl_code_instance_t*)t)->def; - jl_method_t *meth; - if (jl_is_method(t)) - meth = (jl_method_t*)t; - else { - assert(jl_is_method_instance(t)); - meth = ((jl_method_instance_t*)t)->def.method; - } - if (match == meth) - break; - } - if (j == n) { - // intersection has a new method or a method was - // deleted--this is now probably no good, just invalidate - // everything about it now - *maxworld = 0; - if (!_jl_debug_method_invalidation) - break; - jl_array_ptr_set(result, ins++, match); - } - } - if (*maxworld != ~(size_t)0 && _jl_debug_method_invalidation) - jl_array_del_end((jl_array_t*)result, jl_array_nrows(result) - ins); - } -} - -// Test all edges relevant to a method: -//// Visit the entire call graph, starting from edges[idx] to determine if that method is valid -//// Implements Tarjan's SCC (strongly connected components) algorithm, simplified to remove the count variable -//// and slightly modified with an early termination option once the computation reaches its minimum -static int jl_verify_method(jl_code_instance_t *codeinst, size_t *minworld, size_t *maxworld, arraylist_t *stack, htable_t *visiting) -{ - size_t world = jl_atomic_load_relaxed(&codeinst->min_world); - size_t max_valid2 = jl_atomic_load_relaxed(&codeinst->max_world); - if (max_valid2 != WORLD_AGE_REVALIDATION_SENTINEL) { - *minworld = world; - *maxworld = max_valid2; - return 0; - } - *minworld = 1; - size_t current_world = jl_atomic_load_relaxed(&jl_world_counter); - *maxworld = current_world; - assert(jl_is_method_instance(jl_get_ci_mi(codeinst)) && jl_is_method(jl_get_ci_mi(codeinst)->def.method)); - void **bp = ptrhash_bp(visiting, codeinst); - if (*bp != HT_NOTFOUND) - return (char*)*bp - (char*)HT_NOTFOUND; // cycle idx - arraylist_push(stack, (void*)codeinst); - size_t depth = stack->len; - *bp = (char*)HT_NOTFOUND + depth; - JL_TIMING(VERIFY_IMAGE, VERIFY_Methods); - jl_svec_t *callees = jl_atomic_load_relaxed(&codeinst->edges); - assert(jl_is_svec((jl_value_t*)callees)); - // verify current edges - if (callees == jl_emptysvec) { - // quick return: no edges to verify (though we probably shouldn't have gotten here from WORLD_AGE_REVALIDATION_SENTINEL) - } - else if (*maxworld == jl_require_world) { - // if no new worlds were allocated since serializing the base module, then no new validation is worth doing right now either - *minworld = *maxworld; - } - else { - jl_value_t *loctag = NULL; - jl_value_t *sig = NULL; - jl_value_t *matches = NULL; - JL_GC_PUSH3(&loctag, &matches, &sig); - for (size_t j = 0; j < jl_svec_len(callees); ) { - jl_value_t *edge = jl_svecref(callees, j); - size_t min_valid2; - size_t max_valid2; - assert(!jl_is_method(edge)); // `Method`-edge isn't allowed for the optimized one-edge format - if (jl_is_binding_partition(edge)) { - j += 1; - continue; - } - if (jl_is_code_instance(edge)) - edge = (jl_value_t*)jl_get_ci_mi((jl_code_instance_t*)edge); - if (jl_is_method_instance(edge)) { - jl_method_instance_t *mi = (jl_method_instance_t*)edge; - sig = jl_type_intersection(mi->def.method->sig, (jl_value_t*)mi->specTypes); // TODO: ?? - verify_call(sig, callees, j, 1, world, &min_valid2, &max_valid2, &matches); - sig = NULL; - j += 1; - } - else if (jl_is_long(edge)) { - jl_value_t *sig = jl_svecref(callees, j + 1); - size_t nedges = jl_unbox_long(edge); - verify_call(sig, callees, j + 2, nedges, world, &min_valid2, &max_valid2, &matches); - j += 2 + nedges; - edge = sig; - } - else { - jl_method_instance_t *callee = (jl_method_instance_t*)jl_svecref(callees, j + 1); - jl_method_t *meth; - if (jl_is_mtable(callee)) { - // skip the legacy edge (missing backedge) - j += 2; - continue; - } - if (jl_is_code_instance(callee)) - callee = jl_get_ci_mi((jl_code_instance_t*)callee); - if (jl_is_method_instance(callee)) { - meth = callee->def.method; - } - else { - assert(jl_is_method(callee)); - meth = (jl_method_t*)callee; - } - verify_invokesig(edge, meth, world, &min_valid2, &max_valid2); - j += 2; - } - if (*minworld < min_valid2) - *minworld = min_valid2; - if (*maxworld > max_valid2) - *maxworld = max_valid2; - if (max_valid2 != ~(size_t)0 && _jl_debug_method_invalidation) { - jl_array_ptr_1d_push(_jl_debug_method_invalidation, edge); - loctag = jl_cstr_to_string("insert_backedges_callee"); - jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag); - jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)codeinst); - jl_array_ptr_1d_push(_jl_debug_method_invalidation, matches); - } - //jl_static_show((JL_STREAM*)ios_stderr, (jl_value_t*)edge); - //ios_puts(max_valid2 == ~(size_t)0 ? "valid\n" : "INVALID\n", ios_stderr); - if (max_valid2 == 0 && !_jl_debug_method_invalidation) - break; - } - JL_GC_POP(); - } - // verify recursive edges (if valid, or debugging) - size_t cycle = depth; - jl_code_instance_t *cause = codeinst; - if (*maxworld != 0 || _jl_debug_method_invalidation) { - for (size_t j = 0; j < jl_svec_len(callees); j++) { - jl_value_t *edge = jl_svecref(callees, j); - if (!jl_is_code_instance(edge)) - continue; - jl_code_instance_t *callee = (jl_code_instance_t*)edge; - size_t min_valid2; - size_t max_valid2; - size_t child_cycle = jl_verify_method(callee, &min_valid2, &max_valid2, stack, visiting); - if (*minworld < min_valid2) - *minworld = min_valid2; - if (*minworld > max_valid2) - max_valid2 = 0; - if (*maxworld > max_valid2) { - cause = callee; - *maxworld = max_valid2; - } - if (max_valid2 == 0) { - // found what we were looking for, so terminate early - break; - } - else if (child_cycle && child_cycle < cycle) { - // record the cycle will resolve at depth "cycle" - cycle = child_cycle; - } - } - } - if (*maxworld != 0 && cycle != depth) - return cycle; - // If we are the top of the current cycle, now mark all other parts of - // our cycle with what we found. - // Or if we found a failed edge, also mark all of the other parts of the - // cycle as also having a failed edge. - while (stack->len >= depth) { - jl_code_instance_t *child = (jl_code_instance_t*)arraylist_pop(stack); - if (jl_atomic_load_relaxed(&jl_n_threads) == 1) { - // a different thread might simultaneously come to a different, but equally valid, alternative result - assert(jl_atomic_load_relaxed(&child->max_world) == WORLD_AGE_REVALIDATION_SENTINEL); - assert(*minworld <= jl_atomic_load_relaxed(&child->min_world)); - } - if (*maxworld != 0) - jl_atomic_store_relaxed(&child->min_world, *minworld); - jl_atomic_store_relaxed(&child->max_world, *maxworld); - void **bp = ptrhash_bp(visiting, child); - assert(*bp == (char*)HT_NOTFOUND + stack->len + 1); - *bp = HT_NOTFOUND; - if (_jl_debug_method_invalidation && *maxworld < current_world) { - jl_value_t *loctag; - jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)child); - loctag = jl_cstr_to_string("verify_methods"); - JL_GC_PUSH1(&loctag); - jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag); - jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)cause); - JL_GC_POP(); - } - } - //jl_static_show((JL_STREAM*)ios_stderr, (jl_value_t*)codeinst->def); - //ios_puts(max_valid == ~(size_t)0 ? "valid\n\n" : "INVALID\n\n", ios_stderr); - return 0; -} - -static void jl_verify_method_graph(jl_code_instance_t *codeinst, arraylist_t *stack, htable_t *visiting) -{ - size_t minworld; - size_t maxworld; - assert(stack->len == 0); - for (size_t i = 0, hsz = visiting->size; i < hsz; i++) - assert(visiting->table[i] == HT_NOTFOUND); - int child_cycle = jl_verify_method(codeinst, &minworld, &maxworld, stack, visiting); - assert(child_cycle == 0); (void)child_cycle; - assert(stack->len == 0); - for (size_t i = 0, hsz = visiting->size / 2; i < hsz; i++) { - assert(visiting->table[2 * i + 1] == HT_NOTFOUND); - visiting->table[2 * i] = HT_NOTFOUND; - } - if (jl_atomic_load_relaxed(&jl_n_threads) == 1) { // a different thread might simultaneously come to a different, but equally valid, alternative result - assert(maxworld == 0 || jl_atomic_load_relaxed(&codeinst->min_world) == minworld); - assert(jl_atomic_load_relaxed(&codeinst->max_world) == maxworld); - } -} - -// Restore backedges to external targets -// `edges` = [caller1, ...], the list of worklist-owned code instances internally -// `ext_ci_list` = [caller1, ...], the list of worklist-owned code instances externally -static void jl_insert_backedges(jl_array_t *edges, jl_array_t *ext_ci_list) -{ - // determine which CodeInstance objects are still valid in our image - // to enable any applicable new codes - arraylist_t stack; - arraylist_new(&stack, 0); - htable_t visiting; - htable_new(&visiting, 0); - for (size_t external = 0; external < (ext_ci_list ? 2 : 1); external++) { - if (external) - edges = ext_ci_list; - size_t nedges = jl_array_nrows(edges); - for (size_t i = 0; i < nedges; i++) { - jl_code_instance_t *codeinst = (jl_code_instance_t*)jl_array_ptr_ref(edges, i); - jl_svec_t *callees = jl_atomic_load_relaxed(&codeinst->edges); - jl_method_instance_t *caller = jl_get_ci_mi(codeinst); - jl_verify_method_graph(codeinst, &stack, &visiting); - size_t minvalid = jl_atomic_load_relaxed(&codeinst->min_world); - size_t maxvalid = jl_atomic_load_relaxed(&codeinst->max_world); - if (maxvalid >= minvalid) { - if (jl_atomic_load_relaxed(&jl_world_counter) == maxvalid) { - // if this callee is still valid, add all the backedges - for (size_t j = 0; j < jl_svec_len(callees); ) { - jl_value_t *edge = jl_svecref(callees, j); - if (jl_is_long(edge)) { - j += 2; // skip over signature and count but not methods - continue; - } - else if (jl_is_method(edge)) { - j += 1; - continue; - } - else if (jl_is_binding_partition(edge)) { - j += 1; - continue; - } - if (jl_is_code_instance(edge)) - edge = (jl_value_t*)((jl_code_instance_t*)edge)->def; - if (jl_is_method_instance(edge)) { - jl_method_instance_add_backedge((jl_method_instance_t*)edge, NULL, codeinst); - j += 1; - } - else { - jl_value_t *callee = jl_svecref(callees, j + 1); - if (jl_is_mtable(callee)) { - jl_methtable_t *mt = (jl_methtable_t*)callee; - jl_method_table_add_backedge(mt, edge, codeinst); - j += 2; - continue; - } - else if (jl_is_code_instance(callee)) { - callee = (jl_value_t*)((jl_code_instance_t*)callee)->def; - } - else if (jl_is_method(callee)) { - j += 2; - continue; - } - jl_method_instance_add_backedge((jl_method_instance_t*)callee, edge, codeinst); - j += 2; - } - } - } - if (jl_atomic_load_relaxed(&jl_world_counter) == maxvalid) { - maxvalid = ~(size_t)0; - jl_atomic_store_relaxed(&codeinst->max_world, maxvalid); - } - if (external) { - jl_value_t *owner = codeinst->owner; - JL_GC_PROMISE_ROOTED(owner); - - // See #53586, #53109 - assert(jl_atomic_load_relaxed(&codeinst->inferred)); - - if (jl_rettype_inferred(owner, caller, minvalid, maxvalid) != jl_nothing) { - // We already got a code instance for this world age range from somewhere else - we don't need - // this one. - } - else { - jl_mi_cache_insert(caller, codeinst); - } - } - } - } - } - - htable_free(&visiting); - arraylist_free(&stack); -} - static jl_value_t *read_verify_mod_list(ios_t *s, jl_array_t *depmods) { if (!jl_main_module->build_id.lo) { diff --git a/test/precompile.jl b/test/precompile.jl index 3b193e1facd7c..78a96250600a4 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -1004,9 +1004,9 @@ precompile_test_harness("code caching") do dir MA = getfield(@__MODULE__, StaleA) Base.eval(MA, :(nbits(::UInt8) = 8)) @eval using $StaleC - invalidations = ccall(:jl_debug_method_invalidation, Any, (Cint,), 1) + invalidations = Base.StaticData.debug_method_invalidation(true) @eval using $StaleB - ccall(:jl_debug_method_invalidation, Any, (Cint,), 0) + Base.StaticData.debug_method_invalidation(false) MB = getfield(@__MODULE__, StaleB) MC = getfield(@__MODULE__, StaleC) world = Base.get_world_counter() @@ -1820,12 +1820,14 @@ precompile_test_harness("PkgCacheInspector") do load_path end if ocachefile !== nothing - sv = ccall(:jl_restore_package_image_from_file, Any, (Cstring, Any, Cint, Cstring, Cint), ocachefile, depmods, true, "PCI", false) + sv = ccall(:jl_restore_package_image_from_file, Any, (Cstring, Any, Cint, Cstring, Cint), + ocachefile, depmods, #=completeinfo=#true, "PCI", false) else - sv = ccall(:jl_restore_incremental, Any, (Cstring, Any, Cint, Cstring), cachefile, depmods, true, "PCI") + sv = ccall(:jl_restore_incremental, Any, (Cstring, Any, Cint, Cstring), + cachefile, depmods, #=completeinfo=#true, "PCI") end - modules, init_order, external_methods, new_ext_cis, new_method_roots, external_targets, edges = sv + modules, init_order, edges, new_ext_cis, external_methods, new_method_roots, cache_sizes = sv m = only(external_methods).func::Method @test m.name == :repl_cmd && m.nargs < 2 @test new_ext_cis === nothing || any(new_ext_cis) do ci From 6cf2b146c68e85ea62f233b2f6e4bbb9e7e32e93 Mon Sep 17 00:00:00 2001 From: NegaScout <42321060+NegaScout@users.noreply.github.com> Date: Wed, 15 Jan 2025 14:13:39 +0100 Subject: [PATCH 198/342] remove unused Base.GMP.MPZ.import! and test Base.GMP.MPZ.export! (#56903) --- base/gmp.jl | 2 -- test/gmp.jl | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/base/gmp.jl b/base/gmp.jl index d5db71b0630d6..4d2b4b66ac41b 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -264,8 +264,6 @@ end limbs_write!(x::BigInt, a) = ccall((:__gmpz_limbs_write, libgmp), Ptr{Limb}, (mpz_t, Clong), x, a) limbs_finish!(x::BigInt, a) = ccall((:__gmpz_limbs_finish, libgmp), Cvoid, (mpz_t, Clong), x, a) -import!(x::BigInt, a, b, c, d, e, f) = ccall((:__gmpz_import, libgmp), Cvoid, - (mpz_t, Csize_t, Cint, Csize_t, Cint, Csize_t, Ptr{Cvoid}), x, a, b, c, d, e, f) setbit!(x, a) = (ccall((:__gmpz_setbit, libgmp), Cvoid, (mpz_t, bitcnt_t), x, a); x) tstbit(a::BigInt, b) = ccall((:__gmpz_tstbit, libgmp), Cint, (mpz_t, bitcnt_t), a, b) % Bool diff --git a/test/gmp.jl b/test/gmp.jl index 9ca327e63493b..0812775672969 100644 --- a/test/gmp.jl +++ b/test/gmp.jl @@ -445,6 +445,44 @@ end @test string(big(0), base = rand(2:62), pad = 0) == "" end +@testset "Base.GMP.MPZ.export!" begin + + function Base_GMP_MPZ_import!(x::BigInt, n::AbstractVector{T}; order::Integer=-1, nails::Integer=0, endian::Integer=0) where {T<:Base.BitInteger} + ccall((:__gmpz_import, Base.GMP.MPZ.libgmp), + Cvoid, + (Base.GMP.MPZ.mpz_t, Csize_t, Cint, Csize_t, Cint, Csize_t, Ptr{Cvoid}), + x, length(n), order, sizeof(T), endian, nails, n) + return x + end + # test import + bytes_to_import_from = Vector{UInt8}([1, 0]) + int_to_import_to = BigInt() + Base_GMP_MPZ_import!(int_to_import_to, bytes_to_import_from, order=0) + @test int_to_import_to == BigInt(256) + + # test export + int_to_export_from = BigInt(256) + bytes_to_export_to = Vector{UInt8}(undef, 2) + Base.GMP.MPZ.export!(bytes_to_export_to, int_to_export_from, order=0) + @test all(bytes_to_export_to .== bytes_to_import_from) + + # test both composed import(export) is identity + int_to_export_from = BigInt(256) + bytes_to_export_to = Vector{UInt8}(undef, 2) + Base.GMP.MPZ.export!(bytes_to_export_to, int_to_export_from, order=0) + int_to_import_to = BigInt() + Base_GMP_MPZ_import!(int_to_import_to, bytes_to_export_to, order=0) + @test int_to_export_from == int_to_import_to + + # test both composed export(import) is identity + bytes_to_import_from = Vector{UInt8}([1, 0]) + int_to_import_to = BigInt() + Base_GMP_MPZ_import!(int_to_import_to, bytes_to_import_from, order=0) + bytes_to_export_to = Vector{UInt8}(undef, 2) + Base.GMP.MPZ.export!(bytes_to_export_to, int_to_export_from, order=0) + @test all(bytes_to_export_to .== bytes_to_import_from) +end + @test isqrt(big(4)) == 2 @test isqrt(big(5)) == 2 From 30177d0578d283cda3bace0c2984b5fdcd114c2f Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Wed, 15 Jan 2025 22:49:18 +0100 Subject: [PATCH 199/342] cleanup: Remove fallback post-lowering global resolution (#57051) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After recent changes, essentially all global symbol scopes are resolved by lowering, so the code in method.c that replaces symbols by globalrefs is no longer necessary. The one small exception to this were symbols resulting from closure conversion, because these get inserted after the point at which lowering converts symbols to globalrefs. However, in the current design, I think that's basically a bug (and easily addressed by inserting `globalref`s where appropriate). Removing this extra resolution step is not particularly necessary, but for the upcoming binding partition backedges, it removes an ambiguity as to which version of the lowered code to scan. It also partially resolves a very old todo about not performing post-hoc mutation of lowered code (although we still do this for ccall). --- src/jl_exported_funcs.inc | 2 +- src/julia-syntax.scm | 14 +- src/julia_internal.h | 4 +- src/method.c | 355 ++++++++++++----------------- src/toplevel.c | 4 +- stdlib/REPL/src/REPLCompletions.jl | 2 +- 6 files changed, 156 insertions(+), 225 deletions(-) diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index cb48cf6f9962c..b92380df7a49c 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -388,7 +388,7 @@ XX(jl_read_verify_header) \ XX(jl_realloc) \ XX(jl_register_newmeth_tracer) \ - XX(jl_resolve_globals_in_ir) \ + XX(jl_resolve_definition_effects_in_ir) \ XX(jl_restore_excstack) \ XX(jl_restore_incremental) \ XX(jl_restore_package_image_from_file) \ diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 007c3ce820820..7fd2dc7409c0e 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -3683,11 +3683,17 @@ f(x) = yt(x) (else (error (string "invalid assignment location \"" (deparse var) "\""))))) +(define (sig-type-expr namemap name expr) + (let ((newname (get namemap name expr))) + (if (symbol? newname) + `(globalref (thismodule) ,newname) + newname))) + (define (rename-sig-types ex namemap) (pattern-replace (pattern-set (pattern-lambda (call (core (-/ Typeof)) name) - (get namemap name __))) + (sig-type-expr namemap name __))) ex)) ;; replace leading (function) argument type with `typ` @@ -4242,7 +4248,7 @@ f(x) = yt(x) (contains (lambda (x) (eq? x 'kwftype)) sig)) (renamemap (map cons closure-param-names closure-param-syms)) (arg-defs (replace-vars - (fix-function-arg-type sig type-name iskw namemap closure-param-syms) + (fix-function-arg-type sig `(globalref (thismodule) ,type-name) iskw namemap closure-param-syms) renamemap))) (append (map (lambda (gs tvar) (make-assignment gs `(call (core TypeVar) ',tvar (core Any)))) @@ -4270,8 +4276,8 @@ f(x) = yt(x) `(call (core _typeof_captured_variable) ,ve))) capt-vars var-exprs))))) `(new ,(if (null? P) - type-name - `(call (core apply_type) ,type-name ,@P)) + `(globalref (thismodule) ,type-name) + `(call (core apply_type) (globalref (thismodule) ,type-name) ,@P)) ,@var-exprs)))) (if (pair? moved-vars) (set-car! (lam:vinfo lam) diff --git a/src/julia_internal.h b/src/julia_internal.h index a464025edf856..00d603f26c7f2 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -717,8 +717,8 @@ jl_value_t *jl_code_or_ci_for_interpreter(jl_method_instance_t *lam JL_PROPAGATE int jl_code_requires_compiler(jl_code_info_t *src, int include_force_compile); jl_code_info_t *jl_new_code_info_from_ir(jl_expr_t *ast); JL_DLLEXPORT jl_code_info_t *jl_new_code_info_uninit(void); -JL_DLLEXPORT void jl_resolve_globals_in_ir(jl_array_t *stmts, jl_module_t *m, jl_svec_t *sparam_vals, - int binding_effects); +JL_DLLEXPORT void jl_resolve_definition_effects_in_ir(jl_array_t *stmts, jl_module_t *m, jl_svec_t *sparam_vals, + int binding_effects); int get_next_edge(jl_array_t *list, int i, jl_value_t** invokesig, jl_code_instance_t **caller) JL_NOTSAFEPOINT; int set_next_edge(jl_array_t *list, int i, jl_value_t *invokesig, jl_code_instance_t *caller); diff --git a/src/method.c b/src/method.c index 0d173d960c90f..0a58f0d5c482c 100644 --- a/src/method.c +++ b/src/method.c @@ -41,235 +41,160 @@ static void check_c_types(const char *where, jl_value_t *rt, jl_value_t *at) // Resolve references to non-locally-defined variables to become references to global // variables in `module` (unless the rvalue is one of the type parameters in `sparam_vals`). -static jl_value_t *resolve_globals(jl_value_t *expr, jl_module_t *module, jl_svec_t *sparam_vals, +static jl_value_t *resolve_definition_effects(jl_value_t *expr, jl_module_t *module, jl_svec_t *sparam_vals, int binding_effects, int eager_resolve) { if (jl_is_symbol(expr)) { - if (module == NULL) - return expr; - return jl_module_globalref(module, (jl_sym_t*)expr); + jl_error("Found raw symbol in code returned from lowering. Expected all symbols to have been resolved to GlobalRef or slots."); } - else if (jl_is_returnnode(expr)) { - jl_value_t *retval = jl_returnnode_value(expr); - if (retval) { - jl_value_t *val = resolve_globals(retval, module, sparam_vals, binding_effects, eager_resolve); - if (val != retval) { - JL_GC_PUSH1(&val); - expr = jl_new_struct(jl_returnnode_type, val); - JL_GC_POP(); - } - } + if (!jl_is_expr(expr)) { return expr; } - else if (jl_is_enternode(expr)) { - jl_value_t *scope = jl_enternode_scope(expr); - if (scope) { - jl_value_t *val = resolve_globals(scope, module, sparam_vals, binding_effects, eager_resolve); - if (val != scope) { - intptr_t catch_dest = jl_enternode_catch_dest(expr); - JL_GC_PUSH1(&val); - expr = jl_new_struct_uninit(jl_enternode_type); - jl_enternode_catch_dest(expr) = catch_dest; - jl_enternode_scope(expr) = val; - JL_GC_POP(); - } - } + + jl_expr_t *e = (jl_expr_t*)expr; + if (e->head == jl_global_sym && binding_effects) { + // execute the side-effects of "global x" decl immediately: + // creates uninitialized mutable binding in module for each global + jl_eval_global_expr(module, e, 1); + return jl_nothing; + } + // These exprs are not fully linearized + if (e->head == jl_assign_sym) { + jl_exprargset(e, 1, resolve_definition_effects(jl_exprarg(e, 1), module, sparam_vals, binding_effects, eager_resolve)); + return expr; + } else if (e->head == jl_new_opaque_closure_sym) { + jl_exprargset(e, 4, resolve_definition_effects(jl_exprarg(e, 4), module, sparam_vals, binding_effects, eager_resolve)); return expr; } - else if (jl_is_gotoifnot(expr)) { - jl_value_t *cond = resolve_globals(jl_gotoifnot_cond(expr), module, sparam_vals, binding_effects, eager_resolve); - if (cond != jl_gotoifnot_cond(expr)) { - intptr_t label = jl_gotoifnot_label(expr); - JL_GC_PUSH1(&cond); - expr = jl_new_struct_uninit(jl_gotoifnot_type); - set_nth_field(jl_gotoifnot_type, expr, 0, cond, 0); - jl_gotoifnot_label(expr) = label; - JL_GC_POP(); + size_t nargs = jl_array_nrows(e->args); + if (e->head == jl_opaque_closure_method_sym) { + if (nargs != 5) { + jl_error("opaque_closure_method: invalid syntax"); } - return expr; + jl_value_t *name = jl_exprarg(e, 0); + jl_value_t *oc_nargs = jl_exprarg(e, 1); + int isva = jl_exprarg(e, 2) == jl_true; + jl_value_t *functionloc = jl_exprarg(e, 3); + jl_value_t *ci = jl_exprarg(e, 4); + if (!jl_is_code_info(ci)) { + jl_error("opaque_closure_method: lambda should be a CodeInfo"); + } else if (!jl_is_long(oc_nargs)) { + jl_type_error("opaque_closure_method", (jl_value_t*)jl_long_type, oc_nargs); + } + jl_method_t *m = jl_make_opaque_closure_method(module, name, + jl_unbox_long(oc_nargs), functionloc, (jl_code_info_t*)ci, isva, /*isinferred*/0); + return (jl_value_t*)m; } - else if (jl_is_expr(expr)) { - jl_expr_t *e = (jl_expr_t*)expr; - if (e->head == jl_global_sym && binding_effects) { - // execute the side-effects of "global x" decl immediately: - // creates uninitialized mutable binding in module for each global - jl_eval_global_expr(module, e, 1); - expr = jl_nothing; + if (e->head == jl_cfunction_sym) { + JL_NARGS(cfunction method definition, 5, 5); // (type, func, rt, at, cc) + jl_task_t *ct = jl_current_task; + jl_value_t *typ = jl_exprarg(e, 0); + if (!jl_is_type(typ)) + jl_error("first parameter to :cfunction must be a type"); + if (typ == (jl_value_t*)jl_voidpointer_type) { + jl_value_t *a = jl_exprarg(e, 1); + JL_TYPECHK(cfunction method definition, quotenode, a); + *(jl_value_t**)a = jl_toplevel_eval(module, *(jl_value_t**)a); + jl_gc_wb(a, *(jl_value_t**)a); } - if (jl_is_toplevel_only_expr(expr) || e->head == jl_const_sym || - e->head == jl_coverageeffect_sym || e->head == jl_copyast_sym || - e->head == jl_quote_sym || e->head == jl_inert_sym || - e->head == jl_meta_sym || e->head == jl_inbounds_sym || - e->head == jl_boundscheck_sym || e->head == jl_loopinfo_sym || - e->head == jl_aliasscope_sym || e->head == jl_popaliasscope_sym || - e->head == jl_inline_sym || e->head == jl_noinline_sym) { - // ignore these + jl_value_t *rt = jl_exprarg(e, 2); + jl_value_t *at = jl_exprarg(e, 3); + if (!jl_is_type(rt)) { + JL_TRY { + rt = jl_interpret_toplevel_expr_in(module, rt, NULL, sparam_vals); + } + JL_CATCH { + if (jl_typetagis(jl_current_exception(ct), jl_errorexception_type)) + jl_error("could not evaluate cfunction return type (it might depend on a local variable)"); + else + jl_rethrow(); + } + jl_exprargset(e, 2, rt); } - else { - size_t i = 0, nargs = jl_array_nrows(e->args); - if (e->head == jl_opaque_closure_method_sym) { - if (nargs != 5) { - jl_error("opaque_closure_method: invalid syntax"); - } - jl_value_t *name = jl_exprarg(e, 0); - jl_value_t *oc_nargs = jl_exprarg(e, 1); - int isva = jl_exprarg(e, 2) == jl_true; - jl_value_t *functionloc = jl_exprarg(e, 3); - jl_value_t *ci = jl_exprarg(e, 4); - if (!jl_is_code_info(ci)) { - jl_error("opaque_closure_method: lambda should be a CodeInfo"); - } else if (!jl_is_long(oc_nargs)) { - jl_type_error("opaque_closure_method", (jl_value_t*)jl_long_type, oc_nargs); - } - jl_method_t *m = jl_make_opaque_closure_method(module, name, - jl_unbox_long(oc_nargs), functionloc, (jl_code_info_t*)ci, isva, /*isinferred*/0); - return (jl_value_t*)m; + if (!jl_is_svec(at)) { + JL_TRY { + at = jl_interpret_toplevel_expr_in(module, at, NULL, sparam_vals); } - if (e->head == jl_cfunction_sym) { - JL_NARGS(cfunction method definition, 5, 5); // (type, func, rt, at, cc) - jl_task_t *ct = jl_current_task; - jl_value_t *typ = jl_exprarg(e, 0); - if (!jl_is_type(typ)) - jl_error("first parameter to :cfunction must be a type"); - if (typ == (jl_value_t*)jl_voidpointer_type) { - jl_value_t *a = jl_exprarg(e, 1); - JL_TYPECHK(cfunction method definition, quotenode, a); - *(jl_value_t**)a = jl_toplevel_eval(module, *(jl_value_t**)a); - jl_gc_wb(a, *(jl_value_t**)a); - } - jl_value_t *rt = jl_exprarg(e, 2); - jl_value_t *at = jl_exprarg(e, 3); - if (!jl_is_type(rt)) { - JL_TRY { - rt = jl_interpret_toplevel_expr_in(module, rt, NULL, sparam_vals); - } - JL_CATCH { - if (jl_typetagis(jl_current_exception(ct), jl_errorexception_type)) - jl_error("could not evaluate cfunction return type (it might depend on a local variable)"); - else - jl_rethrow(); - } - jl_exprargset(e, 2, rt); - } - if (!jl_is_svec(at)) { - JL_TRY { - at = jl_interpret_toplevel_expr_in(module, at, NULL, sparam_vals); - } - JL_CATCH { - if (jl_typetagis(jl_current_exception(ct), jl_errorexception_type)) - jl_error("could not evaluate cfunction argument type (it might depend on a local variable)"); - else - jl_rethrow(); - } - jl_exprargset(e, 3, at); - } - check_c_types("cfunction method definition", rt, at); - JL_TYPECHK(cfunction method definition, quotenode, jl_exprarg(e, 4)); - JL_TYPECHK(cfunction method definition, symbol, *(jl_value_t**)jl_exprarg(e, 4)); - return expr; + JL_CATCH { + if (jl_typetagis(jl_current_exception(ct), jl_errorexception_type)) + jl_error("could not evaluate cfunction argument type (it might depend on a local variable)"); + else + jl_rethrow(); } - if (e->head == jl_foreigncall_sym) { - JL_NARGSV(ccall method definition, 5); // (fptr, rt, at, nreq, (cc, effects)) - jl_task_t *ct = jl_current_task; - jl_value_t *rt = jl_exprarg(e, 1); - jl_value_t *at = jl_exprarg(e, 2); - if (!jl_is_type(rt)) { - JL_TRY { - rt = jl_interpret_toplevel_expr_in(module, rt, NULL, sparam_vals); - } - JL_CATCH { - if (jl_typetagis(jl_current_exception(ct), jl_errorexception_type)) - jl_error("could not evaluate ccall return type (it might depend on a local variable)"); - else - jl_rethrow(); - } - jl_exprargset(e, 1, rt); - } - if (!jl_is_svec(at)) { - JL_TRY { - at = jl_interpret_toplevel_expr_in(module, at, NULL, sparam_vals); - } - JL_CATCH { - if (jl_typetagis(jl_current_exception(ct), jl_errorexception_type)) - jl_error("could not evaluate ccall argument type (it might depend on a local variable)"); - else - jl_rethrow(); - } - jl_exprargset(e, 2, at); - } - check_c_types("ccall method definition", rt, at); - JL_TYPECHK(ccall method definition, long, jl_exprarg(e, 3)); - JL_TYPECHK(ccall method definition, quotenode, jl_exprarg(e, 4)); - jl_value_t *cc = jl_quotenode_value(jl_exprarg(e, 4)); - if (!jl_is_symbol(cc)) { - JL_TYPECHK(ccall method definition, tuple, cc); - if (jl_nfields(cc) != 2) { - jl_error("In ccall calling convention, expected two argument tuple or symbol."); - } - JL_TYPECHK(ccall method definition, symbol, jl_get_nth_field(cc, 0)); - JL_TYPECHK(ccall method definition, uint16, jl_get_nth_field(cc, 1)); - } - jl_exprargset(e, 0, resolve_globals(jl_exprarg(e, 0), module, sparam_vals, binding_effects, 1)); - i++; + jl_exprargset(e, 3, at); + } + check_c_types("cfunction method definition", rt, at); + JL_TYPECHK(cfunction method definition, quotenode, jl_exprarg(e, 4)); + JL_TYPECHK(cfunction method definition, symbol, *(jl_value_t**)jl_exprarg(e, 4)); + return expr; + } + if (e->head == jl_foreigncall_sym) { + JL_NARGSV(ccall method definition, 5); // (fptr, rt, at, nreq, (cc, effects)) + jl_task_t *ct = jl_current_task; + jl_value_t *rt = jl_exprarg(e, 1); + jl_value_t *at = jl_exprarg(e, 2); + if (!jl_is_type(rt)) { + JL_TRY { + rt = jl_interpret_toplevel_expr_in(module, rt, NULL, sparam_vals); + } + JL_CATCH { + if (jl_typetagis(jl_current_exception(ct), jl_errorexception_type)) + jl_error("could not evaluate ccall return type (it might depend on a local variable)"); + else + jl_rethrow(); } - if (e->head == jl_method_sym || e->head == jl_module_sym || e->head == jl_throw_undef_if_not_sym) { - i++; + jl_exprargset(e, 1, rt); + } + if (!jl_is_svec(at)) { + JL_TRY { + at = jl_interpret_toplevel_expr_in(module, at, NULL, sparam_vals); } - for (; i < nargs; i++) { - // TODO: this should be making a copy, not mutating the source - jl_exprargset(e, i, resolve_globals(jl_exprarg(e, i), module, sparam_vals, binding_effects, eager_resolve)); + JL_CATCH { + if (jl_typetagis(jl_current_exception(ct), jl_errorexception_type)) + jl_error("could not evaluate ccall argument type (it might depend on a local variable)"); + else + jl_rethrow(); } - if (e->head == jl_call_sym && jl_expr_nargs(e) == 3 && - jl_is_globalref(jl_exprarg(e, 0)) && - jl_is_globalref(jl_exprarg(e, 1)) && - jl_is_quotenode(jl_exprarg(e, 2))) { - // replace module_expr.sym with GlobalRef(module, sym) - // for expressions pattern-matching to `getproperty(module_expr, :sym)` in a top-module - // (this is expected to help inference performance) - // TODO: this was broken by linear-IR - jl_value_t *s = jl_fieldref(jl_exprarg(e, 2), 0); - jl_value_t *me = jl_exprarg(e, 1); - jl_value_t *fe = jl_exprarg(e, 0); - jl_module_t *fe_mod = jl_globalref_mod(fe); - jl_sym_t *fe_sym = jl_globalref_name(fe); - jl_module_t *me_mod = jl_globalref_mod(me); - jl_sym_t *me_sym = jl_globalref_name(me); - if (fe_mod->istopmod && !strcmp(jl_symbol_name(fe_sym), "getproperty") && jl_is_symbol(s)) { - if (eager_resolve || jl_binding_resolved_p(me_mod, me_sym)) { - jl_binding_t *b = jl_get_binding(me_mod, me_sym); - jl_value_t *v = jl_get_binding_value_if_const(b); - if (v && jl_is_module(v)) - return jl_module_globalref((jl_module_t*)v, (jl_sym_t*)s); - } - } + jl_exprargset(e, 2, at); + } + check_c_types("ccall method definition", rt, at); + JL_TYPECHK(ccall method definition, long, jl_exprarg(e, 3)); + JL_TYPECHK(ccall method definition, quotenode, jl_exprarg(e, 4)); + jl_value_t *cc = jl_quotenode_value(jl_exprarg(e, 4)); + if (!jl_is_symbol(cc)) { + JL_TYPECHK(ccall method definition, tuple, cc); + if (jl_nfields(cc) != 2) { + jl_error("In ccall calling convention, expected two argument tuple or symbol."); } - if (e->head == jl_call_sym && nargs > 0 && - jl_is_globalref(jl_exprarg(e, 0))) { - // TODO: this hack should be deleted once llvmcall is fixed - jl_value_t *fe = jl_exprarg(e, 0); - jl_module_t *fe_mod = jl_globalref_mod(fe); - jl_sym_t *fe_sym = jl_globalref_name(fe); - if (jl_binding_resolved_p(fe_mod, fe_sym)) { - // look at some known called functions - jl_binding_t *b = jl_get_binding(fe_mod, fe_sym); - if (jl_get_binding_value_if_const(b) == jl_builtin_tuple) { - size_t j; - for (j = 1; j < nargs; j++) { - if (!jl_is_quotenode(jl_exprarg(e, j))) - break; - } - if (j == nargs) { - jl_value_t *val = NULL; - JL_TRY { - val = jl_interpret_toplevel_expr_in(module, (jl_value_t*)e, NULL, sparam_vals); - } - JL_CATCH { - val = NULL; // To make the analyzer happy see #define JL_TRY - } - if (val) - return val; - } + JL_TYPECHK(ccall method definition, symbol, jl_get_nth_field(cc, 0)); + JL_TYPECHK(ccall method definition, uint16, jl_get_nth_field(cc, 1)); + } + } + if (e->head == jl_call_sym && nargs > 0 && + jl_is_globalref(jl_exprarg(e, 0))) { + // TODO: this hack should be deleted once llvmcall is fixed + jl_value_t *fe = jl_exprarg(e, 0); + jl_module_t *fe_mod = jl_globalref_mod(fe); + jl_sym_t *fe_sym = jl_globalref_name(fe); + if (jl_binding_resolved_p(fe_mod, fe_sym)) { + // look at some known called functions + jl_binding_t *b = jl_get_binding(fe_mod, fe_sym); + if (jl_get_binding_value_if_const(b) == jl_builtin_tuple) { + size_t j; + for (j = 1; j < nargs; j++) { + if (!jl_is_quotenode(jl_exprarg(e, j))) + break; + } + if (j == nargs) { + jl_value_t *val = NULL; + JL_TRY { + val = jl_interpret_toplevel_expr_in(module, (jl_value_t*)e, NULL, sparam_vals); + } + JL_CATCH { + val = NULL; // To make the analyzer happy see #define JL_TRY } + if (val) + return val; } } } @@ -277,13 +202,13 @@ static jl_value_t *resolve_globals(jl_value_t *expr, jl_module_t *module, jl_sve return expr; } -JL_DLLEXPORT void jl_resolve_globals_in_ir(jl_array_t *stmts, jl_module_t *m, jl_svec_t *sparam_vals, +JL_DLLEXPORT void jl_resolve_definition_effects_in_ir(jl_array_t *stmts, jl_module_t *m, jl_svec_t *sparam_vals, int binding_effects) { size_t i, l = jl_array_nrows(stmts); for (i = 0; i < l; i++) { jl_value_t *stmt = jl_array_ptr_ref(stmts, i); - jl_array_ptr_set(stmts, i, resolve_globals(stmt, m, sparam_vals, binding_effects, 0)); + jl_array_ptr_set(stmts, i, resolve_definition_effects(stmt, m, sparam_vals, binding_effects, 0)); } } @@ -697,7 +622,7 @@ JL_DLLEXPORT jl_code_info_t *jl_expand_and_resolve(jl_value_t *ex, jl_module_t * JL_GC_PUSH1(&func); if (jl_is_code_info(func)) { jl_array_t *stmts = (jl_array_t*)func->code; - jl_resolve_globals_in_ir(stmts, module, sparam_vals, 1); + jl_resolve_definition_effects_in_ir(stmts, module, sparam_vals, 1); } JL_GC_POP(); return func; @@ -777,7 +702,7 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *mi, size_t if (jl_is_code_info(ex)) { func = (jl_code_info_t*)ex; jl_array_t *stmts = (jl_array_t*)func->code; - jl_resolve_globals_in_ir(stmts, def->module, mi->sparam_vals, 1); + jl_resolve_definition_effects_in_ir(stmts, def->module, mi->sparam_vals, 1); } else { // Lower the user's expression and resolve references to the type parameters @@ -1000,7 +925,7 @@ JL_DLLEXPORT void jl_method_set_source(jl_method_t *m, jl_code_info_t *src) } } else { - st = resolve_globals(st, m->module, sparam_vars, 1, 0); + st = resolve_definition_effects(st, m->module, sparam_vars, 1, 0); } jl_array_ptr_set(copy, i, st); } diff --git a/src/toplevel.c b/src/toplevel.c index 95a053f6135f6..fb217ec7cb52e 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -1048,7 +1048,7 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val jl_get_module_compile(m) != JL_OPTIONS_COMPILE_MIN)) { // use codegen mfunc = jl_method_instance_for_thunk(thk, m); - jl_resolve_globals_in_ir((jl_array_t*)thk->code, m, NULL, 0); + jl_resolve_definition_effects_in_ir((jl_array_t*)thk->code, m, NULL, 0); // Don't infer blocks containing e.g. method definitions, since it's probably not worthwhile. size_t world = jl_atomic_load_acquire(&jl_world_counter); ct->world_age = world; @@ -1062,7 +1062,7 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val // use interpreter assert(thk); if (has_opaque) { - jl_resolve_globals_in_ir((jl_array_t*)thk->code, m, NULL, 0); + jl_resolve_definition_effects_in_ir((jl_array_t*)thk->code, m, NULL, 0); } size_t world = jl_atomic_load_acquire(&jl_world_counter); ct->world_age = world; diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index 723a008b10f28..e8aa1188ec213 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -716,7 +716,7 @@ function CC.const_prop_argument_heuristic(interp::REPLInterpreter, arginfo::CC.A end function resolve_toplevel_symbols!(src::Core.CodeInfo, mod::Module) - @ccall jl_resolve_globals_in_ir( + @ccall jl_resolve_definition_effects_in_ir( #=jl_array_t *stmts=# src.code::Any, #=jl_module_t *m=# mod::Any, #=jl_svec_t *sparam_vals=# Core.svec()::Any, From 2dc3337626cd1fa09d358e3f4b769720c0a0d527 Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Wed, 15 Jan 2025 21:22:35 -0500 Subject: [PATCH 200/342] base/strings: Add documentation to unicode conversion table (#56929) Co-authored-by: Neven Sajko <4944410+nsajko@users.noreply.github.com> --- base/strings/unicode.jl | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/base/strings/unicode.jl b/base/strings/unicode.jl index fcb4a371e9898..f2938ba6021f2 100644 --- a/base/strings/unicode.jl +++ b/base/strings/unicode.jl @@ -174,14 +174,21 @@ function utf8proc_map(str::Union{String,SubString{String}}, options::Integer, ch return String(resize!(buffer, nbytes)) end -# from julia_charmap.h, used by julia_chartransform in the Unicode stdlib +""" +`Dict` of `original codepoint => replacement codepoint` normalizations +to perform on Julia identifiers, to canonicalize characters that +are both easily confused and easily inputted by accident. + +!!! warning + When this table is updated, also update the corresponding table in `src/flisp/julia_charmap.h`. +""" const _julia_charmap = Dict{UInt32,UInt32}( - 0x025B => 0x03B5, - 0x00B5 => 0x03BC, - 0x00B7 => 0x22C5, - 0x0387 => 0x22C5, - 0x2212 => 0x002D, - 0x210F => 0x0127, + 0x025B => 0x03B5, # latin small letter open e -> greek small letter epsilon + 0x00B5 => 0x03BC, # micro sign -> greek small letter mu + 0x00B7 => 0x22C5, # middot char -> dot operator (#25098) + 0x0387 => 0x22C5, # Greek interpunct -> dot operator (#25098) + 0x2212 => 0x002D, # minus -> hyphen-minus (#26193) + 0x210F => 0x0127, # hbar -> small letter h with stroke (#48870) ) utf8proc_map(s::AbstractString, flags::Integer, chartransform::F = identity) where F = utf8proc_map(String(s), flags, chartransform) From b0ae24ffada04c16c1ab278027824e210693df08 Mon Sep 17 00:00:00 2001 From: Neven Sajko <4944410+nsajko@users.noreply.github.com> Date: Thu, 16 Jan 2025 03:23:17 +0100 Subject: [PATCH 201/342] test: add a bunch of `@inferred` to the iterators test set (#56885) The `@inferred` macro is applied to the following functions: * `Base.IteratorSize` * `Base.IteratorEltype` * `eltype` * `axes` * `size` * `length` * `ndims` * `isempty` xref #56802 xref #56838 --- test/iterators.jl | 430 +++++++++++++++++++++++----------------------- 1 file changed, 215 insertions(+), 215 deletions(-) diff --git a/test/iterators.jl b/test/iterators.jl index 1feccf5fb1d3e..06f08cff4f6ad 100644 --- a/test/iterators.jl +++ b/test/iterators.jl @@ -5,7 +5,7 @@ using Random using Base: IdentityUnitRange using Dates: Date, Day -@test Base.IteratorSize(Any) isa Base.SizeUnknown +@test (@inferred Base.IteratorSize(Any)) isa Base.SizeUnknown # zip and filter iterators # issue #4718 @@ -16,27 +16,27 @@ using Dates: Date, Day @test_throws ArgumentError Iterators.reverse(zip("abc", Iterators.cycle("ab"))) let z = zip(1:2) - @test size(z) == (2,) + @test (@inferred size(z)) == (2,) @test collect(z) == [(1,), (2,)] # Issue #13979 - @test eltype(z) == Tuple{Int} + @test (@inferred eltype(z)) == Tuple{Int} end for z in (zip(1:2, 3:4), zip(1:2, 3:5)) @test collect(z) == [(1,3), (2,4)] - @test eltype(z) == Tuple{Int,Int} - @test size(z) == (2,) - @test axes(z) == (Base.OneTo(2),) - @test length(z) == 2 + @test (@inferred eltype(z)) == Tuple{Int,Int} + @test (@inferred size(z)) == (2,) + @test (@inferred axes(z)) == (Base.OneTo(2),) + @test (@inferred length(z)) == 2 end let z = zip(1:2, Iterators.countfrom(3)) @test collect(z) == [(1,3), (2,4)] - @test eltype(z) == Tuple{Int,Int} + @test (@inferred eltype(z)) == Tuple{Int,Int} @test_throws MethodError size(z) # by convention, the zip of a finite and # an infinite iterator has only `length` @test_throws MethodError axes(z) - @test length(z) == 2 + @test (@inferred length(z)) == 2 end let z = zip([i*j for i in 1:3, j in -1:2:1], 1:6) @@ -46,29 +46,29 @@ let z = zip([i*j for i in 1:3, j in -1:2:1], 1:6) (1, 4) (2, 5) (3, 6) ] - @test eltype(z) == Tuple{Int,Int} + @test (@inferred eltype(z)) == Tuple{Int,Int} @test_throws DimensionMismatch size(z) @test_throws DimensionMismatch axes(z) - @test length(z) == 6 + @test (@inferred length(z)) == 6 end let z = zip([i*j for i in 1:3, j in -1:2:1], [i*j for i in 1:3, j in -1:2:1]) @test collect(z) == [(-1, -1) (1, 1) (-2, -2) (2, 2) (-3, -3) (3, 3)] - @test eltype(z) == Tuple{Int,Int} - @test size(z) == (3, 2) - @test axes(z) == (Base.OneTo(3), Base.OneTo(2)) - @test length(z) == 6 + @test (@inferred eltype(z)) == Tuple{Int,Int} + @test (@inferred size(z)) == (3, 2) + @test (@inferred axes(z)) == (Base.OneTo(3), Base.OneTo(2)) + @test (@inferred length(z)) == 6 end let z = zip(1:2, 3:4, 5:6) - @test size(z) == (2,) + @test (@inferred size(z)) == (2,) @test collect(z) == [(1,3,5), (2,4,6)] - @test eltype(z) == Tuple{Int,Int,Int} + @test (@inferred eltype(z)) == Tuple{Int,Int,Int} end -@test eltype(Iterators.filter(isodd, 1:5)) == Int +@test (@inferred eltype(Iterators.filter(isodd, 1:5))) == Int # typed `collect` @test collect(Float64, Iterators.filter(isodd, [1,2,3,4]))[1] === 1.0 @@ -102,10 +102,10 @@ let zeb = IOBuffer("1\n2\n3\n4\n5\n"), @test res == [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')] end -@test length(zip(cycle(1:3), 1:7)) == 7 -@test length(zip(cycle(1:3), 1:7, cycle(1:3))) == 7 -@test length(zip(1:3,product(1:7,cycle(1:3)))) == 3 -@test length(zip(1:3,product(1:7,cycle(1:3)),8)) == 1 +@test (@inferred length(zip(cycle(1:3), 1:7))) == 7 +@test (@inferred length(zip(cycle(1:3), 1:7, cycle(1:3)))) == 7 +@test (@inferred length(zip(1:3,product(1:7,cycle(1:3))))) == 3 +@test (@inferred length(zip(1:3,product(1:7,cycle(1:3)),8))) == 1 @test_throws ArgumentError length(zip()) # length of zip of empty tuple # map @@ -154,7 +154,7 @@ end # take # ---- let t = take(0:2:8, 10), i = 0 - @test length(collect(t)) == 5 == length(t) + @test length(collect(t)) == 5 == @inferred length(t) for j = t @test j == i*2 @@ -171,11 +171,11 @@ let i = 0 @test i == 10 end -@test isempty(take(0:2:8, 0)) +@test @inferred isempty(take(0:2:8, 0)) @test_throws ArgumentError take(0:2:8, -1) -@test length(take(1:3,typemax(Int))) == 3 -@test length(take(countfrom(1),3)) == 3 -@test length(take(1:6,3)) == 3 +@test (@inferred length(take(1:3,typemax(Int)))) == 3 +@test (@inferred length(take(countfrom(1),3))) == 3 +@test (@inferred length(take(1:6,3))) == 3 # drop # ---- @@ -187,15 +187,15 @@ let i = 0 @test i == 4 end -@test isempty(drop(0:2:10, 100)) -@test isempty(collect(drop(0:2:10, 100))) +@test @inferred isempty(drop(0:2:10, 100)) +@test @inferred isempty(collect(drop(0:2:10, 100))) @test_throws ArgumentError drop(0:2:8, -1) -@test length(drop(1:3,typemax(Int))) == 0 -@test length(drop(UInt(1):2, 3)) == 0 -@test length(drop(StepRangeLen(1, 1, UInt(2)), 3)) == 0 -@test Base.IteratorSize(drop(countfrom(1),3)) == Base.IsInfinite() +@test (@inferred length(drop(1:3,typemax(Int)))) == 0 +@test (@inferred length(drop(UInt(1):2, 3))) == 0 +@test (@inferred length(drop(StepRangeLen(1, 1, UInt(2)), 3))) == 0 +@test (@inferred Base.IteratorSize(drop(countfrom(1),3))) == Base.IsInfinite() @test_throws MethodError length(drop(countfrom(1), 3)) -@test Base.IteratorSize(Iterators.drop(Iterators.filter(i -> i>0, 1:10), 2)) == Base.SizeUnknown() +@test (@inferred Base.IteratorSize(Iterators.drop(Iterators.filter(i -> i>0, 1:10), 2))) == Base.SizeUnknown() let x = Iterators.drop(Iterators.Stateful("abc"), 2) @test !Base.isdone(x, nothing) @@ -212,7 +212,7 @@ for xs in Any["abc", [1, 2, 3]] @test drop(drop(xs, 1), 1) === drop(xs, 2) @test take(drop(xs, 1), 1) === drop(take(xs, 2), 1) @test take(drop(xs, 3), 0) === drop(take(xs, 2), 3) - @test isempty(drop(drop(xs, 2), 2)) + @test @inferred isempty(drop(drop(xs, 2), 2)) @test drop(take(drop(xs, 1), 2), 1) === take(drop(xs, 2), 1) @test take(drop(take(xs, 3), 1), 1) === take(drop(xs, 1), 1) end @@ -226,7 +226,7 @@ end @test collect(takewhile(Returns(true),5:10)) == 5:10 @test collect(takewhile(isodd,[1,1,2,3])) == [1,1] @test collect(takewhile(<(2), takewhile(<(3), [1,1,2,3]))) == [1,1] - @test Base.IteratorEltype(typeof(takewhile(<(4),Iterators.map(identity, 1:10)))) isa Base.EltypeUnknown + @test (@inferred Base.IteratorEltype(typeof(takewhile(<(4),Iterators.map(identity, 1:10))))) isa Base.EltypeUnknown end # dropwhile @@ -234,12 +234,12 @@ end @testset begin @test collect(dropwhile(<(4), 1:10)) == 4:10 @test collect(dropwhile(<(4), 1:10)) isa Vector{Int} - @test isempty(dropwhile(<(4), [])) + @test @inferred isempty(dropwhile(<(4), [])) @test collect(dropwhile(Returns(false),1:3)) == 1:3 - @test isempty(dropwhile(Returns(true), 1:3)) + @test @inferred isempty(dropwhile(Returns(true), 1:3)) @test collect(dropwhile(isodd,[1,1,2,3])) == [2,3] @test collect(dropwhile(iseven,dropwhile(isodd,[1,1,2,3]))) == [3] - @test Base.IteratorEltype(typeof(dropwhile(<(4),Iterators.map(identity, 1:10)))) isa Base.EltypeUnknown + @test (@inferred Base.IteratorEltype(typeof(dropwhile(<(4),Iterators.map(identity, 1:10))))) isa Base.EltypeUnknown end # cycle @@ -259,15 +259,15 @@ end @test collect(cycle(Iterators.filter(iseven, 1:4), 2)) == [2, 4, 2, 4] @test collect(take(cycle(countfrom(11), 3), 4)) == 11:14 - @test isempty(cycle(1:0)) == isempty(cycle(1:0, 3)) == true - @test isempty(cycle(1:5, 0)) - @test isempty(cycle(Iterators.filter(iseven, 1:4), 0)) + @test (@inferred isempty(cycle(1:0))) == (@inferred isempty(cycle(1:0, 3))) == true + @test @inferred isempty(cycle(1:5, 0)) + @test @inferred isempty(cycle(Iterators.filter(iseven, 1:4), 0)) - @test eltype(cycle(0:3, 2)) === Int - @test Base.IteratorEltype(cycle(0:3, 2)) == Base.HasEltype() + @test (@inferred eltype(cycle(0:3, 2))) === Int + @test (@inferred Base.IteratorEltype(cycle(0:3, 2))) == Base.HasEltype() Base.haslength(cycle(0:3, 2)) == false # but not sure we should test these - Base.IteratorSize(cycle(0:3, 2)) == Base.SizeUnknown() + (@inferred Base.IteratorSize(cycle(0:3, 2))) == Base.SizeUnknown() end # repeated @@ -286,13 +286,13 @@ let i = 0 i <= 10 || break end end -@test eltype(repeated(0)) == Int -@test eltype(repeated(0, 5)) == Int -@test Base.IteratorSize(repeated(0)) == Base.IsInfinite() -@test Base.IteratorSize(repeated(0, 5)) == Base.HasLength() -@test Base.IteratorEltype(repeated(0)) == Base.HasEltype() -@test Base.IteratorEltype(repeated(0, 5)) == Base.HasEltype() -@test Base.IteratorSize(zip(repeated(0), repeated(0))) == Base.IsInfinite() +@test (@inferred eltype(repeated(0))) == Int +@test (@inferred eltype(repeated(0, 5))) == Int +@test (@inferred Base.IteratorSize(repeated(0))) == Base.IsInfinite() +@test (@inferred Base.IteratorSize(repeated(0, 5))) == Base.HasLength() +@test (@inferred Base.IteratorEltype(repeated(0))) == Base.HasEltype() +@test (@inferred Base.IteratorEltype(repeated(0, 5))) == Base.HasEltype() +@test (@inferred Base.IteratorSize(zip(repeated(0), repeated(0)))) == Base.IsInfinite() # product # ------- @@ -304,8 +304,8 @@ for itr in [product(1:0), product(1:0, 1:1, 1:2), product(1:1, 1:0, 1:2), product(1:1, 1:2 ,1:0)] - @test isempty(itr) - @test isempty(collect(itr)) + @test @inferred isempty(itr) + @test @inferred isempty(collect(itr)) end # collect a product - first iterators runs faster @@ -325,10 +325,10 @@ end let (a, b) = (1:3, [4 6; 5 7]) p = product(a, b) - @test size(p) == (3, 2, 2) - @test length(p) == 12 - @test ndims(p) == 3 - @test eltype(p) == NTuple{2, Int} + @test (@inferred size(p)) == (3, 2, 2) + @test (@inferred length(p)) == 12 + @test (@inferred ndims(p)) == 3 + @test (@inferred eltype(p)) == NTuple{2, Int} cp = collect(p) for i = 1:3 @test cp[i, :, :] == [(i, 4) (i, 6); @@ -356,28 +356,28 @@ let a = 1:2, c = Int32(1):Int32(0) # length - @test length(product()) == 1 - @test length(product(a)) == 2 - @test length(product(a, b)) == 20 - @test length(product(a, b, c)) == 0 + @test (@inferred length(product())) == 1 + @test (@inferred length(product(a))) == 2 + @test (@inferred length(product(a, b))) == 20 + @test (@inferred length(product(a, b, c))) == 0 # size - @test size(product()) == tuple() - @test size(product(a)) == (2,) - @test size(product(a, b)) == (2, 10) - @test size(product(a, b, c)) == (2, 10, 0) + @test (@inferred size(product())) == tuple() + @test (@inferred size(product(a))) == (2,) + @test (@inferred size(product(a, b))) == (2, 10) + @test (@inferred size(product(a, b, c))) == (2, 10, 0) # eltype - @test eltype(product()) == Tuple{} - @test eltype(product(a)) == Tuple{Int} - @test eltype(product(a, b)) == Tuple{Int, Float64} - @test eltype(product(a, b, c)) == Tuple{Int, Float64, Int32} + @test (@inferred eltype(product())) == Tuple{} + @test (@inferred eltype(product(a))) == Tuple{Int} + @test (@inferred eltype(product(a, b))) == Tuple{Int, Float64} + @test (@inferred eltype(product(a, b, c))) == Tuple{Int, Float64, Int32} # ndims - @test ndims(product()) == 0 - @test ndims(product(a)) == 1 - @test ndims(product(a, b)) == 2 - @test ndims(product(a, b, c)) == 3 + @test (@inferred ndims(product())) == 0 + @test (@inferred ndims(product(a))) == 1 + @test (@inferred ndims(product(a, b))) == 2 + @test (@inferred ndims(product(a, b, c))) == 3 end # with multidimensional inputs @@ -397,7 +397,7 @@ let a = randn(4, 4), (4, 4, 3, 3, 3, 2, 2, 2, 2)] for (method, fun) in zip([size, ndims, length], [x->x, length, prod]) for i in 1:length(args) - @test method(product(args[i]...)) == method(collect(product(args[i]...))) == fun(sizes[i]) + @test (@inferred method(product(args[i]...))) == method(collect(product(args[i]...))) == fun(sizes[i]) end end end @@ -413,7 +413,7 @@ let iters = (1:2, for method in [size, length, ndims, eltype] for i = 1:length(iters) args = (iters[i],) - @test method(product(args...)) == method(collect(product(args...))) + @test (@inferred method(product(args...))) == method(collect(product(args...))) for j = 1:length(iters) args = iters[i], iters[j] @test method(product(args...)) == method(collect(product(args...))) @@ -455,48 +455,48 @@ end # IteratorSize trait business let f1 = Iterators.filter(i->i>0, 1:10) - @test Base.IteratorSize(product(f1)) == Base.SizeUnknown() - @test Base.IteratorSize(product(1:2, f1)) == Base.SizeUnknown() - @test Base.IteratorSize(product(f1, 1:2)) == Base.SizeUnknown() - @test Base.IteratorSize(product(f1, f1)) == Base.SizeUnknown() - @test Base.IteratorSize(product(f1, countfrom(1))) == Base.IsInfinite() - @test Base.IteratorSize(product(countfrom(1), f1)) == Base.IsInfinite() -end -@test Base.IteratorSize(product(1:2, countfrom(1))) == Base.IsInfinite() -@test Base.IteratorSize(product(countfrom(2), countfrom(1))) == Base.IsInfinite() -@test Base.IteratorSize(product(countfrom(1), 1:2)) == Base.IsInfinite() -@test Base.IteratorSize(product(1:2)) == Base.HasShape{1}() -@test Base.IteratorSize(product(1:2, 1:2)) == Base.HasShape{2}() -@test Base.IteratorSize(product(take(1:2, 1), take(1:2, 1))) == Base.HasShape{2}() -@test Base.IteratorSize(product(take(1:2, 2))) == Base.HasShape{1}() -@test Base.IteratorSize(product([1 2; 3 4])) == Base.HasShape{2}() -@test Base.IteratorSize(product((1,2,3,4), (5, 6, 7, 8))) == Base.HasShape{2}() # product of ::HasLength and ::HasLength -@test Base.IteratorSize(product(1:2, 3:5, 5:6)) == Base.HasShape{3}() # product of 3 iterators -@test Base.IteratorSize(product([1 2; 3 4], 1:4)) == Base.HasShape{3}() # product of ::HasShape{2} with ::HasShape{1} -@test Base.IteratorSize(product([1 2; 3 4], (1,2))) == Base.HasShape{3}() # product of ::HasShape{2} with ::HasLength + @test (@inferred Base.IteratorSize(product(f1))) == Base.SizeUnknown() + @test (@inferred Base.IteratorSize(product(1:2, f1))) == Base.SizeUnknown() + @test (@inferred Base.IteratorSize(product(f1, 1:2))) == Base.SizeUnknown() + @test (@inferred Base.IteratorSize(product(f1, f1))) == Base.SizeUnknown() + @test (@inferred Base.IteratorSize(product(f1, countfrom(1)))) == Base.IsInfinite() + @test (@inferred Base.IteratorSize(product(countfrom(1), f1))) == Base.IsInfinite() +end +@test (@inferred Base.IteratorSize(product(1:2, countfrom(1)))) == Base.IsInfinite() +@test (@inferred Base.IteratorSize(product(countfrom(2), countfrom(1)))) == Base.IsInfinite() +@test (@inferred Base.IteratorSize(product(countfrom(1), 1:2))) == Base.IsInfinite() +@test (@inferred Base.IteratorSize(product(1:2))) == Base.HasShape{1}() +@test (@inferred Base.IteratorSize(product(1:2, 1:2))) == Base.HasShape{2}() +@test (@inferred Base.IteratorSize(product(take(1:2, 1), take(1:2, 1)))) == Base.HasShape{2}() +@test (@inferred Base.IteratorSize(product(take(1:2, 2)))) == Base.HasShape{1}() +@test (@inferred Base.IteratorSize(product([1 2; 3 4]))) == Base.HasShape{2}() +@test (@inferred Base.IteratorSize(product((1,2,3,4), (5, 6, 7, 8)))) == Base.HasShape{2}() # product of ::HasLength and ::HasLength +@test (@inferred Base.IteratorSize(product(1:2, 3:5, 5:6))) == Base.HasShape{3}() # product of 3 iterators +@test (@inferred Base.IteratorSize(product([1 2; 3 4], 1:4))) == Base.HasShape{3}() # product of ::HasShape{2} with ::HasShape{1} +@test (@inferred Base.IteratorSize(product([1 2; 3 4], (1,2)))) == Base.HasShape{3}() # product of ::HasShape{2} with ::HasLength # IteratorEltype trait business let f1 = Iterators.filter(i->i>0, 1:10) - @test Base.IteratorEltype(product(f1)) == Base.HasEltype() # FIXME? eltype(f1) is Any - @test Base.IteratorEltype(product(1:2, f1)) == Base.HasEltype() # FIXME? eltype(f1) is Any - @test Base.IteratorEltype(product(f1, 1:2)) == Base.HasEltype() # FIXME? eltype(f1) is Any - @test Base.IteratorEltype(product(f1, f1)) == Base.HasEltype() # FIXME? eltype(f1) is Any - @test Base.IteratorEltype(product(f1, countfrom(1))) == Base.HasEltype() # FIXME? eltype(f1) is Any - @test Base.IteratorEltype(product(countfrom(1), f1)) == Base.HasEltype() # FIXME? eltype(f1) is Any -end -@test Base.IteratorEltype(product(1:2, countfrom(1))) == Base.HasEltype() -@test Base.IteratorEltype(product(countfrom(1), 1:2)) == Base.HasEltype() -@test Base.IteratorEltype(product(1:2)) == Base.HasEltype() -@test Base.IteratorEltype(product(1:2, 1:2)) == Base.HasEltype() -@test Base.IteratorEltype(product(take(1:2, 1), take(1:2, 1))) == Base.HasEltype() -@test Base.IteratorEltype(product(take(1:2, 2))) == Base.HasEltype() -@test Base.IteratorEltype(product([1 2; 3 4])) == Base.HasEltype() -@test Base.IteratorEltype(product()) == Base.HasEltype() + @test (@inferred Base.IteratorEltype(product(f1))) == Base.HasEltype() # FIXME? eltype(f1) is Any + @test (@inferred Base.IteratorEltype(product(1:2, f1))) == Base.HasEltype() # FIXME? eltype(f1) is Any + @test (@inferred Base.IteratorEltype(product(f1, 1:2))) == Base.HasEltype() # FIXME? eltype(f1) is Any + @test (@inferred Base.IteratorEltype(product(f1, f1))) == Base.HasEltype() # FIXME? eltype(f1) is Any + @test (@inferred Base.IteratorEltype(product(f1, countfrom(1)))) == Base.HasEltype() # FIXME? eltype(f1) is Any + @test (@inferred Base.IteratorEltype(product(countfrom(1), f1))) == Base.HasEltype() # FIXME? eltype(f1) is Any +end +@test (@inferred Base.IteratorEltype(product(1:2, countfrom(1)))) == Base.HasEltype() +@test (@inferred Base.IteratorEltype(product(countfrom(1), 1:2))) == Base.HasEltype() +@test (@inferred Base.IteratorEltype(product(1:2))) == Base.HasEltype() +@test (@inferred Base.IteratorEltype(product(1:2, 1:2))) == Base.HasEltype() +@test (@inferred Base.IteratorEltype(product(take(1:2, 1), take(1:2, 1)))) == Base.HasEltype() +@test (@inferred Base.IteratorEltype(product(take(1:2, 2)))) == Base.HasEltype() +@test (@inferred Base.IteratorEltype(product([1 2; 3 4]))) == Base.HasEltype() +@test (@inferred Base.IteratorEltype(product())) == Base.HasEltype() @test collect(product(1:2,3:4)) == [(1,3) (1,4); (2,3) (2,4)] -@test isempty(collect(product(1:0,1:2))) -@test length(product(1:2,1:10,4:6)) == 60 -@test Base.IteratorSize(product(1:2, countfrom(1))) == Base.IsInfinite() +@test @inferred isempty(collect(product(1:0,1:2))) +@test (@inferred length(product(1:2,1:10,4:6))) == 60 +@test (@inferred Base.IteratorSize(product(1:2, countfrom(1)))) == Base.IsInfinite() @test Base.iterate(product()) == ((), true) @test Base.iterate(product(), 1) === nothing @@ -512,31 +512,31 @@ end @test collect(flatten(Any[flatten(Any[1:2, 4:5]), flatten(Any[6:7, 8:9])])) == Any[1,2,4,5,6,7,8,9] @test collect(flatten(Any[flatten(Any[1:2, 6:5]), flatten(Any[6:7, 8:9])])) == Any[1,2,6,7,8,9] @test collect(flatten(Any[2:1])) == Any[] -@test eltype(flatten(UnitRange{Int8}[1:2, 3:4])) == Int8 -@test eltype(flatten(([1, 2], [3.0, 4.0]))) == Real -@test eltype(flatten((a = [1, 2], b = Int8[3, 4]))) == Signed -@test eltype(flatten((Int[], Nothing[], Int[]))) == Union{Int, Nothing} -@test eltype(flatten((String[],))) == String -@test eltype(flatten((Int[], UInt[], Int8[],))) == Integer -@test eltype(flatten((; a = Int[], b = Nothing[], c = Int[]))) == Union{Int, Nothing} -@test eltype(flatten((; a = String[],))) == String -@test eltype(flatten((; a = Int[], b = UInt[], c = Int8[],))) == Integer -@test eltype(flatten(())) == Union{} -@test eltype(flatten((;))) == Union{} -@test length(flatten(zip(1:3, 4:6))) == 6 -@test length(flatten(1:6)) == 6 +@test (@inferred eltype(flatten(UnitRange{Int8}[1:2, 3:4]))) == Int8 +@test (@inferred eltype(flatten(([1, 2], [3.0, 4.0])))) == Real +@test (@inferred eltype(flatten((a = [1, 2], b = Int8[3, 4])))) == Signed +@test (@inferred eltype(flatten((Int[], Nothing[], Int[])))) == Union{Int, Nothing} +@test (@inferred eltype(flatten((String[],)))) == String +@test (@inferred eltype(flatten((Int[], UInt[], Int8[],)))) == Integer +@test (@inferred eltype(flatten((; a = Int[], b = Nothing[], c = Int[])))) == Union{Int, Nothing} +@test (@inferred eltype(flatten((; a = String[],)))) == String +@test (@inferred eltype(flatten((; a = Int[], b = UInt[], c = Int8[],)))) == Integer +@test (@inferred eltype(flatten(()))) == Union{} +@test (@inferred eltype(flatten((;)))) == Union{} +@test (@inferred length(flatten(zip(1:3, 4:6)))) == 6 +@test (@inferred length(flatten(1:6))) == 6 @test collect(flatten(Any[])) == Any[] @test collect(flatten(())) == Union{}[] @test_throws ArgumentError length(flatten(NTuple[(1,), ()])) # #16680 @test_throws ArgumentError length(flatten([[1], [1]])) @testset "IteratorSize trait for flatten" begin - @test Base.IteratorSize(Base.Flatten((i for i=1:2) for j=1:1)) == Base.SizeUnknown() - @test Base.IteratorSize(Base.Flatten((1,2))) == Base.HasLength() - @test Base.IteratorSize(Base.Flatten(1:2:4)) == Base.HasLength() + @test (@inferred Base.IteratorSize(Base.Flatten((i for i=1:2) for j=1:1))) == Base.SizeUnknown() + @test (@inferred Base.IteratorSize(Base.Flatten((1,2)))) == Base.HasLength() + @test (@inferred Base.IteratorSize(Base.Flatten(1:2:4))) == Base.HasLength() end -@test Base.IteratorEltype(Base.Flatten((i for i=1:2) for j=1:1)) == Base.EltypeUnknown() +@test (@inferred Base.IteratorEltype(Base.Flatten((i for i=1:2) for j=1:1))) == Base.EltypeUnknown() # see #29112, #29464, #29548 @test Base.return_types(Base.IteratorEltype, Tuple{Array}) == [Base.HasEltype] @@ -656,21 +656,21 @@ end @test_throws ArgumentError partition(1:10, -1) @test_throws ArgumentError partition(1:0, 0) @test_throws ArgumentError partition(1:0, -1) - @test isempty(partition(1:0, 1)) - @test isempty(partition(CartesianIndices((0,1)), 1)) + @test @inferred isempty(partition(1:0, 1)) + @test @inferred isempty(partition(CartesianIndices((0,1)), 1)) end @testset "exact partition eltypes" for a in (Base.OneTo(24), 1:24, 1:1:24, LinRange(1,10,24), .1:.1:2.4, Vector(1:24), CartesianIndices((4, 6)), Dict((1:24) .=> (1:24))) P = partition(a, 2) - @test eltype(P) === typeof(first(P)) - @test Iterators.IteratorEltype(P) == Iterators.HasEltype() + @test (@inferred eltype(P)) === typeof(first(P)) + @test (@inferred Iterators.IteratorEltype(P)) == Iterators.HasEltype() if a isa AbstractArray P = partition(vec(a), 2) - @test eltype(P) === typeof(first(P)) + @test (@inferred eltype(P)) === typeof(first(P)) P = partition(reshape(a, 6, 4), 2) - @test eltype(P) === typeof(first(P)) + @test (@inferred eltype(P)) === typeof(first(P)) P = partition(reshape(a, 2, 3, 4), 2) - @test eltype(P) === typeof(first(P)) + @test (@inferred eltype(P)) === typeof(first(P)) end end @@ -691,19 +691,19 @@ let s = "Monkey 🙈🙊🙊" @test tf(1) == "M|o|n|k|e|y| |🙈|🙊|🙊" end -@test Base.IteratorEltype(partition([1,2,3,4], 2)) == Base.HasEltype() -@test Base.IteratorEltype(partition((2x for x in 1:3), 2)) == Base.EltypeUnknown() +@test (@inferred Base.IteratorEltype(partition([1,2,3,4], 2))) == Base.HasEltype() +@test (@inferred Base.IteratorEltype(partition((2x for x in 1:3), 2))) == Base.EltypeUnknown() # take and friends with arbitrary integers (#19214) for T in (UInt8, UInt16, UInt32, UInt64, UInt128, Int8, Int16, Int128, BigInt) - @test length(take(1:6, T(3))) == 3 - @test length(drop(1:6, T(3))) == 3 - @test length(repeated(1, T(5))) == 5 + @test (@inferred length(take(1:6, T(3)))) == 3 + @test (@inferred length(drop(1:6, T(3)))) == 3 + @test (@inferred length(repeated(1, T(5)))) == 5 @test collect(partition(1:5, T(5)))[1] == 1:5 end @testset "collect finite iterators issue #12009" begin - @test eltype(collect(enumerate(Iterators.Filter(x -> x>0, randn(10))))) == Tuple{Int, Float64} + @test (@inferred eltype(collect(enumerate(Iterators.Filter(x -> x>0, randn(10)))))) == Tuple{Int, Float64} end @testset "product iterator infinite loop" begin @@ -712,8 +712,8 @@ end @testset "filter empty iterable #16704" begin arr = filter(Returns(true), 1:0) - @test length(arr) == 0 - @test eltype(arr) == Int + @test (@inferred length(arr)) == 0 + @test (@inferred eltype(arr)) == Int end @testset "Pairs type" begin @@ -727,19 +727,19 @@ end ) d = pairs(A) @test d === pairs(d) - @test isempty(d) == isempty(A) - @test length(d) == length(A) + @test (@inferred isempty(d)) == isempty(A) + @test (@inferred length(d)) == length(A) @test keys(d) == keys(A) @test values(d) == A - @test Base.IteratorSize(d) == Base.IteratorSize(A) - @test Base.IteratorEltype(d) == Base.HasEltype() - @test Base.IteratorSize(pairs([1 2;3 4])) isa Base.HasShape{2} - @test isempty(d) || haskey(d, first(keys(d))) + @test (@inferred Base.IteratorSize(d)) == Base.IteratorSize(A) + @test (@inferred Base.IteratorEltype(d)) == Base.HasEltype() + @test (@inferred Base.IteratorSize(pairs([1 2;3 4]))) isa Base.HasShape{2} + @test (@inferred isempty(d)) || haskey(d, first(keys(d))) @test collect(v for (k, v) in d) == collect(A) if A isa NamedTuple K = Symbol V = isempty(d) ? Union{} : Float64 - @test isempty(d) || haskey(d, :a) + @test (@inferred isempty(d)) || haskey(d, :a) @test !haskey(d, :abc) @test !haskey(d, 1) @test get(A, :key) do; 99; end == 99 @@ -759,7 +759,7 @@ end end @test keytype(d) == K @test valtype(d) == V - @test eltype(d) == Pair{K, V} + @test (@inferred eltype(d)) == Pair{K, V} end let io = IOBuffer() @@ -806,7 +806,7 @@ end @testset "Iterators.Stateful" begin let a = @inferred(Iterators.Stateful("abcdef")) - @test !isempty(a) + @test !(@inferred isempty(a)) @test popfirst!(a) == 'a' @test collect(Iterators.take(a, 3)) == ['b','c','d'] @test collect(a) == ['e', 'f'] @@ -817,63 +817,63 @@ end @test peek(a) == 3 @test sum(a) == 7 end - @test eltype(Iterators.Stateful("a")) == Char + @test (@inferred eltype(Iterators.Stateful("a"))) == Char # Interaction of zip/Stateful let a = Iterators.Stateful("a"), b = "" - @test isempty(collect(zip(a,b))) - @test !isempty(a) - @test isempty(collect(zip(b,a))) - @test !isempty(a) + @test @inferred isempty(collect(zip(a,b))) + @test !(@inferred isempty(a)) + @test @inferred isempty(collect(zip(b,a))) + @test !(@inferred isempty(a)) end let a = Iterators.Stateful("a"), b = "", c = Iterators.Stateful("c") - @test isempty(collect(zip(a,b,c))) - @test !isempty(a) - @test !isempty(c) - @test isempty(collect(zip(a,c,b))) - @test !isempty(a) - @test !isempty(c) - @test isempty(collect(zip(b,a,c))) - @test !isempty(a) - @test !isempty(c) - @test isempty(collect(zip(b,c,a))) - @test !isempty(a) - @test !isempty(c) - @test isempty(collect(zip(c,a,b))) - @test !isempty(a) - @test !isempty(c) - @test isempty(collect(zip(c,b,a))) - @test !isempty(a) - @test !isempty(c) + @test @inferred isempty(collect(zip(a,b,c))) + @test !(@inferred isempty(a)) + @test !(@inferred isempty(c)) + @test @inferred isempty(collect(zip(a,c,b))) + @test !(@inferred isempty(a)) + @test !(@inferred isempty(c)) + @test @inferred isempty(collect(zip(b,a,c))) + @test !(@inferred isempty(a)) + @test !(@inferred isempty(c)) + @test @inferred isempty(collect(zip(b,c,a))) + @test !(@inferred isempty(a)) + @test !(@inferred isempty(c)) + @test @inferred isempty(collect(zip(c,a,b))) + @test !(@inferred isempty(a)) + @test !(@inferred isempty(c)) + @test @inferred isempty(collect(zip(c,b,a))) + @test !(@inferred isempty(a)) + @test !(@inferred isempty(c)) end let a = Iterators.Stateful("aa"), b = "b", c = Iterators.Stateful("cc") - @test length(collect(zip(a,b,c))) == 1 - @test !isempty(a) - @test !isempty(c) + @test (@inferred length(collect(zip(a,b,c)))) == 1 + @test !(@inferred isempty(a)) + @test !(@inferred isempty(c)) end let a = Iterators.Stateful("aa"), b = "b", c = Iterators.Stateful("cc") - @test length(collect(zip(a,c,b))) == 1 - @test !isempty(a) - @test !isempty(c) + @test (@inferred length(collect(zip(a,c,b)))) == 1 + @test !(@inferred isempty(a)) + @test !(@inferred isempty(c)) end let a = Iterators.Stateful("aa"), b = "b", c = Iterators.Stateful("cc") - @test length(collect(zip(b,a,c))) == 1 - @test !isempty(a) - @test !isempty(c) + @test (@inferred length(collect(zip(b,a,c)))) == 1 + @test !(@inferred isempty(a)) + @test !(@inferred isempty(c)) end let a = Iterators.Stateful("aa"), b = "b", c = Iterators.Stateful("cc") - @test length(collect(zip(b,c,a))) == 1 - @test !isempty(a) - @test !isempty(c) + @test (@inferred length(collect(zip(b,c,a)))) == 1 + @test !(@inferred isempty(a)) + @test !(@inferred isempty(c)) end let a = Iterators.Stateful("aa"), b = "b", c = Iterators.Stateful("cc") - @test length(collect(zip(c,a,b))) == 1 - @test !isempty(a) - @test !isempty(c) + @test (@inferred length(collect(zip(c,a,b)))) == 1 + @test !(@inferred isempty(a)) + @test !(@inferred isempty(c)) end let a = Iterators.Stateful("aa"), b = "b", c = Iterators.Stateful("cc") - @test length(collect(zip(c,b,a))) == 1 - @test !isempty(a) - @test !isempty(c) + @test (@inferred length(collect(zip(c,b,a)))) == 1 + @test !(@inferred isempty(a)) + @test !(@inferred isempty(c)) end let z = zip(Iterators.Stateful("ab"), Iterators.Stateful("b"), Iterators.Stateful("c")) v, s = iterate(z) @@ -894,10 +894,10 @@ end @testset "inference for large zip #26765" begin x = zip(1:2, ["a", "b"], (1.0, 2.0), Base.OneTo(2), Iterators.repeated("a"), 1.0:0.2:2.0, (1 for i in 1:2), Iterators.Stateful(["a", "b", "c"]), (1.0 for i in 1:2, j in 1:3)) - @test Base.IteratorSize(x) isa Base.SizeUnknown + @test (@inferred Base.IteratorSize(x)) isa Base.SizeUnknown x = zip(1:2, ["a", "b"], (1.0, 2.0), Base.OneTo(2), Iterators.repeated("a"), 1.0:0.2:2.0, (1 for i in 1:2), Iterators.cycle(Iterators.Stateful(["a", "b", "c"])), (1.0 for i in 1:2, j in 1:3)) - @test Base.IteratorSize(x) isa Base.HasLength + @test (@inferred Base.IteratorSize(x)) isa Base.HasLength @test @inferred(length(x)) == 2 z = Iterators.filter(x -> x[1] >= 1, x) @test @inferred(eltype(z)) <: Tuple{Int,String,Float64,Int,String,Float64,Any,String,Any} @@ -906,23 +906,23 @@ end end @testset "Stateful fix #30643" begin - @test Base.IteratorSize(1:10) isa Base.HasShape{1} + @test (@inferred Base.IteratorSize(1:10)) isa Base.HasShape{1} a = Iterators.Stateful(1:10) - @test Base.IteratorSize(a) isa Base.SizeUnknown + @test (@inferred Base.IteratorSize(a)) isa Base.SizeUnknown @test !Base.isdone(a) @test length(collect(a)) == 10 @test Base.isdone(a) b = Iterators.Stateful(Iterators.take(1:10,3)) - @test Base.IteratorSize(b) isa Base.SizeUnknown + @test (@inferred Base.IteratorSize(b)) isa Base.SizeUnknown @test !Base.isdone(b) @test length(collect(b)) == 3 @test Base.isdone(b) c = Iterators.Stateful(Iterators.countfrom(1)) - @test Base.IteratorSize(c) isa Base.IsInfinite + @test (@inferred Base.IteratorSize(c)) isa Base.IsInfinite @test !Base.isdone(Iterators.take(c,3)) @test length(collect(Iterators.take(c,3))) == 3 d = Iterators.Stateful(Iterators.filter(isodd,1:10)) - @test Base.IteratorSize(d) isa Base.SizeUnknown + @test (@inferred Base.IteratorSize(d)) isa Base.SizeUnknown @test length(collect(Iterators.take(d,3))) == 3 @test length(collect(d)) == 2 @test length(collect(d)) == 0 @@ -964,7 +964,7 @@ end end @testset "flatten empty tuple" begin - @test isempty(collect(Iterators.flatten(()))) + @test @inferred isempty(collect(Iterators.flatten(()))) end @testset "Iterators.accumulate" begin @@ -976,10 +976,10 @@ end @test collect(Iterators.accumulate(+, (x for x in [true])))::Vector{Int} == [1] @test collect(Iterators.accumulate(+, (x for x in [true, true, false])))::Vector{Int} == [1, 2, 2] @test collect(Iterators.accumulate(+, (x for x in [true]), init=10.0))::Vector{Float64} == [11.0] - @test length(Iterators.accumulate(+, [10,20,30])) == 3 - @test size(Iterators.accumulate(max, rand(2,3))) == (2,3) - @test Base.IteratorSize(Iterators.accumulate(max, rand(2,3))) === Base.IteratorSize(rand(2,3)) - @test Base.IteratorEltype(Iterators.accumulate(*, ())) isa Base.EltypeUnknown + @test (@inferred length(Iterators.accumulate(+, [10,20,30]))) == 3 + @test (@inferred size(Iterators.accumulate(max, rand(2,3)))) == (2,3) + @test (@inferred Base.IteratorSize(Iterators.accumulate(max, rand(2,3)))) === Base.IteratorSize(rand(2,3)) + @test (@inferred Base.IteratorEltype(Iterators.accumulate(*, ()))) isa Base.EltypeUnknown end @testset "Base.accumulate" begin @@ -989,13 +989,13 @@ end end @testset "IteratorSize trait for zip" begin - @test Base.IteratorSize(zip()) == Base.IsInfinite() # for zip of empty tuple - @test Base.IteratorSize(zip((1,2,3), repeated(0))) == Base.HasLength() # for zip of ::HasLength and ::IsInfinite - @test Base.IteratorSize(zip( 1:5, repeated(0) )) == Base.HasLength() # for zip of ::HasShape and ::IsInfinite - @test Base.IteratorSize(zip(repeated(0), (1,2,3))) == Base.HasLength() # for zip of ::IsInfinite and ::HasLength - @test Base.IteratorSize(zip(repeated(0), 1:5 )) == Base.HasLength() # for zip of ::IsInfinite and ::HasShape - @test Base.IteratorSize(zip((1,2,3), 1:5) ) == Base.HasLength() # for zip of ::HasLength and ::HasShape - @test Base.IteratorSize(zip(1:5, (1,2,3)) ) == Base.HasLength() # for zip of ::HasShape and ::HasLength + @test (@inferred Base.IteratorSize(zip())) == Base.IsInfinite() # for zip of empty tuple + @test (@inferred Base.IteratorSize(zip((1,2,3), repeated(0)))) == Base.HasLength() # for zip of ::HasLength and ::IsInfinite + @test (@inferred Base.IteratorSize(zip( 1:5, repeated(0) ))) == Base.HasLength() # for zip of ::HasShape and ::IsInfinite + @test (@inferred Base.IteratorSize(zip(repeated(0), (1,2,3)))) == Base.HasLength() # for zip of ::IsInfinite and ::HasLength + @test (@inferred Base.IteratorSize(zip(repeated(0), 1:5 ))) == Base.HasLength() # for zip of ::IsInfinite and ::HasShape + @test (@inferred Base.IteratorSize(zip((1,2,3), 1:5) )) == Base.HasLength() # for zip of ::HasLength and ::HasShape + @test (@inferred Base.IteratorSize(zip(1:5, (1,2,3)) )) == Base.HasLength() # for zip of ::HasShape and ::HasLength end @testset "proper partition for non-1-indexed vector" begin @@ -1018,7 +1018,7 @@ end @testset "isempty and isdone for Generators" begin itr = eachline(IOBuffer("foo\n")) gen = (x for x in itr) - @test !isempty(gen) + @test !(@inferred isempty(gen)) @test !Base.isdone(gen) @test collect(gen) == ["foo"] end From 316f0fe0b0e454093b44095bb99b273d4158bdc0 Mon Sep 17 00:00:00 2001 From: David Anthoff Date: Thu, 16 Jan 2025 08:05:28 -0500 Subject: [PATCH 202/342] Construct proper URIs for paths when run on WSL in tests (#57061) https://github.com/JuliaLang/julia/pull/55454 produces the correct URIs when run on WSL, but the tests don't use the same logic and so they fail on WSL at the moment. This fixes the tests on WSL. CC @tecosaur --- test/path.jl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/path.jl b/test/path.jl index 4c2c7034577d5..2515d765d8ca9 100644 --- a/test/path.jl +++ b/test/path.jl @@ -312,7 +312,14 @@ end @testset "uripath" begin - host = if Sys.iswindows() "" else gethostname() end + host = if Sys.iswindows() + "" + elseif ispath("/proc/sys/fs/binfmt_misc/WSLInterop") + distro = get(ENV, "WSL_DISTRO_NAME", "") # See + "wsl%24/$distro" # See and + else + gethostname() + end sysdrive, uridrive = if Sys.iswindows() "C:\\", "C:/" else "/", "" end @test Base.Filesystem.uripath("$(sysdrive)some$(sep)file.txt") == "file://$host/$(uridrive)some/file.txt" @test Base.Filesystem.uripath("$(sysdrive)another$(sep)$(sep)folder$(sep)file.md") == "file://$host/$(uridrive)another/folder/file.md" From 0c7dd964f67d5a31750f5779d858c3d52aba931e Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Fri, 17 Jan 2025 01:54:24 -0500 Subject: [PATCH 203/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?SparseArrays=20stdlib=20from=205f52721=20to=20212981b=20(#57065?= =?UTF-8?q?)?= 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: main Julia branch: master Old commit: 5f52721 New commit: 212981b Julia version: 1.12.0-DEV SparseArrays version: 1.12.0 Bump invoked by: @dkarrasch Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaSparse/SparseArrays.jl/compare/5f527215c188ee99247cdce31ba8ce9e11f35055...212981bf29b03ba460d3251ee9aa4399931b3f2d ``` $ git log --oneline 5f52721..212981b 212981b Solve with `AdjointFactorization` of Cholmod and `Adjoint` rhs (#595) ``` 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-212981bf29b03ba460d3251ee9aa4399931b3f2d.tar.gz/md5 create mode 100644 deps/checksums/SparseArrays-212981bf29b03ba460d3251ee9aa4399931b3f2d.tar.gz/sha512 delete mode 100644 deps/checksums/SparseArrays-5f527215c188ee99247cdce31ba8ce9e11f35055.tar.gz/md5 delete mode 100644 deps/checksums/SparseArrays-5f527215c188ee99247cdce31ba8ce9e11f35055.tar.gz/sha512 diff --git a/deps/checksums/SparseArrays-212981bf29b03ba460d3251ee9aa4399931b3f2d.tar.gz/md5 b/deps/checksums/SparseArrays-212981bf29b03ba460d3251ee9aa4399931b3f2d.tar.gz/md5 new file mode 100644 index 0000000000000..3fddcf07235f8 --- /dev/null +++ b/deps/checksums/SparseArrays-212981bf29b03ba460d3251ee9aa4399931b3f2d.tar.gz/md5 @@ -0,0 +1 @@ +621e67dc98707b587fb0f6e319dadbb2 diff --git a/deps/checksums/SparseArrays-212981bf29b03ba460d3251ee9aa4399931b3f2d.tar.gz/sha512 b/deps/checksums/SparseArrays-212981bf29b03ba460d3251ee9aa4399931b3f2d.tar.gz/sha512 new file mode 100644 index 0000000000000..68885439a1213 --- /dev/null +++ b/deps/checksums/SparseArrays-212981bf29b03ba460d3251ee9aa4399931b3f2d.tar.gz/sha512 @@ -0,0 +1 @@ +5608adf92eaf7479eacf5ed75b3139438d0d4acf53d55a38c73a553c7fd899f553e1648fa657d35b9a0289e69fc461025dae5f8d15ec891eafcab3a663a8413a diff --git a/deps/checksums/SparseArrays-5f527215c188ee99247cdce31ba8ce9e11f35055.tar.gz/md5 b/deps/checksums/SparseArrays-5f527215c188ee99247cdce31ba8ce9e11f35055.tar.gz/md5 deleted file mode 100644 index 946bec189c1bd..0000000000000 --- a/deps/checksums/SparseArrays-5f527215c188ee99247cdce31ba8ce9e11f35055.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -4b07db52a5a6d3cc6eeab380bd783a1e diff --git a/deps/checksums/SparseArrays-5f527215c188ee99247cdce31ba8ce9e11f35055.tar.gz/sha512 b/deps/checksums/SparseArrays-5f527215c188ee99247cdce31ba8ce9e11f35055.tar.gz/sha512 deleted file mode 100644 index 846867193d932..0000000000000 --- a/deps/checksums/SparseArrays-5f527215c188ee99247cdce31ba8ce9e11f35055.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -4c631f1046ad0a6b972a4dce285c2092372ecbed269c83524c10b4be5124035670d703af53e1f8058d23230be20c06aa554097cc9bc7a12b3de3c039d3c545e8 diff --git a/stdlib/SparseArrays.version b/stdlib/SparseArrays.version index 3f6ab5b878069..0234c754191f8 100644 --- a/stdlib/SparseArrays.version +++ b/stdlib/SparseArrays.version @@ -1,4 +1,4 @@ SPARSEARRAYS_BRANCH = main -SPARSEARRAYS_SHA1 = 5f527215c188ee99247cdce31ba8ce9e11f35055 +SPARSEARRAYS_SHA1 = 212981bf29b03ba460d3251ee9aa4399931b3f2d SPARSEARRAYS_GIT_URL := https://github.com/JuliaSparse/SparseArrays.jl.git SPARSEARRAYS_TAR_URL = https://api.github.com/repos/JuliaSparse/SparseArrays.jl/tarball/$1 From 81e79e5bfc5ccfd9d8a8d5825d5a508f1009d7b2 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 17 Jan 2025 06:31:59 -0500 Subject: [PATCH 204/342] codegen: handle recursive sparam calls in API (#57047) Fixes #56690 --- src/ccall.cpp | 5 +--- src/codegen.cpp | 56 +++++++++++++++++++-------------------- src/llvm-codegen-shared.h | 23 ++++++++-------- 3 files changed, 40 insertions(+), 44 deletions(-) diff --git a/src/ccall.cpp b/src/ccall.cpp index 1b635ca40840f..eb64adef447f4 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -461,10 +461,7 @@ static Value *runtime_apply_type_env(jl_codectx_t &ctx, jl_value_t *ty) Value *args[] = { literal_pointer_val(ctx, ty), literal_pointer_val(ctx, (jl_value_t*)ctx.linfo->def.method->sig), - ctx.builder.CreateInBoundsGEP( - ctx.types().T_prjlvalue, - ctx.spvals_ptr, - ConstantInt::get(ctx.types().T_size, sizeof(jl_svec_t) / sizeof(jl_value_t*))) + emit_ptrgep(ctx, maybe_decay_tracked(ctx, ctx.spvals_ptr), sizeof(jl_svec_t)) }; auto call = ctx.builder.CreateCall(prepare_call(jlapplytype_func), ArrayRef(args)); addRetAttr(call, Attribute::getWithAlignment(ctx.builder.getContext(), Align(16))); diff --git a/src/codegen.cpp b/src/codegen.cpp index 7bc14d2d0347f..eefc675bdd665 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1263,12 +1263,11 @@ static const auto jlsubtype_func = new JuliaFunction<>{ static const auto jlapplytype_func = new JuliaFunction<>{ XSTR(jl_instantiate_type_in_env), [](LLVMContext &C) { - auto T_jlvalue = JuliaType::get_jlvalue_ty(C); - auto T_pjlvalue = PointerType::get(T_jlvalue, 0); - auto T_prjlvalue = PointerType::get(T_jlvalue, AddressSpace::Tracked); - auto T_pprjlvalue = PointerType::get(T_prjlvalue, 0); - return FunctionType::get(T_prjlvalue, - {T_pjlvalue, T_pjlvalue, T_pprjlvalue}, false); + auto T_ptr = PointerType::get(C, 0); + auto T_tracked = PointerType::get(C, AddressSpace::Tracked); + auto T_derived = PointerType::get(C, AddressSpace::Derived); + return FunctionType::get(T_tracked, + {T_ptr, T_ptr, T_derived}, false); }, [](LLVMContext &C) { return AttributeList::get(C, @@ -1377,11 +1376,10 @@ static const auto jlfieldisdefinedchecked_func = new JuliaFunction{ XSTR(jl_get_cfunction_trampoline), [](LLVMContext &C) { - auto T_jlvalue = JuliaType::get_jlvalue_ty(C); - auto T_pjlvalue = PointerType::get(T_jlvalue, 0); - auto T_prjlvalue = PointerType::get(T_jlvalue, AddressSpace::Tracked); - auto T_ppjlvalue = PointerType::get(T_pjlvalue, 0); - auto T_pprjlvalue = PointerType::get(T_prjlvalue, 0); + auto T_pjlvalue = PointerType::get(C, 0); + auto T_prjlvalue = PointerType::get(C, AddressSpace::Tracked); + auto T_ppjlvalue = PointerType::get(C, 0); + auto T_derived = PointerType::get(C, AddressSpace::Derived); return FunctionType::get(T_prjlvalue, { T_prjlvalue, // f (object) @@ -1390,7 +1388,7 @@ static const auto jlgetcfunctiontrampoline_func = new JuliaFunction<>{ T_pjlvalue, // fill FunctionType::get(getPointerTy(C), { getPointerTy(C), T_ppjlvalue }, false)->getPointerTo(), // trampoline T_pjlvalue, // env - T_pprjlvalue, // vals + T_derived, // vals }, false); }, [](LLVMContext &C) { return AttributeList::get(C, @@ -5610,18 +5608,23 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayR assert(jl_is_method_instance(mi)); if (mi == ctx.linfo) { // handle self-recursion specially (TODO: assuming ci is a valid invoke for mi?) - jl_returninfo_t::CallingConv cc = jl_returninfo_t::CallingConv::Boxed; - FunctionType *ft = ctx.f->getFunctionType(); - StringRef protoname = ctx.f->getName(); + Function *f = ctx.f; + FunctionType *ft = f->getFunctionType(); if (ft == ctx.types().T_jlfunc) { - result = emit_call_specfun_boxed(ctx, ctx.rettype, protoname, nullptr, argv, nargs, rt, age_ok); - handled = true; + Value *ret = emit_jlcall(ctx, f, nullptr, argv, nargs, julia_call); + result = update_julia_type(ctx, mark_julia_type(ctx, ret, true, ctx.rettype), rt); } - else if (ft != ctx.types().T_jlfuncparams) { + else if (ft == ctx.types().T_jlfuncparams) { + Value *ret = emit_jlcall(ctx, f, ctx.spvals_ptr, argv, nargs, julia_call2); + result = update_julia_type(ctx, mark_julia_type(ctx, ret, true, ctx.rettype), rt); + } + else { unsigned return_roots = 0; + jl_returninfo_t::CallingConv cc = jl_returninfo_t::CallingConv::Boxed; + StringRef protoname = f->getName(); result = emit_call_specfun_other(ctx, mi, ctx.rettype, protoname, nullptr, argv, nargs, &cc, &return_roots, rt, age_ok); - handled = true; } + handled = true; } else { if (ci) { @@ -5630,7 +5633,6 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayR // check if we know how to handle this specptr if (invoke == jl_fptr_const_return_addr) { result = mark_julia_const(ctx, codeinst->rettype_const); - handled = true; } else { bool specsig, needsparams; @@ -5640,8 +5642,8 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayR push_frames(ctx, ctx.linfo, mi); Value *r = emit_jlcall(ctx, jlinvoke_func, track_pjlvalue(ctx, literal_pointer_val(ctx, (jl_value_t*)mi)), argv, nargs, julia_call2); result = mark_julia_type(ctx, r, true, rt); - handled = true; - } else { + } + else { std::string name; StringRef protoname; bool need_to_emit = true; @@ -5689,7 +5691,6 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayR result = emit_call_specfun_other(ctx, codeinst, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, &cc, &return_roots, rt, age_ok); else result = emit_call_specfun_boxed(ctx, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, rt, age_ok); - handled = true; if (need_to_emit) { Function *trampoline_decl = cast(jl_Module->getNamedValue(protoname)); ctx.call_targets[codeinst] = {cc, return_roots, trampoline_decl, nullptr, specsig}; @@ -5698,6 +5699,7 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayR } } } + handled = true; } } } @@ -6078,8 +6080,7 @@ static jl_cgval_t emit_sparam(jl_codectx_t &ctx, size_t i) return mark_julia_const(ctx, e); } } - assert(ctx.spvals_ptr != NULL); - Value *bp = emit_ptrgep(ctx, ctx.spvals_ptr, i * sizeof(jl_value_t*) + sizeof(jl_svec_t)); + Value *bp = emit_ptrgep(ctx, maybe_decay_tracked(ctx, ctx.spvals_ptr), i * sizeof(jl_value_t*) + sizeof(jl_svec_t)); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const); Value *sp = ai.decorateInst(ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, bp, Align(sizeof(void*)))); setName(ctx.emission_context, sp, "sparam"); @@ -6131,8 +6132,7 @@ static jl_cgval_t emit_isdefined(jl_codectx_t &ctx, jl_value_t *sym, int allow_i return mark_julia_const(ctx, jl_true); } } - assert(ctx.spvals_ptr != NULL); - Value *bp = emit_ptrgep(ctx, ctx.spvals_ptr, i * sizeof(jl_value_t*) + sizeof(jl_svec_t)); + Value *bp = emit_ptrgep(ctx, maybe_decay_tracked(ctx, ctx.spvals_ptr), i * sizeof(jl_value_t*) + sizeof(jl_svec_t)); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const); Value *sp = ai.decorateInst(ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, bp, Align(sizeof(void*)))); isnull = ctx.builder.CreateICmpNE(emit_typeof(ctx, sp, false, true), emit_tagfrom(ctx, jl_tvar_type)); @@ -8000,7 +8000,7 @@ static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, con literal_pointer_val(ctx, (jl_value_t*)fill), F, closure_types ? literal_pointer_val(ctx, (jl_value_t*)unionall_env) : Constant::getNullValue(ctx.types().T_pjlvalue), - closure_types ? ctx.spvals_ptr : ConstantPointerNull::get(cast(ctx.types().T_pprjlvalue)) + closure_types ? decay_derived(ctx, ctx.spvals_ptr) : ConstantPointerNull::get(ctx.builder.getPtrTy(AddressSpace::Derived)) }); outboxed = true; } diff --git a/src/llvm-codegen-shared.h b/src/llvm-codegen-shared.h index d9551e0552f9c..ff6f5a97299d7 100644 --- a/src/llvm-codegen-shared.h +++ b/src/llvm-codegen-shared.h @@ -51,9 +51,9 @@ namespace JuliaType { static inline auto get_jlfunc_ty(llvm::LLVMContext &C) { auto T_prjlvalue = get_prjlvalue_ty(C); - auto T_pprjlvalue = llvm::PointerType::get(T_prjlvalue, 0); + auto T_pprjlvalue = llvm::PointerType::get(C, 0); return llvm::FunctionType::get(T_prjlvalue, { - T_prjlvalue, // function + T_prjlvalue, // function T_pprjlvalue, // args[] llvm::Type::getInt32Ty(C)}, // nargs false); @@ -61,21 +61,21 @@ namespace JuliaType { static inline auto get_jlfunc2_ty(llvm::LLVMContext &C) { auto T_prjlvalue = get_prjlvalue_ty(C); - auto T_pprjlvalue = llvm::PointerType::get(T_prjlvalue, 0); + auto T_pprjlvalue = llvm::PointerType::get(C, 0); return llvm::FunctionType::get(T_prjlvalue, { - T_prjlvalue, // function + T_prjlvalue, // function T_pprjlvalue, // args[] llvm::Type::getInt32Ty(C), // nargs - T_prjlvalue}, // linfo + T_prjlvalue}, // linfo false); } static inline auto get_jlfunc3_ty(llvm::LLVMContext &C) { auto T_prjlvalue = get_prjlvalue_ty(C); - auto T_pprjlvalue = llvm::PointerType::get(T_prjlvalue, 0); + auto T_pprjlvalue = llvm::PointerType::get(C, 0); auto T = get_pjlvalue_ty(C, Derived); return llvm::FunctionType::get(T_prjlvalue, { - T, // function + T, // function T_pprjlvalue, // args[] llvm::Type::getInt32Ty(C)}, // nargs false); @@ -83,13 +83,12 @@ namespace JuliaType { static inline auto get_jlfuncparams_ty(llvm::LLVMContext &C) { auto T_prjlvalue = get_prjlvalue_ty(C); - auto T_pprjlvalue = llvm::PointerType::get(T_prjlvalue, 0); + auto T_pprjlvalue = llvm::PointerType::get(C, 0); return llvm::FunctionType::get(T_prjlvalue, { - T_prjlvalue, // function + T_prjlvalue, // function T_pprjlvalue, // args[] - llvm::Type::getInt32Ty(C), - T_pprjlvalue, // linfo->sparam_vals - }, // nargs + llvm::Type::getInt32Ty(C), // nargs + T_prjlvalue}, // linfo->sparam_vals false); } From 9ea547a36e4d3e0d36bd45ec20552508a3075722 Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Fri, 17 Jan 2025 10:28:20 -0700 Subject: [PATCH 205/342] Add try/catch around handle_message() to catch errors during logging. (#57004) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/JuliaLang/julia/issues/56889. Before this PR, an exception thrown while constructing the objects to log (the `msg`) would be caught and logged. However, an exception thrown while _printing_ the msg to an IO would _not_ be caught, and can abort the program. This breaks the promise that enabling verbose debug logging shouldn't introduce new crashes. After this PR, an exception thrown during handle_message is caught and logged, just like an exception during `msg` construction: ```julia julia> struct Foo end julia> Base.show(::IO, ::Foo) = error("oh no") julia> begin # Unexpectedly, the execption thrown while printing `Foo()` escapes @info Foo() # So we never reach this line! :'( println("~~~~~ ALL DONE ~~~~~~~~") end ┌ Error: Exception while generating log record in module Main at REPL[10]:3 │ exception = │ oh no │ Stacktrace: │ [1] error(s::String) │ @ Base ./error.jl:44 │ [2] show(::IOBuffer, ::Foo) │ @ Main ./REPL[9]:1 ... │ [30] repl_main │ @ ./client.jl:593 [inlined] │ [31] _start() │ @ Base ./client.jl:568 └ @ Main REPL[10]:3 ~~~~~ ALL DONE ~~~~~~~~ ``` This PR respects the change made in https://github.com/JuliaLang/julia/pull/36600 to keep the codegen as small as possible, by putting the new try/catch into a no-inlined function, so that we don't have to introduce a new try/catch in the macro-generated code body. --------- Co-authored-by: Jameson Nash --- base/logging/logging.jl | 14 +++++++++++++- test/corelogging.jl | 13 +++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/base/logging/logging.jl b/base/logging/logging.jl index 5cf3882a300ec..41721e84cc934 100644 --- a/base/logging/logging.jl +++ b/base/logging/logging.jl @@ -409,7 +409,7 @@ function logmsg_code(_module, file, line, level, message, exs...) end line = $(log_data._line) local msg, kwargs - $(logrecord) && invokelatest($handle_message, + $(logrecord) && $handle_message_nothrow( logger, level, msg, _module, group, id, file, line; kwargs...) end @@ -420,6 +420,18 @@ function logmsg_code(_module, file, line, level, message, exs...) end end +@noinline function handle_message_nothrow(logger, level, msg, _module, group, id, file, line; kwargs...) + @nospecialize + try + @invokelatest handle_message( + logger, level, msg, _module, group, id, file, line; + kwargs...) + + catch err + @invokelatest logging_error(logger, level, _module, group, id, file, line, err, true) + end +end + function process_logmsg_exs(_orig_module, _file, _line, level, message, exs...) @nospecialize local _group, _id diff --git a/test/corelogging.jl b/test/corelogging.jl index b8cd3716cad2e..154202da759c2 100644 --- a/test/corelogging.jl +++ b/test/corelogging.jl @@ -114,6 +114,19 @@ end @test only(collect_test_logs(logmsg)[1]).kwargs[:x] === "the y" end end +@testset "Log message handle_message exception handling" begin + # Exceptions in log handling (printing) of msg are caught by default. + struct Foo end + Base.show(::IO, ::Foo) = 1 ÷ 0 + + # We cannot use `@test_logs` here, since test_logs does not actually _print_ the message + # (i.e. it does not invoke handle_message). To test exception handling during printing, + # we have to use `@test_warn` to see what was printed. + @test_warn r"Error: Exception while generating log record in module .*DivideError: integer division error"s @info Foo() + + # Exceptions in log handling (printing) of attributes are caught by default + @test_warn r"Error: Exception while generating log record in module .*DivideError: integer division error"s @info "foo" x=Foo() +end @testset "Special keywords" begin logger = TestLogger() From 98f8aca9ac8eb1c9467b685c7e8594d981192d96 Mon Sep 17 00:00:00 2001 From: Eduardo Souza Date: Sat, 18 Jan 2025 04:53:52 +1100 Subject: [PATCH 206/342] Adding `precompile_field_replace` to MMTk's roots (#57073) Add `precompile_field_replace` and update the `mmtk_julia` binding version to account for the change from https://github.com/JuliaLang/julia/commit/b8ab9f37469d9c19eeac1f9b5d40a499d3a176e8. --- deps/checksums/mmtk_julia | 4 ++++ .../md5 | 1 - .../sha512 | 1 - deps/mmtk_julia.version | 4 ++-- src/gc-mmtk.c | 3 +++ 5 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 deps/checksums/mmtk_julia delete mode 100644 deps/checksums/mmtk_julia-b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214.tar.gz/md5 delete mode 100644 deps/checksums/mmtk_julia-b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214.tar.gz/sha512 diff --git a/deps/checksums/mmtk_julia b/deps/checksums/mmtk_julia new file mode 100644 index 0000000000000..49b7a50a8e136 --- /dev/null +++ b/deps/checksums/mmtk_julia @@ -0,0 +1,4 @@ +mmtk_julia-b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214.tar.gz/md5/1911cf084d26c48e2ed58af3d268b4b6 +mmtk_julia-b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214.tar.gz/sha512/75beab54398989c46b62e714b242cf6705d88d220f40c21e494e0f29161437f5fbe9ba05b543d2353a1ad76f4239ac4025b476be0be864649f310f14935289fe +mmtk_julia-f07d66aafc86af84ea988b35335acc9bbc770fa1.tar.gz/md5/38afb5db6d8c55413a4ec96aefa2ebb4 +mmtk_julia-f07d66aafc86af84ea988b35335acc9bbc770fa1.tar.gz/sha512/78525582a46a6baf8d33df7b622e55cf244439afcd7192ba55489c1bc18393d1237d2903d517c610484bf9e2a7338ad31435a9cbf70889d6bcf87c40cec829e5 \ No newline at end of file diff --git a/deps/checksums/mmtk_julia-b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214.tar.gz/md5 b/deps/checksums/mmtk_julia-b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214.tar.gz/md5 deleted file mode 100644 index fc6955c8f2e7b..0000000000000 --- a/deps/checksums/mmtk_julia-b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -1911cf084d26c48e2ed58af3d268b4b6 diff --git a/deps/checksums/mmtk_julia-b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214.tar.gz/sha512 b/deps/checksums/mmtk_julia-b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214.tar.gz/sha512 deleted file mode 100644 index ea916976895a3..0000000000000 --- a/deps/checksums/mmtk_julia-b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -75beab54398989c46b62e714b242cf6705d88d220f40c21e494e0f29161437f5fbe9ba05b543d2353a1ad76f4239ac4025b476be0be864649f310f14935289fe diff --git a/deps/mmtk_julia.version b/deps/mmtk_julia.version index 60f7cffe7b4de..4d821bffd5b9b 100644 --- a/deps/mmtk_julia.version +++ b/deps/mmtk_julia.version @@ -1,4 +1,4 @@ MMTK_JULIA_BRANCH = master -MMTK_JULIA_SHA1 = b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214 +MMTK_JULIA_SHA1 = f07d66aafc86af84ea988b35335acc9bbc770fa1 MMTK_JULIA_GIT_URL := https://github.com/mmtk/mmtk-julia.git -MMTK_JULIA_TAR_URL = https://github.com/mmtk/mmtk-julia/archive/refs/tags/v0.30.2.tar.gz +MMTK_JULIA_TAR_URL = https://github.com/mmtk/mmtk-julia/archive/refs/tags/v0.30.3.tar.gz diff --git a/src/gc-mmtk.c b/src/gc-mmtk.c index 78882c8eb0225..5ec1e34cc1acd 100644 --- a/src/gc-mmtk.c +++ b/src/gc-mmtk.c @@ -497,6 +497,9 @@ JL_DLLEXPORT void jl_gc_scan_vm_specific_roots(RootsWorkClosure* closure) add_node_to_tpinned_roots_buffer(closure, &tpinned_buf, &tpinned_len, jl_global_roots_list); add_node_to_tpinned_roots_buffer(closure, &tpinned_buf, &tpinned_len, jl_global_roots_keyset); + // FIXME: transivitely pinning for now, should be removed after we add moving Immix + add_node_to_tpinned_roots_buffer(closure, &tpinned_buf, &tpinned_len, precompile_field_replace); + // Push the result of the work. (closure->report_nodes_func)(buf.ptr, len, buf.cap, closure->data, false); (closure->report_tpinned_nodes_func)(tpinned_buf.ptr, tpinned_len, tpinned_buf.cap, closure->data, false); From 647b9f4c53f66fed106e2dcac3906fe55a280e7c Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Fri, 17 Jan 2025 18:19:01 -0500 Subject: [PATCH 207/342] Add timeout parameter to `wait(::Condition)` (#56974) We have a need for this capability. I believe this closes https://github.com/JuliaLang/julia/issues/36217. The implementation is straightforward and there are a couple of tests. --- base/condition.jl | 90 +++++++++++++++++++++++++++++++++++++++++++++-- test/channels.jl | 17 +++++++++ 2 files changed, 104 insertions(+), 3 deletions(-) diff --git a/base/condition.jl b/base/condition.jl index fd771c9be346a..90c53b7ad310d 100644 --- a/base/condition.jl +++ b/base/condition.jl @@ -125,20 +125,104 @@ proceeding. """ function wait end +# wait with timeout +# +# The behavior of wait changes if a timeout is specified. There are +# three concurrent entities that can interact: +# 1. Task W: the task that calls wait w/timeout. +# 2. Task T: the task created to handle a timeout. +# 3. Task N: the task that notifies the Condition being waited on. +# +# Typical flow: +# - W enters the Condition's wait queue. +# - W creates T and stops running (calls wait()). +# - T, when scheduled, waits on a Timer. +# - Two common outcomes: +# - N notifies the Condition. +# - W starts running, closes the Timer, sets waiter_left and returns +# the notify'ed value. +# - The closed Timer throws an EOFError to T which simply ends. +# - The Timer expires. +# - T starts running and locks the Condition. +# - T confirms that waiter_left is unset and that W is still in the +# Condition's wait queue; it then removes W from the wait queue, +# sets dosched to true and unlocks the Condition. +# - If dosched is true, T schedules W with the special :timed_out +# value. +# - T ends. +# - W runs and returns :timed_out. +# +# Some possible interleavings: +# - N notifies the Condition but the Timer expires and T starts running +# before W: +# - W closing the expired Timer is benign. +# - T will find that W is no longer in the Condition's wait queue +# (which is protected by a lock) and will not schedule W. +# - N notifies the Condition; W runs and calls wait on the Condition +# again before the Timer expires: +# - W sets waiter_left before leaving. When T runs, it will find that +# waiter_left is set and will not schedule W. +# +# The lock on the Condition's wait queue and waiter_left together +# ensure proper synchronization and behavior of the tasks involved. + """ - wait(c::GenericCondition; first::Bool=false) + wait(c::GenericCondition; first::Bool=false, timeout::Real=0.0) Wait for [`notify`](@ref) on `c` and return the `val` parameter passed to `notify`. If the keyword `first` is set to `true`, the waiter will be put _first_ in line to wake up on `notify`. Otherwise, `wait` has first-in-first-out (FIFO) behavior. + +If `timeout` is specified, cancel the `wait` when it expires and return +`:timed_out`. The minimum value for `timeout` is 0.001 seconds, i.e. 1 +millisecond. """ -function wait(c::GenericCondition; first::Bool=false) +function wait(c::GenericCondition; first::Bool=false, timeout::Real=0.0) + timeout == 0.0 || timeout ≥ 1e-3 || throw(ArgumentError("timeout must be ≥ 1 millisecond")) + ct = current_task() _wait2(c, ct, first) token = unlockall(c.lock) + + timer::Union{Timer, Nothing} = nothing + waiter_left::Union{Threads.Atomic{Bool}, Nothing} = nothing + if timeout > 0.0 + timer = Timer(timeout) + waiter_left = Threads.Atomic{Bool}(false) + # start a task to wait on the timer + t = Task() do + try + wait(timer) + catch e + # if the timer was closed, the waiting task has been scheduled; do nothing + e isa EOFError && return + end + dosched = false + lock(c.lock) + # Confirm that the waiting task is still in the wait queue and remove it. If + # the task is not in the wait queue, it must have been notified already so we + # don't do anything here. + if !waiter_left[] && ct.queue == c.waitq + dosched = true + Base.list_deletefirst!(c.waitq, ct) + end + unlock(c.lock) + # send the waiting task a timeout + dosched && schedule(ct, :timed_out) + end + t.sticky = false + Threads._spawn_set_thrpool(t, :interactive) + schedule(t) + end + try - return wait() + res = wait() + if timer !== nothing + close(timer) + waiter_left[] = true + end + return res catch q = ct.queue; q === nothing || Base.list_deletefirst!(q::IntrusiveLinkedList{Task}, ct) rethrow() diff --git a/test/channels.jl b/test/channels.jl index 4acf6c94da1b6..6e74a2079234c 100644 --- a/test/channels.jl +++ b/test/channels.jl @@ -1,6 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license using Random +using Base.Threads using Base: Experimental using Base: n_avail @@ -39,6 +40,22 @@ end @test fetch(t) == "finished" end +@testset "timed wait on Condition" begin + a = Threads.Condition() + @test_throws ArgumentError @lock a wait(a; timeout=0.0005) + @test @lock a wait(a; timeout=0.1)==:timed_out + lock(a) + @spawn begin + @lock a notify(a) + end + @test try + wait(a; timeout=2) + true + finally + unlock(a) + end +end + @testset "various constructors" begin c = Channel() @test eltype(c) == Any From 11c692e1084a631bb40d5348b7074ed58c634714 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Fri, 17 Jan 2025 20:54:15 -0300 Subject: [PATCH 208/342] add option to dump backtrace of stop-the-world straggler (#57045) This is still a work in progress, but it should help determine what a straggler thread was doing during the stop-the-world phase and why it failed to reach a safepoint in a timely manner. We've encountered long TTSP issues in production, and this tool should provide a valuable means to accurately diagnose them. --- base/options.jl | 1 + src/jloptions.c | 12 ++++++++++++ src/jloptions.h | 1 + src/julia_internal.h | 2 ++ src/safepoint.c | 31 +++++++++++++++++++++++++++---- src/stackwalk.c | 19 +++++++++++++++++++ test/cmdlineargs.jl | 6 ++++++ test/threads_exec.jl | 25 +++++++++++++++++++++++++ 8 files changed, 93 insertions(+), 4 deletions(-) diff --git a/base/options.jl b/base/options.jl index 7e7808bd5c047..3281ec0de98d2 100644 --- a/base/options.jl +++ b/base/options.jl @@ -62,6 +62,7 @@ struct JLOptions trace_compile_timing::Int8 trim::Int8 task_metrics::Int8 + timeout_for_safepoint_straggler_s::Int16 end # This runs early in the sysimage != is not defined yet diff --git a/src/jloptions.c b/src/jloptions.c index c68b5ce193d98..2c5a9074eb465 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -153,6 +153,7 @@ JL_DLLEXPORT void jl_init_options(void) 0, // trace_compile_timing JL_TRIM_NO, // trim 0, // task_metrics + -1, // timeout_for_safepoint_straggler_s }; jl_options_initialized = 1; } @@ -311,6 +312,8 @@ static const char opts_hidden[] = " --output-asm Generate an assembly file (.s)\n" " --output-incremental={yes|no*} Generate an incremental output file (rather than\n" " complete)\n" + " --timeout-for-safepoint-straggler If this value is set, then we will dump the backtrace for a thread\n" + " that fails to reach a safepoint within the specified time\n" " --trace-compile={stderr|name} Print precompile statements for methods compiled\n" " during execution or save to stderr or a path. Methods that\n" " were recompiled are printed in yellow or with a trailing\n" @@ -346,6 +349,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) opt_warn_scope, opt_inline, opt_polly, + opt_timeout_for_safepoint_straggler, opt_trace_compile, opt_trace_compile_timing, opt_trace_dispatch, @@ -427,6 +431,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) { "warn-scope", required_argument, 0, opt_warn_scope }, { "inline", required_argument, 0, opt_inline }, { "polly", required_argument, 0, opt_polly }, + { "timeout-for-safepoint-straggler", required_argument, 0, opt_timeout_for_safepoint_straggler }, { "trace-compile", required_argument, 0, opt_trace_compile }, { "trace-compile-timing", no_argument, 0, opt_trace_compile_timing }, { "trace-dispatch", required_argument, 0, opt_trace_dispatch }, @@ -970,6 +975,13 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) else jl_errorf("julia: invalid argument to --permalloc-pkgimg={yes|no} (%s)", optarg); break; + case opt_timeout_for_safepoint_straggler: + errno = 0; + long timeout = strtol(optarg, &endptr, 10); + if (errno != 0 || optarg == endptr || timeout < 1 || timeout > INT16_MAX) + jl_errorf("julia: --timeout-for-safepoint-straggler=; seconds must be an integer between 1 and %d", INT16_MAX); + jl_options.timeout_for_safepoint_straggler_s = (int16_t)timeout; + break; case opt_trim: if (optarg == NULL || !strcmp(optarg,"safe")) jl_options.trim = JL_TRIM_SAFE; diff --git a/src/jloptions.h b/src/jloptions.h index 211122242cbbd..a8cc4a9a9e33d 100644 --- a/src/jloptions.h +++ b/src/jloptions.h @@ -66,6 +66,7 @@ typedef struct { int8_t trace_compile_timing; int8_t trim; int8_t task_metrics; + int16_t timeout_for_safepoint_straggler_s; } jl_options_t; #endif diff --git a/src/julia_internal.h b/src/julia_internal.h index 00d603f26c7f2..3e4967c9d4dca 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -215,6 +215,8 @@ typedef struct { size_t bt_size; int tid; } jl_record_backtrace_result_t; +JL_DLLEXPORT JL_DLLEXPORT size_t jl_try_record_thread_backtrace(jl_ptls_t ptls2, struct _jl_bt_element_t *bt_data, + size_t max_bt_size) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_record_backtrace_result_t jl_record_backtrace(jl_task_t *t, struct _jl_bt_element_t *bt_data, size_t max_bt_size, int all_tasks_profiler) JL_NOTSAFEPOINT; extern volatile struct _jl_bt_element_t *profile_bt_data_prof; diff --git a/src/safepoint.c b/src/safepoint.c index 7eab653edd089..66bea539861f8 100644 --- a/src/safepoint.c +++ b/src/safepoint.c @@ -149,10 +149,33 @@ void jl_gc_wait_for_the_world(jl_ptls_t* gc_all_tls_states, int gc_n_threads) // Use system mutexes rather than spin locking to minimize wasted CPU time // while we wait for other threads reach a safepoint. // This is particularly important when run under rr. - uv_mutex_lock(&safepoint_lock); - if (!jl_atomic_load_relaxed(&ptls2->gc_state)) - uv_cond_wait(&safepoint_cond_begin, &safepoint_lock); - uv_mutex_unlock(&safepoint_lock); + if (jl_options.timeout_for_safepoint_straggler_s == -1) { // timeout was not specified: no need to dump the backtrace + uv_mutex_lock(&safepoint_lock); + if (!jl_atomic_load_relaxed(&ptls2->gc_state)) { + uv_cond_wait(&safepoint_cond_begin, &safepoint_lock); + } + uv_mutex_unlock(&safepoint_lock); + } + else { + const int64_t timeout = jl_options.timeout_for_safepoint_straggler_s * 1000000000; // convert to nanoseconds + int ret = 0; + uv_mutex_lock(&safepoint_lock); + if (!jl_atomic_load_relaxed(&ptls2->gc_state)) { + ret = uv_cond_timedwait(&safepoint_cond_begin, &safepoint_lock, timeout); + } + uv_mutex_unlock(&safepoint_lock); + // If we woke up because of a timeout, print the backtrace of the straggler + if (ret == UV_ETIMEDOUT) { + jl_safe_printf("===== Thread %d failed to reach safepoint after %d seconds, printing backtrace below =====\n", ptls2->tid + 1, jl_options.timeout_for_safepoint_straggler_s); + // Try to record the backtrace of the straggler using `jl_try_record_thread_backtrace` + jl_ptls_t ptls = jl_current_task->ptls; + 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); + } + } + } } } } diff --git a/src/stackwalk.c b/src/stackwalk.c index f1d807908cf42..14dc5709671dc 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -1260,6 +1260,25 @@ static void suspend(void *ctx) suspenddata->success = jl_thread_suspend_and_get_state(suspenddata->old, 1, suspenddata->c); } +JL_DLLEXPORT size_t jl_try_record_thread_backtrace(jl_ptls_t ptls2, jl_bt_element_t *bt_data, size_t max_bt_size) JL_NOTSAFEPOINT +{ + int16_t tid = ptls2->tid; + jl_task_t *t = NULL; + bt_context_t *context = NULL; + bt_context_t c; + suspend_t suspenddata = {tid, &c}; + jl_with_stackwalk_lock(suspend, &suspenddata); + if (!suspenddata.success) { + return 0; + } + // thread is stopped, safe to read the task it was running before we stopped it + t = jl_atomic_load_relaxed(&ptls2->current_task); + context = &c; + size_t bt_size = rec_backtrace_ctx(bt_data, max_bt_size, context, ptls2->previous_task ? NULL : t->gcstack); + jl_thread_resume(tid); + return bt_size; +} + JL_DLLEXPORT jl_record_backtrace_result_t jl_record_backtrace(jl_task_t *t, jl_bt_element_t *bt_data, size_t max_bt_size, int all_tasks_profiler) JL_NOTSAFEPOINT { int16_t tid = INT16_MAX; diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index 74f953250cd37..3ff7836223b84 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -1238,3 +1238,9 @@ end @test parse(UInt64,read(`$exename --heap-size-hint=$str -E "Base.JLOptions().heap_size_hint"`, String)) == val end end + +@testset "--timeout-for-safepoint-straggler" begin + exename = `$(Base.julia_cmd())` + timeout = 120 + @test parse(Int,read(`$exename --timeout-for-safepoint-straggler=$timeout -E "Base.JLOptions().timeout_for_safepoint_straggler_s"`, String)) == timeout +end diff --git a/test/threads_exec.jl b/test/threads_exec.jl index d77cf06905f44..65e5ef57c911b 100644 --- a/test/threads_exec.jl +++ b/test/threads_exec.jl @@ -1536,4 +1536,29 @@ end end end +@testset "--timeout-for-safepoint-straggler command-line flag" begin + program = " + function main() + t = Threads.@spawn begin + ccall(:uv_sleep, Cvoid, (Cuint,), 5000) + end + # Force a GC + ccall(:uv_sleep, Cvoid, (Cuint,), 1000) + GC.gc() + wait(t) + end + main() + " + tmp_output_filename = tempname() + tmp_output_file = open(tmp_output_filename, "w") + if isnothing(tmp_output_file) + error("Failed to open file $tmp_output_filename") + end + run(pipeline(`$(Base.julia_cmd()) --threads=4 --timeout-for-safepoint-straggler=1 -e $program`, stderr=tmp_output_file)) + # Check whether we printed the straggler's backtrace + @test !isempty(read(tmp_output_filename, String)) + close(tmp_output_file) + rm(tmp_output_filename) +end + end # main testset From 1262bf8484f2d70226dd2345fd77475ff3d71c94 Mon Sep 17 00:00:00 2001 From: Eduardo Souza Date: Sat, 18 Jan 2025 15:57:49 +1100 Subject: [PATCH 209/342] Building Julia with MMTk using BinaryBuilder (#56989) Adding `mmtk-julia` as a BinaryBuilder dependency and using that as the default setup for building Julia with MMTk. ~NB: still have to update the version and checksum files after https://github.com/JuliaPackaging/Yggdrasil/pull/10288 gets merged.~ --- Make.inc | 2 +- Makefile | 4 ++++ deps/checksums/mmtk_julia | 4 +++- deps/mmtk_julia.mk | 8 ++++++++ deps/mmtk_julia.version | 2 ++ 5 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Make.inc b/Make.inc index 26b5ae7752555..16e238c6f0683 100644 --- a/Make.inc +++ b/Make.inc @@ -1402,7 +1402,7 @@ CSL_NEXT_GLIBCXX_VERSION=GLIBCXX_3\.4\.34|GLIBCXX_3\.5\.|GLIBCXX_4\. # Note: we explicitly _do not_ define `CSL` here, since it requires some more # advanced techniques to decide whether it should be installed from a BB source # or not. See `deps/csl.mk` for more detail. -BB_PROJECTS := BLASTRAMPOLINE OPENBLAS LLVM LIBSUITESPARSE OPENLIBM GMP OPENSSL LIBSSH2 NGHTTP2 MPFR CURL LIBGIT2 PCRE LIBUV LIBUNWIND DSFMT OBJCONV ZLIB P7ZIP LLD LIBTRACYCLIENT BOLT +BB_PROJECTS := BLASTRAMPOLINE OPENBLAS LLVM LIBSUITESPARSE OPENLIBM GMP OPENSSL LIBSSH2 NGHTTP2 MPFR CURL LIBGIT2 PCRE LIBUV LIBUNWIND DSFMT OBJCONV ZLIB P7ZIP LLD LIBTRACYCLIENT BOLT MMTK_JULIA define SET_BB_DEFAULT # First, check to see if BB is disabled on a global setting ifeq ($$(USE_BINARYBUILDER),0) diff --git a/Makefile b/Makefile index 20d131ee8524c..b193b3849c6aa 100644 --- a/Makefile +++ b/Makefile @@ -281,6 +281,10 @@ endif endif endif +ifneq (${MMTK_PLAN},None) +JL_PRIVATE_LIBS-0 += libmmtk_julia +endif + # Note that we disable MSYS2's path munging here, as otherwise # it replaces our `:`-separated list as a `;`-separated one. define stringreplace diff --git a/deps/checksums/mmtk_julia b/deps/checksums/mmtk_julia index 49b7a50a8e136..979ab79e52207 100644 --- a/deps/checksums/mmtk_julia +++ b/deps/checksums/mmtk_julia @@ -1,4 +1,6 @@ mmtk_julia-b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214.tar.gz/md5/1911cf084d26c48e2ed58af3d268b4b6 mmtk_julia-b69acf5af7a7dd97c1cc6fd99f7c2d51b477f214.tar.gz/sha512/75beab54398989c46b62e714b242cf6705d88d220f40c21e494e0f29161437f5fbe9ba05b543d2353a1ad76f4239ac4025b476be0be864649f310f14935289fe mmtk_julia-f07d66aafc86af84ea988b35335acc9bbc770fa1.tar.gz/md5/38afb5db6d8c55413a4ec96aefa2ebb4 -mmtk_julia-f07d66aafc86af84ea988b35335acc9bbc770fa1.tar.gz/sha512/78525582a46a6baf8d33df7b622e55cf244439afcd7192ba55489c1bc18393d1237d2903d517c610484bf9e2a7338ad31435a9cbf70889d6bcf87c40cec829e5 \ No newline at end of file +mmtk_julia-f07d66aafc86af84ea988b35335acc9bbc770fa1.tar.gz/sha512/78525582a46a6baf8d33df7b622e55cf244439afcd7192ba55489c1bc18393d1237d2903d517c610484bf9e2a7338ad31435a9cbf70889d6bcf87c40cec829e5 +mmtk_julia.v0.30.3+1.x86_64-linux-gnu.tar.gz/md5/631b204574da7062802dac501a4b711f +mmtk_julia.v0.30.3+1.x86_64-linux-gnu.tar.gz/sha512/daaed59d08fc49621479ed638dea0aac0cba123986e486571447e8e21e9a098776ce2e87fbd92ddea276782fc44621f23d40fa213296b28e1d4480553c7de4f7 diff --git a/deps/mmtk_julia.mk b/deps/mmtk_julia.mk index 7ec55426821c3..424113fd4164c 100644 --- a/deps/mmtk_julia.mk +++ b/deps/mmtk_julia.mk @@ -6,6 +6,7 @@ MMTK_MOVING := 0 MMTK_VARS := MMTK_PLAN=$(MMTK_PLAN) MMTK_MOVING=$(MMTK_MOVING) +ifneq ($(USE_BINARYBUILDER_MMTK_JULIA),1) $(eval $(call git-external,mmtk_julia,MMTK_JULIA,,,$(BUILDDIR))) get-mmtk_julia: $(MMTK_JULIA_SRC_FILE) @@ -70,3 +71,10 @@ $(build_prefix)/manifest/mmtk_julia: $(BUILDROOT)/usr/lib/libmmtk_julia.so @echo $(UNINSTALL_mmtk_julia) > $@ endif # MMTK_JULIA_DIR + +else +# We are building using the BinaryBuilder version of the binding + +$(eval $(call bb-install,mmtk_julia,MMTK_JULIA,false)) + +endif # USE_BINARYBUILDER_MMTK_JULIA diff --git a/deps/mmtk_julia.version b/deps/mmtk_julia.version index 4d821bffd5b9b..cb1e8064f9825 100644 --- a/deps/mmtk_julia.version +++ b/deps/mmtk_julia.version @@ -2,3 +2,5 @@ MMTK_JULIA_BRANCH = master MMTK_JULIA_SHA1 = f07d66aafc86af84ea988b35335acc9bbc770fa1 MMTK_JULIA_GIT_URL := https://github.com/mmtk/mmtk-julia.git MMTK_JULIA_TAR_URL = https://github.com/mmtk/mmtk-julia/archive/refs/tags/v0.30.3.tar.gz +MMTK_JULIA_JLL_VER := 0.30.3+1 +MMTK_JULIA_JLL_NAME := mmtk_julia From 17402876ec235dd66452983a39f8521f9ff62936 Mon Sep 17 00:00:00 2001 From: Alex Arslan Date: Fri, 17 Jan 2025 23:33:23 -0800 Subject: [PATCH 210/342] Block thread from receiving profile signal with stackwalk lock (#57089) This is Jameson's proposed amendment to the changes made in #57035 that introduced a deadlock on FreeBSD, amusingly in service of fixing a deadlock on Linux. On Linux and (non-macOS) BSD, instead of acquiring and releasing a lock on the profiler in `jl_with_stackwalk_lock`, we're just blocking the thread from receiving the profiler's `SIGUSR2` signal at all. This should fix #57058; I don't get the deadlock locally on FreeBSD with this change, but it's AArch64 instead of x86-64 like on CI, so let's see if this also makes CI happy. If so, closes #57059. Co-authored-by: Jameson Nash --- src/signals-unix.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/signals-unix.c b/src/signals-unix.c index 91d3378068f84..788539b1f5096 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -310,23 +310,14 @@ int exc_reg_is_write_fault(uintptr_t esr) { #include #include -typedef struct { - void (*f)(void*) JL_NOTSAFEPOINT; - void *ctx; -} callback_t; -static int with_dl_iterate_phdr_lock(struct dl_phdr_info *info, size_t size, void *data) -{ - jl_lock_profile(); - callback_t *callback = (callback_t*)data; - callback->f(callback->ctx); - jl_unlock_profile(); - return 1; // only call this once -} - void jl_with_stackwalk_lock(void (*f)(void*), void *ctx) { - callback_t callback = {f, ctx}; - dl_iterate_phdr(with_dl_iterate_phdr_lock, &callback); + sigset_t sset, oset; + sigemptyset(&sset); + sigaddset(&sset, SIGUSR2); + pthread_sigmask(SIG_BLOCK, &sset, &oset); + f(ctx); + pthread_sigmask(SIG_SETMASK, &oset, NULL); } #if defined(_OS_LINUX_) && (defined(_CPU_X86_64_) || defined(_CPU_X86_)) From fa9478b5178052ef00690732fe363601182b6922 Mon Sep 17 00:00:00 2001 From: Markus Hauru Date: Sat, 18 Jan 2025 12:00:51 +0000 Subject: [PATCH 211/342] Fix regular expressions in Test tests (#57085) Several tests for Test.jl weren't really testing for much because `|` characters were taken to be or operators in the regular expressions. Co-authored-by: Chengyu Han --- stdlib/Test/test/runtests.jl | 54 ++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/stdlib/Test/test/runtests.jl b/stdlib/Test/test/runtests.jl index 995d2c983437c..98755590a5291 100644 --- a/stdlib/Test/test/runtests.jl +++ b/stdlib/Test/test/runtests.jl @@ -870,12 +870,12 @@ let msg = read(pipeline(ignorestatus(`$(Base.julia_cmd()) --startup-file=no --co end end'`), stderr=devnull), String) @test occursin(r""" - Test Summary: | Pass Fail Total Time - Foo Tests | 2 2 4 \s*\d*.\ds - Animals | 1 1 2 \s*\d*.\ds - Felines | 1 1 \s*\d*.\ds - Canines | 1 1 \s*\d*.\ds - Arrays | 1 1 2 \s*\d*.\ds + Test Summary: \| Pass Fail Total Time + Foo Tests \| 2 2 4 \s*\d*\.\ds + Animals \| 1 1 2 \s*\d*\.\ds + Felines \| 1 1 \s*\d*\.\ds + Canines \| 1 1 \s*\d*\.\ds + Arrays \| 1 1 2 \s*\d*\.\ds """, msg) end @@ -1253,17 +1253,17 @@ end @testset "verbose option" begin expected = r""" - Test Summary: | Pass Total Time - Parent | 9 9 \s*\d*.\ds - Child 1 | 3 3 \s*\d*.\ds - Child 1.1 (long name) | 1 1 \s*\d*.\ds - Child 1.2 | 1 1 \s*\d*.\ds - Child 1.3 | 1 1 \s*\d*.\ds - Child 2 | 3 3 \s*\d*.\ds - Child 3 | 3 3 \s*\d*.\ds - Child 3.1 | 1 1 \s*\d*.\ds - Child 3.2 | 1 1 \s*\d*.\ds - Child 3.3 | 1 1 \s*\d*.\ds + Test Summary: \| Pass Total Time + Parent \| 9 9 \s*\d*\.\ds + Child 1 \| 3 3 \s*\d*\.\ds + Child 1\.1 \(long name\) \| 1 1 \s*\d*\.\ds + Child 1\.2 \| 1 1 \s*\d*\.\ds + Child 1\.3 \| 1 1 \s*\d*\.\ds + Child 2 \| 3 3 \s*\d*\.\ds + Child 3 \| 3 3 \s*\d*\.\ds + Child 3\.1 \| 1 1 \s*\d*\.\ds + Child 3\.2 \| 1 1 \s*\d*\.\ds + Child 3\.3 \| 1 1 \s*\d*\.\ds """ mktemp() do f, _ @@ -1324,9 +1324,9 @@ end @testset "failfast option" begin @testset "non failfast (default)" begin expected = r""" - Test Summary: | Pass Fail Error Total Time - Foo | 1 2 1 4 \s*\d*.\ds - Bar | 1 1 2 \s*\d*.\ds + Test Summary: \| Pass Fail Error Total Time + Foo \| 1 2 1 4 \s*\d*\.\ds + Bar \| 1 1 2 \s*\d*\.\ds """ mktemp() do f, _ @@ -1350,8 +1350,8 @@ end end @testset "failfast" begin expected = r""" - Test Summary: | Fail Total Time - Foo | 1 1 \s*\d*.\ds + Test Summary: \| Fail Total Time + Foo \| 1 1 \s*\d*\.\ds """ mktemp() do f, _ @@ -1375,9 +1375,9 @@ end end @testset "failfast passes to child testsets" begin expected = r""" - Test Summary: | Fail Total Time - PackageName | 1 1 \s*\d*.\ds - 1 | 1 1 \s*\d*.\ds + Test Summary: \| Fail Total Time + Foo \| 1 1 \s*\d*\.\ds + 1 \| 1 1 \s*\d*\.\ds """ mktemp() do f, _ @@ -1401,8 +1401,8 @@ end end @testset "failfast via env var" begin expected = r""" - Test Summary: | Fail Total Time - Foo | 1 1 \s*\d*.\ds + Test Summary: \| Fail Total Time + Foo \| 1 1 \s*\d*\.\ds """ mktemp() do f, _ From cbc47c9fb852773e379cce062d6bd2aec743a7cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= <765740+giordano@users.noreply.github.com> Date: Sun, 19 Jan 2025 00:10:33 +0100 Subject: [PATCH 212/342] [Test] Improve regex matching expected test summaries (#57096) Allow for more spaces between the "Total" and "Time" columns, in case tests take occasionally longer than usual. Fix #57095. --- stdlib/Test/test/runtests.jl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/stdlib/Test/test/runtests.jl b/stdlib/Test/test/runtests.jl index 98755590a5291..02523dc6fd911 100644 --- a/stdlib/Test/test/runtests.jl +++ b/stdlib/Test/test/runtests.jl @@ -870,7 +870,7 @@ let msg = read(pipeline(ignorestatus(`$(Base.julia_cmd()) --startup-file=no --co end end'`), stderr=devnull), String) @test occursin(r""" - Test Summary: \| Pass Fail Total Time + Test Summary: \| Pass Fail Total +Time Foo Tests \| 2 2 4 \s*\d*\.\ds Animals \| 1 1 2 \s*\d*\.\ds Felines \| 1 1 \s*\d*\.\ds @@ -1253,7 +1253,7 @@ end @testset "verbose option" begin expected = r""" - Test Summary: \| Pass Total Time + Test Summary: \| Pass Total +Time Parent \| 9 9 \s*\d*\.\ds Child 1 \| 3 3 \s*\d*\.\ds Child 1\.1 \(long name\) \| 1 1 \s*\d*\.\ds @@ -1324,7 +1324,7 @@ end @testset "failfast option" begin @testset "non failfast (default)" begin expected = r""" - Test Summary: \| Pass Fail Error Total Time + Test Summary: \| Pass Fail Error Total +Time Foo \| 1 2 1 4 \s*\d*\.\ds Bar \| 1 1 2 \s*\d*\.\ds """ @@ -1350,7 +1350,7 @@ end end @testset "failfast" begin expected = r""" - Test Summary: \| Fail Total Time + Test Summary: \| Fail Total +Time Foo \| 1 1 \s*\d*\.\ds """ @@ -1375,7 +1375,7 @@ end end @testset "failfast passes to child testsets" begin expected = r""" - Test Summary: \| Fail Total Time + Test Summary: \| Fail Total +Time Foo \| 1 1 \s*\d*\.\ds 1 \| 1 1 \s*\d*\.\ds """ @@ -1401,7 +1401,7 @@ end end @testset "failfast via env var" begin expected = r""" - Test Summary: \| Fail Total Time + Test Summary: \| Fail Total +Time Foo \| 1 1 \s*\d*\.\ds """ @@ -1712,7 +1712,7 @@ end # this tests both the `TestCounts` parts as well as the fallback `x`s expected = r""" - Test Summary: \| Pass Fail Error Broken Total Time + Test Summary: \| Pass Fail Error Broken Total +Time outer \| 3 1 1 1 6 \s*\d*.\ds a \| 1 1 \s*\d*.\ds custom \| 1 1 1 1 4 \s*\?s From 2ca125f6f3d4e49d1ae0db762270edc1b4875bb0 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Mon, 20 Jan 2025 10:26:49 +0900 Subject: [PATCH 213/342] docs: show binding name for `No documentation found for ...` message (#57093) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Making it more informative. E.g., the difference for `help?> Base._wait` is: ```diff diff --git a/old b/new index 87f9b2d43a..5fb065658a 100644 --- a/old +++ b/new @@ -5,7 +5,7 @@ │ │ • `Base._wait` - No documentation found for private symbol. + No documentation found for private binding `Base._wait`. `Base._wait` is a `Function`. ``` --- stdlib/REPL/src/docview.jl | 5 +++-- test/docs.jl | 40 ++++++++++++++++++++------------------ 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/stdlib/REPL/src/docview.jl b/stdlib/REPL/src/docview.jl index 0868d3e80c824..e0710d89a67e2 100644 --- a/stdlib/REPL/src/docview.jl +++ b/stdlib/REPL/src/docview.jl @@ -301,10 +301,11 @@ function summarize(binding::Binding, sig) if defined(binding) binding_res = resolve(binding) if !isa(binding_res, Module) + varstr = "$(binding.mod).$(binding.var)" if Base.ispublic(binding.mod, binding.var) - println(io, "No documentation found for public symbol.\n") + println(io, "No documentation found for public binding `$varstr`.\n") else - println(io, "No documentation found for private symbol.\n") + println(io, "No documentation found for private binding `$varstr`.\n") end end summarize(io, binding_res, binding) diff --git a/test/docs.jl b/test/docs.jl index 8cfdbba3f2d97..0fff85e90cb59 100644 --- a/test/docs.jl +++ b/test/docs.jl @@ -684,9 +684,11 @@ end @doc "This should document @m1... since its the result of expansion" @m2_11993 @test (@doc @m1_11993) !== nothing let d = (@doc :@m2_11993), - macro_doc = Markdown.parse("`$(curmod_prefix == "Main." ? "" : curmod_prefix)@m2_11993` is a macro.") + varstr = "$(curmod_prefix == "Main." ? "" : curmod_prefix)@m2_11993" + docstr = Markdown.Code("", "$curmod_prefix@m2_11993") + macro_doc = Markdown.parse("`$varstr` is a macro.") @test docstring_startswith(d, doc""" - No documentation found for private symbol. + No documentation found for private binding $docstr. $macro_doc""") end @@ -901,7 +903,7 @@ Binding `$(curmod_prefix)Undocumented.bindingdoesnotexist` does not exist. @test docstrings_equal(@doc(Undocumented.bindingdoesnotexist), doc"$doc_str") doc_str = Markdown.parse(""" -No documentation found for public symbol. +No documentation found for public binding `$(curmod_prefix)Undocumented.A`. # Summary ``` @@ -917,7 +919,7 @@ $(curmod_prefix)Undocumented.C @test docstrings_equal(@doc(Undocumented.A), doc"$doc_str") doc_str = Markdown.parse(""" -No documentation found for public symbol. +No documentation found for public binding `$(curmod_prefix)Undocumented.B`. # Summary ``` @@ -937,7 +939,7 @@ $(curmod_prefix)Undocumented.B <: $(curmod_prefix)Undocumented.A <: Any @test docstrings_equal(@doc(Undocumented.B), doc"$doc_str") doc_str = Markdown.parse(""" -No documentation found for public symbol. +No documentation found for public binding `$(curmod_prefix)Undocumented.C`. # Summary ``` @@ -952,7 +954,7 @@ $(curmod_prefix)Undocumented.C <: $(curmod_prefix)Undocumented.A <: Any @test docstrings_equal(@doc(Undocumented.C), doc"$doc_str") doc_str = Markdown.parse(""" -No documentation found for private symbol. +No documentation found for private binding `$(curmod_prefix)Undocumented.D`. # Summary ``` @@ -974,7 +976,7 @@ $(curmod_prefix)Undocumented.D <: $(curmod_prefix)Undocumented.B <: $(curmod_pre @test docstrings_equal(@doc(Undocumented.D), doc"$doc_str") doc_str = Markdown.parse(""" -No documentation found for public symbol. +No documentation found for public binding `$(curmod_prefix)Undocumented.at0`. # Summary @@ -994,7 +996,7 @@ $(curmod_prefix)Undocumented.st4{T<:Number, N} @test docstrings_equal(@doc(Undocumented.at0), doc"$doc_str") doc_str = Markdown.parse(""" -No documentation found for private symbol. +No documentation found for private binding `$(curmod_prefix)Undocumented.at1`. # Summary @@ -1017,7 +1019,7 @@ $(curmod_prefix)Undocumented.at1{T>:Integer, N} <: $(curmod_prefix)Undocumented. @test docstrings_equal(@doc(Undocumented.at1), doc"$doc_str") doc_str = Markdown.parse(""" -No documentation found for private symbol. +No documentation found for private binding `$(curmod_prefix)Undocumented.at_`. # Summary @@ -1036,7 +1038,7 @@ $(curmod_prefix)Undocumented.st4{Int64, N} @test docstrings_equal(@doc(Undocumented.at_), doc"$doc_str") doc_str = Markdown.parse(""" -No documentation found for public symbol. +No documentation found for public binding `$(curmod_prefix)Undocumented.pt2`. # Summary @@ -1053,7 +1055,7 @@ $(curmod_prefix)Undocumented.pt2{T<:Number, N, A>:Integer} <: $(curmod_prefix)Un @test docstrings_equal(@doc(Undocumented.pt2), doc"$doc_str") doc_str = Markdown.parse(""" -No documentation found for private symbol. +No documentation found for private binding `$(curmod_prefix)Undocumented.st3`. # Summary @@ -1076,7 +1078,7 @@ $(curmod_prefix)Undocumented.st3{T<:Integer, N} <: $(curmod_prefix)Undocumented. @test docstrings_equal(@doc(Undocumented.st3), doc"$doc_str") doc_str = Markdown.parse(""" -No documentation found for private symbol. +No documentation found for private binding `$(curmod_prefix)Undocumented.st4`. # Summary @@ -1098,7 +1100,7 @@ $(curmod_prefix)Undocumented.st4{T, N} <: $(curmod_prefix)Undocumented.at0{T, N} @test docstrings_equal(@doc(Undocumented.st4), doc"$doc_str") doc_str = Markdown.parse(""" -No documentation found for private symbol. +No documentation found for private binding `$(curmod_prefix)Undocumented.st5`. # Summary @@ -1119,7 +1121,7 @@ $(curmod_prefix)Undocumented.st5{T>:Int64, N} <: $(curmod_prefix)Undocumented.at @test docstrings_equal(@doc(Undocumented.st5), doc"$doc_str") doc_str = Markdown.parse(""" -No documentation found for private symbol. +No documentation found for private binding `$(curmod_prefix)Undocumented.mt6`. # Summary @@ -1140,7 +1142,7 @@ $(curmod_prefix)Undocumented.mt6{T<:Integer, N} <: $(curmod_prefix)Undocumented. @test docstrings_equal(@doc(Undocumented.mt6), doc"$doc_str") doc_str = Markdown.parse(""" -No documentation found for private symbol. +No documentation found for private binding `$(curmod_prefix)Undocumented.ut7`. # Summary @@ -1154,7 +1156,7 @@ No documentation found for private symbol. @test docstrings_equal(@doc(Undocumented.ut7), doc"$doc_str") doc_str = Markdown.parse(""" -No documentation found for private symbol. +No documentation found for private binding `$(curmod_prefix)Undocumented.ut8`. # Summary @@ -1170,7 +1172,7 @@ No documentation found for private symbol. @test docstrings_equal(@doc(Undocumented.ut8), doc"$doc_str") doc_str = Markdown.parse(""" -No documentation found for private symbol. +No documentation found for private binding `$(curmod_prefix)Undocumented.ut9`. # Summary @@ -1189,7 +1191,7 @@ let d = @doc(Undocumented.f) io = IOBuffer() show(io, MIME"text/markdown"(), d) @test startswith(String(take!(io)),""" - No documentation found for private symbol. + No documentation found for private binding `$(curmod_prefix)Undocumented.f`. `$(curmod_prefix)Undocumented.f` is a `Function`. """) @@ -1199,7 +1201,7 @@ let d = @doc(Undocumented.undocumented) io = IOBuffer() show(io, MIME"text/markdown"(), d) @test startswith(String(take!(io)), """ - No documentation found for private symbol. + No documentation found for private binding `$(curmod_prefix)Undocumented.undocumented`. `$(curmod_prefix)Undocumented.undocumented` is a `Function`. """) From 755d7ece07d78f681c8d3cb07be489bb7104c847 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Mon, 20 Jan 2025 18:10:10 -0500 Subject: [PATCH 214/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?SHA=20stdlib=20from=208fa221d=20to=204451e13=20(#57110)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SHA-4451e1362e425bcbc1652ecf55fc0e525b18fb63.tar.gz/md5 | 1 + .../SHA-4451e1362e425bcbc1652ecf55fc0e525b18fb63.tar.gz/sha512 | 1 + .../SHA-8fa221ddc8f3b418d9929084f1644f4c32c9a27e.tar.gz/md5 | 1 - .../SHA-8fa221ddc8f3b418d9929084f1644f4c32c9a27e.tar.gz/sha512 | 1 - stdlib/SHA.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/SHA-4451e1362e425bcbc1652ecf55fc0e525b18fb63.tar.gz/md5 create mode 100644 deps/checksums/SHA-4451e1362e425bcbc1652ecf55fc0e525b18fb63.tar.gz/sha512 delete mode 100644 deps/checksums/SHA-8fa221ddc8f3b418d9929084f1644f4c32c9a27e.tar.gz/md5 delete mode 100644 deps/checksums/SHA-8fa221ddc8f3b418d9929084f1644f4c32c9a27e.tar.gz/sha512 diff --git a/deps/checksums/SHA-4451e1362e425bcbc1652ecf55fc0e525b18fb63.tar.gz/md5 b/deps/checksums/SHA-4451e1362e425bcbc1652ecf55fc0e525b18fb63.tar.gz/md5 new file mode 100644 index 0000000000000..cbd2acb2c6f66 --- /dev/null +++ b/deps/checksums/SHA-4451e1362e425bcbc1652ecf55fc0e525b18fb63.tar.gz/md5 @@ -0,0 +1 @@ +7b511b7dab411685206d0d90cc1fb56e diff --git a/deps/checksums/SHA-4451e1362e425bcbc1652ecf55fc0e525b18fb63.tar.gz/sha512 b/deps/checksums/SHA-4451e1362e425bcbc1652ecf55fc0e525b18fb63.tar.gz/sha512 new file mode 100644 index 0000000000000..5201bbdcc40f9 --- /dev/null +++ b/deps/checksums/SHA-4451e1362e425bcbc1652ecf55fc0e525b18fb63.tar.gz/sha512 @@ -0,0 +1 @@ +960367406d80e46e8e742bcb0f7f0e4b089b664c2321ca82953eb760b325693ae57f431d891ccf56c3ab9146bc29682d2d1767bc635f4dbe6dd4d80030a42487 diff --git a/deps/checksums/SHA-8fa221ddc8f3b418d9929084f1644f4c32c9a27e.tar.gz/md5 b/deps/checksums/SHA-8fa221ddc8f3b418d9929084f1644f4c32c9a27e.tar.gz/md5 deleted file mode 100644 index 52e05f5e427ae..0000000000000 --- a/deps/checksums/SHA-8fa221ddc8f3b418d9929084f1644f4c32c9a27e.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -e52615827242aae56422a4f73a8c6878 diff --git a/deps/checksums/SHA-8fa221ddc8f3b418d9929084f1644f4c32c9a27e.tar.gz/sha512 b/deps/checksums/SHA-8fa221ddc8f3b418d9929084f1644f4c32c9a27e.tar.gz/sha512 deleted file mode 100644 index e6b8446587554..0000000000000 --- a/deps/checksums/SHA-8fa221ddc8f3b418d9929084f1644f4c32c9a27e.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -7b1df257616aaa9067f822a88dddf52bc10f9f61e3a0728e33e595455bd7167e680c50371c41cb25f8c8a9fb9cf40225847df1523a6c6f3571a471f7163f563c diff --git a/stdlib/SHA.version b/stdlib/SHA.version index 4b33964a6dcdb..a5d4372d5798b 100644 --- a/stdlib/SHA.version +++ b/stdlib/SHA.version @@ -1,4 +1,4 @@ SHA_BRANCH = master -SHA_SHA1 = 8fa221ddc8f3b418d9929084f1644f4c32c9a27e +SHA_SHA1 = 4451e1362e425bcbc1652ecf55fc0e525b18fb63 SHA_GIT_URL := https://github.com/JuliaCrypto/SHA.jl.git SHA_TAR_URL = https://api.github.com/repos/JuliaCrypto/SHA.jl/tarball/$1 From 2e6ffbccab206d5b3963f4396ba0d541cc2394d1 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Mon, 20 Jan 2025 21:23:42 -0500 Subject: [PATCH 215/342] Capture/silence some noisy test warnings (#57111) --- Compiler/test/codegen.jl | 2 +- test/ambiguous.jl | 2 +- test/boundscheck_exec.jl | 7 +++---- test/channel_threadpool.jl | 16 +++++++--------- test/spawn.jl | 2 +- test/syntax.jl | 3 ++- 6 files changed, 15 insertions(+), 17 deletions(-) diff --git a/Compiler/test/codegen.jl b/Compiler/test/codegen.jl index 9b92f560c64fc..ff61ac719c59e 100644 --- a/Compiler/test/codegen.jl +++ b/Compiler/test/codegen.jl @@ -1031,7 +1031,7 @@ end # Make sure that code that has unbound sparams works #https://github.com/JuliaLang/julia/issues/56739 -f56739(a) where {T} = a +@test_warn r"declares type variable T but does not use it" @eval f56739(a) where {T} = a @test f56739(1) == 1 g56739(x) = @noinline f56739(x) diff --git a/test/ambiguous.jl b/test/ambiguous.jl index 43ec1aab0557d..5f859e773f5d2 100644 --- a/test/ambiguous.jl +++ b/test/ambiguous.jl @@ -97,7 +97,7 @@ ambig(x::Union{Char, Int16}) = 's' # Automatic detection of ambiguities -const allowed_undefineds = Set([]) +const allowed_undefineds = Set([GlobalRef(Base, :active_repl)]) let Distributed = get(Base.loaded_modules, Base.PkgId(Base.UUID("8ba89e20-285c-5b6f-9357-94700520ee1b"), "Distributed"), diff --git a/test/boundscheck_exec.jl b/test/boundscheck_exec.jl index 85df1d64017b4..3b2f853999229 100644 --- a/test/boundscheck_exec.jl +++ b/test/boundscheck_exec.jl @@ -298,7 +298,7 @@ end end |> only === Type{Int} if bc_opt == bc_default -@testset "Array/Memory escape analysis" begin + # Array/Memory escape analysis function no_allocate(T::Type{<:Union{Memory, Vector}}) v = T(undef, 2) v[1] = 2 @@ -308,8 +308,8 @@ if bc_opt == bc_default function test_alloc(::Type{T}; broken=false) where T @test (@allocated no_allocate(T)) == 0 broken=broken end - @testset "$T" for T in [Memory, Vector] - @testset "$ET" for ET in [Int, Float32, Union{Int, Float64}] + for T in [Memory, Vector] + for ET in [Int, Float32, Union{Int, Float64}] no_allocate(T{ET}) #compile # allocations aren't removed for Union eltypes which they theoretically could be eventually test_alloc(T{ET}, broken=(ET==Union{Int, Float64})) @@ -345,6 +345,5 @@ if bc_opt == bc_default no_alias_prove(1) @test_broken (@allocated no_alias_prove(5)) == 0 end -end end diff --git a/test/channel_threadpool.jl b/test/channel_threadpool.jl index 4509604087fa8..54c2fc0f83e09 100644 --- a/test/channel_threadpool.jl +++ b/test/channel_threadpool.jl @@ -3,12 +3,10 @@ using Test using Base.Threads -@testset "Task threadpools" begin - c = Channel{Symbol}() do c; put!(c, threadpool(current_task())); end - @test take!(c) === threadpool(current_task()) - c = Channel{Symbol}(spawn = true) do c; put!(c, threadpool(current_task())); end - @test take!(c) === :default - c = Channel{Symbol}(threadpool = :interactive) do c; put!(c, threadpool(current_task())); end - @test take!(c) === :interactive - @test_throws ArgumentError Channel{Symbol}(threadpool = :foo) do c; put!(c, :foo); end -end +c = Channel{Symbol}() do c; put!(c, threadpool(current_task())); end +@test take!(c) === threadpool(current_task()) +c = Channel{Symbol}(spawn = true) do c; put!(c, threadpool(current_task())); end +@test take!(c) === :default +c = Channel{Symbol}(threadpool = :interactive) do c; put!(c, threadpool(current_task())); end +@test take!(c) === :interactive +@test_throws ArgumentError Channel{Symbol}(threadpool = :foo) do c; put!(c, :foo); end diff --git a/test/spawn.jl b/test/spawn.jl index c1802ba1f74da..0356cf9871424 100644 --- a/test/spawn.jl +++ b/test/spawn.jl @@ -78,7 +78,7 @@ out = read(`$echocmd hello` & `$echocmd world`, String) @test occursin("hello", out) @test read(pipeline(`$echocmd hello` & `$echocmd world`, sortcmd), String) == "hello\nworld\n" -@test (run(`$printfcmd " \033[34m[stdio passthrough ok]\033[0m\n"`); true) +@test_warn r"[stdio passthrough ok]" run(pipeline(`$printfcmd " \033[34m[stdio passthrough ok]\033[0m\n"`, stdout=stderr, stderr=stderr)) # Test for SIGPIPE being a failure condition @test_throws ProcessFailedException run(pipeline(yescmd, `head`, devnull)) diff --git a/test/syntax.jl b/test/syntax.jl index 9fd0204821eab..bdf9579b134eb 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -3971,11 +3971,12 @@ end # Module Replacement module ReplacementContainer + using Test module ReplaceMe const x = 1 end const Old = ReplaceMe - module ReplaceMe + @test_warn r"WARNING: replacing module ReplaceMe" @eval module ReplaceMe const x = 2 end end From 90d346f9b9760584d94a3f16a76f56acb45cdf01 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Tue, 21 Jan 2025 21:15:44 +0900 Subject: [PATCH 216/342] fix `help?> StructType.field` command (#57107) `help?> StructType.field` currently errors when `StructType` doesn't have any field documentation at all. This commit adds a proper guard against such cases. --- stdlib/REPL/src/docview.jl | 18 +++++++++++------- stdlib/REPL/test/docview.jl | 3 +++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/stdlib/REPL/src/docview.jl b/stdlib/REPL/src/docview.jl index e0710d89a67e2..313994505b3ee 100644 --- a/stdlib/REPL/src/docview.jl +++ b/stdlib/REPL/src/docview.jl @@ -662,13 +662,17 @@ function fielddoc(binding::Binding, field::Symbol) for mod in modules dict = meta(mod; autoinit=false) isnothing(dict) && continue - if haskey(dict, binding) - multidoc = dict[binding] - if haskey(multidoc.docs, Union{}) - fields = multidoc.docs[Union{}].data[:fields] - if haskey(fields, field) - doc = fields[field] - return isa(doc, Markdown.MD) ? doc : Markdown.parse(doc) + multidoc = get(dict, binding, nothing) + if multidoc !== nothing + structdoc = get(multidoc.docs, Union{}, nothing) + if structdoc !== nothing + fieldsdoc = get(structdoc.data, :fields, nothing) + if fieldsdoc !== nothing + fielddoc = get(fieldsdoc, field, nothing) + if fielddoc !== nothing + return isa(fielddoc, Markdown.MD) ? + fielddoc : Markdown.parse(fielddoc) + end end end end diff --git a/stdlib/REPL/test/docview.jl b/stdlib/REPL/test/docview.jl index 02f1dc8238f04..c81715ad69921 100644 --- a/stdlib/REPL/test/docview.jl +++ b/stdlib/REPL/test/docview.jl @@ -92,6 +92,9 @@ end @test endswith(get_help_standard("StructWithOneField.not_a_field"), "StructWithOneField` has field `field1`.\n") @test endswith(get_help_standard("StructWithTwoFields.not_a_field"), "StructWithTwoFields` has fields `field1`, and `field2`.\n") @test endswith(get_help_standard("StructWithThreeFields.not_a_field"), "StructWithThreeFields` has fields `field1`, `field2`, and `field3`.\n") + + # Shouldn't error if the struct doesn't have any field documentations at all. + @test endswith(get_help_standard("Int.not_a_field"), "`$Int` has no fields.\n") end module InternalWarningsTests From ff5f66c655277636e7e27a7927611af2805d4a2e Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 21 Jan 2025 10:01:35 -0500 Subject: [PATCH 217/342] codegen: export all ABIs that we refer to in codegen (#57083) Since codegen may refer to these, it helps to have the linker able to resolve them, if that case ever happens. Fixes #56701 --- src/gf.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gf.c b/src/gf.c index ba28edfbeeff7..ea25ed2eae4ff 100644 --- a/src/gf.c +++ b/src/gf.c @@ -3034,19 +3034,19 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t return codeinst; } -jl_value_t *jl_fptr_const_return(jl_value_t *f, jl_value_t **args, uint32_t nargs, jl_code_instance_t *m) +JL_DLLEXPORT jl_value_t *jl_fptr_const_return(jl_value_t *f, jl_value_t **args, uint32_t nargs, jl_code_instance_t *m) { return m->rettype_const; } -jl_value_t *jl_fptr_args(jl_value_t *f, jl_value_t **args, uint32_t nargs, jl_code_instance_t *m) +JL_DLLEXPORT jl_value_t *jl_fptr_args(jl_value_t *f, jl_value_t **args, uint32_t nargs, jl_code_instance_t *m) { jl_fptr_args_t invoke = jl_atomic_load_relaxed(&m->specptr.fptr1); assert(invoke && "Forgot to set specptr for jl_fptr_args!"); return invoke(f, args, nargs); } -jl_value_t *jl_fptr_sparam(jl_value_t *f, jl_value_t **args, uint32_t nargs, jl_code_instance_t *m) +JL_DLLEXPORT jl_value_t *jl_fptr_sparam(jl_value_t *f, jl_value_t **args, uint32_t nargs, jl_code_instance_t *m) { jl_svec_t *sparams = jl_get_ci_mi(m)->sparam_vals; assert(sparams != jl_emptysvec); From 7a1a6f32ec89745844b93cfabe2fe48fcac03ded Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 21 Jan 2025 10:03:00 -0500 Subject: [PATCH 218/342] codegen: use correct rettype ABI for aotcompile (#57082) This only really can differ in aotcompile, so it was hard to notice that that the attempted code simplification in db25494f62 wasn't correct and could lead to ABI mismatches at runtime. Fixes #57018 --- src/aotcompile.cpp | 2 +- src/codegen.cpp | 17 ++++++++--------- src/jitlayers.h | 3 ++- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 0235758979cd1..5524518da46fa 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -2223,7 +2223,7 @@ void jl_get_llvmf_defn_impl(jl_llvmf_dump_t* dump, jl_method_instance_t *mi, jl_ output.imaging_mode = jl_options.image_codegen; output.temporary_roots = jl_alloc_array_1d(jl_array_any_type, 0); JL_GC_PUSH1(&output.temporary_roots); - auto decls = jl_emit_code(m, mi, src, NULL, output); + auto decls = jl_emit_code(m, mi, src, mi->specTypes, src->rettype, output); output.temporary_roots = nullptr; JL_GC_POP(); // GC the global_targets array contents now since reflection doesn't need it diff --git a/src/codegen.cpp b/src/codegen.cpp index eefc675bdd665..7cfcc52db29c7 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4381,7 +4381,7 @@ static jl_llvm_functions_t jl_method_instance_t *lam, jl_code_info_t *src, jl_value_t *abi, - jl_value_t *rettype, + jl_value_t *jlrettype, jl_codegen_params_t ¶ms); static void emit_hasnofield_error_ifnot(jl_codectx_t &ctx, Value *ok, jl_datatype_t *type, jl_cgval_t name); @@ -5533,12 +5533,12 @@ static jl_value_t *get_ci_abi(jl_code_instance_t *ci) return jl_get_ci_mi(ci)->specTypes; } -static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, jl_code_instance_t *ci, jl_value_t *jlretty, StringRef specFunctionObject, jl_code_instance_t *fromexternal, +static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, jl_code_instance_t *ci, StringRef specFunctionObject, jl_code_instance_t *fromexternal, ArrayRef argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *return_roots, jl_value_t *inferred_retty, Value *age_ok) { jl_method_instance_t *mi = jl_get_ci_mi(ci); bool is_opaque_closure = jl_is_method(mi->def.value) && mi->def.method->is_for_opaque_closure; - return emit_call_specfun_other(ctx, is_opaque_closure, get_ci_abi(ci), jlretty, NULL, + return emit_call_specfun_other(ctx, is_opaque_closure, get_ci_abi(ci), ci->rettype, NULL, specFunctionObject, fromexternal, argv, nargs, cc, return_roots, inferred_retty, age_ok); } @@ -5688,7 +5688,7 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayR jl_returninfo_t::CallingConv cc = jl_returninfo_t::CallingConv::Boxed; unsigned return_roots = 0; if (specsig) - result = emit_call_specfun_other(ctx, codeinst, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, &cc, &return_roots, rt, age_ok); + result = emit_call_specfun_other(ctx, codeinst, protoname, external ? codeinst : nullptr, argv, nargs, &cc, &return_roots, rt, age_ok); else result = emit_call_specfun_boxed(ctx, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, rt, age_ok); if (need_to_emit) { @@ -10029,7 +10029,8 @@ jl_llvm_functions_t jl_emit_code( orc::ThreadSafeModule &m, jl_method_instance_t *li, jl_code_info_t *src, - jl_value_t *abi, + jl_value_t *abi_at, + jl_value_t *abi_rt, jl_codegen_params_t ¶ms) { JL_TIMING(CODEGEN, CODEGEN_LLVM); @@ -10038,10 +10039,8 @@ jl_llvm_functions_t jl_emit_code( assert((params.params == &jl_default_cgparams /* fast path */ || !params.cache || compare_cgparams(params.params, &jl_default_cgparams)) && "functions compiled with custom codegen params must not be cached"); - if (!abi) - abi = li->specTypes; JL_TRY { - decls = emit_function(m, li, src, abi, src->rettype, params); + decls = emit_function(m, li, src, abi_at, abi_rt, params); auto stream = *jl_ExecutionEngine->get_dump_emitted_mi_name_stream(); if (stream) { jl_printf(stream, "%s\t", decls.specFunctionObject.c_str()); @@ -10112,7 +10111,7 @@ jl_llvm_functions_t jl_emit_codeinst( return jl_llvm_functions_t(); // user error } //assert(jl_egal((jl_value_t*)jl_atomic_load_relaxed(&codeinst->debuginfo), (jl_value_t*)src->debuginfo) && "trying to generate code for a codeinst for an incompatible src"); - jl_llvm_functions_t decls = jl_emit_code(m, jl_get_ci_mi(codeinst), src, get_ci_abi(codeinst), params); + jl_llvm_functions_t decls = jl_emit_code(m, jl_get_ci_mi(codeinst), src, get_ci_abi(codeinst), codeinst->rettype, params); return decls; } diff --git a/src/jitlayers.h b/src/jitlayers.h index 7198c9b2f0210..4637670ec588c 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -278,7 +278,8 @@ jl_llvm_functions_t jl_emit_code( orc::ThreadSafeModule &M, jl_method_instance_t *mi, jl_code_info_t *src, - jl_value_t *abi, + jl_value_t *abi_at, + jl_value_t *abi_rt, jl_codegen_params_t ¶ms); jl_llvm_functions_t jl_emit_codeinst( From 4e13e0e449aee71a5ad7f335fbc8812d28c51cf2 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 21 Jan 2025 10:04:45 -0500 Subject: [PATCH 219/342] inference: fix lattice for unusual InterConditional return and Const Bool representations (#57080) Fixes #54886 Rule introduced by 55cee67 --- Compiler/src/abstractinterpretation.jl | 11 ++++++++++- Compiler/src/typelattice.jl | 7 +++++++ Compiler/test/inference.jl | 20 ++++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index 59510dbfbb65a..a6c75ed411082 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -3785,7 +3785,7 @@ function update_bestguess!(interp::AbstractInterpreter, frame::InferenceState, slottypes = frame.slottypes rt = widenreturn(rt, BestguessInfo(interp, bestguess, nargs, slottypes, currstate)) # narrow representation of bestguess slightly to prepare for tmerge with rt - if rt isa InterConditional && bestguess isa Const + if rt isa InterConditional && bestguess isa Const && bestguess.val isa Bool slot_id = rt.slot old_id_type = widenconditional(slottypes[slot_id]) if bestguess.val === true && rt.elsetype !== Bottom @@ -3793,6 +3793,15 @@ function update_bestguess!(interp::AbstractInterpreter, frame::InferenceState, elseif bestguess.val === false && rt.thentype !== Bottom bestguess = InterConditional(slot_id, Bottom, old_id_type) end + # or narrow representation of rt slightly to prepare for tmerge with bestguess + elseif bestguess isa InterConditional && rt isa Const && rt.val isa Bool + slot_id = bestguess.slot + old_id_type = widenconditional(slottypes[slot_id]) + if rt.val === true && bestguess.elsetype !== Bottom + rt = InterConditional(slot_id, old_id_type, Bottom) + elseif rt.val === false && bestguess.thentype !== Bottom + rt = InterConditional(slot_id, Bottom, old_id_type) + end end # copy limitations to return value if !isempty(frame.pclimitations) diff --git a/Compiler/src/typelattice.jl b/Compiler/src/typelattice.jl index bd0d24167b75a..6f7612b836c89 100644 --- a/Compiler/src/typelattice.jl +++ b/Compiler/src/typelattice.jl @@ -395,6 +395,13 @@ end end a = Bool elseif isa(b, ConditionalT) + if isa(a, Const) && isa(a.val, Bool) + if (a.val === true && b.thentype === Any && b.elsetype === Bottom) || + (a.val === false && b.elsetype === Any && b.thentype === Bottom) + # this Conditional contains distinctly no lattice information, and is simply an alternative representation of the Const Bool used for internal tracking purposes + return true + end + end return false end return ⊑(widenlattice(lattice), a, b) diff --git a/Compiler/test/inference.jl b/Compiler/test/inference.jl index 21d29c376bb27..b74460203e66e 100644 --- a/Compiler/test/inference.jl +++ b/Compiler/test/inference.jl @@ -2734,6 +2734,26 @@ vacond(cnd, va...) = cnd ? va : 0 vacond(isa(x, Tuple{Int,Int}), x, x) end |> only == Union{Int,Tuple{Any,Any}} +let A = Core.Const(true) + B = Core.InterConditional(2, Tuple, Union{}) + C = Core.InterConditional(2, Any, Union{}) + L = ipo_lattice(Compiler.NativeInterpreter()) + @test !⊑(L, A, B) + @test ⊑(L, B, A) + @test tmerge(L, A, B) == C + @test ⊑(L, A, C) +end +function tail_is_ntuple((@nospecialize t::Tuple)) + if unknown + t isa Tuple + else + tail_is_ntuple(t) + end +end +tail_is_ntuple_val((@nospecialize t::Tuple)) = Val(tail_is_ntuple(t)) +@test Base.return_types(tail_is_ntuple, (Tuple,)) |> only === Bool +@test Base.return_types(tail_is_ntuple_val, (Tuple,)) |> only === Val{true} + # https://github.com/JuliaLang/julia/issues/47435 is_closed_ex(e::InvalidStateException) = true is_closed_ex(e) = false From 323ca86cb5ff614b713c3995ea11b7755b74190c Mon Sep 17 00:00:00 2001 From: Chengyu Han Date: Wed, 22 Jan 2025 00:15:50 +0800 Subject: [PATCH 220/342] base: add `Sys.detectwsl()` (#57069) Close #36425, fix #36354 ## How to detect WSL? There are a number of ways that can be used to detect WSL environments, but each can have false positives. We finally chose to use the same method as Snapd to detect WSL. Because Windows installs Ubuntu LTS as WSL by default. So we assume that Snapd's detection method will work for most users. - Ubuntu/Snapd: https://github.com/canonical/snapd/blob/03a578a5dff26467dcc80580fcd4720a486185a5/release/release.go#L151-L172 - microsoft/WSL#423 - microsoft/WSL#4071 - https://superuser.com/q/1749781/1460597 ## Known limitations - this is a runtime test, and thus cannot meaningfully be used in `@static if` constructs. - Linux users can create their own - `/proc/sys/fs/binfmt_misc/WSLInterop` file - or `/run/WSL/` folder to pretend to be a WSL environment. --- - I've tested this under: Ubuntu 22.04.5 LTS (default/Offical) and alpine-release-3.17.0 (win store) - [x] Add compat, NEWS, tests - [x] Take a look at different detect methods, figure out which one is more robust --------- Co-authored-by: Gautam Mishra Co-authored-by: Max Horn <241512+fingolfin@users.noreply.github.com> Co-authored-by: Chengyu Han Co-authored-by: Alex Arslan --- NEWS.md | 1 + base/sysinfo.jl | 24 +++++++++++++++++++++++- test/osutils.jl | 5 +++++ test/path.jl | 2 +- 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 6c378c8186007..71014e1e57695 100644 --- a/NEWS.md +++ b/NEWS.md @@ -97,6 +97,7 @@ New library functions * `uuid7()` creates an RFC 9652 compliant UUID with version 7 ([#54834]). * `insertdims(array; dims)` allows to insert singleton dimensions into an array which is the inverse operation to `dropdims`. ([#45793]) * The new `Fix` type is a generalization of `Fix1/Fix2` for fixing a single argument ([#54653]). +* `Sys.detectwsl()` allows to testing if Julia is running inside WSL at runtime. ([#57069]) New library features -------------------- diff --git a/base/sysinfo.jl b/base/sysinfo.jl index 7dab313cf4f57..c96c318ec053b 100644 --- a/base/sysinfo.jl +++ b/base/sysinfo.jl @@ -36,7 +36,8 @@ export BINDIR, isreadable, iswritable, username, - which + which, + detectwsl import ..Base: show @@ -532,6 +533,27 @@ including e.g. a WebAssembly JavaScript embedding in a web browser. """ isjsvm(os::Symbol) = (os === :Emscripten) +""" + Sys.detectwsl() + +Runtime predicate for testing if Julia is running inside +Windows Subsystem for Linux (WSL). + +!!! note + Unlike `Sys.iswindows`, `Sys.islinux` etc., this is a runtime test, and thus + cannot meaningfully be used in `@static if` constructs. + +!!! compat "Julia 1.12" + This function requires at least Julia 1.12. +""" +function detectwsl() + # We use the same approach as canonical/snapd do to detect WSL + islinux() && ( + isfile("/proc/sys/fs/binfmt_misc/WSLInterop") + || isdir("/run/WSL") + ) +end + for f in (:isunix, :islinux, :isbsd, :isapple, :iswindows, :isfreebsd, :isopenbsd, :isnetbsd, :isdragonfly, :isjsvm) @eval $f() = $(getfield(@__MODULE__, f)(KERNEL)) end diff --git a/test/osutils.jl b/test/osutils.jl index 5e72675279cbc..9eb708b670298 100644 --- a/test/osutils.jl +++ b/test/osutils.jl @@ -29,6 +29,11 @@ using Libdl else @test Sys.windows_version() >= v"1.0.0-" end + + # TODO: When we have a WSL CI, add a new test here `@test detectwsl()` + if !Sys.islinux() + @test !Sys.detectwsl() + end end @testset "@static" begin diff --git a/test/path.jl b/test/path.jl index 2515d765d8ca9..a2824a24c8bce 100644 --- a/test/path.jl +++ b/test/path.jl @@ -314,7 +314,7 @@ @testset "uripath" begin host = if Sys.iswindows() "" - elseif ispath("/proc/sys/fs/binfmt_misc/WSLInterop") + elseif Sys.detectwsl() distro = get(ENV, "WSL_DISTRO_NAME", "") # See "wsl%24/$distro" # See and else From eb9f24c8ceb964464939775e164366939755393c Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 21 Jan 2025 13:12:05 -0500 Subject: [PATCH 221/342] inference: ensure inferring reachable code methods (#57088) PR #51317 was a bit over-eager about inferring inferring unreachable code methods. Filter out the Vararg case, since that can be handled by simply removing it instead of discarding the whole call. Fixes #56628 --- Compiler/src/abstractinterpretation.jl | 4 ++- Compiler/src/ssair/inlining.jl | 1 + Compiler/src/tfuncs.jl | 36 ++++++++++++++------------ Compiler/src/typeutils.jl | 7 ++++- Compiler/test/inference.jl | 6 +++++ 5 files changed, 36 insertions(+), 18 deletions(-) diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index a6c75ed411082..300feeae53e9a 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -368,6 +368,7 @@ function find_union_split_method_matches(interp::AbstractInterpreter, argtypes:: for i in 1:length(split_argtypes) arg_n = split_argtypes[i]::Vector{Any} sig_n = argtypes_to_type(arg_n) + sig_n === Bottom && continue mt = ccall(:jl_method_table_for, Any, (Any,), sig_n) mt === nothing && return FailedMethodMatch("Could not identify method table for call") mt = mt::MethodTable @@ -614,7 +615,7 @@ function abstract_call_method(interp::AbstractInterpreter, sigtuple = unwrap_unionall(sig) sigtuple isa DataType || return Future(MethodCallResult(Any, Any, Effects(), nothing, false, false)) - all(@nospecialize(x) -> valid_as_lattice(unwrapva(x), true), sigtuple.parameters) || + all(@nospecialize(x) -> isvarargtype(x) || valid_as_lattice(x, true), sigtuple.parameters) || return Future(MethodCallResult(Union{}, Any, EFFECTS_THROWS, nothing, false, false)) # catch bad type intersections early if is_nospecializeinfer(method) @@ -2840,6 +2841,7 @@ function abstract_call_unknown(interp::AbstractInterpreter, @nospecialize(ft), end # non-constant function, but the number of arguments is known and the `f` is not a builtin or intrinsic atype = argtypes_to_type(arginfo.argtypes) + atype === Bottom && return Future(CallMeta(Union{}, Union{}, EFFECTS_THROWS, NoCallInfo())) # accidentally unreachable return abstract_call_gf_by_type(interp, nothing, arginfo, si, atype, sv, max_methods)::Future end diff --git a/Compiler/src/ssair/inlining.jl b/Compiler/src/ssair/inlining.jl index 0c0d14bf8f25a..120b891f09a9f 100644 --- a/Compiler/src/ssair/inlining.jl +++ b/Compiler/src/ssair/inlining.jl @@ -1399,6 +1399,7 @@ function handle_call!(todo::Vector{Pair{Int,Any}}, cases === nothing && return nothing cases, handled_all_cases, fully_covered, joint_effects = cases atype = argtypes_to_type(sig.argtypes) + atype === Union{} && return nothing # accidentally actually unreachable handle_cases!(todo, ir, idx, stmt, atype, cases, handled_all_cases, fully_covered, joint_effects) end diff --git a/Compiler/src/tfuncs.jl b/Compiler/src/tfuncs.jl index cfb865b06e9e5..fe21f6381e8cd 100644 --- a/Compiler/src/tfuncs.jl +++ b/Compiler/src/tfuncs.jl @@ -3016,24 +3016,28 @@ function abstract_applicable(interp::AbstractInterpreter, argtypes::Vector{Any}, isvarargtype(argtypes[2]) && return Future(CallMeta(Bool, ArgumentError, EFFECTS_THROWS, NoCallInfo())) argtypes = argtypes[2:end] atype = argtypes_to_type(argtypes) - matches = find_method_matches(interp, argtypes, atype; max_methods) - info = NoCallInfo() - if isa(matches, FailedMethodMatch) - rt = Bool # too many matches to analyze + if atype === Union{} + rt = Union{} # accidentally unreachable code else - (; valid_worlds, applicable) = matches - update_valid_age!(sv, valid_worlds) - napplicable = length(applicable) - if napplicable == 0 - rt = Const(false) # never any matches - elseif !fully_covering(matches) || any_ambig(matches) - # Account for the fact that we may encounter a MethodError with a non-covered or ambiguous signature. - rt = Bool + matches = find_method_matches(interp, argtypes, atype; max_methods) + info = NoCallInfo() + if isa(matches, FailedMethodMatch) + rt = Bool # too many matches to analyze else - rt = Const(true) # has applicable matches - end - if rt !== Bool - info = VirtualMethodMatchInfo(matches.info) + (; valid_worlds, applicable) = matches + update_valid_age!(sv, valid_worlds) + napplicable = length(applicable) + if napplicable == 0 + rt = Const(false) # never any matches + elseif !fully_covering(matches) || any_ambig(matches) + # Account for the fact that we may encounter a MethodError with a non-covered or ambiguous signature. + rt = Bool + else + rt = Const(true) # has applicable matches + end + if rt !== Bool + info = VirtualMethodMatchInfo(matches.info) + end end end return Future(CallMeta(rt, Union{}, EFFECTS_TOTAL, info)) diff --git a/Compiler/src/typeutils.jl b/Compiler/src/typeutils.jl index 5175e00612270..d588a9aee1a6c 100644 --- a/Compiler/src/typeutils.jl +++ b/Compiler/src/typeutils.jl @@ -54,7 +54,12 @@ has_extended_info(@nospecialize x) = (!isa(x, Type) && !isvarargtype(x)) || isTy # certain combinations of `a` and `b` where one/both isa/are `Union`/`UnionAll` type(s)s. isnotbrokensubtype(@nospecialize(a), @nospecialize(b)) = (!iskindtype(b) || !isType(a) || hasuniquerep(a.parameters[1]) || b <: a) -argtypes_to_type(argtypes::Array{Any,1}) = Tuple{anymap(@nospecialize(a) -> isvarargtype(a) ? a : widenconst(a), argtypes)...} +function argtypes_to_type(argtypes::Array{Any,1}) + argtypes = anymap(@nospecialize(a) -> isvarargtype(a) ? a : widenconst(a), argtypes) + filter!(@nospecialize(x) -> !isvarargtype(x) || valid_as_lattice(unwrapva(x), true), argtypes) + all(@nospecialize(x) -> isvarargtype(x) || valid_as_lattice(x, true), argtypes) || return Bottom + return Tuple{argtypes...} +end function isknownlength(t::DataType) isvatuple(t) || return true diff --git a/Compiler/test/inference.jl b/Compiler/test/inference.jl index b74460203e66e..d4ea990e7d148 100644 --- a/Compiler/test/inference.jl +++ b/Compiler/test/inference.jl @@ -6182,3 +6182,9 @@ end <: Any end return out end == Union{Float64,DomainError} + +# issue #56628 +@test Compiler.argtypes_to_type(Any[ Int, UnitRange{Int}, Vararg{Pair{Any, Union{}}} ]) === Tuple{Int, UnitRange{Int}} +@test Compiler.argtypes_to_type(Any[ Int, UnitRange{Int}, Vararg{Pair{Any, Union{}}}, Float64 ]) === Tuple{Int, UnitRange{Int}, Float64} +@test Compiler.argtypes_to_type(Any[ Int, UnitRange{Int}, Vararg{Pair{Any, Union{}}}, Float64, Memory{2} ]) === Union{} +@test Base.return_types(Tuple{Tuple{Int, Vararg{Pair{Any, Union{}}}}},) do x; Returns(true)(x...); end |> only === Bool From cb553897e82f7bc6a51d30c1db531f54abae1a8b Mon Sep 17 00:00:00 2001 From: Oscar Smith Date: Tue, 21 Jan 2025 13:19:54 -0500 Subject: [PATCH 222/342] minor fma cleanup (#57041) This removes the redundant `fma_llvm` function, and makes it so systems with Float16 fma can actually use it rather than the Float32 fallback path. --- base/floatfuncs.jl | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/base/floatfuncs.jl b/base/floatfuncs.jl index 2c26f7cff1133..f373325770ef9 100644 --- a/base/floatfuncs.jl +++ b/base/floatfuncs.jl @@ -276,6 +276,9 @@ significantly more expensive than `x*y+z`. `fma` is used to improve accuracy in algorithms. See [`muladd`](@ref). """ function fma end +function fma_emulated(a::Float16, b::Float16, c::Float16) + Float16(muladd(Float32(a), Float32(b), Float32(c))) #don't use fma if the hardware doesn't have it. +end function fma_emulated(a::Float32, b::Float32, c::Float32)::Float32 ab = Float64(a) * b res = ab+c @@ -348,19 +351,14 @@ function fma_emulated(a::Float64, b::Float64,c::Float64) s = (abs(abhi) > abs(c)) ? (abhi-r+c+ablo) : (c-r+abhi+ablo) return r+s end -fma_llvm(x::Float32, y::Float32, z::Float32) = fma_float(x, y, z) -fma_llvm(x::Float64, y::Float64, z::Float64) = fma_float(x, y, z) # Disable LLVM's fma if it is incorrect, e.g. because LLVM falls back # onto a broken system libm; if so, use a software emulated fma -@assume_effects :consistent fma(x::Float32, y::Float32, z::Float32) = Core.Intrinsics.have_fma(Float32) ? fma_llvm(x,y,z) : fma_emulated(x,y,z) -@assume_effects :consistent fma(x::Float64, y::Float64, z::Float64) = Core.Intrinsics.have_fma(Float64) ? fma_llvm(x,y,z) : fma_emulated(x,y,z) - -function fma(a::Float16, b::Float16, c::Float16) - Float16(muladd(Float32(a), Float32(b), Float32(c))) #don't use fma if the hardware doesn't have it. +@assume_effects :consistent function fma(x::T, y::T, z::T) where {T<:IEEEFloat} + Core.Intrinsics.have_fma(T) ? fma_float(x,y,z) : fma_emulated(x,y,z) end -# This is necessary at least on 32-bit Intel Linux, since fma_llvm may +# This is necessary at least on 32-bit Intel Linux, since fma_float may # have called glibc, and some broken glibc fma implementations don't # properly restore the rounding mode Rounding.setrounding_raw(Float32, Rounding.JL_FE_TONEAREST) From b70761f76dee4fc4194f61ac6a53d7e05c6f3c92 Mon Sep 17 00:00:00 2001 From: Neven Sajko <4944410+nsajko@users.noreply.github.com> Date: Tue, 21 Jan 2025 21:19:16 +0100 Subject: [PATCH 223/342] allow `rand!` with explicit SIMD to be used for various dense arrays (#57101) --- stdlib/Random/src/XoshiroSimd.jl | 7 ++++--- stdlib/Random/test/runtests.jl | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/stdlib/Random/src/XoshiroSimd.jl b/stdlib/Random/src/XoshiroSimd.jl index 58544714dd9f5..f77be4a347111 100644 --- a/stdlib/Random/src/XoshiroSimd.jl +++ b/stdlib/Random/src/XoshiroSimd.jl @@ -292,20 +292,21 @@ end return i end +const MutableDenseArray = Union{Base.MutableDenseArrayType{T}, UnsafeView{T}} where {T} -function rand!(rng::Union{TaskLocalRNG, Xoshiro}, dst::Array{T}, ::SamplerTrivial{CloseOpen01{T}}) where {T<:Union{Float16,Float32,Float64}} +function rand!(rng::Union{TaskLocalRNG, Xoshiro}, dst::MutableDenseArray{T}, ::SamplerTrivial{CloseOpen01{T}}) where {T<:Union{Float16,Float32,Float64}} GC.@preserve dst xoshiro_bulk(rng, convert(Ptr{UInt8}, pointer(dst)), length(dst)*sizeof(T), T, xoshiroWidth(), _bits2float) dst end for T in BitInteger_types - @eval function rand!(rng::Union{TaskLocalRNG, Xoshiro}, dst::Union{Array{$T}, UnsafeView{$T}}, ::SamplerType{$T}) + @eval function rand!(rng::Union{TaskLocalRNG, Xoshiro}, dst::MutableDenseArray{$T}, ::SamplerType{$T}) GC.@preserve dst xoshiro_bulk(rng, convert(Ptr{UInt8}, pointer(dst)), length(dst)*sizeof($T), UInt8, xoshiroWidth()) dst end end -function rand!(rng::Union{TaskLocalRNG, Xoshiro}, dst::Array{Bool}, ::SamplerType{Bool}) +function rand!(rng::Union{TaskLocalRNG, Xoshiro}, dst::MutableDenseArray{Bool}, ::SamplerType{Bool}) GC.@preserve dst xoshiro_bulk(rng, convert(Ptr{UInt8}, pointer(dst)), length(dst), Bool, xoshiroWidth()) dst end diff --git a/stdlib/Random/test/runtests.jl b/stdlib/Random/test/runtests.jl index 9b46951f63ff5..13edf2e6553ec 100644 --- a/stdlib/Random/test/runtests.jl +++ b/stdlib/Random/test/runtests.jl @@ -370,9 +370,10 @@ for rng in ([], [MersenneTwister(0)], [RandomDevice()], [Xoshiro()]) a8 = rand!(rng..., GenericArray{T}(undef, 2, 3), cc) ::GenericArray{T, 2} a9 = rand!(rng..., OffsetArray(Array{T}(undef, 5), 9), cc) ::OffsetArray{T, 1} a10 = rand!(rng..., OffsetArray(Array{T}(undef, 2, 3), (-2, 4)), cc) ::OffsetArray{T, 2} + a11 = rand!(rng..., Memory{T}(undef, 5), cc) ::Memory{T} @test size(a1) == (5,) @test size(a2) == size(a3) == (2, 3) - for a in [a0, a1..., a2..., a3..., a4..., a5..., a6..., a7..., a8..., a9..., a10...] + for a in [a0, a1..., a2..., a3..., a4..., a5..., a6..., a7..., a8..., a9..., a10..., a11...] if C isa Type @test a isa C else @@ -392,6 +393,7 @@ for rng in ([], [MersenneTwister(0)], [RandomDevice()], [Xoshiro()]) (T <: Tuple || T <: Pair) && continue X = T == Bool ? T[0,1] : T[0,1,2] for A in (Vector{T}(undef, 5), + Memory{T}(undef, 5), Matrix{T}(undef, 2, 3), GenericArray{T}(undef, 5), GenericArray{T}(undef, 2, 3), From e03de0b883c044723d84cb4a4f93a6dd1ba99728 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 21 Jan 2025 23:22:37 +0100 Subject: [PATCH 224/342] Remove `jl_task_stack_buffer` (again) (#57116) This was removed previously in PR #54527 but had to be reverted in PR #54559 as one usage remained (more by accident then by design). This has since then been resolved. This is also part of PR #56477 but that seems stalled right now, and in fact merging parts of it now may make the review of it easier later on... --- src/jl_exported_funcs.inc | 1 - src/julia_gcext.h | 9 --------- src/task.c | 28 ---------------------------- 3 files changed, 38 deletions(-) diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index b92380df7a49c..c1b29a091511b 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -449,7 +449,6 @@ XX(jl_tagged_gensym) \ XX(jl_take_buffer) \ XX(jl_task_get_next) \ - XX(jl_task_stack_buffer) \ XX(jl_termios_size) \ XX(jl_test_cpu_feature) \ XX(jl_threadid) \ diff --git a/src/julia_gcext.h b/src/julia_gcext.h index 05140e4b09ace..e124f58a09402 100644 --- a/src/julia_gcext.h +++ b/src/julia_gcext.h @@ -135,15 +135,6 @@ JL_DLLEXPORT int jl_gc_conservative_gc_support_enabled(void); // NOTE: Only valid to call from within a GC context. JL_DLLEXPORT jl_value_t *jl_gc_internal_obj_base_ptr(void *p) JL_NOTSAFEPOINT; -// Return a non-null pointer to the start of the stack area if the task -// has an associated stack buffer. In that case, *size will also contain -// the size of that stack buffer upon return. Also, if task is a thread's -// current task, that thread's id will be stored in *tid; otherwise, -// *tid will be set to -1. -// -// DEPRECATED: use jl_active_task_stack() instead. -JL_DLLEXPORT void *jl_task_stack_buffer(jl_task_t *task, size_t *size, int *tid); - // Query the active and total stack range for the given task, and set // *active_start and *active_end respectively *total_start and *total_end // accordingly. The range for the active part is a best-effort approximation diff --git a/src/task.c b/src/task.c index d56d60eb58cb5..37e7f0e1f5440 100644 --- a/src/task.c +++ b/src/task.c @@ -352,34 +352,6 @@ void JL_NORETURN jl_finish_task(jl_task_t *ct) abort(); } -JL_DLLEXPORT void *jl_task_stack_buffer(jl_task_t *task, size_t *size, int *ptid) -{ - size_t off = 0; -#ifndef _OS_WINDOWS_ - jl_ptls_t ptls0 = jl_atomic_load_relaxed(&jl_all_tls_states)[0]; - if (ptls0->root_task == task) { - // See jl_init_root_task(). The root task of the main thread - // has its buffer enlarged by an artificial 3000000 bytes, but - // that means that the start of the buffer usually points to - // inaccessible memory. We need to correct for this. - off = ROOT_TASK_STACK_ADJUSTMENT; - } -#endif - jl_ptls_t ptls2 = task->ptls; - *ptid = -1; - if (ptls2) { - *ptid = jl_atomic_load_relaxed(&task->tid); -#ifdef COPY_STACKS - if (task->ctx.copy_stack) { - *size = ptls2->stacksize; - return (char *)ptls2->stackbase - *size; - } -#endif - } - *size = task->ctx.bufsz - off; - return (void *)((char *)task->ctx.stkbuf + off); -} - JL_DLLEXPORT void jl_active_task_stack(jl_task_t *task, char **active_start, char **active_end, char **total_start, char **total_end) From f91436eae7265a01bff17e35887cd9b8e15c8fdc Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Tue, 21 Jan 2025 18:14:11 -0500 Subject: [PATCH 225/342] Add test for #57115 (#57120) Closes #57115. This issue was accidentally resolved on master by #54894, but it is important enough that we should have test coverage for it. --- test/precompile.jl | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/test/precompile.jl b/test/precompile.jl index 78a96250600a4..55e97f5608b08 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -1094,6 +1094,17 @@ precompile_test_harness("invoke") do dir f44320(::Any) = 2 g44320() = invoke(f44320, Tuple{Any}, 0) g44320() + # Issue #57115 + f57115(@nospecialize(::Any)) = error("unimplemented") + function g57115(@nospecialize(x)) + if @noinline rand(Bool) + # Add an 'invoke' edge from 'foo' to 'bar' + Core.invoke(f57115, Tuple{Any}, x) + else + # ... and also an identical 'call' edge + @noinline f57115(x) + end + end # Adding new specializations should not invalidate `invoke`s function getlast(itr) @@ -1110,6 +1121,8 @@ precompile_test_harness("invoke") do dir """ module $CallerModule using $InvokeModule + import $InvokeModule: f57115, g57115 + # involving external modules callf(x) = f(x) callg(x) = x < 5 ? g(x) : invoke(g, Tuple{Real}, x) @@ -1130,6 +1143,8 @@ precompile_test_harness("invoke") do dir # Issue #44320 f44320(::Real) = 3 + # Issue #57115 + f57115(::Int) = 1 call_getlast(x) = getlast(x) @@ -1150,6 +1165,7 @@ precompile_test_harness("invoke") do dir @noinline internalnc(3) @noinline call_getlast([1,2,3]) end + precompile(g57115, (Any,)) # Now that we've precompiled, invalidate with a new method that overrides the `invoke` dispatch $InvokeModule.h(x::Integer) = -1 @@ -1217,6 +1233,30 @@ precompile_test_harness("invoke") do dir m = only(methods(M.g44320)) @test (m.specializations::Core.MethodInstance).cache.max_world == typemax(UInt) + m = only(methods(M.g57115)) + mi = m.specializations::Core.MethodInstance + + f_m = get_method_for_type(M.f57115, Any) + f_mi = f_m.specializations::Core.MethodInstance + + # Make sure that f57115(::Any) has a 'call' backedge to 'g57115' + has_f_call_backedge = false + i = 1 + while i ≤ length(f_mi.backedges) + if f_mi.backedges[i] isa DataType + # invoke edge - skip + i += 2 + else + caller = f_mi.backedges[i]::Core.CodeInstance + if caller.def === mi + has_f_call_backedge = true + break + end + i += 1 + end + end + @test has_f_call_backedge + m = which(MI.getlast, (Any,)) @test (m.specializations::Core.MethodInstance).cache.max_world == typemax(UInt) From 294c4a63a0cd37dff72a51b2d9210a36ae2ff174 Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Wed, 22 Jan 2025 07:06:42 -0500 Subject: [PATCH 226/342] runtime_intrinsics.c: Remove duplicated line of code (#57123) --- src/runtime_intrinsics.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/runtime_intrinsics.c b/src/runtime_intrinsics.c index 1790b9bd8d106..90afa3fb6bddf 100644 --- a/src/runtime_intrinsics.c +++ b/src/runtime_intrinsics.c @@ -812,7 +812,6 @@ static void jl_##name##16(unsigned runtime_nbits, void *pa, void *pb, void *pr) runtime_nbits = 16; \ float R = OP(A, B); \ *(uint16_t*)pr = float_to_half(R); \ - *(uint16_t*)pr = float_to_half(R); \ } #define bi_intrinsic_bfloat(OP, name) \ @@ -903,7 +902,6 @@ static void jl_##name##16(unsigned runtime_nbits, void *pa, void *pb, void *pc, runtime_nbits = 16; \ float R = OP(A, B, C); \ *(uint16_t*)pr = float_to_half(R); \ - *(uint16_t*)pr = float_to_half(R); \ } #define ter_intrinsic_bfloat(OP, name) \ From 7f99e95377c61515a63aed6ca6500e837f34f69f Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Wed, 22 Jan 2025 13:40:53 +0100 Subject: [PATCH 227/342] bpart: Start enforcing minimum world age for const bparts (#57102) Currently, even though the binding partition system is implemented, it is largely enabled. New `const` definitions get magically "backdated" to the first world age in which the binding was undefined. Additionally, they do not get their own world age and there is currently no `latestworld` marker after `const` definitions. This PR changes this situation to give const markers their own world age with appropriate `latestworld` increments. Both of these are mandatory for `const` replacement to work. The other thing this PR does is prepare to remove the automatic "backdating". To see the difference, consider: ``` function foo($i) Core.eval(:(const x = $i)) x end ``` Without an intervening world age increment, this will throw an UndefVarError on this PR. I believe this is the best option for two reasons: 1. It will allow us infer these to `Union{}` in the future (thus letting inference prune dead code faster). 2. I think it is less confusing in terms of the world age semantics for `const` definitions to become active only after they are defined. To illustrate the second point, suppose we did keep the automatic backdating. Then we would have: ``` foo(1) => 1 foo(2) => 1 foo(3) => 2 ``` as opposed to on this PR: ``` foo(1) => UndefVarError foo(2) => 1 foo(3) => 2 ``` The semantics are consistent, of course, but I am concerned that an automatic backdating will give users the wrong mental model about world age, since it "fixes itself" the first time, but if you Revise it, it will give an unexpected answer. I think this would encourage accidentally bad code patterns that only break under Revise (where they are hard to debug). The counterpoint of course is that that not backdating is a more breaking choice. As with the rest of the 1.12-era world age semantics changes, I think taking a look at PkgEval will be helpful. --- Compiler/src/abstractinterpretation.jl | 11 ++-- Compiler/src/optimize.jl | 2 +- Compiler/src/ssair/ir.jl | 4 +- Compiler/src/ssair/legacy.jl | 2 +- Compiler/src/ssair/verify.jl | 12 +++- Compiler/src/tfuncs.jl | 2 +- Compiler/test/inline.jl | 4 +- base/Base.jl | 1 + base/client.jl | 12 ++-- base/essentials.jl | 6 ++ base/loading.jl | 22 +++++--- base/logging/logging.jl | 4 +- base/reflection.jl | 77 +++++++++++++++++++------- base/runtime_internals.jl | 16 ++++-- src/codegen.cpp | 34 ++++++++---- src/gf.c | 21 ++++--- src/init.c | 13 +++-- src/jlapi.c | 11 ++-- src/julia-syntax.scm | 14 ++++- src/julia.h | 1 - src/julia_internal.h | 14 +++-- src/method.c | 30 +++++++--- src/module.c | 43 +++++++------- src/staticdata.c | 15 ++++- src/toplevel.c | 38 +++++++++++-- stdlib/REPL/src/REPLCompletions.jl | 16 ++++-- stdlib/REPL/src/precompile.jl | 1 + stdlib/REPL/test/precompilation.jl | 2 +- stdlib/REPL/test/repl.jl | 8 +-- stdlib/Serialization/test/runtests.jl | 16 +++--- test/core.jl | 2 +- test/loading.jl | 1 + test/precompile.jl | 16 ++++-- test/runtests.jl | 6 +- test/syntax.jl | 1 + test/worlds.jl | 4 +- 36 files changed, 318 insertions(+), 164 deletions(-) diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index 300feeae53e9a..2b1a7fb2dd448 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -3456,10 +3456,10 @@ world_range(ir::IRCode) = ir.valid_worlds world_range(ci::CodeInfo) = WorldRange(ci.min_world, ci.max_world) world_range(compact::IncrementalCompact) = world_range(compact.ir) -function force_binding_resolution!(g::GlobalRef) +function force_binding_resolution!(g::GlobalRef, world::UInt) # Force resolution of the binding # TODO: This will go away once we switch over to fully partitioned semantics - ccall(:jl_globalref_boundp, Cint, (Any,), g) + ccall(:jl_force_binding_resolution, Cvoid, (Any, Csize_t), g, world) return nothing end @@ -3477,7 +3477,7 @@ function abstract_eval_globalref_type(g::GlobalRef, src::Union{CodeInfo, IRCode, # This method is surprisingly hot. For performance, don't ask the runtime to resolve # the binding unless necessary - doing so triggers an additional lookup, which though # not super expensive is hot enough to show up in benchmarks. - force_binding_resolution!(g) + force_binding_resolution!(g, min_world(worlds)) return abstract_eval_globalref_type(g, src, false) end # return Union{} @@ -3490,7 +3490,7 @@ function abstract_eval_globalref_type(g::GlobalRef, src::Union{CodeInfo, IRCode, end function lookup_binding_partition!(interp::AbstractInterpreter, g::GlobalRef, sv::AbsIntState) - force_binding_resolution!(g) + force_binding_resolution!(g, get_inference_world(interp)) partition = lookup_binding_partition(get_inference_world(interp), g) update_valid_age!(sv, WorldRange(partition.min_world, partition.max_world)) partition @@ -3539,7 +3539,8 @@ function abstract_eval_globalref(interp::AbstractInterpreter, g::GlobalRef, saw_ partition = abstract_eval_binding_partition!(interp, g, sv) ret = abstract_eval_partition_load(interp, partition) if ret.rt !== Union{} && ret.exct === UndefVarError && InferenceParams(interp).assume_bindings_static - if isdefined(g, :binding) && isdefined(g.binding, :value) + b = convert(Core.Binding, g) + if isdefined(b, :value) ret = RTEffects(ret.rt, Union{}, Effects(generic_getglobal_effects, nothrow=true)) end # We do not assume in general that assigned global bindings remain assigned. diff --git a/Compiler/src/optimize.jl b/Compiler/src/optimize.jl index 12b2f3c9a269f..9f74f028507cd 100644 --- a/Compiler/src/optimize.jl +++ b/Compiler/src/optimize.jl @@ -1286,7 +1286,7 @@ function convert_to_ircode(ci::CodeInfo, sv::OptimizationState) # types of call arguments only once `slot2reg` converts this `IRCode` to the SSA form # and eliminates slots (see below) argtypes = sv.slottypes - return IRCode(stmts, sv.cfg, di, argtypes, meta, sv.sptypes, WorldRange(ci.min_world, ci.max_world)) + return IRCode(stmts, sv.cfg, di, argtypes, meta, sv.sptypes, world_range(ci)) end function process_meta!(meta::Vector{Expr}, @nospecialize stmt) diff --git a/Compiler/src/ssair/ir.jl b/Compiler/src/ssair/ir.jl index 9103dba04fa54..f86ada2309ddc 100644 --- a/Compiler/src/ssair/ir.jl +++ b/Compiler/src/ssair/ir.jl @@ -434,7 +434,7 @@ struct IRCode function IRCode(stmts::InstructionStream, cfg::CFG, debuginfo::DebugInfoStream, argtypes::Vector{Any}, meta::Vector{Expr}, sptypes::Vector{VarState}, valid_worlds=WorldRange(typemin(UInt), typemax(UInt))) - return new(stmts, argtypes, sptypes, debuginfo, cfg, NewNodeStream(), meta) + return new(stmts, argtypes, sptypes, debuginfo, cfg, NewNodeStream(), meta, valid_worlds) end function IRCode(ir::IRCode, stmts::InstructionStream, cfg::CFG, new_nodes::NewNodeStream) di = ir.debuginfo @@ -1462,7 +1462,7 @@ function process_node!(compact::IncrementalCompact, result_idx::Int, inst::Instr result[result_idx][:stmt] = GotoNode(label) result_idx += 1 elseif isa(stmt, GlobalRef) - total_flags = IR_FLAG_CONSISTENT | IR_FLAG_EFFECT_FREE + total_flags = IR_FLAG_CONSISTENT | IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW flag = result[result_idx][:flag] if has_flag(flag, total_flags) ssa_rename[idx] = stmt diff --git a/Compiler/src/ssair/legacy.jl b/Compiler/src/ssair/legacy.jl index 675ca2dea9b32..64a39c72ad9eb 100644 --- a/Compiler/src/ssair/legacy.jl +++ b/Compiler/src/ssair/legacy.jl @@ -44,7 +44,7 @@ function inflate_ir!(ci::CodeInfo, sptypes::Vector{VarState}, argtypes::Vector{A di = DebugInfoStream(nothing, ci.debuginfo, nstmts) stmts = InstructionStream(code, ssavaluetypes, info, di.codelocs, ci.ssaflags) meta = Expr[] - return IRCode(stmts, cfg, di, argtypes, meta, sptypes, WorldRange(ci.min_world, ci.max_world)) + return IRCode(stmts, cfg, di, argtypes, meta, sptypes, world_range(ci)) end """ diff --git a/Compiler/src/ssair/verify.jl b/Compiler/src/ssair/verify.jl index 12eb09be693f3..fa16bdcc7ab19 100644 --- a/Compiler/src/ssair/verify.jl +++ b/Compiler/src/ssair/verify.jl @@ -12,7 +12,7 @@ end if !isdefined(@__MODULE__, Symbol("@verify_error")) macro verify_error(arg) - arg isa String && return esc(:(print && println(stderr, $arg))) + arg isa String && return esc(:(print && println($(GlobalRef(Core, :stderr)), $arg))) isexpr(arg, :string) || error("verify_error macro expected a string expression") pushfirst!(arg.args, GlobalRef(Core, :stderr)) pushfirst!(arg.args, :println) @@ -61,8 +61,14 @@ function check_op(ir::IRCode, domtree::DomTree, @nospecialize(op), use_bb::Int, raise_error() end elseif isa(op, GlobalRef) - if !isdefined(op.mod, op.name) || !isconst(op.mod, op.name) - @verify_error "Unbound GlobalRef not allowed in value position" + force_binding_resolution!(op, min_world(ir.valid_worlds)) + bpart = lookup_binding_partition(min_world(ir.valid_worlds), op) + while is_some_imported(binding_kind(bpart)) && max_world(ir.valid_worlds) <= bpart.max_world + imported_binding = partition_restriction(bpart)::Core.Binding + bpart = lookup_binding_partition(min_world(ir.valid_worlds), imported_binding) + end + if !is_defined_const_binding(binding_kind(bpart)) || (bpart.max_world < max_world(ir.valid_worlds)) + @verify_error "Unbound or partitioned GlobalRef not allowed in value position" raise_error() end elseif isa(op, Expr) diff --git a/Compiler/src/tfuncs.jl b/Compiler/src/tfuncs.jl index fe21f6381e8cd..74c8026ca0cf5 100644 --- a/Compiler/src/tfuncs.jl +++ b/Compiler/src/tfuncs.jl @@ -1109,7 +1109,7 @@ function _getfield_tfunc_const(@nospecialize(sv), name::Const) if isa(sv, DataType) && nv == DATATYPE_TYPES_FIELDINDEX && isdefined(sv, nv) return Const(getfield(sv, nv)) end - if isconst(typeof(sv), nv) + if !isa(sv, Module) && isconst(typeof(sv), nv) if isdefined(sv, nv) return Const(getfield(sv, nv)) end diff --git a/Compiler/test/inline.jl b/Compiler/test/inline.jl index 5f95fb761859e..b8ff14405391d 100644 --- a/Compiler/test/inline.jl +++ b/Compiler/test/inline.jl @@ -149,7 +149,7 @@ end (src, _) = only(code_typed(sum27403, Tuple{Vector{Int}})) @test !any(src.code) do x - x isa Expr && x.head === :invoke && x.args[2] !== Core.GlobalRef(Base, :throw_boundserror) + x isa Expr && x.head === :invoke && !(x.args[2] in (Core.GlobalRef(Base, :throw_boundserror), Base.throw_boundserror)) end end @@ -313,7 +313,7 @@ end const _a_global_array = [1] f_inline_global_getindex() = _a_global_array[1] let ci = code_typed(f_inline_global_getindex, Tuple{})[1].first - @test any(x->(isexpr(x, :call) && x.args[1] === GlobalRef(Base, :memoryrefget)), ci.code) + @test any(x->(isexpr(x, :call) && x.args[1] in (GlobalRef(Base, :memoryrefget), Base.memoryrefget)), ci.code) end # Issue #29114 & #36087 - Inlining of non-tuple splats diff --git a/base/Base.jl b/base/Base.jl index 20b1636c29a8d..04f732a4309c9 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -401,6 +401,7 @@ end # we know whether the .ji can just give the Base copy or not. # TODO: We may want to do this earlier to avoid TOCTOU issues. const _compiler_require_dependencies = Any[] +@Core.latestworld for i = 1:length(_included_files) isassigned(_included_files, i) || continue (mod, file) = _included_files[i] diff --git a/base/client.jl b/base/client.jl index e95d518d3e501..2527d382c695d 100644 --- a/base/client.jl +++ b/base/client.jl @@ -299,7 +299,7 @@ function exec_options(opts) elseif cmd == 'm' entrypoint = push!(split(arg, "."), "main") Base.eval(Main, Expr(:import, Expr(:., Symbol.(entrypoint)...))) - if !should_use_main_entrypoint() + if !invokelatest(should_use_main_entrypoint) error("`main` in `$arg` not declared as entry point (use `@main` to do so)") end return false @@ -408,8 +408,7 @@ function load_InteractiveUtils(mod::Module=Main) return nothing end end - Core.eval(mod, :(using Base.MainInclude.InteractiveUtils)) - return MainInclude.InteractiveUtils + return Core.eval(mod, :(using Base.MainInclude.InteractiveUtils; Base.MainInclude.InteractiveUtils)) end function load_REPL() @@ -556,11 +555,12 @@ function _start() local ret = 0 try repl_was_requested = exec_options(JLOptions()) - if should_use_main_entrypoint() && !is_interactive + if invokelatest(should_use_main_entrypoint) && !is_interactive + main = invokelatest(getglobal, Main, :main) if Base.generating_output() - precompile(Main.main, (typeof(ARGS),)) + precompile(main, (typeof(ARGS),)) else - ret = invokelatest(Main.main, ARGS) + ret = invokelatest(main, ARGS) end elseif (repl_was_requested || is_interactive) # Run the Base `main`, which will either load the REPL stdlib diff --git a/base/essentials.jl b/base/essentials.jl index fa5cf79192f56..58e4ce1125093 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -1266,6 +1266,9 @@ arbitrary code in fixed worlds. `world` may be `UnitRange`, in which case the ma will error unless the binding is valid and has the same value across the entire world range. +As a special case, the world `∞` always refers to the latest world, even if that world +is newer than the world currently running. + The `@world` macro is primarily used in the printing of bindings that are no longer available in the current world. @@ -1290,6 +1293,9 @@ julia> fold This functionality requires at least Julia 1.12. """ macro world(sym, world) + if world == :∞ + world = Expr(:call, get_world_counter) + end if isa(sym, Symbol) return :($(_resolve_in_world)($(esc(world)), $(QuoteNode(GlobalRef(__module__, sym))))) elseif isa(sym, GlobalRef) diff --git a/base/loading.jl b/base/loading.jl index 4193aae13b96a..240406292246b 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -2364,6 +2364,18 @@ function require(into::Module, mod::Symbol) return invoke_in_world(world, __require, into, mod) end +function check_for_hint(into, mod) + return begin + if isdefined(into, mod) && getfield(into, mod) isa Module + true, "." + elseif isdefined(parentmodule(into), mod) && getfield(parentmodule(into), mod) isa Module + true, ".." + else + false, "" + end + end +end + function __require(into::Module, mod::Symbol) if into === __toplevel__ && generating_output(#=incremental=#true) error("`using/import $mod` outside of a Module detected. Importing a package outside of a module \ @@ -2377,15 +2389,7 @@ function __require(into::Module, mod::Symbol) if uuidkey_env === nothing where = PkgId(into) if where.uuid === nothing - hint, dots = begin - if isdefined(into, mod) && getfield(into, mod) isa Module - true, "." - elseif isdefined(parentmodule(into), mod) && getfield(parentmodule(into), mod) isa Module - true, ".." - else - false, "" - end - end + hint, dots = invokelatest(check_for_hint, into, mod) hint_message = hint ? ", maybe you meant `import/using $(dots)$(mod)`" : "" install_message = if mod != :Pkg start_sentence = hint ? "Otherwise, run" : "Run" diff --git a/base/logging/logging.jl b/base/logging/logging.jl index 41721e84cc934..a1a8417bcb388 100644 --- a/base/logging/logging.jl +++ b/base/logging/logging.jl @@ -372,7 +372,7 @@ function logmsg_code(_module, file, line, level, message, exs...) kwargs = (;$(log_data.kwargs...)) true else - @invokelatest logging_error(logger, level, _module, group, id, file, line, err, false) + @invokelatest $(logging_error)(logger, level, _module, group, id, file, line, err, false) false end end @@ -384,7 +384,7 @@ function logmsg_code(_module, file, line, level, message, exs...) kwargs = (;$(log_data.kwargs...)) true catch err - @invokelatest logging_error(logger, level, _module, group, id, file, line, err, true) + @invokelatest $(logging_error)(logger, level, _module, group, id, file, line, err, true) false end end diff --git a/base/reflection.jl b/base/reflection.jl index f9c5dd9765533..78e701692a2a7 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -1362,6 +1362,18 @@ macro invoke(ex) return esc(out) end +apply_gr(gr::GlobalRef, @nospecialize args...) = getglobal(gr.mod, gr.name)(args...) +apply_gr_kw(@nospecialize(kwargs::NamedTuple), gr::GlobalRef, @nospecialize args...) = Core.kwcall(kwargs, getglobal(gr.mod, gr.name), args...) + +function invokelatest_gr(gr::GlobalRef, @nospecialize args...; kwargs...) + @inline + kwargs = merge(NamedTuple(), kwargs) + if isempty(kwargs) + return Core._call_latest(apply_gr, gr, args...) + end + return Core._call_latest(apply_gr_kw, kwargs, gr, args...) +end + """ @invokelatest f(args...; kwargs...) @@ -1375,22 +1387,11 @@ It also supports the following syntax: - `@invokelatest xs[i]` expands to `Base.invokelatest(getindex, xs, i)` - `@invokelatest xs[i] = v` expands to `Base.invokelatest(setindex!, xs, v, i)` -```jldoctest -julia> @macroexpand @invokelatest f(x; kw=kwv) -:(Base.invokelatest(f, x; kw = kwv)) - -julia> @macroexpand @invokelatest x.f -:(Base.invokelatest(Base.getproperty, x, :f)) - -julia> @macroexpand @invokelatest x.f = v -:(Base.invokelatest(Base.setproperty!, x, :f, v)) - -julia> @macroexpand @invokelatest xs[i] -:(Base.invokelatest(Base.getindex, xs, i)) - -julia> @macroexpand @invokelatest xs[i] = v -:(Base.invokelatest(Base.setindex!, xs, v, i)) -``` +!!! note + If `f` is a global, it will be resolved consistently + in the (latest) world as the call target. However, all other arguments + (as well as `f` itself if it is not a literal global) will be evaluated + in the current world age. !!! compat "Julia 1.7" This macro requires Julia 1.7 or later. @@ -1404,11 +1405,45 @@ julia> @macroexpand @invokelatest xs[i] = v macro invokelatest(ex) topmod = _topmod(__module__) f, args, kwargs = destructure_callex(topmod, ex) - out = Expr(:call, GlobalRef(Base, :invokelatest)) - isempty(kwargs) || push!(out.args, Expr(:parameters, kwargs...)) - push!(out.args, f) - append!(out.args, args) - return esc(out) + + if !isa(f, GlobalRef) + out_f = Expr(:call, GlobalRef(Base, :invokelatest)) + isempty(kwargs) || push!(out_f.args, Expr(:parameters, kwargs...)) + + if isexpr(f, :(.)) + s = gensym() + check = quote + $s = $(f.args[1]) + isa($s, Module) + end + push!(out_f.args, Expr(:(.), s, f.args[2])) + else + push!(out_f.args, f) + end + append!(out_f.args, args) + + if @isdefined(s) + f = :(GlobalRef($s, $(f.args[2]))) + elseif !isa(f, Symbol) + return esc(out_f) + else + check = :($(Expr(:isglobal, f))) + end + end + + out_gr = Expr(:call, GlobalRef(Base, :invokelatest_gr)) + isempty(kwargs) || push!(out_gr.args, Expr(:parameters, kwargs...)) + push!(out_gr.args, isa(f, GlobalRef) ? QuoteNode(f) : + isa(f, Symbol) ? QuoteNode(GlobalRef(__module__, f)) : + f) + append!(out_gr.args, args) + + if isa(f, GlobalRef) + return esc(out_gr) + end + + # f::Symbol + return esc(:($check ? $out_gr : $out_f)) end function destructure_callex(topmod::Module, @nospecialize(ex)) diff --git a/base/runtime_internals.jl b/base/runtime_internals.jl index 67694e533ac47..964e8063dd5af 100644 --- a/base/runtime_internals.jl +++ b/base/runtime_internals.jl @@ -239,12 +239,16 @@ function lookup_binding_partition(world::UInt, b::Core.Binding) ccall(:jl_get_binding_partition, Ref{Core.BindingPartition}, (Any, UInt), b, world) end -function lookup_binding_partition(world::UInt, gr::Core.GlobalRef) +function convert(::Type{Core.Binding}, gr::Core.GlobalRef) if isdefined(gr, :binding) - b = gr.binding + return gr.binding else - b = ccall(:jl_get_module_binding, Ref{Core.Binding}, (Any, Any, Cint), gr.mod, gr.name, true) + return ccall(:jl_get_module_binding, Ref{Core.Binding}, (Any, Any, Cint), gr.mod, gr.name, true) end +end + +function lookup_binding_partition(world::UInt, gr::Core.GlobalRef) + b = convert(Core.Binding, gr) return lookup_binding_partition(world, b) end @@ -420,7 +424,11 @@ end """ isconst(t::DataType, s::Union{Int,Symbol}) -> Bool -Determine whether a field `s` is declared `const` in a given type `t`. +Determine whether a field `s` is const in a given type `t` +in the sense that a read from said field is consistent +for egal objects. Note in particular that out-of-bounds +fields are considered const under this definition (because +they always throw). """ function isconst(@nospecialize(t::Type), s::Symbol) @_foldable_meta diff --git a/src/codegen.cpp b/src/codegen.cpp index 7cfcc52db29c7..e047632923f68 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3136,8 +3136,11 @@ static jl_value_t *static_eval(jl_codectx_t &ctx, jl_value_t *ex) { if (jl_is_symbol(ex)) { jl_sym_t *sym = (jl_sym_t*)ex; - if (jl_is_const(ctx.module, sym)) - return jl_get_global(ctx.module, sym); + jl_binding_t *bnd = jl_get_module_binding(ctx.module, sym, 0); + jl_binding_partition_t *bpart = jl_get_binding_partition_all(bnd, ctx.min_world, ctx.max_world); + jl_ptr_kind_union_t pku = jl_walk_binding_inplace_all(&bnd, &bpart, ctx.min_world, ctx.max_world); + if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) + return decode_restriction_value(pku); return NULL; } if (jl_is_slotnumber(ex) || jl_is_argument(ex)) @@ -3158,11 +3161,15 @@ static jl_value_t *static_eval(jl_codectx_t &ctx, jl_value_t *ex) jl_sym_t *s = NULL; if (jl_is_globalref(ex)) { s = jl_globalref_name(ex); - jl_binding_t *b = jl_get_binding(jl_globalref_mod(ex), s); - jl_value_t *v = jl_get_binding_value_if_const(b); + jl_binding_t *bnd = jl_get_module_binding(jl_globalref_mod(ex), s, 0); + jl_binding_partition_t *bpart = jl_get_binding_partition_all(bnd, ctx.min_world, ctx.max_world); + jl_ptr_kind_union_t pku = jl_walk_binding_inplace_all(&bnd, &bpart, ctx.min_world, ctx.max_world); + jl_value_t *v = NULL; + if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) + v = decode_restriction_value(pku); if (v) { - if (b->deprecated) - cg_bdw(ctx, s, b); + if (bnd->deprecated) + cg_bdw(ctx, s, bnd); return v; } return NULL; @@ -3181,11 +3188,15 @@ static jl_value_t *static_eval(jl_codectx_t &ctx, jl_value_t *ex) // Assumes that the module is rooted somewhere. s = (jl_sym_t*)static_eval(ctx, jl_exprarg(e, 2)); if (s && jl_is_symbol(s)) { - jl_binding_t *b = jl_get_binding(m, s); - jl_value_t *v = jl_get_binding_value_if_const(b); + jl_binding_t *bnd = jl_get_module_binding(m, s, 0); + jl_binding_partition_t *bpart = jl_get_binding_partition_all(bnd, ctx.min_world, ctx.max_world); + jl_ptr_kind_union_t pku = jl_walk_binding_inplace_all(&bnd, &bpart, ctx.min_world, ctx.max_world); + jl_value_t *v = NULL; + if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) + v = decode_restriction_value(pku); if (v) { - if (b->deprecated) - cg_bdw(ctx, s, b); + if (bnd->deprecated) + cg_bdw(ctx, s, bnd); return v; } } @@ -3465,14 +3476,13 @@ static jl_cgval_t emit_globalref(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t * return mark_julia_const(ctx, constval); } } - if (!bpart) { + if (!bpart || decode_restriction_kind(pku) != BINDING_KIND_GLOBAL) { return emit_globalref_runtime(ctx, bnd, mod, name); } Value *bp = julia_binding_gv(ctx, bnd); if (bnd->deprecated) { cg_bdw(ctx, name, bnd); } - assert(decode_restriction_kind(pku) == BINDING_KIND_GLOBAL); jl_value_t *ty = decode_restriction_value(pku); bp = julia_binding_pvalue(ctx, bp); if (ty == nullptr) diff --git a/src/gf.c b/src/gf.c index ea25ed2eae4ff..710dda208f0b2 100644 --- a/src/gf.c +++ b/src/gf.c @@ -292,7 +292,8 @@ jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_a { jl_sym_t *sname = jl_symbol(name); if (dt == NULL) { - jl_value_t *f = jl_new_generic_function_with_supertype(sname, jl_core_module, jl_builtin_type); + // Builtins are specially considered available from world 0 + jl_value_t *f = jl_new_generic_function_with_supertype(sname, jl_core_module, jl_builtin_type, 0); jl_set_const(jl_core_module, sname, f); dt = (jl_datatype_t*)jl_typeof(f); } @@ -3790,10 +3791,8 @@ jl_value_t *jl_gf_invoke_by_method(jl_method_t *method, jl_value_t *gf, jl_value return _jl_invoke(gf, args, nargs - 1, mfunc, world); } -// Return value is rooted globally -jl_function_t *jl_new_generic_function_with_supertype(jl_sym_t *name, jl_module_t *module, jl_datatype_t *st) +jl_sym_t *jl_gf_supertype_name(jl_sym_t *name) { - // type name is function name prefixed with # size_t l = strlen(jl_symbol_name(name)); char *prefixed; prefixed = (char*)malloc_s(l+2); @@ -3801,6 +3800,14 @@ jl_function_t *jl_new_generic_function_with_supertype(jl_sym_t *name, jl_module_ strcpy(&prefixed[1], jl_symbol_name(name)); jl_sym_t *tname = jl_symbol(prefixed); free(prefixed); + return tname; +} + +// Return value is rooted globally +jl_function_t *jl_new_generic_function_with_supertype(jl_sym_t *name, jl_module_t *module, jl_datatype_t *st, size_t new_world) +{ + // type name is function name prefixed with # + jl_sym_t *tname = jl_gf_supertype_name(name); jl_datatype_t *ftype = (jl_datatype_t*)jl_new_datatype( tname, module, st, jl_emptysvec, jl_emptysvec, jl_emptysvec, jl_emptysvec, 0, 0, 0); @@ -3808,7 +3815,7 @@ jl_function_t *jl_new_generic_function_with_supertype(jl_sym_t *name, jl_module_ JL_GC_PUSH1(&ftype); ftype->name->mt->name = name; jl_gc_wb(ftype->name->mt, name); - jl_set_const(module, tname, (jl_value_t*)ftype); + jl_declare_constant_val3(NULL, module, tname, (jl_value_t*)ftype, BINDING_KIND_CONST, new_world); jl_value_t *f = jl_new_struct(ftype); ftype->instance = f; jl_gc_wb(ftype, f); @@ -3816,9 +3823,9 @@ jl_function_t *jl_new_generic_function_with_supertype(jl_sym_t *name, jl_module_ return (jl_function_t*)f; } -jl_function_t *jl_new_generic_function(jl_sym_t *name, jl_module_t *module) +jl_function_t *jl_new_generic_function(jl_sym_t *name, jl_module_t *module, size_t new_world) { - return jl_new_generic_function_with_supertype(name, module, jl_function_type); + return jl_new_generic_function_with_supertype(name, module, jl_function_type, new_world); } struct ml_matches_env { diff --git a/src/init.c b/src/init.c index 7b41e63e98455..e69467c75bd73 100644 --- a/src/init.c +++ b/src/init.c @@ -249,6 +249,8 @@ JL_DLLEXPORT void jl_atexit_hook(int exitcode) JL_NOTSAFEPOINT_ENTER } if (jl_base_module) { + size_t last_age = ct->world_age; + ct->world_age = jl_get_world_counter(); jl_value_t *f = jl_get_global(jl_base_module, jl_symbol("_atexit")); if (f != NULL) { jl_value_t **fargs; @@ -257,10 +259,7 @@ JL_DLLEXPORT void jl_atexit_hook(int exitcode) JL_NOTSAFEPOINT_ENTER fargs[1] = jl_box_int32(exitcode); JL_TRY { assert(ct); - size_t last_age = ct->world_age; - ct->world_age = jl_get_world_counter(); jl_apply(fargs, 2); - ct->world_age = last_age; } JL_CATCH { jl_printf((JL_STREAM*)STDERR_FILENO, "\natexit hook threw an error: "); @@ -270,10 +269,15 @@ JL_DLLEXPORT void jl_atexit_hook(int exitcode) JL_NOTSAFEPOINT_ENTER } JL_GC_POP(); } + ct->world_age = last_age; } - if (ct && exitcode == 0) + if (ct && exitcode == 0) { + size_t last_age = ct->world_age; + ct->world_age = jl_get_world_counter(); jl_write_compiler_output(); + ct->world_age = last_age; + } jl_print_gc_stats(JL_STDERR); if (jl_options.code_coverage) @@ -893,6 +897,7 @@ static NOINLINE void _finish_julia_init(JL_IMAGE_SEARCH rel, jl_ptls_t ptls, jl_ jl_init_primitives(); jl_init_main_module(); jl_load(jl_core_module, "boot.jl"); + jl_current_task->world_age = jl_atomic_load_acquire(&jl_world_counter); post_boot_hooks(); } diff --git a/src/jlapi.c b/src/jlapi.c index defb2db6ac911..b8fbda801f43b 100644 --- a/src/jlapi.c +++ b/src/jlapi.c @@ -910,26 +910,29 @@ static NOINLINE int true_main(int argc, char *argv[]) { jl_set_ARGS(argc, argv); + + jl_task_t *ct = jl_current_task; + size_t last_age = ct->world_age; + ct->world_age = jl_get_world_counter(); + jl_function_t *start_client = jl_base_module ? (jl_function_t*)jl_get_global(jl_base_module, jl_symbol("_start")) : NULL; - jl_task_t *ct = jl_current_task; if (start_client) { int ret = 1; JL_TRY { - size_t last_age = ct->world_age; - ct->world_age = jl_get_world_counter(); jl_value_t *r = jl_apply(&start_client, 1); if (jl_typeof(r) != (jl_value_t*)jl_int32_type) jl_type_error("typeassert", (jl_value_t*)jl_int32_type, r); ret = jl_unbox_int32(r); - ct->world_age = last_age; } JL_CATCH { jl_no_exc_handler(jl_current_exception(ct), ct); } + ct->world_age = last_age; return ret; } + ct->world_age = last_age; // run program if specified, otherwise enter REPL if (argc > 0) { diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 7fd2dc7409c0e..57f67755df692 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -433,7 +433,7 @@ (inert ,loc))) ,body)))) (if (or (symbol? name) (globalref? name)) - `(block ,@generator (method ,name) ,mdef (unnecessary ,name)) ;; return the function + `(block ,@generator (method ,name) (latestworld-if-toplevel) ,mdef (unnecessary ,name)) ;; return the function (if (not (null? generator)) `(block ,@generator ,mdef) mdef)))))) @@ -531,6 +531,7 @@ `(call (core ifelse) (false) (false) (block ;; forward-declare function so its type can occur in the signature of the inner method below ,@(if (or (symbol? name) (globalref? name)) `((method ,name)) '()) + (latestworld-if-toplevel) ;; call with keyword args pre-sorted - original method code goes here ,(method-def-expr- @@ -1515,6 +1516,7 @@ (scope-block (block (hardscope) (local (= ,(cadr arg) ,rr)) ,.(map (lambda (v) `(,(car e) (globalref (thismodule) ,v) ,v)) (filter-not-underscore (lhs-vars (cadr arg)))) + (latestworld) ,rr)))))))) (else (error "expected assignment after \"const\""))))))) @@ -2473,7 +2475,7 @@ (error "Opaque closure argument type may not be specified both in the method signature and separately")) (if (or (varargexpr? lastarg) (vararg? lastarg)) '(true) '(false)))) - (meth (caddr (caddr (expand-forms F)))) ;; `method` expr + (meth (cadddr (caddr (expand-forms F)))) ;; `method` expr (lam (cadddr meth)) (sig-block (caddr meth)) (sig-block (if (and (pair? sig-block) (eq? (car sig-block) 'block)) @@ -3154,6 +3156,11 @@ (else `(globalref (thismodule) ,e))))) ((or (not (pair? e)) (quoted? e) (memq (car e) '(toplevel symbolicgoto symboliclabel toplevel-only))) e) + ((eq? (car e) 'isglobal) + (let ((val (and scope (get (scope:table scope) (cadr e) #f)))) + (cond (val `(false)) + ((underscore-symbol? (cadr e)) `(false)) + (else `(true))))) ((eq? (car e) 'global) (check-valid-name (cadr e)) e) @@ -3793,7 +3800,7 @@ f(x) = yt(x) (Set '(quote top core lineinfo line inert local-def unnecessary copyast meta inbounds boundscheck loopinfo decl aliasscope popaliasscope thunk with-static-parameters toplevel-only - global globalref assign-const-if-global thismodule + global globalref assign-const-if-global isglobal thismodule const atomic null true false ssavalue isdefined toplevel module lambda error gc_preserve_begin gc_preserve_end import using export public inline noinline purity))) @@ -4296,6 +4303,7 @@ f(x) = yt(x) `(toplevel-butfirst ,(convert-assignment name mk-closure fname lam interp opaq parsed-method-stack globals locals) ,@typedef + (latestworld) ,@(map (lambda (v) `(moved-local ,v)) moved-vars) ,@sp-inits ,@mk-method diff --git a/src/julia.h b/src/julia.h index b5416568b7ae9..699b3cc196411 100644 --- a/src/julia.h +++ b/src/julia.h @@ -2009,7 +2009,6 @@ JL_DLLEXPORT int jl_defines_or_exports_p(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT int jl_binding_resolved_p(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT int jl_globalref_is_const(jl_globalref_t *gr); -JL_DLLEXPORT int jl_globalref_boundp(jl_globalref_t *gr); JL_DLLEXPORT jl_value_t *jl_get_globalref_value(jl_globalref_t *gr); JL_DLLEXPORT jl_value_t *jl_get_global(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var); JL_DLLEXPORT void jl_set_global(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT); diff --git a/src/julia_internal.h b/src/julia_internal.h index 3e4967c9d4dca..0da6d412c8a49 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -828,8 +828,8 @@ jl_value_t *modify_value(jl_value_t *ty, _Atomic(jl_value_t*) *p, jl_value_t *pa jl_value_t *modify_bits(jl_value_t *ty, char *p, uint8_t *psel, jl_value_t *parent, jl_value_t *op, jl_value_t *rhs, enum atomic_kind isatomic); int setonce_bits(jl_datatype_t *rty, char *p, jl_value_t *owner, jl_value_t *rhs, enum atomic_kind isatomic); jl_expr_t *jl_exprn(jl_sym_t *head, size_t n); -jl_function_t *jl_new_generic_function(jl_sym_t *name, jl_module_t *module); -jl_function_t *jl_new_generic_function_with_supertype(jl_sym_t *name, jl_module_t *module, jl_datatype_t *st); +jl_function_t *jl_new_generic_function(jl_sym_t *name, jl_module_t *module, size_t new_world); +jl_function_t *jl_new_generic_function_with_supertype(jl_sym_t *name, jl_module_t *module, jl_datatype_t *st, size_t new_world); int jl_foreach_reachable_mtable(int (*visit)(jl_methtable_t *mt, void *env), void *env); int foreach_mtable_in_module(jl_module_t *m, int (*visit)(jl_methtable_t *mt, void *env), void *env); void jl_init_main_module(void); @@ -842,6 +842,7 @@ JL_DLLEXPORT void jl_eval_const_decl(jl_module_t *m, jl_value_t *arg, jl_value_t void jl_binding_set_type(jl_binding_t *b, jl_module_t *mod, jl_sym_t *sym, jl_value_t *ty); void jl_eval_global_expr(jl_module_t *m, jl_expr_t *ex, int set_type); JL_DLLEXPORT void jl_declare_global(jl_module_t *m, jl_value_t *arg, jl_value_t *set_type); +JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val3(jl_binding_t *b JL_ROOTING_ARGUMENT, jl_module_t *mod, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT JL_MAYBE_UNROOTED, enum jl_partition_kind, size_t new_world) JL_GLOBALLY_ROOTED; JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *m, jl_value_t *e, int fast, int expanded, const char **toplevel_filename, int *toplevel_lineno); STATIC_INLINE struct _jl_module_using *module_usings_getidx(jl_module_t *m JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT; @@ -985,15 +986,15 @@ STATIC_INLINE int jl_bkind_is_some_guard(enum jl_partition_kind kind) JL_NOTSAFE return kind == BINDING_KIND_FAILED || kind == BINDING_KIND_GUARD || kind == BINDING_KIND_DECLARED; } -JL_DLLEXPORT jl_binding_partition_t *jl_get_binding_partition(jl_binding_t *b JL_PROPAGATES_ROOT, size_t world); -JL_DLLEXPORT jl_binding_partition_t *jl_get_binding_partition_all(jl_binding_t *b JL_PROPAGATES_ROOT, size_t min_world, size_t max_world); +JL_DLLEXPORT jl_binding_partition_t *jl_get_binding_partition(jl_binding_t *b JL_PROPAGATES_ROOT, size_t world) JL_GLOBALLY_ROOTED; +JL_DLLEXPORT jl_binding_partition_t *jl_get_binding_partition_all(jl_binding_t *b JL_PROPAGATES_ROOT, size_t min_world, size_t max_world) JL_GLOBALLY_ROOTED; EXTERN_INLINE_DECLARE uint8_t jl_bpart_get_kind(jl_binding_partition_t *bpart) JL_NOTSAFEPOINT { return decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)); } -STATIC_INLINE jl_ptr_kind_union_t jl_walk_binding_inplace(jl_binding_t **bnd, jl_binding_partition_t **bpart, size_t world) JL_NOTSAFEPOINT; -STATIC_INLINE jl_ptr_kind_union_t jl_walk_binding_inplace_all(jl_binding_t **bnd, jl_binding_partition_t **bpart, size_t min_world, size_t max_world) JL_NOTSAFEPOINT; +STATIC_INLINE jl_ptr_kind_union_t jl_walk_binding_inplace(jl_binding_t **bnd, jl_binding_partition_t **bpart JL_PROPAGATES_ROOT, size_t world) JL_NOTSAFEPOINT; +STATIC_INLINE jl_ptr_kind_union_t jl_walk_binding_inplace_all(jl_binding_t **bnd, jl_binding_partition_t **bpart JL_PROPAGATES_ROOT, size_t min_world, size_t max_world) JL_NOTSAFEPOINT; #ifndef __clang_analyzer__ STATIC_INLINE jl_ptr_kind_union_t jl_walk_binding_inplace(jl_binding_t **bnd, jl_binding_partition_t **bpart, size_t world) JL_NOTSAFEPOINT @@ -1669,6 +1670,7 @@ JL_DLLEXPORT void jl_set_next_task(jl_task_t *task) JL_NOTSAFEPOINT; // -- synchronization utilities -- // extern jl_mutex_t typecache_lock; +extern jl_mutex_t world_counter_lock; #if defined(__APPLE__) void jl_mach_gc_end(void) JL_NOTSAFEPOINT; diff --git a/src/method.c b/src/method.c index 0a58f0d5c482c..4b39de9aa67e1 100644 --- a/src/method.c +++ b/src/method.c @@ -1073,16 +1073,28 @@ JL_DLLEXPORT void jl_check_gf(jl_value_t *gf, jl_sym_t *name) JL_DLLEXPORT jl_value_t *jl_declare_const_gf(jl_binding_t *b, jl_module_t *mod, jl_sym_t *name) { - jl_value_t *gf = jl_get_binding_value_if_const(b); - if (gf) { - jl_check_gf(gf, b->globalref->name); - return gf; - } - jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - if (!jl_bkind_is_some_guard(decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)))) + JL_LOCK(&world_counter_lock); + size_t new_world = jl_atomic_load_relaxed(&jl_world_counter) + 1; + jl_binding_partition_t *bpart = jl_get_binding_partition(b, new_world); + jl_ptr_kind_union_t pku = jl_walk_binding_inplace(&b, &bpart, new_world); + jl_value_t *gf = NULL; + if (!jl_bkind_is_some_guard(decode_restriction_kind(pku))) { + if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) { + gf = decode_restriction_value(pku); + JL_GC_PROMISE_ROOTED(gf); + jl_check_gf(gf, b->globalref->name); + JL_UNLOCK(&world_counter_lock); + return gf; + } jl_errorf("cannot define function %s; it already has a value", jl_symbol_name(name)); - gf = (jl_value_t*)jl_new_generic_function(name, mod); - jl_declare_constant_val(b, mod, name, gf); + } + gf = (jl_value_t*)jl_new_generic_function(name, mod, new_world); + // From this point on (if we didn't error), we're committed to raising the world age, + // because we've used it to declare the type name. + jl_atomic_store_release(&jl_world_counter, new_world); + jl_declare_constant_val3(b, mod, name, gf, BINDING_KIND_CONST, new_world); + JL_GC_PROMISE_ROOTED(gf); + JL_UNLOCK(&world_counter_lock); return gf; } diff --git a/src/module.c b/src/module.c index 66049031f8790..be6779727bfdc 100644 --- a/src/module.c +++ b/src/module.c @@ -411,13 +411,13 @@ typedef struct _modstack_t { jl_sym_t *var; struct _modstack_t *prev; } modstack_t; -static jl_binding_t *jl_resolve_owner(jl_binding_t *b/*optional*/, jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, modstack_t *st); +static jl_binding_t *jl_resolve_owner(jl_binding_t *b/*optional*/, jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, modstack_t *st, size_t world); JL_DLLEXPORT jl_value_t *jl_reresolve_binding_value_seqcst(jl_binding_t *b) { jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); if (jl_bkind_is_some_guard(decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)))) { - jl_resolve_owner(b, b->globalref->mod, b->globalref->name, NULL); + jl_resolve_owner(b, b->globalref->mod, b->globalref->name, NULL, jl_current_task->world_age); } return jl_get_binding_value_seqcst(b); } @@ -473,7 +473,7 @@ static int eq_bindings(jl_binding_partition_t *owner, jl_binding_t *alias, size_ } // find a binding from a module's `usings` list -static jl_binding_t *using_resolve_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, jl_module_t **from, modstack_t *st, int warn) +static jl_binding_t *using_resolve_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, jl_module_t **from, modstack_t *st, int warn, size_t world) { jl_binding_t *b = NULL; jl_binding_partition_t *bpart = NULL; @@ -487,20 +487,20 @@ static jl_binding_t *using_resolve_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl JL_UNLOCK(&m->lock); jl_binding_t *tempb = jl_get_module_binding(imp, var, 0); if (tempb != NULL && tempb->exportp) { - tempb = jl_resolve_owner(NULL, imp, var, st); // find the owner for tempb + tempb = jl_resolve_owner(NULL, imp, var, st, world); // find the owner for tempb if (tempb == NULL) // couldn't resolve; try next using (see issue #6105) continue; - jl_binding_partition_t *tempbpart = jl_get_binding_partition(tempb, jl_current_task->world_age); + jl_binding_partition_t *tempbpart = jl_get_binding_partition(tempb, world); jl_ptr_kind_union_t tempb_pku = jl_atomic_load_relaxed(&tempbpart->restriction); - assert(decode_restriction_kind(tempb_pku) == BINDING_KIND_GLOBAL || decode_restriction_kind(tempb_pku) == BINDING_KIND_DECLARED || jl_bkind_is_some_constant(decode_restriction_kind(tempb_pku))); + assert(jl_bkind_is_some_guard(decode_restriction_kind(tempb_pku)) || decode_restriction_kind(tempb_pku) == BINDING_KIND_GLOBAL || decode_restriction_kind(tempb_pku) == BINDING_KIND_DECLARED || jl_bkind_is_some_constant(decode_restriction_kind(tempb_pku))); (void)tempb_pku; - if (bpart != NULL && !tempb->deprecated && !b->deprecated && !eq_bindings(tempbpart, b, jl_current_task->world_age)) { + if (bpart != NULL && !tempb->deprecated && !b->deprecated && !eq_bindings(tempbpart, b, world)) { if (warn) { // set usingfailed=1 to avoid repeating this warning // the owner will still be NULL, so it can be later imported or defined tempb = jl_get_module_binding(m, var, 1); - tempbpart = jl_get_binding_partition(tempb, jl_current_task->world_age); + tempbpart = jl_get_binding_partition(tempb, world); jl_atomic_store_release(&tempbpart->restriction, encode_restriction(NULL, BINDING_KIND_FAILED)); } return NULL; @@ -524,7 +524,7 @@ static jl_module_t *jl_binding_dbgmodule(jl_binding_t *b, jl_module_t *m, jl_sym if (decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)) != BINDING_KIND_GLOBAL) { // for implicitly imported globals, try to re-resolve it to find the module we got it from most directly jl_module_t *from = NULL; - jl_binding_t *b2 = using_resolve_binding(m, var, &from, NULL, 0); + jl_binding_t *b2 = using_resolve_binding(m, var, &from, NULL, 0, jl_current_task->world_age); if (b2) { jl_binding_partition_t *b2part = jl_get_binding_partition(b2, jl_current_task->world_age); if (eq_bindings(b2part, b, jl_current_task->world_age)) @@ -538,11 +538,11 @@ static jl_module_t *jl_binding_dbgmodule(jl_binding_t *b, jl_module_t *m, jl_sym static void jl_binding_dep_message(jl_module_t *m, jl_sym_t *name, jl_binding_t *b); // get binding for reading. might return NULL for unbound. -static jl_binding_t *jl_resolve_owner(jl_binding_t *b/*optional*/, jl_module_t *m, jl_sym_t *var, modstack_t *st) +static jl_binding_t *jl_resolve_owner(jl_binding_t *b/*optional*/, jl_module_t *m, jl_sym_t *var, modstack_t *st, size_t world) { if (b == NULL) b = jl_get_module_binding(m, var, 1); - jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + jl_binding_partition_t *bpart = jl_get_binding_partition(b, world); jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); retry: if (decode_restriction_kind(pku) == BINDING_KIND_FAILED) @@ -561,7 +561,7 @@ static jl_binding_t *jl_resolve_owner(jl_binding_t *b/*optional*/, jl_module_t * } } jl_module_t *from = NULL; // for error message printing - b2 = using_resolve_binding(m, var, &from, &top, 1); + b2 = using_resolve_binding(m, var, &from, &top, 1, world); if (b2 == NULL) return NULL; assert(from); @@ -594,7 +594,7 @@ static jl_binding_t *jl_resolve_owner(jl_binding_t *b/*optional*/, jl_module_t * } return b2; } - jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); + jl_walk_binding_inplace(&b, &bpart, world); return b; } @@ -606,7 +606,7 @@ JL_DLLEXPORT jl_binding_t *jl_binding_owner(jl_module_t *m, jl_sym_t *var) jl_module_t *from = m; jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); if (decode_restriction_kind(pku) == BINDING_KIND_GUARD) { - b = using_resolve_binding(m, var, &from, NULL, 0); + b = using_resolve_binding(m, var, &from, NULL, 0, jl_current_task->world_age); bpart = jl_get_binding_partition(b, jl_current_task->world_age); } pku = jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); @@ -637,7 +637,7 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_type(jl_module_t *m, jl_sym_t *var) JL_DLLEXPORT jl_binding_t *jl_get_binding(jl_module_t *m, jl_sym_t *var) { - return jl_resolve_owner(NULL, m, var, NULL); + return jl_resolve_owner(NULL, m, var, NULL, jl_current_task->world_age); } JL_DLLEXPORT jl_binding_t *jl_get_binding_or_error(jl_module_t *m, jl_sym_t *var) @@ -1001,7 +1001,7 @@ JL_DLLEXPORT jl_binding_t *jl_get_module_binding(jl_module_t *m, jl_sym_t *var, JL_DLLEXPORT jl_value_t *jl_get_globalref_value(jl_globalref_t *gr) { jl_binding_t *b = gr->binding; - b = jl_resolve_owner(b, gr->mod, gr->name, NULL); + b = jl_resolve_owner(b, gr->mod, gr->name, NULL, jl_current_task->world_age); // ignores b->deprecated return b == NULL ? NULL : jl_get_binding_value(b); } @@ -1028,6 +1028,7 @@ JL_DLLEXPORT void jl_set_const(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var // this function is mostly only used during initialization, so the data races here are not too important to us jl_binding_t *bp = jl_get_module_binding(m, var, 1); jl_binding_partition_t *bpart = jl_get_binding_partition(bp, jl_current_task->world_age); + assert(jl_bkind_is_some_guard(decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)))); jl_atomic_store_release(&bpart->restriction, encode_restriction(val, BINDING_KIND_CONST)); jl_gc_wb(bpart, val); } @@ -1047,11 +1048,10 @@ void jl_invalidate_binding_refs(jl_globalref_t *ref, jl_binding_partition_t *inv JL_GC_POP(); } -extern jl_mutex_t world_counter_lock; JL_DLLEXPORT void jl_disable_binding(jl_globalref_t *gr) { jl_binding_t *b = gr->binding; - b = jl_resolve_owner(b, gr->mod, gr->name, NULL); + b = jl_resolve_owner(b, gr->mod, gr->name, NULL, jl_current_task->world_age); jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); if (decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)) == BINDING_KIND_GUARD) { @@ -1074,18 +1074,17 @@ JL_DLLEXPORT void jl_disable_binding(jl_globalref_t *gr) JL_DLLEXPORT int jl_globalref_is_const(jl_globalref_t *gr) { jl_binding_t *b = gr->binding; - b = jl_resolve_owner(b, gr->mod, gr->name, NULL); + b = jl_resolve_owner(b, gr->mod, gr->name, NULL, jl_current_task->world_age); jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); if (!bpart) return 0; return jl_bkind_is_some_constant(decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction))); } -JL_DLLEXPORT int jl_globalref_boundp(jl_globalref_t *gr) +JL_DLLEXPORT void jl_force_binding_resolution(jl_globalref_t *gr, size_t world) { jl_binding_t *b = gr->binding; - b = jl_resolve_owner(b, gr->mod, gr->name, NULL); - return b && jl_get_binding_value(b) != NULL; + jl_resolve_owner(b, gr->mod, gr->name, NULL, world); } JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var) diff --git a/src/staticdata.c b/src/staticdata.c index 7fad87652b26a..ff352cd8c152f 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -1674,8 +1674,18 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED #ifndef _P64 write_uint(f, decode_restriction_kind(pku)); #endif - write_uint(f, bpart->min_world); - write_uint(f, jl_atomic_load_relaxed(&bpart->max_world)); + size_t max_world = jl_atomic_load_relaxed(&bpart->max_world); + if (max_world == ~(size_t)0) { + // Still valid. Will be considered primordial after re-load. + // We could consider updating min_world to the loaded world, but + // there doesn't appear to be much point. + write_uint(f, 0); + write_uint(f, max_world); + } else { + // The world will not be reachable after loading + write_uint(f, 1); + write_uint(f, 0); + } write_pointerfield(s, (jl_value_t*)jl_atomic_load_relaxed(&bpart->next)); #ifdef _P64 write_uint(f, decode_restriction_kind(pku)); // This will be moved back into place during deserialization (if necessary) @@ -2714,7 +2724,6 @@ static void jl_strip_all_codeinfos(void) jl_genericmemory_t *jl_global_roots_list; jl_genericmemory_t *jl_global_roots_keyset; jl_mutex_t global_roots_lock; -extern jl_mutex_t world_counter_lock; jl_mutex_t precompile_field_replace_lock; jl_svec_t *precompile_field_replace JL_GLOBALLY_ROOTED; diff --git a/src/toplevel.c b/src/toplevel.c index fb217ec7cb52e..dee9029e2feb7 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -66,14 +66,13 @@ void jl_module_run_initializer(jl_module_t *m) { JL_TIMING(INIT_MODULE, INIT_MODULE); jl_timing_show_module(m, JL_TIMING_DEFAULT_BLOCK); - jl_function_t *f = jl_module_get_initializer(m); - if (f == NULL) - return; jl_task_t *ct = jl_current_task; size_t last_age = ct->world_age; JL_TRY { ct->world_age = jl_atomic_load_acquire(&jl_world_counter); - jl_apply(&f, 1); + jl_function_t *f = jl_module_get_initializer(m); + if (f != NULL) + jl_apply(&f, 1); ct->world_age = last_age; } JL_CATCH { @@ -740,10 +739,15 @@ static void jl_eval_errorf(jl_module_t *m, const char *filename, int lineno, con JL_GC_POP(); } -JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val2(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *val, enum jl_partition_kind constant_kind) +JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val3( + jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *val, + enum jl_partition_kind constant_kind, size_t new_world) { JL_GC_PUSH1(&val); - jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + if (!b) { + b = jl_get_module_binding(mod, var, 1); + } + jl_binding_partition_t *bpart = jl_get_binding_partition(b, new_world); jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); int did_warn = 0; while (1) { @@ -780,10 +784,27 @@ JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val2(jl_binding_t *b, j break; } } + // N.B.: This backdates the first definition of the constant to world age 0 for backwards compatibility + // TODO: Mark this specially with a separate partition. + if (bpart->min_world != 0) + bpart->min_world = new_world; JL_GC_POP(); return bpart; } +JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val2( + jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *val, + enum jl_partition_kind constant_kind) +{ + JL_LOCK(&world_counter_lock); + size_t new_world = jl_atomic_load_relaxed(&jl_world_counter) + 1; + jl_binding_partition_t *bpart = jl_declare_constant_val3(b, mod, var, val, constant_kind, new_world); + if (bpart->min_world == new_world) + jl_atomic_store_release(&jl_world_counter, new_world); + JL_UNLOCK(&world_counter_lock); + return bpart; +} + JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *val) { return jl_declare_constant_val2(b, mod, var, val, val ? BINDING_KIND_CONST : BINDING_KIND_UNDEF_CONST); @@ -869,6 +890,7 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val else if (head == jl_using_sym) { jl_sym_t *name = NULL; jl_module_t *from = eval_import_from(m, ex, "using"); + ct->world_age = jl_atomic_load_acquire(&jl_world_counter); size_t i = 0; if (from) { i = 1; @@ -908,6 +930,7 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val jl_expr_t *path = (jl_expr_t*)jl_exprarg(a, 0); name = NULL; jl_module_t *import = eval_import_path(m, from, ((jl_expr_t*)path)->args, &name, "using"); + ct->world_age = jl_atomic_load_acquire(&jl_world_counter); assert(name); check_macro_rename(name, asname, "using"); // `using A: B as C` syntax @@ -919,11 +942,13 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val "syntax: malformed \"using\" statement"); } JL_GC_POP(); + ct->world_age = last_age; return jl_nothing; } else if (head == jl_import_sym) { jl_sym_t *name = NULL; jl_module_t *from = eval_import_from(m, ex, "import"); + ct->world_age = jl_atomic_load_acquire(&jl_world_counter); size_t i = 0; if (from) { i = 1; @@ -967,6 +992,7 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val "syntax: malformed \"import\" statement"); } JL_GC_POP(); + ct->world_age = last_age; return jl_nothing; } else if (head == jl_export_sym || head == jl_public_sym) { diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index e8aa1188ec213..c63c5a557acd8 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -639,18 +639,24 @@ function is_call_graph_uncached(sv::CC.InferenceState) return is_call_graph_uncached(parent::CC.InferenceState) end -isdefined_globalref(g::GlobalRef) = !iszero(ccall(:jl_globalref_boundp, Cint, (Any,), g)) - # aggressive global binding resolution within `repl_frame` function CC.abstract_eval_globalref(interp::REPLInterpreter, g::GlobalRef, bailed::Bool, sv::CC.InferenceState) + # Ignore saw_latestworld + partition = CC.abstract_eval_binding_partition!(interp, g, sv) if (interp.limit_aggressive_inference ? is_repl_frame(sv) : is_call_graph_uncached(sv)) - if isdefined_globalref(g) + if CC.is_defined_const_binding(CC.binding_kind(partition)) return Pair{CC.RTEffects, Union{Nothing, Core.BindingPartition}}( - CC.RTEffects(Const(ccall(:jl_get_globalref_value, Any, (Any,), g)), Union{}, CC.EFFECTS_TOTAL), nothing) + CC.RTEffects(Const(CC.partition_restriction(partition)), Union{}, CC.EFFECTS_TOTAL), partition) + else + b = convert(Core.Binding, g) + if CC.binding_kind(partition) == CC.BINDING_KIND_GLOBAL && isdefined(b, :value) + return Pair{CC.RTEffects, Union{Nothing, Core.BindingPartition}}( + CC.RTEffects(Const(b.value), Union{}, CC.EFFECTS_TOTAL), partition) + end end return Pair{CC.RTEffects, Union{Nothing, Core.BindingPartition}}( - CC.RTEffects(Union{}, UndefVarError, CC.EFFECTS_THROWS), nothing) + CC.RTEffects(Union{}, UndefVarError, CC.EFFECTS_THROWS), partition) end return @invoke CC.abstract_eval_globalref(interp::CC.AbstractInterpreter, g::GlobalRef, bailed::Bool, sv::CC.InferenceState) diff --git a/stdlib/REPL/src/precompile.jl b/stdlib/REPL/src/precompile.jl index daa01f626aeab..4f3b3a6eae083 100644 --- a/stdlib/REPL/src/precompile.jl +++ b/stdlib/REPL/src/precompile.jl @@ -8,6 +8,7 @@ import ..REPL Base._track_dependencies[] = false try Base.include(@__MODULE__, joinpath(Sys.BINDIR, "..", "share", "julia", "test", "testhelpers", "FakePTYs.jl")) + @Core.latestworld import .FakePTYs: open_fake_pty finally Base._track_dependencies[] = true diff --git a/stdlib/REPL/test/precompilation.jl b/stdlib/REPL/test/precompilation.jl index 7efcf0b5e8282..01a062644596c 100644 --- a/stdlib/REPL/test/precompilation.jl +++ b/stdlib/REPL/test/precompilation.jl @@ -33,7 +33,7 @@ if !Sys.iswindows() # given this test checks that startup is snappy, it's best to add workloads to # contrib/generate_precompile.jl rather than increase this number. But if that's not # possible, it'd be helpful to add a comment with the statement and a reason below - expected_precompiles = 0 + expected_precompiles = 1 n_precompiles = count(r"precompile\(", tracecompile_out) diff --git a/stdlib/REPL/test/repl.jl b/stdlib/REPL/test/repl.jl index 809913502c3d7..8944fd76f31de 100644 --- a/stdlib/REPL/test/repl.jl +++ b/stdlib/REPL/test/repl.jl @@ -769,9 +769,9 @@ fake_repl() do stdin_write, stdout_read, repl julia> A = 3\e[201~ """) @test Main.A == 3 - @test Base.invokelatest(Main.foo, 4) - @test Base.invokelatest(Main.T17599, 3).a == 3 - @test !Base.invokelatest(Main.foo, 2) + @test @invokelatest(Main.foo(4)) + @test @invokelatest(Main.T17599(3)).a == 3 + @test !@invokelatest(Main.foo(2)) sendrepl2("""\e[200~ julia> goo(x) = x + 1 @@ -781,7 +781,7 @@ fake_repl() do stdin_write, stdout_read, repl 4\e[201~ """) @test Main.A == 4 - @test Base.invokelatest(Main.goo, 4) == 5 + @test @invokelatest(Main.goo(4)) == 5 # Test prefix removal only active in bracket paste mode sendrepl2("julia = 4\n julia> 3 && (A = 1)\n") diff --git a/stdlib/Serialization/test/runtests.jl b/stdlib/Serialization/test/runtests.jl index 4d9b439e639d7..f1b83ca947c7e 100644 --- a/stdlib/Serialization/test/runtests.jl +++ b/stdlib/Serialization/test/runtests.jl @@ -130,7 +130,7 @@ create_serialization_stream() do s # user-defined module modtype = eval(Meta.parse("$(modstring)")) serialize(s, modtype) seek(s, 0) - @test deserialize(s) === modtype + @test invokelatest(deserialize, s) === modtype end # DataType @@ -151,7 +151,7 @@ create_serialization_stream() do s # user-defined type utype = eval(Meta.parse("$(usertype)")) serialize(s, utype) seek(s, 0) - @test deserialize(s) === utype + @test invokelatest(deserialize, s) === utype end create_serialization_stream() do s # user-defined type @@ -160,7 +160,7 @@ create_serialization_stream() do s # user-defined type utype = eval(Meta.parse("$(usertype)")) serialize(s, utype) seek(s, 0) - @test deserialize(s) === utype + @test invokelatest(deserialize, s) === utype end create_serialization_stream() do s # user-defined type @@ -169,7 +169,7 @@ create_serialization_stream() do s # user-defined type utype = eval(Meta.parse("$(usertype)")) serialize(s, utype) seek(s, 0) - @test deserialize(s) == utype + @test invokelatest(deserialize, s) == utype end create_serialization_stream() do s # immutable struct with 1 field @@ -178,7 +178,7 @@ create_serialization_stream() do s # immutable struct with 1 field utype = eval(Meta.parse("$(usertype)")) serialize(s, utype) seek(s, 0) - @test deserialize(s) == utype + @test invokelatest(deserialize, s) == utype end create_serialization_stream() do s # immutable struct with 2 field @@ -187,7 +187,7 @@ create_serialization_stream() do s # immutable struct with 2 field utval = eval(Meta.parse("$(usertype)(1,2)")) serialize(s, utval) seek(s, 0) - @test deserialize(s) === utval + @test invokelatest(deserialize, s) === utval end create_serialization_stream() do s # immutable struct with 3 field @@ -196,7 +196,7 @@ create_serialization_stream() do s # immutable struct with 3 field utval = eval(Meta.parse("$(usertype)(1,2,3)")) serialize(s, utval) seek(s, 0) - @test deserialize(s) === utval + @test invokelatest(deserialize, s) === utval end create_serialization_stream() do s # immutable struct with 4 field @@ -205,7 +205,7 @@ create_serialization_stream() do s # immutable struct with 4 field utval = eval(Meta.parse("$(usertype)(1,2,3,4)")) serialize(s, utval) seek(s, 0) - @test deserialize(s) === utval + @test invokelatest(deserialize, s) === utval end # Expression diff --git a/test/core.jl b/test/core.jl index 4bbb2ca368019..3886e6728df10 100644 --- a/test/core.jl +++ b/test/core.jl @@ -2622,7 +2622,7 @@ end # issue #8338 let ex = Expr(:(=), :(f8338(x;y=4)), :(x*y)) eval(ex) - @test invokelatest(f8338, 2) == 8 + @test (@invokelatest f8338(2)) == 8 end # call overloading (#2403) diff --git a/test/loading.jl b/test/loading.jl index 09f96e1f43578..be8f08b4bfe22 100644 --- a/test/loading.jl +++ b/test/loading.jl @@ -798,6 +798,7 @@ end @testset "`::AbstractString` constraint on the path argument to `include`" begin for m ∈ (NotPkgModule, evalfile("testhelpers/just_module.jl")) + @Core.latestworld let i = m.include @test !applicable(i, (nothing,)) @test !applicable(i, (identity, nothing,)) diff --git a/test/precompile.jl b/test/precompile.jl index 55e97f5608b08..f5a412b416ddc 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -610,13 +610,17 @@ precompile_test_harness(false) do dir @eval using UseBaz @test haskey(Base.loaded_modules, Base.PkgId("UseBaz")) @test haskey(Base.loaded_modules, Base.PkgId("Baz")) - @test Base.invokelatest(UseBaz.biz) === 1 - @test Base.invokelatest(UseBaz.buz) === 2 - @test UseBaz.generating == 0 - @test UseBaz.incremental == 0 + invokelatest() do + @test UseBaz.biz() === 1 + @test UseBaz.buz() === 2 + @test UseBaz.generating == 0 + @test UseBaz.incremental == 0 + end @eval using Baz - @test Base.invokelatest(Baz.baz) === 1 - @test Baz === UseBaz.Baz + invokelatest() do + @test Baz.baz() === 1 + @test Baz === UseBaz.Baz + end # should not throw if the cachefile does not exist @test !isfile("DoesNotExist.ji") diff --git a/test/runtests.jl b/test/runtests.jl index fd0326d48ee6c..f0c5e1b94c376 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -112,7 +112,7 @@ cd(@__DIR__) do @everywhere include("testdefs.jl") if use_revise - Base.invokelatest(revise_trackall) + @invokelatest revise_trackall() Distributed.remotecall_eval(Main, workers(), revise_init_expr) end @@ -250,7 +250,7 @@ cd(@__DIR__) do wrkr = p before = time() resp, duration = try - r = remotecall_fetch(runtests, wrkr, test, test_path(test); seed=seed) + r = remotecall_fetch(@Base.world(runtests, ∞), wrkr, test, test_path(test); seed=seed) r, time() - before catch e isa(e, InterruptException) && return @@ -310,7 +310,7 @@ cd(@__DIR__) do t == "SharedArrays" && (isolate = false) before = time() resp, duration = try - r = Base.invokelatest(runtests, t, test_path(t), isolate, seed=seed) # runtests is defined by the include above + r = @invokelatest runtests(t, test_path(t), isolate, seed=seed) # runtests is defined by the include above r, time() - before catch e isa(e, InterruptException) && rethrow() diff --git a/test/syntax.jl b/test/syntax.jl index bdf9579b134eb..aaeeea7aec161 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -3303,6 +3303,7 @@ const typeof = error end let ex = :(const $(esc(:x)) = 1; (::typeof($(esc(:foo43993))))() = $(esc(:x))) Core.eval(M43993, Expr(:var"hygienic-scope", ex, Core)) + @Core.latestworld @test M43993.x === 1 @test invokelatest(M43993.foo43993) === 1 end diff --git a/test/worlds.jl b/test/worlds.jl index 268a6664571fb..8bc96f8303aef 100644 --- a/test/worlds.jl +++ b/test/worlds.jl @@ -115,14 +115,14 @@ wc265_41332a = Task(tls_world_age) global wc265_41332d = Task(tls_world_age) nothing end)() -@test wc265 + 2 == get_world_counter() == tls_world_age() +@test wc265 + 3 == get_world_counter() == tls_world_age() schedule(wc265_41332a) schedule(wc265_41332b) schedule(wc265_41332c) schedule(wc265_41332d) @test wc265 == fetch(wc265_41332a) @test wc265 + 1 == fetch(wc265_41332b) -@test wc265 + 2 == fetch(wc265_41332c) +@test wc265 + 3 == fetch(wc265_41332c) @test wc265 + 1 == fetch(wc265_41332d) chnls, tasks = Base.channeled_tasks(2, wfunc) t265 = tasks[1] From 61e8f1d3e561e480a05285745239c0df66f111ef Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 22 Jan 2025 14:55:49 +0100 Subject: [PATCH 228/342] Move `jl_task_t` to `julia_threads.h` (#57117) This is a subset of PR #56477 . I hope that it will be easier to get this merged first, as it just moves things around, afterwards we can update #56477 and it will be considerably smaller, and will thus hopefully break less often (and in less bad ways) over time. (I can perform the required update of that PR, too). See also PR #57116 which contains another independent part of that PR. --- src/julia.h | 85 +++++---------------------------------------- src/julia_threads.h | 70 +++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 77 deletions(-) diff --git a/src/julia.h b/src/julia.h index 699b3cc196411..4c699ba059c65 100644 --- a/src/julia.h +++ b/src/julia.h @@ -72,21 +72,20 @@ typedef struct _jl_tls_states_t *jl_ptls_t; #endif #include "gc-interface.h" #include "julia_atomics.h" -#include "julia_threads.h" #include "julia_assert.h" +// the common fields are hidden before the pointer, but the following macro is +// used to indicate which types below are subtypes of jl_value_t +#define JL_DATA_TYPE +typedef struct _jl_value_t jl_value_t; +#include "julia_threads.h" + #ifdef __cplusplus extern "C" { #endif // core data types ------------------------------------------------------------ -// the common fields are hidden before the pointer, but the following macro is -// used to indicate which types below are subtypes of jl_value_t -#define JL_DATA_TYPE - -typedef struct _jl_value_t jl_value_t; - struct _jl_taggedvalue_bits { uintptr_t gc:2; uintptr_t in_image:1; @@ -484,9 +483,6 @@ typedef struct _jl_abi_override_t { jl_method_instance_t *def; } jl_abi_override_t; -// all values are callable as Functions -typedef jl_value_t jl_function_t; - typedef struct { JL_DATA_TYPE jl_sym_t *name; @@ -2262,12 +2258,8 @@ JL_DLLEXPORT void jl_sigatomic_end(void); // tasks and exceptions ------------------------------------------------------- -typedef struct _jl_timing_block_t jl_timing_block_t; -typedef struct _jl_timing_event_t jl_timing_event_t; -typedef struct _jl_excstack_t jl_excstack_t; - // info describing an exception handler -typedef struct _jl_handler_t { +struct _jl_handler_t { jl_jmp_buf eh_ctx; jl_gcframe_t *gcstack; jl_value_t *scope; @@ -2277,68 +2269,7 @@ typedef struct _jl_handler_t { sig_atomic_t defer_signal; jl_timing_block_t *timing_stack; size_t world_age; -} jl_handler_t; - -#define JL_RNG_SIZE 5 // xoshiro 4 + splitmix 1 - -typedef struct _jl_task_t { - JL_DATA_TYPE - jl_value_t *next; // invasive linked list for scheduler - jl_value_t *queue; // invasive linked list for scheduler - jl_value_t *tls; - jl_value_t *donenotify; - jl_value_t *result; - jl_value_t *scope; - jl_function_t *start; - _Atomic(uint8_t) _state; - uint8_t sticky; // record whether this Task can be migrated to a new thread - uint16_t priority; - _Atomic(uint8_t) _isexception; // set if `result` is an exception to throw or that we exited with - uint8_t pad0[3]; - // === 64 bytes (cache line) - uint64_t rngState[JL_RNG_SIZE]; - // flag indicating whether or not to record timing metrics for this task - uint8_t metrics_enabled; - uint8_t pad1[3]; - // timestamp this task first entered the run queue - _Atomic(uint64_t) first_enqueued_at; - // timestamp this task was most recently scheduled to run - _Atomic(uint64_t) last_started_running_at; - // time this task has spent running; updated when it yields or finishes. - _Atomic(uint64_t) running_time_ns; - // === 64 bytes (cache line) - // timestamp this task finished (i.e. entered state DONE or FAILED). - _Atomic(uint64_t) finished_at; - -// hidden state: - - // id of owning thread - does not need to be defined until the task runs - _Atomic(int16_t) tid; - // threadpool id - int8_t threadpoolid; - // Reentrancy bits - // Bit 0: 1 if we are currently running inference/codegen - // Bit 1-2: 0-3 counter of how many times we've reentered inference - // Bit 3: 1 if we are writing the image and inference is illegal - uint8_t reentrant_timing; - // 2 bytes of padding on 32-bit, 6 bytes on 64-bit - // uint16_t padding2_32; - // uint48_t padding2_64; - // saved gc stack top for context switches - jl_gcframe_t *gcstack; - size_t world_age; - // quick lookup for current ptls - jl_ptls_t ptls; // == jl_all_tls_states[tid] -#ifdef USE_TRACY - const char *name; -#endif - // saved exception stack - jl_excstack_t *excstack; - // current exception handler - jl_handler_t *eh; - // saved thread state - jl_ucontext_t ctx; // pointer into stkbuf, if suspended -} jl_task_t; +}; #define JL_TASK_STATE_RUNNABLE 0 #define JL_TASK_STATE_DONE 1 diff --git a/src/julia_threads.h b/src/julia_threads.h index b6ef65dc7fe52..061eb9266e7a7 100644 --- a/src/julia_threads.h +++ b/src/julia_threads.h @@ -218,6 +218,76 @@ typedef struct _jl_tls_states_t { #endif } jl_tls_states_t; +#define JL_RNG_SIZE 5 // xoshiro 4 + splitmix 1 + +// all values are callable as Functions +typedef jl_value_t jl_function_t; + +typedef struct _jl_timing_block_t jl_timing_block_t; +typedef struct _jl_timing_event_t jl_timing_event_t; +typedef struct _jl_excstack_t jl_excstack_t; + +typedef struct _jl_handler_t jl_handler_t; + +typedef struct _jl_task_t { + JL_DATA_TYPE + jl_value_t *next; // invasive linked list for scheduler + jl_value_t *queue; // invasive linked list for scheduler + jl_value_t *tls; + jl_value_t *donenotify; + jl_value_t *result; + jl_value_t *scope; + jl_function_t *start; + _Atomic(uint8_t) _state; + uint8_t sticky; // record whether this Task can be migrated to a new thread + uint16_t priority; + _Atomic(uint8_t) _isexception; // set if `result` is an exception to throw or that we exited with + uint8_t pad0[3]; + // === 64 bytes (cache line) + uint64_t rngState[JL_RNG_SIZE]; + // flag indicating whether or not to record timing metrics for this task + uint8_t metrics_enabled; + uint8_t pad1[3]; + // timestamp this task first entered the run queue + _Atomic(uint64_t) first_enqueued_at; + // timestamp this task was most recently scheduled to run + _Atomic(uint64_t) last_started_running_at; + // time this task has spent running; updated when it yields or finishes. + _Atomic(uint64_t) running_time_ns; + // === 64 bytes (cache line) + // timestamp this task finished (i.e. entered state DONE or FAILED). + _Atomic(uint64_t) finished_at; + +// hidden state: + + // id of owning thread - does not need to be defined until the task runs + _Atomic(int16_t) tid; + // threadpool id + int8_t threadpoolid; + // Reentrancy bits + // Bit 0: 1 if we are currently running inference/codegen + // Bit 1-2: 0-3 counter of how many times we've reentered inference + // Bit 3: 1 if we are writing the image and inference is illegal + uint8_t reentrant_timing; + // 2 bytes of padding on 32-bit, 6 bytes on 64-bit + // uint16_t padding2_32; + // uint48_t padding2_64; + // saved gc stack top for context switches + jl_gcframe_t *gcstack; + size_t world_age; + // quick lookup for current ptls + jl_ptls_t ptls; // == jl_all_tls_states[tid] +#ifdef USE_TRACY + const char *name; +#endif + // saved exception stack + jl_excstack_t *excstack; + // current exception handler + jl_handler_t *eh; + // saved thread state + jl_ucontext_t ctx; // pointer into stkbuf, if suspended +} jl_task_t; + JL_DLLEXPORT void *jl_get_ptls_states(void); // Update codegen version in `ccall.cpp` after changing either `pause` or `wake` From eed336505356b51efc0ab6fa0daa46d339878efe Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Wed, 22 Jan 2025 12:51:09 -0500 Subject: [PATCH 229/342] Docs: Update version that version-named manifests works from (#56709) --- doc/src/manual/code-loading.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/manual/code-loading.md b/doc/src/manual/code-loading.md index 5c8315693c71e..24e64b0ca068e 100644 --- a/doc/src/manual/code-loading.md +++ b/doc/src/manual/code-loading.md @@ -63,7 +63,7 @@ Each kind of environment defines these three maps differently, as detailed in th ### Project environments -A project environment is determined by a directory containing a project file called `Project.toml`, and optionally a manifest file called `Manifest.toml`. These files may also be called `JuliaProject.toml` and `JuliaManifest.toml`, in which case `Project.toml` and `Manifest.toml` are ignored. This allows for coexistence with other tools that might consider files called `Project.toml` and `Manifest.toml` significant. For pure Julia projects, however, the names `Project.toml` and `Manifest.toml` are preferred. However, from Julia v1.11 onwards, `(Julia)Manifest-v{major}.{minor}.toml` is recognized as a format to make a given julia version use a specific manifest file i.e. in the same folder, a `Manifest-v1.11.toml` would be used by v1.11 and `Manifest.toml` by any other julia version. +A project environment is determined by a directory containing a project file called `Project.toml`, and optionally a manifest file called `Manifest.toml`. These files may also be called `JuliaProject.toml` and `JuliaManifest.toml`, in which case `Project.toml` and `Manifest.toml` are ignored. This allows for coexistence with other tools that might consider files called `Project.toml` and `Manifest.toml` significant. For pure Julia projects, however, the names `Project.toml` and `Manifest.toml` are preferred. However, from Julia v1.10.8 onwards, `(Julia)Manifest-v{major}.{minor}.toml` is recognized as a format to make a given julia version use a specific manifest file i.e. in the same folder, a `Manifest-v1.11.toml` would be used by v1.11 and `Manifest.toml` by any other julia version. The roots, graph and paths maps of a project environment are defined as follows: From 090e291eba1b7668bfc5234215750b4bd80f5387 Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Wed, 22 Jan 2025 17:30:00 -0500 Subject: [PATCH 230/342] runtime_intrinsics.c: Correct `max_double` (#57124) Closes #57119. --- src/runtime_intrinsics.c | 8 ++--- test/intrinsics.jl | 78 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 80 insertions(+), 6 deletions(-) diff --git a/src/runtime_intrinsics.c b/src/runtime_intrinsics.c index 90afa3fb6bddf..49d510cc48c34 100644 --- a/src/runtime_intrinsics.c +++ b/src/runtime_intrinsics.c @@ -1424,17 +1424,17 @@ bi_fintrinsic(_min, min_float) float max_float(float x, float y) JL_NOTSAFEPOINT { float diff = x - y; - float argmin = signbit(diff) ? y : x; + float argmax = signbit(diff) ? y : x; int is_nan = isnan(x) || isnan(y); - return is_nan ? diff : argmin; + return is_nan ? diff : argmax; } double max_double(double x, double y) JL_NOTSAFEPOINT { double diff = x - y; - double argmin = signbit(diff) ? x : y; + double argmax = signbit(diff) ? y : x; int is_nan = isnan(x) || isnan(y); - return is_nan ? diff : argmin; + return is_nan ? diff : argmax; } #define _max(a, b) sizeof(a) == sizeof(float) ? max_float(a, b) : max_double(a, b) diff --git a/test/intrinsics.jl b/test/intrinsics.jl index 7a63cd1c0a62e..bc1838ce2c68b 100644 --- a/test/intrinsics.jl +++ b/test/intrinsics.jl @@ -147,9 +147,81 @@ macro test_intrinsic(intr, args...) end end +@testset "Float64 intrinsics" begin + # unary + @test_intrinsic Core.Intrinsics.abs_float Float64(-3.3) Float64(3.3) + @test_intrinsic Core.Intrinsics.neg_float Float64(3.3) Float64(-3.3) + @test_intrinsic Core.Intrinsics.fpext Float64 Float64(3.3) Float64(3.3) + + # binary + @test_intrinsic Core.Intrinsics.add_float Float64(3.3) Float64(2) Float64(5.3) + @test_intrinsic Core.Intrinsics.sub_float Float64(3.3) Float64(2) Float64(1.2999999999999998) + @test_intrinsic Core.Intrinsics.mul_float Float64(3.3) Float64(2) Float64(6.6) + @test_intrinsic Core.Intrinsics.div_float Float64(3.3) Float64(2) Float64(1.65) + @test_intrinsic Core.Intrinsics.max_float Float64(1.0) Float64(2.0) Float64(2.0) + @test_intrinsic Core.Intrinsics.min_float Float64(1.0) Float64(2.0) Float64(1.0) + + # ternary + @test_intrinsic Core.Intrinsics.fma_float Float64(3.3) Float64(4.4) Float64(5.5) Float64(20.02) + @test_intrinsic Core.Intrinsics.muladd_float Float64(3.3) Float64(4.4) Float64(5.5) Float64(20.02) + + # boolean + @test_intrinsic Core.Intrinsics.eq_float Float64(3.3) Float64(3.3) true + @test_intrinsic Core.Intrinsics.eq_float Float64(3.3) Float64(2) false + @test_intrinsic Core.Intrinsics.ne_float Float64(3.3) Float64(3.3) false + @test_intrinsic Core.Intrinsics.ne_float Float64(3.3) Float64(2) true + @test_intrinsic Core.Intrinsics.le_float Float64(3.3) Float64(3.3) true + @test_intrinsic Core.Intrinsics.le_float Float64(3.3) Float64(2) false + + # conversions + @test_intrinsic Core.Intrinsics.sitofp Float64 3 Float64(3.0) + @test_intrinsic Core.Intrinsics.uitofp Float64 UInt(3) Float64(3.0) + @test_intrinsic Core.Intrinsics.fptosi Int Float64(3.3) 3 + @test_intrinsic Core.Intrinsics.fptoui UInt Float64(3.3) UInt(3) +end + +@testset "Float32 intrinsics" begin + # unary + @test_intrinsic Core.Intrinsics.abs_float Float32(-3.3) Float32(3.3) + @test_intrinsic Core.Intrinsics.neg_float Float32(3.3) Float32(-3.3) + @test_intrinsic Core.Intrinsics.fpext Float32 Float32(3.3) Float32(3.3) + @test_intrinsic Core.Intrinsics.fpext Float64 Float32(3.3) 3.299999952316284 + @test_intrinsic Core.Intrinsics.fptrunc Float32 Float64(3.3) Float32(3.3) + + # binary + @test_intrinsic Core.Intrinsics.add_float Float32(3.3) Float32(2) Float32(5.3) + @test_intrinsic Core.Intrinsics.sub_float Float32(3.3) Float32(2) Float32(1.3) + @test_intrinsic Core.Intrinsics.mul_float Float32(3.3) Float32(2) Float32(6.6) + @test_intrinsic Core.Intrinsics.div_float Float32(3.3) Float32(2) Float32(1.65) + @test_intrinsic Core.Intrinsics.max_float Float32(1.0) Float32(2.0) Float32(2.0) + @test_intrinsic Core.Intrinsics.min_float Float32(1.0) Float32(2.0) Float32(1.0) + + # ternary + @test_intrinsic Core.Intrinsics.fma_float Float32(3.3) Float32(4.4) Float32(5.5) Float32(20.02) + @test_intrinsic Core.Intrinsics.muladd_float Float32(3.3) Float32(4.4) Float32(5.5) Float32(20.02) + + # boolean + @test_intrinsic Core.Intrinsics.eq_float Float32(3.3) Float32(3.3) true + @test_intrinsic Core.Intrinsics.eq_float Float32(3.3) Float32(2) false + @test_intrinsic Core.Intrinsics.ne_float Float32(3.3) Float32(3.3) false + @test_intrinsic Core.Intrinsics.ne_float Float32(3.3) Float32(2) true + @test_intrinsic Core.Intrinsics.le_float Float32(3.3) Float32(3.3) true + @test_intrinsic Core.Intrinsics.le_float Float32(3.3) Float32(2) false + + # conversions + @test_intrinsic Core.Intrinsics.sitofp Float32 3 Float32(3.0) + @test_intrinsic Core.Intrinsics.uitofp Float32 UInt(3) Float32(3.0) + @test_intrinsic Core.Intrinsics.fptosi Int Float32(3.3) 3 + @test_intrinsic Core.Intrinsics.fptoui UInt Float32(3.3) UInt(3) +end + @testset "Float16 intrinsics" begin # unary + @test_intrinsic Core.Intrinsics.abs_float Float16(-3.3) Float16(3.3) @test_intrinsic Core.Intrinsics.neg_float Float16(3.3) Float16(-3.3) + # See + #broken @test_intrinsic Core.Intrinsics.fpext Float16 Float16(3.3) Float16(3.3) + @test_broken Core.Intrinsics.fpext(Float16, Float16(3.3)) === Float16(3.3) @test_intrinsic Core.Intrinsics.fpext Float32 Float16(3.3) 3.3007812f0 @test_intrinsic Core.Intrinsics.fpext Float64 Float16(3.3) 3.30078125 @test_intrinsic Core.Intrinsics.fptrunc Float16 Float32(3.3) Float16(3.3) @@ -160,6 +232,8 @@ end @test_intrinsic Core.Intrinsics.sub_float Float16(3.3) Float16(2) Float16(1.301) @test_intrinsic Core.Intrinsics.mul_float Float16(3.3) Float16(2) Float16(6.6) @test_intrinsic Core.Intrinsics.div_float Float16(3.3) Float16(2) Float16(1.65) + @test_intrinsic Core.Intrinsics.max_float Float16(1.0) Float16(2.0) Float16(2.0) + @test_intrinsic Core.Intrinsics.min_float Float16(1.0) Float16(2.0) Float16(1.0) # ternary @test_intrinsic Core.Intrinsics.fma_float Float16(3.3) Float16(4.4) Float16(5.5) Float16(20.02) @@ -174,8 +248,8 @@ end @test_intrinsic Core.Intrinsics.le_float Float16(3.3) Float16(2) false # conversions - @test_intrinsic Core.Intrinsics.sitofp Float16 3 Float16(3f0) - @test_intrinsic Core.Intrinsics.uitofp Float16 UInt(3) Float16(3f0) + @test_intrinsic Core.Intrinsics.sitofp Float16 3 Float16(3.0) + @test_intrinsic Core.Intrinsics.uitofp Float16 UInt(3) Float16(3.0) @test_intrinsic Core.Intrinsics.fptosi Int Float16(3.3) 3 @test_intrinsic Core.Intrinsics.fptoui UInt Float16(3.3) UInt(3) end From f52c4ab7215d81d7fea1fd2f4043b1f20c92dce3 Mon Sep 17 00:00:00 2001 From: Jakob Nybo Nissen Date: Thu, 23 Jan 2025 12:12:15 +0100 Subject: [PATCH 231/342] Expand on docstring of GC.safepoint (#57128) Update the docstring to mention the following points: * Safepoints are very fast, but may still degrade performance in tight loops * Safepoints do not trigger the GC, but instead stops a task from blocking GC that would otherwise run. * Switch terminology from mentioning 'threads' to 'tasks' --- base/gcutils.jl | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/base/gcutils.jl b/base/gcutils.jl index 84a184537ffc0..60b8ecdd17d65 100644 --- a/base/gcutils.jl +++ b/base/gcutils.jl @@ -243,12 +243,21 @@ end GC.safepoint() Inserts a point in the program where garbage collection may run. -This can be useful in rare cases in multi-threaded programs where some threads -are allocating memory (and hence may need to run GC) but other threads are doing -only simple operations (no allocation, task switches, or I/O). -Calling this function periodically in non-allocating threads allows garbage + +Safepoints are fast and do not themselves trigger garbage collection. +However, if another thread has requested the GC to run, reaching a safepoint will +cause the current thread to block and wait for the GC. + +This can be useful in rare cases in multi-threaded programs where some tasks +are allocating memory (and hence may need to run GC) but other tasks are doing +only simple operations (no allocation, task switches, or I/O), which do not +yield control to Julia's runtime, and therefore blocks the GC from running. +Calling this function periodically in the non-allocating tasks allows garbage collection to run. +Note that even though safepoints are fast (typically around 2 clock cycles), +they can still degrade performance if called in a tight loop. + !!! compat "Julia 1.4" This function is available as of Julia 1.4. """ From 88c71dd2164030ef9563a57ef3f1072581d8efca Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Thu, 23 Jan 2025 09:51:06 -0500 Subject: [PATCH 232/342] REPL: Handle message from `complete_methods!` when max methods is hit (#57138) --- stdlib/REPL/src/REPLCompletions.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index c63c5a557acd8..26ad6651cd880 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -1097,6 +1097,9 @@ function complete_keyword_argument(partial::String, last_idx::Int, context_modul last_word = partial[wordrange] # the word to complete kwargs = Set{String}() for m in methods + # if MAX_METHOD_COMPLETIONS is hit a single TextCompletion is return by complete_methods! with an explanation + # which can be ignored here + m isa TextCompletion && continue m::MethodCompletion possible_kwargs = Base.kwarg_decl(m.method) current_kwarg_candidates = String[] From b76fd9f3148b66d418c1fbac3d729c0d318a654d Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 23 Jan 2025 15:02:46 -0500 Subject: [PATCH 233/342] codegen: fix unsound mark_volatile_vars implementation (#57131) The previous implementation was incorrect, leading to failing to mark variables correctly. The new implementation is more conservative. This simple analysis assumes that inference has normally run or that performance doesn't matter for a particular block of code. Fixes #56996 --- Compiler/test/codegen.jl | 17 +++++ src/codegen.cpp | 149 ++++++++++++++++++++------------------- 2 files changed, 93 insertions(+), 73 deletions(-) diff --git a/Compiler/test/codegen.jl b/Compiler/test/codegen.jl index ff61ac719c59e..57a9c26aefac6 100644 --- a/Compiler/test/codegen.jl +++ b/Compiler/test/codegen.jl @@ -1041,3 +1041,20 @@ struct Vec56937 x::NTuple{8, VecElement{Int}} end x56937 = Ref(Vec56937(ntuple(_->VecElement(1),8))) @test x56937[].x[1] == VecElement{Int}(1) # shouldn't crash + +# issue #56996 +let + ()->() # trigger various heuristics + Base.Experimental.@force_compile + default_rng_orig = [] # make a value in a Slot + try + # overwrite the gc-slots in the exception branch + throw(ErrorException("This test is supposed to throw an error")) + catch ex + # destroy any values that aren't referenced + GC.gc() + # make sure that default_rng_orig value is still valid + @noinline copy!([], default_rng_orig) + end + nothing +end diff --git a/src/codegen.cpp b/src/codegen.cpp index e047632923f68..60e53f75638ed 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3282,24 +3282,7 @@ static bool local_var_occurs(jl_value_t *e, int sl) return false; } -static std::set assigned_in_try(jl_array_t *stmts, int s, long l) -{ - std::set av; - for(int i=s; i < l; i++) { - jl_value_t *st = jl_array_ptr_ref(stmts,i); - if (jl_is_expr(st)) { - if (((jl_expr_t*)st)->head == jl_assign_sym) { - jl_value_t *ar = jl_exprarg(st, 0); - if (jl_is_slotnumber(ar)) { - av.insert(jl_slot_number(ar)-1); - } - } - } - } - return av; -} - -static void mark_volatile_vars(jl_array_t *stmts, SmallVectorImpl &slots) +static bool have_try_block(jl_array_t *stmts) { size_t slength = jl_array_dim0(stmts); for (int i = 0; i < (int)slength; i++) { @@ -3308,19 +3291,38 @@ static void mark_volatile_vars(jl_array_t *stmts, SmallVectorImpl int last = jl_enternode_catch_dest(st); if (last == 0) continue; - std::set as = assigned_in_try(stmts, i + 1, last - 1); - for (int j = 0; j < (int)slength; j++) { - if (j < i || j > last) { - std::set::iterator it = as.begin(); - for (; it != as.end(); it++) { - if (local_var_occurs(jl_array_ptr_ref(stmts, j), *it)) { - jl_varinfo_t &vi = slots[*it]; - vi.isVolatile = true; - } - } + return 1; + } + } + return 0; +} + +// conservative marking of all variables potentially used after a catch block that were assigned before it +static void mark_volatile_vars(jl_array_t *stmts, SmallVectorImpl &slots, const std::set &bbstarts) +{ + if (!have_try_block(stmts)) + return; + size_t slength = jl_array_dim0(stmts); + BitVector assigned_in_block(slots.size()); // conservatively only ignore slots assigned in the same basic block + for (int j = 0; j < (int)slength; j++) { + if (bbstarts.count(j + 1)) + assigned_in_block.reset(); + jl_value_t *stmt = jl_array_ptr_ref(stmts, j); + if (jl_is_expr(stmt)) { + jl_expr_t *e = (jl_expr_t*)stmt; + if (e->head == jl_assign_sym) { + jl_value_t *l = jl_exprarg(e, 0); + if (jl_is_slotnumber(l)) { + assigned_in_block.set(jl_slot_number(l)-1); } } } + for (int slot = 0; slot < (int)slots.size(); slot++) { + if (!assigned_in_block.test(slot) && local_var_occurs(stmt, slot)) { + jl_varinfo_t &vi = slots[slot]; + vi.isVolatile = true; + } + } } } @@ -8439,7 +8441,6 @@ static jl_llvm_functions_t ctx.code = src->code; ctx.source = src; - std::map labels; ctx.module = jl_is_method(lam->def.method) ? lam->def.method->module : lam->def.module; ctx.linfo = lam; ctx.name = name_from_method_instance(lam); @@ -8499,6 +8500,49 @@ static jl_llvm_functions_t if (dbgFuncName.empty()) // Should never happen anymore? debug_enabled = false; + // First go through and collect all branch targets, so we know where to + // split basic blocks. + std::set branch_targets; // 1-indexed, sorted + for (size_t i = 0; i < stmtslen; ++i) { + jl_value_t *stmt = jl_array_ptr_ref(stmts, i); + if (jl_is_gotoifnot(stmt)) { + int dest = jl_gotoifnot_label(stmt); + branch_targets.insert(dest); + // The next 1-indexed statement + branch_targets.insert(i + 2); + } + else if (jl_is_returnnode(stmt)) { + // We don't do dead branch elimination before codegen + // so we need to make sure to start a BB after any + // return node, even if they aren't otherwise branch + // targets. + if (i + 2 <= stmtslen) + branch_targets.insert(i + 2); + } + else if (jl_is_enternode(stmt)) { + branch_targets.insert(i + 1); + if (i + 2 <= stmtslen) + branch_targets.insert(i + 2); + size_t catch_dest = jl_enternode_catch_dest(stmt); + if (catch_dest) + branch_targets.insert(catch_dest); + } + else if (jl_is_gotonode(stmt)) { + int dest = jl_gotonode_label(stmt); + branch_targets.insert(dest); + if (i + 2 <= stmtslen) + branch_targets.insert(i + 2); + } + else if (jl_is_phinode(stmt)) { + jl_array_t *edges = (jl_array_t*)jl_fieldref_noalloc(stmt, 0); + for (size_t j = 0; j < jl_array_nrows(edges); ++j) { + size_t edge = jl_array_data(edges, int32_t)[j]; + if (edge == i) + branch_targets.insert(i + 1); + } + } + } + // step 2. process var-info lists to see what vars need boxing int n_ssavalues = jl_is_long(src->ssavaluetypes) ? jl_unbox_long(src->ssavaluetypes) : jl_array_nrows(src->ssavaluetypes); size_t vinfoslen = jl_array_dim0(src->slotflags); @@ -8559,7 +8603,7 @@ static jl_llvm_functions_t simple_use_analysis(ctx, jl_array_ptr_ref(stmts, i)); // determine which vars need to be volatile - mark_volatile_vars(stmts, ctx.slots); + mark_volatile_vars(stmts, ctx.slots, branch_targets); // step 4. determine function signature if (!specsig) @@ -9310,8 +9354,8 @@ static jl_llvm_functions_t // step 11b. Do codegen in control flow order SmallVector workstack; - std::map BB; - std::map come_from_bb; + DenseMap BB; + DenseMap come_from_bb; int cursor = 0; int current_label = 0; auto find_next_stmt = [&] (int seq_next) { @@ -9430,47 +9474,6 @@ static jl_llvm_functions_t come_from_bb[0] = ctx.builder.GetInsertBlock(); - // First go through and collect all branch targets, so we know where to - // split basic blocks. - std::set branch_targets; // 1-indexed - { - for (size_t i = 0; i < stmtslen; ++i) { - jl_value_t *stmt = jl_array_ptr_ref(stmts, i); - if (jl_is_gotoifnot(stmt)) { - int dest = jl_gotoifnot_label(stmt); - branch_targets.insert(dest); - // The next 1-indexed statement - branch_targets.insert(i + 2); - } else if (jl_is_returnnode(stmt)) { - // We don't do dead branch elimination before codegen - // so we need to make sure to start a BB after any - // return node, even if they aren't otherwise branch - // targets. - if (i + 2 <= stmtslen) - branch_targets.insert(i + 2); - } else if (jl_is_enternode(stmt)) { - branch_targets.insert(i + 1); - if (i + 2 <= stmtslen) - branch_targets.insert(i + 2); - size_t catch_dest = jl_enternode_catch_dest(stmt); - if (catch_dest) - branch_targets.insert(catch_dest); - } else if (jl_is_gotonode(stmt)) { - int dest = jl_gotonode_label(stmt); - branch_targets.insert(dest); - if (i + 2 <= stmtslen) - branch_targets.insert(i + 2); - } else if (jl_is_phinode(stmt)) { - jl_array_t *edges = (jl_array_t*)jl_fieldref_noalloc(stmt, 0); - for (size_t j = 0; j < jl_array_nrows(edges); ++j) { - size_t edge = jl_array_data(edges, int32_t)[j]; - if (edge == i) - branch_targets.insert(i + 1); - } - } - } - } - for (int label : branch_targets) { BasicBlock *bb = BasicBlock::Create(ctx.builder.getContext(), "L" + std::to_string(label), f); From 3054c681785473d689290da96205956a962fa283 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Thu, 23 Jan 2025 20:36:33 -0300 Subject: [PATCH 234/342] Don't use altstack for the sigusr2 handler (#57134) This works around an rr bug with nested signal handlers and syscalls. But it's also mostly unecessary as it doesn't need to handle stack overflows --- src/signals-unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/signals-unix.c b/src/signals-unix.c index 788539b1f5096..c730f27f16def 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -1208,7 +1208,7 @@ void jl_install_default_signal_handlers(void) memset(&act, 0, sizeof(struct sigaction)); sigemptyset(&act.sa_mask); act.sa_sigaction = usr2_handler; - act.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTART; + act.sa_flags = SA_SIGINFO | SA_RESTART; if (sigaction(SIGUSR2, &act, NULL) < 0) { jl_errorf("fatal error: sigaction: %s", strerror(errno)); } From 6eb42dbc69140e3bf4583a2b87b50bf3e7bdd29f Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 24 Jan 2025 02:23:29 +0100 Subject: [PATCH 235/342] Fix missing nargs setting in abioverride test (#57144) The only place that really reads this is the debug info generation, which is not enabled by default, but this test would crash if you ran it on a debug build of julia. --- Compiler/test/abioverride.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/Compiler/test/abioverride.jl b/Compiler/test/abioverride.jl index da9b1f92786e5..49907ea8e4c63 100644 --- a/Compiler/test/abioverride.jl +++ b/Compiler/test/abioverride.jl @@ -40,6 +40,7 @@ let world = Base.tls_world_age() ## Remove the argument resize!(new_source.slotnames, 2) resize!(new_source.slotflags, 2) + new_source.nargs = 2 # Construct the CodeInstance from the modified CodeInfo data global new_ci = Core.CodeInstance(Core.ABIOverride(Tuple{typeof(myplus), Int}, mi), From bcddc653386f09b6f6aa7ebe5d1151ee1d4a6c82 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Fri, 24 Jan 2025 14:25:58 -0500 Subject: [PATCH 236/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?LinearAlgebra=20stdlib=20from=201137b4c=20to=20da6d052=20(#5715?= =?UTF-8?q?1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: LinearAlgebra URL: https://github.com/JuliaLang/LinearAlgebra.jl.git Stdlib branch: master Julia branch: master Old commit: 1137b4c New commit: da6d052 Julia version: 1.12.0-DEV LinearAlgebra version: 1.12.0 Bump invoked by: @dkarrasch Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaLang/LinearAlgebra.jl/compare/1137b4c7fa8297cef17c4ae0982d7d89d4ab7dd8...da6d0521347daf5e42b3d09cdb757d4488528c7b ``` $ git log --oneline 1137b4c..da6d052 da6d052 Bump version number to v1.12.0 (#1180) cecf025 test: use `BLAS.libblastrampoline` (#1170) adcd1ea Delete .ci/Manifest.toml (#1173) 53032fe Rearrange tests (#1157) beee169 Delete .ci/Manifest.toml c869685 test: use `BLAS.libblastrampoline` 9bc292d Improve AbstractQ coverage (#1160) a622302 Consistently check matrix sizes in matmul (#1152) 6e5ea12 `sqrt`, `cbrt` and `log` for dense diagonal matrices (#1156) 959d985 Remove old debug functionality in triangular.jl (#1124) 8d9b14f Higher-order functions in `factorize` to obtain structure (#1135) 7c0ecd6 avoid division by zero in svd(::Diagonal) (#1150) 39a7e3c docs: fix unexported function names in svd doc (#1151) ``` Co-authored-by: dkarrasch <26658441+dkarrasch@users.noreply.github.com> --- .../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-1137b4c7fa8297cef17c4ae0982d7d89d4ab7dd8.tar.gz/md5 delete mode 100644 deps/checksums/LinearAlgebra-1137b4c7fa8297cef17c4ae0982d7d89d4ab7dd8.tar.gz/sha512 create mode 100644 deps/checksums/LinearAlgebra-da6d0521347daf5e42b3d09cdb757d4488528c7b.tar.gz/md5 create mode 100644 deps/checksums/LinearAlgebra-da6d0521347daf5e42b3d09cdb757d4488528c7b.tar.gz/sha512 diff --git a/deps/checksums/LinearAlgebra-1137b4c7fa8297cef17c4ae0982d7d89d4ab7dd8.tar.gz/md5 b/deps/checksums/LinearAlgebra-1137b4c7fa8297cef17c4ae0982d7d89d4ab7dd8.tar.gz/md5 deleted file mode 100644 index 5bd44506fd874..0000000000000 --- a/deps/checksums/LinearAlgebra-1137b4c7fa8297cef17c4ae0982d7d89d4ab7dd8.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -eb4df255412ad9a05b807010f626afc8 diff --git a/deps/checksums/LinearAlgebra-1137b4c7fa8297cef17c4ae0982d7d89d4ab7dd8.tar.gz/sha512 b/deps/checksums/LinearAlgebra-1137b4c7fa8297cef17c4ae0982d7d89d4ab7dd8.tar.gz/sha512 deleted file mode 100644 index 23617698dd26e..0000000000000 --- a/deps/checksums/LinearAlgebra-1137b4c7fa8297cef17c4ae0982d7d89d4ab7dd8.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -3b4bf7b761d9585fb2d5c5b8418770be4d1d4399a5f25dd5b2e08785506f0732c8e140ada6f82f6d8a7a77a2c2f79e2feecd6eb0e19eda0c3ee519ba554c19ec diff --git a/deps/checksums/LinearAlgebra-da6d0521347daf5e42b3d09cdb757d4488528c7b.tar.gz/md5 b/deps/checksums/LinearAlgebra-da6d0521347daf5e42b3d09cdb757d4488528c7b.tar.gz/md5 new file mode 100644 index 0000000000000..1771370455266 --- /dev/null +++ b/deps/checksums/LinearAlgebra-da6d0521347daf5e42b3d09cdb757d4488528c7b.tar.gz/md5 @@ -0,0 +1 @@ +810a9f842ee40d03e55c698130620963 diff --git a/deps/checksums/LinearAlgebra-da6d0521347daf5e42b3d09cdb757d4488528c7b.tar.gz/sha512 b/deps/checksums/LinearAlgebra-da6d0521347daf5e42b3d09cdb757d4488528c7b.tar.gz/sha512 new file mode 100644 index 0000000000000..f696212eda4fc --- /dev/null +++ b/deps/checksums/LinearAlgebra-da6d0521347daf5e42b3d09cdb757d4488528c7b.tar.gz/sha512 @@ -0,0 +1 @@ +4197a863c0f5052f0b85f1c04b6f42f71bf35af572f507dbc475e868a7c057bebd11f8258451b7d0a728012f238abfd88943fe80b83df63728af2fcc01199604 diff --git a/stdlib/LinearAlgebra.version b/stdlib/LinearAlgebra.version index 3dac27119172a..e877475771829 100644 --- a/stdlib/LinearAlgebra.version +++ b/stdlib/LinearAlgebra.version @@ -1,4 +1,4 @@ LINEARALGEBRA_BRANCH = master -LINEARALGEBRA_SHA1 = 1137b4c7fa8297cef17c4ae0982d7d89d4ab7dd8 +LINEARALGEBRA_SHA1 = da6d0521347daf5e42b3d09cdb757d4488528c7b LINEARALGEBRA_GIT_URL := https://github.com/JuliaLang/LinearAlgebra.jl.git LINEARALGEBRA_TAR_URL = https://api.github.com/repos/JuliaLang/LinearAlgebra.jl/tarball/$1 From 899d2f50ab9a8b9d29365e093f480874d64bdd31 Mon Sep 17 00:00:00 2001 From: Eduardo Souza Date: Sat, 25 Jan 2025 06:37:50 +1100 Subject: [PATCH 237/342] Skip some stock GC-specific tests when using MMTk (#57104) As noted in https://github.com/JuliaLang/julia/issues/57103, there are a few tests that are specific to the stock GC and will fail for MMTk. For now, this PR simply skips those tests when not using the stock GC until we agree on how to approach the incompatibilities described in the issue. --- base/Base.jl | 2 ++ base/gcutils.jl | 11 ++++++++ base/timing.jl | 6 ++-- stdlib/Profile/test/allocs.jl | 13 +++++++-- stdlib/Profile/test/runtests.jl | 3 ++ test/checked.jl | 8 ++++-- test/cmdlineargs.jl | 49 +++++++++++++++++++-------------- test/gc.jl | 12 +++++--- test/misc.jl | 4 ++- 9 files changed, 75 insertions(+), 33 deletions(-) diff --git a/base/Base.jl b/base/Base.jl index 04f732a4309c9..379347f027f69 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -128,6 +128,8 @@ include("sysinfo.jl") include("libc.jl") using .Libc: getpid, gethostname, time, memcpy, memset, memmove, memcmp +const USING_STOCK_GC = occursin("stock", GC.gc_active_impl()) + # These used to be in build_h.jl and are retained for backwards compatibility. # NOTE: keep in sync with `libblastrampoline_jll.libblastrampoline`. const libblas_name = "libblastrampoline" * (Sys.iswindows() ? "-5" : "") diff --git a/base/gcutils.jl b/base/gcutils.jl index 60b8ecdd17d65..d5e6f4597739f 100644 --- a/base/gcutils.jl +++ b/base/gcutils.jl @@ -281,4 +281,15 @@ function logging_enabled() ccall(:jl_is_gc_logging_enabled, Cint, ()) != 0 end +""" + GC.gc_active_impl() + +Return a string stating which GC implementation is being used and possibly +its version according to the list of supported GCs +""" +function gc_active_impl() + unsafe_string(ccall(:jl_gc_active_impl, Ptr{UInt8}, ())) +end + + end # module GC diff --git a/base/timing.jl b/base/timing.jl index 65c2a643d6a52..61fa73f2eff62 100644 --- a/base/timing.jl +++ b/base/timing.jl @@ -109,10 +109,8 @@ function gc_page_utilization_data() return Base.unsafe_wrap(Array, page_utilization_raw, JL_GC_N_MAX_POOLS, own=false) end - -const USING_STOCK_GC = occursin("stock", unsafe_string(ccall(:jl_gc_active_impl, Ptr{UInt8}, ()))) # Full sweep reasons are currently only available for the stock GC -@static if USING_STOCK_GC +@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] @@ -135,7 +133,7 @@ function full_sweep_reasons() d = Dict{Symbol, Int64}() # populate the dictionary according to the reasons above for the stock GC # otherwise return an empty dictionary for now - @static if USING_STOCK_GC + @static if Base.USING_STOCK_GC reason = cglobal(:jl_full_sweep_reasons, UInt64) reasons_as_array = Base.unsafe_wrap(Vector{UInt64}, reason, length(FULL_SWEEP_REASONS), own=false) for (i, r) in enumerate(FULL_SWEEP_REASONS) diff --git a/stdlib/Profile/test/allocs.jl b/stdlib/Profile/test/allocs.jl index d4930a2b7f5ed..5607783c782f9 100644 --- a/stdlib/Profile/test/allocs.jl +++ b/stdlib/Profile/test/allocs.jl @@ -73,8 +73,14 @@ end @test length(first_alloc.stacktrace) > 0 @test length(string(first_alloc.type)) > 0 - @testset for type in (Task, Vector{Float64},) - @test length(filter(a->a.type <: type, profile.allocs)) >= NUM_TASKS + # Issue #57103: This test does not work with MMTk because of fastpath + # allocation which never calls the allocation profiler. + # TODO: We should port these observability tools (e.g. allocation + # profiler and heap snapshot) to MMTk + @static if Base.USING_STOCK_GC + @testset for type in (Task, Vector{Float64},) + @test length(filter(a->a.type <: type, profile.allocs)) >= NUM_TASKS + end end # TODO: it would be nice to assert that these tasks @@ -143,6 +149,8 @@ end @test length([a for a in prof.allocs if a.type == String]) >= 1 end +# FIXME: Issue #57103 disabling test for MMTk. +@static if Base.USING_STOCK_GC @testset "alloc profiler catches allocs from codegen" begin @eval begin struct MyType x::Int; y::Int end @@ -162,6 +170,7 @@ end @test length(prof.allocs) >= 1 @test length([a for a in prof.allocs if a.type == MyType]) >= 1 end +end @testset "alloc profiler catches allocs from buffer resize" begin f(a) = for _ in 1:100; push!(a, 1); end diff --git a/stdlib/Profile/test/runtests.jl b/stdlib/Profile/test/runtests.jl index b73a2a618011b..e7877b949a17e 100644 --- a/stdlib/Profile/test/runtests.jl +++ b/stdlib/Profile/test/runtests.jl @@ -344,6 +344,8 @@ end @test only(node.down).first == lidict[8] end +# FIXME: Issue #57103: heap snapshots are currently not supported in MMTk +@static if Base.USING_STOCK_GC @testset "HeapSnapshot" begin tmpdir = mktempdir() @@ -374,6 +376,7 @@ end rm(fname) rm(tmpdir, force = true, recursive = true) end +end @testset "PageProfile" begin fname = "$(getpid())_$(time_ns())" diff --git a/test/checked.jl b/test/checked.jl index 4031918a38730..b93c8796162c5 100644 --- a/test/checked.jl +++ b/test/checked.jl @@ -331,8 +331,12 @@ end @test checked_pow(BigInt(2), 2) == BigInt(4) @test checked_pow(BigInt(2), 100) == BigInt(1267650600228229401496703205376) - # Perf test: Make sure BigInts allocs don't scale with the power: - @test @allocations(checked_pow(BigInt(2), 2)) ≈ @allocations(checked_pow(BigInt(2), 10000)) rtol=0.9 + # FIXME: Issue #57103: the following test may fail because + # allocation may not be logged via MMTk's fastpath allocation + @static if Base.USING_STOCK_GC + # Perf test: Make sure BigInts allocs don't scale with the power: + @test @allocations(checked_pow(BigInt(2), 2)) ≈ @allocations(checked_pow(BigInt(2), 10000)) rtol=0.9 + end end @testset "Additional tests" begin diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index 3ff7836223b84..ec7a51e804d3f 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -383,29 +383,33 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no` @test p.exitcode == 1 && p.termsignal == 0 end - # --gcthreads - code = "print(Threads.ngcthreads())" - cpu_threads = ccall(:jl_effective_threads, Int32, ()) - @test string(cpu_threads) == - read(`$exename --threads auto -e $code`, String) == - read(`$exename --threads=auto -e $code`, String) == - read(`$exename -tauto -e $code`, String) == - read(`$exename -t auto -e $code`, String) - for nt in (nothing, "1") - withenv("JULIA_NUM_GC_THREADS" => nt) do - @test read(`$exename --gcthreads=2 -e $code`, String) == "2" - end - withenv("JULIA_NUM_GC_THREADS" => nt) do - @test read(`$exename --gcthreads=2,1 -e $code`, String) == "3" + # FIXME: Issue #57103 --gcthreads does not have the same semantics + # for Stock GC and MMTk, so the tests below are specific to the Stock GC + @static if Base.USING_STOCK_GC + # --gcthreads + code = "print(Threads.ngcthreads())" + cpu_threads = ccall(:jl_effective_threads, Int32, ()) + @test string(cpu_threads) == + read(`$exename --threads auto -e $code`, String) == + read(`$exename --threads=auto -e $code`, String) == + read(`$exename -tauto -e $code`, String) == + read(`$exename -t auto -e $code`, String) + for nt in (nothing, "1") + withenv("JULIA_NUM_GC_THREADS" => nt) do + @test read(`$exename --gcthreads=2 -e $code`, String) == "2" + end + withenv("JULIA_NUM_GC_THREADS" => nt) do + @test read(`$exename --gcthreads=2,1 -e $code`, String) == "3" + end end - end - withenv("JULIA_NUM_GC_THREADS" => 2) do - @test read(`$exename -e $code`, String) == "2" - end + withenv("JULIA_NUM_GC_THREADS" => 2) do + @test read(`$exename -e $code`, String) == "2" + end - withenv("JULIA_NUM_GC_THREADS" => "2,1") do - @test read(`$exename -e $code`, String) == "3" + withenv("JULIA_NUM_GC_THREADS" => "2,1") do + @test read(`$exename -e $code`, String) == "3" + end end # --machine-file @@ -1182,6 +1186,10 @@ end end end +# FIXME: Issue #57103: MMTK currently does not use --heap-size-hint since it only +# supports setting up a hard limit unlike the Stock GC +# which takes it as a soft limit. For now, we skip the tests below for MMTk +@static if Base.USING_STOCK_GC @testset "heap size hint" begin #heap-size-hint, we reserve 250 MB for non GC memory (llvm, etc.) @test readchomp(`$(Base.julia_cmd()) --startup-file=no --heap-size-hint=500M -e "println(@ccall jl_gc_get_max_memory()::UInt64)"`) == "$((500-250)*1024*1024)" @@ -1201,6 +1209,7 @@ end @test readchomp(`$(Base.julia_cmd()) --startup-file=no --heap-size-hint=10M -e "println(@ccall jl_gc_get_max_memory()::UInt64)"`) == "$(1*1024*1024)" end +end ## `Main.main` entrypoint diff --git a/test/gc.jl b/test/gc.jl index c532f17f04eb5..3e9f03ef40d92 100644 --- a/test/gc.jl +++ b/test/gc.jl @@ -67,6 +67,9 @@ end run_gctest("gc/chunks.jl") end +#FIXME: Issue #57103 disabling tests for MMTk, since +# they rely on information that is specific to the stock GC. +@static if Base.USING_STOCK_GC @testset "GC page metrics" begin run_nonzero_page_utilization_test() run_pg_size_test() @@ -76,13 +79,14 @@ end issue_54275_test() end -@testset "Base.GC docstrings" begin - @test isempty(Docs.undocumented_names(GC)) -end - @testset "Full GC reasons" begin full_sweep_reasons_test() end +end + +@testset "Base.GC docstrings" begin + @test isempty(Docs.undocumented_names(GC)) +end #testset doesn't work here because this needs to run in top level #Check that we ensure objects in toplevel exprs are rooted diff --git a/test/misc.jl b/test/misc.jl index 7070fd49f5f36..070952db89032 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -1453,7 +1453,8 @@ end @test_throws ErrorException finalizer(x->nothing, 1) @test_throws ErrorException finalizer(C_NULL, 1) - +# FIXME: Issue #57103 Test is specific to Stock GC +@static if Base.USING_STOCK_GC @testset "GC utilities" begin GC.gc() GC.gc(true); GC.gc(false) @@ -1473,6 +1474,7 @@ end @test occursin("GC: pause", read(tmppath, String)) end end +end @testset "fieldtypes Module" begin @test fieldtypes(Module) === () From 246e408757170fb2b600454a853a80777934c88e Mon Sep 17 00:00:00 2001 From: Sam Schweigel <33556084+xal-0@users.noreply.github.com> Date: Fri, 24 Jan 2025 16:28:53 -0800 Subject: [PATCH 238/342] Fix JULIA_EXCLUSIVE setting affinity on non-worker threads (#57136) With JULIA_EXCLUSIVE=1, we would try to give both worker and interactive threads an exclusive CPU, causing --threads=auto to produce a "Too many threads requested" error. Fixes #50702. --- doc/src/manual/environment-variables.md | 7 +++-- src/init.c | 4 +-- src/julia.h | 3 ++ src/threading.c | 42 +++++++++++++++---------- test/threads.jl | 6 ++-- 5 files changed, 40 insertions(+), 22 deletions(-) diff --git a/doc/src/manual/environment-variables.md b/doc/src/manual/environment-variables.md index b3bfa5204e603..ff505db1f11f2 100644 --- a/doc/src/manual/environment-variables.md +++ b/doc/src/manual/environment-variables.md @@ -397,8 +397,11 @@ during image compilation. Defaults to 0. ### [`JULIA_EXCLUSIVE`](@id JULIA_EXCLUSIVE) If set to anything besides `0`, then Julia's thread policy is consistent with -running on a dedicated machine: the master thread is on proc 0, and threads are -affinitized. Otherwise, Julia lets the operating system handle thread policy. +running on a dedicated machine: each thread in the default threadpool is +affinitized. [Interactive threads](@ref man-threadpools) remain under the +control of the operating system scheduler. + +Otherwise, Julia lets the operating system handle thread policy. ## Garbage Collection diff --git a/src/init.c b/src/init.c index e69467c75bd73..f383a8f4620be 100644 --- a/src/init.c +++ b/src/init.c @@ -907,8 +907,8 @@ static NOINLINE void _finish_julia_init(JL_IMAGE_SEARCH rel, jl_ptls_t ptls, jl_ jl_n_markthreads = 0; jl_n_sweepthreads = 0; jl_n_gcthreads = 0; - jl_n_threads_per_pool[0] = 0; // Interactive threadpool - jl_n_threads_per_pool[1] = 1; // Default threadpool + jl_n_threads_per_pool[JL_THREADPOOL_ID_INTERACTIVE] = 0; + jl_n_threads_per_pool[JL_THREADPOOL_ID_DEFAULT] = 1; } else { post_image_load_hooks(); } diff --git a/src/julia.h b/src/julia.h index 4c699ba059c65..1088f669ad773 100644 --- a/src/julia.h +++ b/src/julia.h @@ -2053,6 +2053,9 @@ extern JL_DLLIMPORT _Atomic(int) jl_n_threads; extern JL_DLLIMPORT int jl_n_gcthreads; extern int jl_n_markthreads; extern int jl_n_sweepthreads; + +#define JL_THREADPOOL_ID_INTERACTIVE 0 +#define JL_THREADPOOL_ID_DEFAULT 1 extern JL_DLLIMPORT int *jl_n_threads_per_pool; // environment entries diff --git a/src/threading.c b/src/threading.c index 77956786af3f4..ab63114fc9c8f 100644 --- a/src/threading.c +++ b/src/threading.c @@ -778,9 +778,9 @@ void jl_init_threading(void) } jl_all_tls_states_size = nthreads + nthreadsi + ngcthreads; - jl_n_threads_per_pool = (int*)malloc_s(2 * sizeof(int)); - jl_n_threads_per_pool[0] = nthreadsi; - jl_n_threads_per_pool[1] = nthreads; + jl_n_threads_per_pool = (int*)calloc_s(jl_n_threadpools * sizeof(int)); + jl_n_threads_per_pool[JL_THREADPOOL_ID_INTERACTIVE] = nthreadsi; + jl_n_threads_per_pool[JL_THREADPOOL_ID_DEFAULT] = nthreads; assert(jl_all_tls_states_size > 0); jl_atomic_store_release(&jl_all_tls_states, (jl_ptls_t*)calloc(jl_all_tls_states_size, sizeof(jl_ptls_t))); jl_atomic_store_release(&jl_n_threads, jl_all_tls_states_size); @@ -793,7 +793,10 @@ uv_barrier_t thread_init_done; void jl_start_threads(void) { int nthreads = jl_atomic_load_relaxed(&jl_n_threads); - int ngcthreads = jl_n_gcthreads; + int ninteractive_threads = jl_n_threads_per_pool[JL_THREADPOOL_ID_INTERACTIVE]; + int ndefault_threads = jl_n_threads_per_pool[JL_THREADPOOL_ID_DEFAULT]; + int nmutator_threads = nthreads - jl_n_gcthreads; + int cpumasksize = uv_cpumask_size(); char *cp; int i, exclusive; @@ -808,36 +811,43 @@ void jl_start_threads(void) if (cp && strcmp(cp, "0") != 0) exclusive = 1; - // exclusive use: affinitize threads, master thread on proc 0, rest - // according to a 'compact' policy + // exclusive use: affinitize threads, master thread on proc 0, threads in + // default pool according to a 'compact' policy // non-exclusive: no affinity settings; let the kernel move threads about if (exclusive) { - if (nthreads > jl_cpu_threads()) { + if (ndefault_threads > jl_cpu_threads()) { jl_printf(JL_STDERR, "ERROR: Too many threads requested for %s option.\n", MACHINE_EXCLUSIVE_NAME); exit(1); } memset(mask, 0, cpumasksize); - mask[0] = 1; - uvtid = uv_thread_self(); - uv_thread_setaffinity(&uvtid, mask, NULL, cpumasksize); - mask[0] = 0; + + // If there are no interactive threads, the master thread is in the + // default pool and we must affinitize it + if (ninteractive_threads == 0) { + mask[0] = 1; + uvtid = uv_thread_self(); + uv_thread_setaffinity(&uvtid, mask, NULL, cpumasksize); + mask[0] = 0; + } } // create threads uv_barrier_init(&thread_init_done, nthreads); // GC/System threads need to be after the worker threads. - int nmutator_threads = nthreads - ngcthreads; - for (i = 1; i < nmutator_threads; ++i) { jl_threadarg_t *t = (jl_threadarg_t *)malloc_s(sizeof(jl_threadarg_t)); // ownership will be passed to the thread t->tid = i; t->barrier = &thread_init_done; uv_thread_create(&uvtid, jl_threadfun, t); - if (exclusive) { - mask[i] = 1; + + // Interactive pool threads get the low IDs, so check if this is a + // default pool thread. The master thread is already on CPU 0. + if (exclusive && i >= ninteractive_threads) { + assert(i - ninteractive_threads < cpumasksize); + mask[i - ninteractive_threads] = 1; uv_thread_setaffinity(&uvtid, mask, NULL, cpumasksize); - mask[i] = 0; + mask[i - ninteractive_threads] = 0; } uv_thread_detach(&uvtid); } diff --git a/test/threads.jl b/test/threads.jl index 179279dbab4e6..43fbea1e351a2 100644 --- a/test/threads.jl +++ b/test/threads.jl @@ -123,10 +123,11 @@ if AFFINITY_SUPPORTED end end -function get_nthreads(options = ``; cpus = nothing) +function get_nthreads(options = ``; cpus = nothing, exclusive = false) cmd = `$(Base.julia_cmd()) --startup-file=no $(options)` cmd = `$cmd -e "print(Threads.threadpoolsize())"` - cmd = addenv(cmd, "JULIA_EXCLUSIVE" => "0", "JULIA_NUM_THREADS" => "auto") + cmd = addenv(cmd, "JULIA_EXCLUSIVE" => exclusive ? "1" : "0", + "JULIA_NUM_THREADS" => "auto") if cpus !== nothing cmd = setcpuaffinity(cmd, cpus) end @@ -138,6 +139,7 @@ end allowed_cpus = findall(uv_thread_getaffinity()) if length(allowed_cpus) ≥ 2 @test get_nthreads() ≥ 2 + @test get_nthreads(exclusive = true) ≥ 2 @test get_nthreads(cpus = allowed_cpus[1:1]) == 1 @test get_nthreads(cpus = allowed_cpus[2:2]) == 1 @test get_nthreads(cpus = allowed_cpus[1:2]) == 2 From 6cd750ddf75a2069e6bea8c84b243e76edfcf815 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sat, 25 Jan 2025 03:50:41 +0100 Subject: [PATCH 239/342] bpart: Give a warning when accessing a backdated const binding (#57133) This implements the strategy proposed in https://github.com/JuliaLang/julia/pull/57102#issuecomment-2605511266. Example: ``` julia> function foo(i) eval(:(const x = $i)) x end foo (generic function with 1 method) julia> foo(1) WARNING: Detected access to binding Main.x in a world prior to its definition world. Julia 1.12 has introduced more strict world age semantics for global bindings. !!! This code may malfunction under Revise. !!! This code will error in future versions of Julia. Hint: Add an appropriate `invokelatest` around the access to this binding. 1 ``` The warning is triggered once per binding to avoid spamming for repeated access. --- Compiler/src/Compiler.jl | 3 +- Compiler/src/abstractinterpretation.jl | 5 ++ Compiler/src/ssair/slot2ssa.jl | 4 -- Compiler/src/ssair/verify.jl | 11 +++- Compiler/test/invalidation.jl | 2 +- base/Base_compiler.jl | 4 ++ base/boot.jl | 8 ++- base/docs/bindings.jl | 4 +- base/runtime_internals.jl | 3 +- base/show.jl | 17 +++--- doc/src/manual/methods.md | 5 +- src/codegen.cpp | 3 +- src/julia.h | 22 +++++--- src/julia_internal.h | 12 +++- src/module.c | 77 +++++++++++++++++++++----- src/rtutils.c | 6 +- src/toplevel.c | 23 +++++--- stdlib/REPL/src/REPL.jl | 4 +- stdlib/Test/src/Test.jl | 21 ++++--- test/worlds.jl | 8 +-- 20 files changed, 171 insertions(+), 71 deletions(-) diff --git a/Compiler/src/Compiler.jl b/Compiler/src/Compiler.jl index ea939f86422c5..b83dc0b5970e1 100644 --- a/Compiler/src/Compiler.jl +++ b/Compiler/src/Compiler.jl @@ -49,7 +49,8 @@ using Core: ABIOverride, Builtin, CodeInstance, IntrinsicFunction, MethodInstanc using Base using Base: @_foldable_meta, @_gc_preserve_begin, @_gc_preserve_end, @nospecializeinfer, - BINDING_KIND_GLOBAL, BINDING_KIND_UNDEF_CONST, Base, BitVector, Bottom, Callable, DataTypeFieldDesc, + BINDING_KIND_GLOBAL, BINDING_KIND_UNDEF_CONST, BINDING_KIND_BACKDATED_CONST, + Base, BitVector, Bottom, Callable, DataTypeFieldDesc, EffectsOverride, Filter, Generator, IteratorSize, JLOptions, NUM_EFFECTS_OVERRIDES, OneTo, Ordering, RefValue, SizeUnknown, _NAMEDTUPLE_NAME, _array_for, _bits_findnext, _methods_by_ftype, _uniontypes, all, allocatedinline, any, diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index 2b1a7fb2dd448..dbd7e76615116 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -3524,6 +3524,11 @@ function abstract_eval_partition_load(interp::AbstractInterpreter, partition::Co end if is_defined_const_binding(kind) + if kind == BINDING_KIND_BACKDATED_CONST + # Infer this as guard. We do not want a later const definition to retroactively improve + # inference results in an earlier world. + return RTEffects(Any, UndefVarError, generic_getglobal_effects) + end rt = Const(partition_restriction(partition)) return RTEffects(rt, Union{}, Effects(EFFECTS_TOTAL, inaccessiblememonly=is_mutation_free_argtype(rt) ? ALWAYS_TRUE : ALWAYS_FALSE)) end diff --git a/Compiler/src/ssair/slot2ssa.jl b/Compiler/src/ssair/slot2ssa.jl index 80dffdab23243..e0f3e207789a3 100644 --- a/Compiler/src/ssair/slot2ssa.jl +++ b/Compiler/src/ssair/slot2ssa.jl @@ -137,10 +137,6 @@ function fixemup!(@specialize(slot_filter), @specialize(rename_slot), ir::IRCode return nothing end op[] = x - elseif isa(val, GlobalRef) && !(isdefined(val.mod, val.name) && isconst(val.mod, val.name)) - typ = typ_for_val(val, ci, ir, idx, Any[]) - new_inst = NewInstruction(val, typ) - op[] = NewSSAValue(insert_node!(ir, idx, new_inst).id - length(ir.stmts)) elseif isexpr(val, :static_parameter) ty = typ_for_val(val, ci, ir, idx, Any[]) if isa(ty, Const) diff --git a/Compiler/src/ssair/verify.jl b/Compiler/src/ssair/verify.jl index fa16bdcc7ab19..779a28afe9f56 100644 --- a/Compiler/src/ssair/verify.jl +++ b/Compiler/src/ssair/verify.jl @@ -121,7 +121,7 @@ function verify_ir(ir::IRCode, print::Bool=true, if mi !== nothing push!(error_args, "\n", " Method instance: ", mi) end - error(error_args...) + invokelatest(error, error_args...) end # Verify CFG graph. Must be well formed to construct domtree if !(length(ir.cfg.blocks) - 1 <= length(ir.cfg.index) <= length(ir.cfg.blocks)) @@ -380,6 +380,15 @@ function verify_ir(ir::IRCode, print::Bool=true, # undefined GlobalRef is OK in isdefined continue end + elseif stmt.head === :throw_undef_if_not + if length(stmt.args) > 3 + @verify_error "malformed throw_undef_if_not" + raise_error() + end + if stmt.args[1] isa GlobalRef + # undefined GlobalRef is OK in throw_undef_if_not + continue + end elseif stmt.head === :gc_preserve_end # We allow gc_preserve_end tokens to span across try/catch # blocks, which isn't allowed for regular SSA values, so diff --git a/Compiler/test/invalidation.jl b/Compiler/test/invalidation.jl index 2642c1647a682..b77c7677e6987 100644 --- a/Compiler/test/invalidation.jl +++ b/Compiler/test/invalidation.jl @@ -55,7 +55,7 @@ let mi = Base.method_instance(basic_caller, (Float64,)) end # this redefinition below should invalidate the cache -const BASIC_CALLER_WORLD = Base.get_world_counter() +const BASIC_CALLER_WORLD = Base.get_world_counter()+1 basic_callee(x) = x, x @test !isdefined(Base.method_instance(basic_callee, (Float64,)), :cache) let mi = Base.method_instance(basic_caller, (Float64,)) diff --git a/base/Base_compiler.jl b/base/Base_compiler.jl index db3ebb0232e38..abeec81f0c028 100644 --- a/base/Base_compiler.jl +++ b/base/Base_compiler.jl @@ -257,6 +257,10 @@ using .Order include("coreir.jl") include("invalidation.jl") +# Because lowering inserts direct references, it is mandatory for this binding +# to exist before we start inferring code. +function string end + # For OS specific stuff # We need to strcat things here, before strings are really defined function strcat(x::String, y::String) diff --git a/base/boot.jl b/base/boot.jl index 53e439d83ebe2..9b386f90d4abe 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -383,9 +383,10 @@ struct StackOverflowError <: Exception end struct UndefRefError <: Exception end struct UndefVarError <: Exception var::Symbol + world::UInt scope # a Module or Symbol or other object describing the context where this variable was looked for (e.g. Main or :local or :static_parameter) - UndefVarError(var::Symbol) = new(var) - UndefVarError(var::Symbol, @nospecialize scope) = new(var, scope) + UndefVarError(var::Symbol) = new(var, ccall(:jl_get_tls_world_age, UInt, ())) + UndefVarError(var::Symbol, @nospecialize scope) = new(var, ccall(:jl_get_tls_world_age, UInt, ()), scope) end struct ConcurrencyViolationError <: Exception msg::AbstractString @@ -717,7 +718,8 @@ macro __doc__(x) end isbasicdoc(@nospecialize x) = (isa(x, Expr) && x.head === :.) || isa(x, Union{QuoteNode, Symbol}) -iscallexpr(ex::Expr) = (isa(ex, Expr) && ex.head === :where) ? iscallexpr(ex.args[1]) : (isa(ex, Expr) && ex.head === :call) +firstarg(arg1, args...) = arg1 +iscallexpr(ex::Expr) = (isa(ex, Expr) && ex.head === :where) ? iscallexpr(firstarg(ex.args...)) : (isa(ex, Expr) && ex.head === :call) iscallexpr(ex) = false function ignoredoc(source, mod, str, expr) (isbasicdoc(expr) || iscallexpr(expr)) && return Expr(:escape, nothing) diff --git a/base/docs/bindings.jl b/base/docs/bindings.jl index 6095d52a28e5a..5c65a35659f81 100644 --- a/base/docs/bindings.jl +++ b/base/docs/bindings.jl @@ -16,8 +16,8 @@ end bindingexpr(x) = Expr(:call, Binding, splitexpr(x)...) -defined(b::Binding) = isdefined(b.mod, b.var) -resolve(b::Binding) = getfield(b.mod, b.var) +defined(b::Binding) = invokelatest(isdefined, b.mod, b.var) +resolve(b::Binding) = invokelatest(getfield, b.mod, b.var) function splitexpr(x::Expr) isexpr(x, :macrocall) ? splitexpr(x.args[1]) : diff --git a/base/runtime_internals.jl b/base/runtime_internals.jl index 964e8063dd5af..b61e24c11f3f9 100644 --- a/base/runtime_internals.jl +++ b/base/runtime_internals.jl @@ -229,8 +229,9 @@ const BINDING_KIND_FAILED = 0x6 const BINDING_KIND_DECLARED = 0x7 const BINDING_KIND_GUARD = 0x8 const BINDING_KIND_UNDEF_CONST = 0x9 +const BINDING_KIND_BACKDATED_CONST = 0xa -is_defined_const_binding(kind::UInt8) = (kind == BINDING_KIND_CONST || kind == BINDING_KIND_CONST_IMPORT) +is_defined_const_binding(kind::UInt8) = (kind == BINDING_KIND_CONST || kind == BINDING_KIND_CONST_IMPORT || kind == BINDING_KIND_BACKDATED_CONST) is_some_const_binding(kind::UInt8) = (is_defined_const_binding(kind) || kind == BINDING_KIND_UNDEF_CONST) is_some_imported(kind::UInt8) = (kind == BINDING_KIND_IMPLICIT || kind == BINDING_KIND_EXPLICIT || kind == BINDING_KIND_IMPORTED) is_some_guard(kind::UInt8) = (kind == BINDING_KIND_GUARD || kind == BINDING_KIND_DECLARED || kind == BINDING_KIND_FAILED || kind == BINDING_KIND_UNDEF_CONST) diff --git a/base/show.jl b/base/show.jl index de45ca07e3131..42788f05eceb5 100644 --- a/base/show.jl +++ b/base/show.jl @@ -35,7 +35,7 @@ function _isself(ft::DataType) isdefined(ftname, :mt) || return false name = ftname.mt.name mod = parentmodule(ft) # NOTE: not necessarily the same as ft.name.mt.module - return isdefined(mod, name) && ft == typeof(getfield(mod, name)) + return invokelatest(isdefinedglobal, mod, name) && ft == typeof(invokelatest(getglobal, mod, name)) end function show(io::IO, ::MIME"text/plain", f::Function) @@ -542,8 +542,8 @@ function show_function(io::IO, f::Function, compact::Bool, fallback::Function) fallback(io, f) elseif compact print(io, mt.name) - elseif isdefined(mt, :module) && isdefined(mt.module, mt.name) && - getfield(mt.module, mt.name) === f + elseif isdefined(mt, :module) && isdefinedglobal(mt.module, mt.name) && + getglobal(mt.module, mt.name) === f # this used to call the removed internal function `is_exported_from_stdlib`, which effectively # just checked for exports from Core and Base. mod = get(io, :module, UsesCoreAndBaseOnly) @@ -1025,15 +1025,15 @@ function isvisible(sym::Symbol, parent::Module, from::Module) from_owner = ccall(:jl_binding_owner, Ptr{Cvoid}, (Any, Any), from, sym) return owner !== C_NULL && from_owner === owner && !isdeprecated(parent, sym) && - isdefined(from, sym) # if we're going to return true, force binding resolution + isdefinedglobal(from, sym) # if we're going to return true, force binding resolution end function is_global_function(tn::Core.TypeName, globname::Union{Symbol,Nothing}) if globname !== nothing globname_str = string(globname::Symbol) if ('#' ∉ globname_str && '@' ∉ globname_str && isdefined(tn, :module) && - isbindingresolved(tn.module, globname) && isdefined(tn.module, globname) && - isconcretetype(tn.wrapper) && isa(getfield(tn.module, globname), tn.wrapper)) + isbindingresolved(tn.module, globname) && isdefinedglobal(tn.module, globname) && + isconcretetype(tn.wrapper) && isa(getglobal(tn.module, globname), tn.wrapper)) return true end end @@ -3364,7 +3364,10 @@ function print_partition(io::IO, partition::Core.BindingPartition) end print(io, " - ") kind = binding_kind(partition) - if is_defined_const_binding(kind) + if kind == BINDING_KIND_BACKDATED_CONST + print(io, "backdated constant binding to ") + print(io, partition_restriction(partition)) + elseif is_defined_const_binding(kind) print(io, "constant binding to ") print(io, partition_restriction(partition)) elseif kind == BINDING_KIND_UNDEF_CONST diff --git a/doc/src/manual/methods.md b/doc/src/manual/methods.md index 3c234b17f10d8..e448c62465b0d 100644 --- a/doc/src/manual/methods.md +++ b/doc/src/manual/methods.md @@ -587,12 +587,13 @@ In the example above, we see that the "current world" (in which the method `newf is one greater than the task-local "runtime world" that was fixed when the execution of `tryeval` started. Sometimes it is necessary to get around this (for example, if you are implementing the above REPL). -Fortunately, there is an easy solution: call the function using [`Base.invokelatest`](@ref): +Fortunately, there is an easy solution: call the function using [`Base.invokelatest`](@ref) or +the macro version [`Base.@invokelatest`](@ref): ```jldoctest julia> function tryeval2() @eval newfun2() = 2 - Base.invokelatest(newfun2) + @invokelatest newfun2() end tryeval2 (generic function with 1 method) diff --git a/src/codegen.cpp b/src/codegen.cpp index 60e53f75638ed..19ee1e9161152 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3469,7 +3469,8 @@ static jl_cgval_t emit_globalref(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t * break; pku = jl_atomic_load_acquire(&bpart->restriction); } - if (bpart && jl_bkind_is_some_constant(decode_restriction_kind(pku))) { + enum jl_partition_kind kind = decode_restriction_kind(pku); + if (bpart && (jl_bkind_is_some_constant(kind) && kind != BINDING_KIND_BACKDATED_CONST)) { jl_value_t *constval = decode_restriction_value(pku); if (!constval) { undef_var_error_ifnot(ctx, ConstantInt::get(getInt1Ty(ctx.builder.getContext()), 0), name, (jl_value_t*)mod); diff --git a/src/julia.h b/src/julia.h index 1088f669ad773..f36133088119f 100644 --- a/src/julia.h +++ b/src/julia.h @@ -647,7 +647,10 @@ enum jl_partition_kind { // Undef Constant: This binding partition is a constant declared using `const`, but // without a value. // ->restriction is NULL - BINDING_KIND_UNDEF_CONST = 0x9 + BINDING_KIND_UNDEF_CONST = 0x9, + // Backated constant. A constant that was backdated for compatibility. In all other + // ways equivalent to BINDING_KIND_CONST, but prints a warning on access + BINDING_KIND_BACKDATED_CONST = 0xa, }; #ifdef _P64 @@ -693,7 +696,7 @@ typedef struct _jl_binding_t { jl_globalref_t *globalref; // cached GlobalRef for this binding _Atomic(jl_value_t*) value; _Atomic(jl_binding_partition_t*) partitions; - uint8_t declared:1; + uint8_t did_print_backdate_admonition:1; uint8_t exportp:1; // `public foo` sets `publicp`, `export foo` sets both `publicp` and `exportp` uint8_t publicp:1; // exportp without publicp is not allowed. uint8_t deprecated:2; // 0=not deprecated, 1=renamed, 2=moved to another package @@ -2025,10 +2028,6 @@ JL_DLLEXPORT void jl_module_public(jl_module_t *from, jl_sym_t *s, int exported) JL_DLLEXPORT int jl_is_imported(jl_module_t *m, jl_sym_t *s); JL_DLLEXPORT int jl_module_exports_p(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT void jl_add_standard_imports(jl_module_t *m); -STATIC_INLINE jl_function_t *jl_get_function(jl_module_t *m, const char *name) -{ - return (jl_function_t*)jl_get_global(m, jl_symbol(name)); -} // eq hash tables JL_DLLEXPORT jl_genericmemory_t *jl_eqtable_put(jl_genericmemory_t *h JL_ROOTING_ARGUMENT, jl_value_t *key, jl_value_t *val JL_ROOTED_ARGUMENT, int *inserted); @@ -2590,9 +2589,18 @@ typedef struct { } jl_nullable_float32_t; #define jl_root_task (jl_current_task->ptls->root_task) - JL_DLLEXPORT jl_task_t *jl_get_current_task(void) JL_GLOBALLY_ROOTED JL_NOTSAFEPOINT; +STATIC_INLINE jl_function_t *jl_get_function(jl_module_t *m, const char *name) +{ + jl_task_t *ct = jl_get_current_task(); + size_t last_world = ct->world_age; + ct->world_age = jl_get_world_counter(); + jl_value_t *r = jl_get_global(m, jl_symbol(name)); + ct->world_age = last_world; + return (jl_function_t*)r; +} + // TODO: we need to pin the task while using this (set pure bit) JL_DLLEXPORT jl_jmp_buf *jl_get_safe_restore(void) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_set_safe_restore(jl_jmp_buf *) JL_NOTSAFEPOINT; diff --git a/src/julia_internal.h b/src/julia_internal.h index 0da6d412c8a49..a838b75e506a2 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -933,6 +933,10 @@ EXTERN_INLINE_DECLARE enum jl_partition_kind decode_restriction_kind(jl_ptr_kind if (bits == BINDING_KIND_CONST) { return BINDING_KIND_UNDEF_CONST; } + } else { + if (bits == BINDING_KIND_DECLARED) { + return BINDING_KIND_BACKDATED_CONST; + } } return (enum jl_partition_kind)bits; @@ -956,12 +960,14 @@ STATIC_INLINE jl_ptr_kind_union_t encode_restriction(jl_value_t *val, enum jl_pa #ifdef _P64 if (kind == BINDING_KIND_GUARD || kind == BINDING_KIND_DECLARED || kind == BINDING_KIND_FAILED || kind == BINDING_KIND_UNDEF_CONST) assert(val == NULL); - else if (kind == BINDING_KIND_IMPLICIT || kind == BINDING_KIND_CONST) + else if (kind == BINDING_KIND_IMPLICIT || kind == BINDING_KIND_CONST || kind == BINDING_KIND_BACKDATED_CONST) assert(val != NULL); if (kind == BINDING_KIND_GUARD) kind = BINDING_KIND_IMPLICIT; else if (kind == BINDING_KIND_UNDEF_CONST) kind = BINDING_KIND_CONST; + else if (kind == BINDING_KIND_BACKDATED_CONST) + kind = BINDING_KIND_DECLARED; assert((((uintptr_t)val) & 0x7) == 0); return ((jl_ptr_kind_union_t)val) | kind; #else @@ -975,11 +981,11 @@ STATIC_INLINE int jl_bkind_is_some_import(enum jl_partition_kind kind) JL_NOTSAF } STATIC_INLINE int jl_bkind_is_some_constant(enum jl_partition_kind kind) JL_NOTSAFEPOINT { - return kind == BINDING_KIND_CONST || kind == BINDING_KIND_CONST_IMPORT || kind == BINDING_KIND_UNDEF_CONST; + return kind == BINDING_KIND_CONST || kind == BINDING_KIND_CONST_IMPORT || kind == BINDING_KIND_UNDEF_CONST || kind == BINDING_KIND_BACKDATED_CONST; } STATIC_INLINE int jl_bkind_is_defined_constant(enum jl_partition_kind kind) JL_NOTSAFEPOINT { - return kind == BINDING_KIND_CONST || kind == BINDING_KIND_CONST_IMPORT; + return kind == BINDING_KIND_CONST || kind == BINDING_KIND_CONST_IMPORT || kind == BINDING_KIND_BACKDATED_CONST; } STATIC_INLINE int jl_bkind_is_some_guard(enum jl_partition_kind kind) JL_NOTSAFEPOINT { diff --git a/src/module.c b/src/module.c index be6779727bfdc..f4c56e19efa61 100644 --- a/src/module.c +++ b/src/module.c @@ -241,6 +241,7 @@ static jl_binding_t *new_binding(jl_module_t *mod, jl_sym_t *name) b->exportp = 0; b->publicp = 0; b->deprecated = 0; + b->did_print_backdate_admonition = 0; JL_GC_PUSH1(&b); b->globalref = jl_new_globalref(mod, name, b); jl_gc_wb(b, b->globalref); @@ -322,14 +323,37 @@ JL_DLLEXPORT jl_module_t *jl_get_module_of_binding(jl_module_t *m, jl_sym_t *var return b->globalref->mod; // TODO: deprecate this? } +static NOINLINE void print_backdate_admonition(jl_binding_t *b) JL_NOTSAFEPOINT +{ + jl_safe_printf( + "WARNING: Detected access to binding `%s.%s` in a world prior to its definition world.\n" + " Julia 1.12 has introduced more strict world age semantics for global bindings.\n" + " !!! This code may malfunction under Revise.\n" + " !!! This code will error in future versions of Julia.\n" + "Hint: Add an appropriate `invokelatest` around the access to this binding.\n", + jl_symbol_name(b->globalref->mod->name), jl_symbol_name(b->globalref->name)); + b->did_print_backdate_admonition = 1; +} + +static inline void check_backdated_binding(jl_binding_t *b, enum jl_partition_kind kind) JL_NOTSAFEPOINT +{ + if (__unlikely(kind == BINDING_KIND_BACKDATED_CONST) && + !b->did_print_backdate_admonition) { + print_backdate_admonition(b); + } +} + JL_DLLEXPORT jl_value_t *jl_get_binding_value(jl_binding_t *b) { jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); jl_ptr_kind_union_t pku = jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); - if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) + enum jl_partition_kind kind = decode_restriction_kind(pku); + if (jl_bkind_is_some_guard(kind)) return NULL; - if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) + if (jl_bkind_is_some_constant(kind)) { + check_backdated_binding(b, kind); return decode_restriction_value(pku); + } return jl_atomic_load_relaxed(&b->value); } @@ -337,10 +361,13 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_seqcst(jl_binding_t *b) { jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); jl_ptr_kind_union_t pku = jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); - if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) + enum jl_partition_kind kind = decode_restriction_kind(pku); + if (jl_bkind_is_some_guard(kind)) return NULL; - if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) + if (jl_bkind_is_some_constant(kind)) { + check_backdated_binding(b, kind); return decode_restriction_value(pku); + } return jl_atomic_load(&b->value); } @@ -348,10 +375,12 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_const(jl_binding_t *b) { jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); jl_ptr_kind_union_t pku = jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); - if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) + enum jl_partition_kind kind = decode_restriction_kind(pku); + if (jl_bkind_is_some_guard(kind)) return NULL; - if (!jl_bkind_is_some_constant(decode_restriction_kind(pku))) + if (!jl_bkind_is_some_constant(kind)) return NULL; + check_backdated_binding(b, kind); return decode_restriction_value(pku); } @@ -368,10 +397,12 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_resolved_and_const(jl_binding_t if (bpart->min_world > jl_current_task->world_age || jl_current_task->world_age > max_world) return NULL; jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) + enum jl_partition_kind kind = decode_restriction_kind(pku); + if (jl_bkind_is_some_guard(kind)) return NULL; - if (!jl_bkind_is_some_constant(decode_restriction_kind(pku))) + if (!jl_bkind_is_some_constant(kind)) return NULL; + check_backdated_binding(b, kind); return decode_restriction_value(pku); } @@ -388,12 +419,15 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_resolved(jl_binding_t *b) if (bpart->min_world > jl_current_task->world_age || jl_current_task->world_age > max_world) return NULL; jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) + enum jl_partition_kind kind = decode_restriction_kind(pku); + if (jl_bkind_is_some_guard(kind)) return NULL; - if (jl_bkind_is_some_import(decode_restriction_kind(pku))) + if (jl_bkind_is_some_import(kind)) return NULL; - if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) + if (jl_bkind_is_some_constant(kind)) { + check_backdated_binding(b, kind); return decode_restriction_value(pku); + } return jl_atomic_load_relaxed(&b->value); } @@ -895,13 +929,26 @@ JL_DLLEXPORT int jl_boundp(jl_module_t *m, jl_sym_t *var, int allow_import) // u jl_binding_t *b = jl_get_module_binding(m, var, allow_import); if (!b) return 0; + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + if (!bpart) + return 0; + jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); if (!allow_import) { - jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - if (!bpart || jl_bkind_is_some_import(decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)))) + if (!bpart || jl_bkind_is_some_import(decode_restriction_kind(pku))) return 0; - return jl_get_binding_value(b) != NULL; + } else { + if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) { + jl_resolve_owner(b, b->globalref->mod, b->globalref->name, NULL, jl_current_task->world_age); + } + pku = jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); + } + if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) + return 0; + if (jl_bkind_is_defined_constant(decode_restriction_kind(pku))) { + // N.B.: No backdated check for isdefined + return 1; } - return jl_reresolve_binding_value_seqcst(b) != NULL; + return jl_atomic_load(&b->value) != NULL; } JL_DLLEXPORT int jl_defines_or_exports_p(jl_module_t *m, jl_sym_t *var) diff --git a/src/rtutils.c b/src/rtutils.c index 00a5b639d8683..6515b80c5d2b5 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -148,8 +148,10 @@ JL_DLLEXPORT void JL_NORETURN jl_undefined_var_error(jl_sym_t *var, jl_value_t * } jl_errorf("UndefVarError(%s%s%s)", jl_symbol_name(var), s1, s2); } - JL_GC_PUSH1(&scope); - jl_throw(jl_new_struct(jl_undefvarerror_type, var, scope)); + jl_value_t *active_age = NULL; + JL_GC_PUSH2(&scope, &active_age); + active_age = jl_box_long(jl_current_task->world_age); + jl_throw(jl_new_struct(jl_undefvarerror_type, var, active_age, scope)); } JL_DLLEXPORT void JL_NORETURN jl_has_no_field_error(jl_datatype_t *t, jl_sym_t *var) diff --git a/src/toplevel.c b/src/toplevel.c index dee9029e2feb7..30e78bf813fc8 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -669,7 +669,7 @@ static void import_module(jl_module_t *JL_NONNULL m, jl_module_t *import, jl_sym if (decode_restriction_kind(pku) != BINDING_KIND_GUARD && decode_restriction_kind(pku) != BINDING_KIND_FAILED) { // Unlike regular constant declaration, we allow this as long as we eventually end up at a constant. pku = jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); - if (decode_restriction_kind(pku) == BINDING_KIND_CONST || decode_restriction_kind(pku) == BINDING_KIND_CONST_IMPORT) { + if (decode_restriction_kind(pku) == BINDING_KIND_CONST || decode_restriction_kind(pku) == BINDING_KIND_BACKDATED_CONST || decode_restriction_kind(pku) == BINDING_KIND_CONST_IMPORT) { // Already declared (e.g. on another thread) or imported. if (decode_restriction_value(pku) == (jl_value_t*)import) return; @@ -770,6 +770,12 @@ JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val3( jl_symbol_name(var)); did_warn = 1; } + if (new_world > bpart->min_world) { + // TODO: Invoke invalidation logic here + jl_atomic_store_relaxed(&bpart->max_world, new_world - 1); + bpart = jl_get_binding_partition(b, new_world); + pku = jl_atomic_load_relaxed(&bpart->restriction); + } } else if (!jl_bkind_is_some_guard(decode_restriction_kind(pku))) { if (jl_bkind_is_some_import(decode_restriction_kind(pku))) { jl_errorf("cannot declare %s.%s constant; it was already declared as an import", @@ -779,15 +785,16 @@ JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val3( jl_symbol_name(mod->name), jl_symbol_name(var)); } } - if (jl_atomic_cmpswap(&bpart->restriction, &pku, encode_restriction(val, constant_kind))) { - jl_gc_wb(bpart, val); - break; + if (!jl_atomic_cmpswap(&bpart->restriction, &pku, encode_restriction(val, constant_kind))) { + continue; } - } - // N.B.: This backdates the first definition of the constant to world age 0 for backwards compatibility - // TODO: Mark this specially with a separate partition. - if (bpart->min_world != 0) + jl_gc_wb(bpart, val); + int needs_backdate = bpart->min_world == 0 && new_world && val; bpart->min_world = new_world; + if (needs_backdate) { + jl_declare_constant_val3(b, mod, var, val, BINDING_KIND_BACKDATED_CONST, 0); + } + } JL_GC_POP(); return bpart; } diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index 6c3f4bd4ba73a..f83fa867748af 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -33,9 +33,9 @@ function UndefVarError_hint(io::IO, ex::UndefVarError) if isdefined(ex, :scope) scope = ex.scope if scope isa Module - bpart = Base.lookup_binding_partition(Base.get_world_counter(), GlobalRef(scope, var)) + bpart = Base.lookup_binding_partition(ex.world, GlobalRef(scope, var)) kind = Base.binding_kind(bpart) - if kind === Base.BINDING_KIND_GLOBAL || kind === Base.BINDING_KIND_CONST || kind == Base.BINDING_KIND_DECLARED + if kind === Base.BINDING_KIND_GLOBAL || kind === Base.BINDING_KIND_UNDEF_CONST || kind == Base.BINDING_KIND_DECLARED print(io, "\nSuggestion: add an appropriate import or assignment. This global was declared but not assigned.") elseif kind === Base.BINDING_KIND_FAILED print(io, "\nHint: It looks like two or more modules export different ", diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index 79fdb89399d42..88fd055f7bd58 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -783,6 +783,19 @@ end const MACROEXPAND_LIKE = Symbol.(("@macroexpand", "@macroexpand1", "macroexpand")) +function isequalexception(@nospecialize(a), @nospecialize(b)) + for fld in 1:nfields(b) + if !isequal(getfield(a, fld), getfield(b, fld)) + return false + end + end + return true +end +function isequalexception(a::UndefVarError, b::UndefVarError) + # Ignore different world ages + return isequal(a.var, b.var) && isequal(a.scope, b.scope) +end + # An internal function, called by the code generated by @test_throws # to evaluate and catch the thrown exception - if it exists function do_test_throws(result::ExecutionResult, orig_expr, extype) @@ -817,13 +830,7 @@ function do_test_throws(result::ExecutionResult, orig_expr, extype) if isa(extype, UndefVarError) && !isdefined(extype, :scope) success = exc isa UndefVarError && exc.var == extype.var else isa(exc, typeof(extype)) - success = true - for fld in 1:nfields(extype) - if !isequal(getfield(extype, fld), getfield(exc, fld)) - success = false - break - end - end + success = isequalexception(exc, extype) end else message_only = true diff --git a/test/worlds.jl b/test/worlds.jl index 8bc96f8303aef..025aaba6cea4f 100644 --- a/test/worlds.jl +++ b/test/worlds.jl @@ -115,15 +115,15 @@ wc265_41332a = Task(tls_world_age) global wc265_41332d = Task(tls_world_age) nothing end)() -@test wc265 + 3 == get_world_counter() == tls_world_age() +@test wc265 + 4 == get_world_counter() == tls_world_age() schedule(wc265_41332a) schedule(wc265_41332b) schedule(wc265_41332c) schedule(wc265_41332d) @test wc265 == fetch(wc265_41332a) -@test wc265 + 1 == fetch(wc265_41332b) -@test wc265 + 3 == fetch(wc265_41332c) -@test wc265 + 1 == fetch(wc265_41332d) +@test wc265 + 2 == fetch(wc265_41332b) +@test wc265 + 4 == fetch(wc265_41332c) +@test wc265 + 2 == fetch(wc265_41332d) chnls, tasks = Base.channeled_tasks(2, wfunc) t265 = tasks[1] From 0625b3a0a661b869b24bb025b5ce2d5db94e8040 Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Sun, 26 Jan 2025 19:47:07 -0500 Subject: [PATCH 240/342] Add `Experimental.wait_with_timeout` (#57148) Remove the `timeout` parameter to `wait(::Condition)` added in https://github.com/JuliaLang/julia/pull/56974 and add this logic to `Experimental.wait_with_timeout`. --------- Co-authored-by: Jameson Nash Co-authored-by: Nick Robinson --- base/condition.jl | 90 ++--------------------------------- base/experimental.jl | 109 +++++++++++++++++++++++++++++++++++++++++++ test/channels.jl | 7 ++- 3 files changed, 115 insertions(+), 91 deletions(-) diff --git a/base/condition.jl b/base/condition.jl index 90c53b7ad310d..fd771c9be346a 100644 --- a/base/condition.jl +++ b/base/condition.jl @@ -125,104 +125,20 @@ proceeding. """ function wait end -# wait with timeout -# -# The behavior of wait changes if a timeout is specified. There are -# three concurrent entities that can interact: -# 1. Task W: the task that calls wait w/timeout. -# 2. Task T: the task created to handle a timeout. -# 3. Task N: the task that notifies the Condition being waited on. -# -# Typical flow: -# - W enters the Condition's wait queue. -# - W creates T and stops running (calls wait()). -# - T, when scheduled, waits on a Timer. -# - Two common outcomes: -# - N notifies the Condition. -# - W starts running, closes the Timer, sets waiter_left and returns -# the notify'ed value. -# - The closed Timer throws an EOFError to T which simply ends. -# - The Timer expires. -# - T starts running and locks the Condition. -# - T confirms that waiter_left is unset and that W is still in the -# Condition's wait queue; it then removes W from the wait queue, -# sets dosched to true and unlocks the Condition. -# - If dosched is true, T schedules W with the special :timed_out -# value. -# - T ends. -# - W runs and returns :timed_out. -# -# Some possible interleavings: -# - N notifies the Condition but the Timer expires and T starts running -# before W: -# - W closing the expired Timer is benign. -# - T will find that W is no longer in the Condition's wait queue -# (which is protected by a lock) and will not schedule W. -# - N notifies the Condition; W runs and calls wait on the Condition -# again before the Timer expires: -# - W sets waiter_left before leaving. When T runs, it will find that -# waiter_left is set and will not schedule W. -# -# The lock on the Condition's wait queue and waiter_left together -# ensure proper synchronization and behavior of the tasks involved. - """ - wait(c::GenericCondition; first::Bool=false, timeout::Real=0.0) + wait(c::GenericCondition; first::Bool=false) Wait for [`notify`](@ref) on `c` and return the `val` parameter passed to `notify`. If the keyword `first` is set to `true`, the waiter will be put _first_ in line to wake up on `notify`. Otherwise, `wait` has first-in-first-out (FIFO) behavior. - -If `timeout` is specified, cancel the `wait` when it expires and return -`:timed_out`. The minimum value for `timeout` is 0.001 seconds, i.e. 1 -millisecond. """ -function wait(c::GenericCondition; first::Bool=false, timeout::Real=0.0) - timeout == 0.0 || timeout ≥ 1e-3 || throw(ArgumentError("timeout must be ≥ 1 millisecond")) - +function wait(c::GenericCondition; first::Bool=false) ct = current_task() _wait2(c, ct, first) token = unlockall(c.lock) - - timer::Union{Timer, Nothing} = nothing - waiter_left::Union{Threads.Atomic{Bool}, Nothing} = nothing - if timeout > 0.0 - timer = Timer(timeout) - waiter_left = Threads.Atomic{Bool}(false) - # start a task to wait on the timer - t = Task() do - try - wait(timer) - catch e - # if the timer was closed, the waiting task has been scheduled; do nothing - e isa EOFError && return - end - dosched = false - lock(c.lock) - # Confirm that the waiting task is still in the wait queue and remove it. If - # the task is not in the wait queue, it must have been notified already so we - # don't do anything here. - if !waiter_left[] && ct.queue == c.waitq - dosched = true - Base.list_deletefirst!(c.waitq, ct) - end - unlock(c.lock) - # send the waiting task a timeout - dosched && schedule(ct, :timed_out) - end - t.sticky = false - Threads._spawn_set_thrpool(t, :interactive) - schedule(t) - end - try - res = wait() - if timer !== nothing - close(timer) - waiter_left[] = true - end - return res + return wait() catch q = ct.queue; q === nothing || Base.list_deletefirst!(q::IntrusiveLinkedList{Task}, ct) rethrow() diff --git a/base/experimental.jl b/base/experimental.jl index 17871b4f346d6..e35e920298c3d 100644 --- a/base/experimental.jl +++ b/base/experimental.jl @@ -10,6 +10,7 @@ module Experimental using Base: Threads, sync_varname, is_function_def, @propagate_inbounds +using Base: GenericCondition using Base.Meta """ @@ -577,4 +578,112 @@ function task_wall_time_ns(t::Task=current_task()) return end_at - start_at end +# wait_with_timeout +# +# A version of `wait(c::Condition)` that additionally allows the +# specification of a timeout. This is experimental as it will likely +# be dropped when a cancellation framework is added. +# +# The parallel behavior of wait_with_timeout is specified here. There +# are three concurrent entities that can interact: +# 1. Task W: the task that calls wait_with_timeout. +# 2. Task T: the task created to handle a timeout. +# 3. Task N: the task that notifies the Condition being waited on. +# +# Typical flow: +# - W enters the Condition's wait queue. +# - W creates T and stops running (calls wait()). +# - T, when scheduled, waits on a Timer. +# - Two common outcomes: +# - N notifies the Condition. +# - W starts running, closes the Timer, sets waiter_left and returns +# the notify'ed value. +# - The closed Timer throws an EOFError to T which simply ends. +# - The Timer expires. +# - T starts running and locks the Condition. +# - T confirms that waiter_left is unset and that W is still in the +# Condition's wait queue; it then removes W from the wait queue, +# sets dosched to true and unlocks the Condition. +# - If dosched is true, T schedules W with the special :timed_out +# value. +# - T ends. +# - W runs and returns :timed_out. +# +# Some possible interleavings: +# - N notifies the Condition but the Timer expires and T starts running +# before W: +# - W closing the expired Timer is benign. +# - T will find that W is no longer in the Condition's wait queue +# (which is protected by a lock) and will not schedule W. +# - N notifies the Condition; W runs and calls wait on the Condition +# again before the Timer expires: +# - W sets waiter_left before leaving. When T runs, it will find that +# waiter_left is set and will not schedule W. +# +# The lock on the Condition's wait queue and waiter_left together +# ensure proper synchronization and behavior of the tasks involved. + +""" + wait_with_timeout(c::GenericCondition; first::Bool=false, timeout::Real=0.0) + +Wait for [`notify`](@ref) on `c` and return the `val` parameter passed to `notify`. + +If the keyword `first` is set to `true`, the waiter will be put _first_ +in line to wake up on `notify`. Otherwise, `wait` has first-in-first-out (FIFO) behavior. + +If `timeout` is specified, cancel the `wait` when it expires and return +`:timed_out`. The minimum value for `timeout` is 0.001 seconds, i.e. 1 +millisecond. +""" +function wait_with_timeout(c::GenericCondition; first::Bool=false, timeout::Real=0.0) + ct = current_task() + Base._wait2(c, ct, first) + token = Base.unlockall(c.lock) + + timer::Union{Timer, Nothing} = nothing + waiter_left::Union{Threads.Atomic{Bool}, Nothing} = nothing + if timeout > 0.0 + timer = Timer(timeout) + waiter_left = Threads.Atomic{Bool}(false) + # start a task to wait on the timer + t = Task() do + try + wait(timer) + catch e + # if the timer was closed, the waiting task has been scheduled; do nothing + e isa EOFError && return + end + dosched = false + lock(c.lock) + # Confirm that the waiting task is still in the wait queue and remove it. If + # the task is not in the wait queue, it must have been notified already so we + # don't do anything here. + if !waiter_left[] && ct.queue == c.waitq + dosched = true + Base.list_deletefirst!(c.waitq, ct) + end + unlock(c.lock) + # send the waiting task a timeout + dosched && schedule(ct, :timed_out) + end + t.sticky = false + Threads._spawn_set_thrpool(t, :interactive) + schedule(t) + end + + try + res = wait() + if timer !== nothing + close(timer) + waiter_left[] = true + end + return res + catch + q = ct.queue; q === nothing || Base.list_deletefirst!(q::IntrusiveLinkedList{Task}, ct) + rethrow() + finally + Base.relockall(c.lock, token) + end +end + end # module diff --git a/test/channels.jl b/test/channels.jl index 6e74a2079234c..d654bc63be586 100644 --- a/test/channels.jl +++ b/test/channels.jl @@ -40,16 +40,15 @@ end @test fetch(t) == "finished" end -@testset "timed wait on Condition" begin +@testset "wait_with_timeout on Condition" begin a = Threads.Condition() - @test_throws ArgumentError @lock a wait(a; timeout=0.0005) - @test @lock a wait(a; timeout=0.1)==:timed_out + @test @lock a Experimental.wait_with_timeout(a; timeout=0.1)==:timed_out lock(a) @spawn begin @lock a notify(a) end @test try - wait(a; timeout=2) + Experimental.wait_with_timeout(a; timeout=2) true finally unlock(a) From 47a6ad0b2adbcee14274a1c1375d3940745ef4ba Mon Sep 17 00:00:00 2001 From: Eduardo Souza Date: Tue, 28 Jan 2025 03:47:20 +1100 Subject: [PATCH 241/342] Adding stock gc heap resizing heuristics to MMTk (#57147) This PR sets MMTk to use the stock GC heuristics for heap resizing by default. It also updates the `mmtk-julia` version to incorporate the changes that support the new gc triggering heuristics (see https://github.com/mmtk/mmtk-julia/pull/222). --- contrib/refresh_checksums.mk | 2 +- deps/checksums/mmtk_julia | 4 +++ deps/mmtk_julia.version | 6 ++-- src/gc-mmtk.c | 54 ++++++++++++++++++++++++++++-------- 4 files changed, 50 insertions(+), 16 deletions(-) diff --git a/contrib/refresh_checksums.mk b/contrib/refresh_checksums.mk index 5a787b0b67cb1..fa7cddc705958 100644 --- a/contrib/refresh_checksums.mk +++ b/contrib/refresh_checksums.mk @@ -24,7 +24,7 @@ CLANG_TRIPLETS=$(filter %-darwin %-freebsd,$(TRIPLETS)) NON_CLANG_TRIPLETS=$(filter-out %-darwin %-freebsd,$(TRIPLETS)) # These are the projects currently using BinaryBuilder; both GCC-expanded and non-GCC-expanded: -BB_PROJECTS=openssl libssh2 nghttp2 mpfr curl libgit2 pcre libuv unwind llvmunwind dsfmt objconv p7zip zlib libsuitesparse openlibm blastrampoline libtracyclient +BB_PROJECTS=openssl libssh2 nghttp2 mpfr curl libgit2 pcre libuv unwind llvmunwind dsfmt objconv p7zip zlib libsuitesparse openlibm blastrampoline libtracyclient mmtk_julia BB_GCC_EXPANDED_PROJECTS=openblas csl BB_CXX_EXPANDED_PROJECTS=gmp llvm clang llvm-tools lld # These are non-BB source-only deps diff --git a/deps/checksums/mmtk_julia b/deps/checksums/mmtk_julia index 979ab79e52207..098937aea1991 100644 --- a/deps/checksums/mmtk_julia +++ b/deps/checksums/mmtk_julia @@ -4,3 +4,7 @@ mmtk_julia-f07d66aafc86af84ea988b35335acc9bbc770fa1.tar.gz/md5/38afb5db6d8c55413 mmtk_julia-f07d66aafc86af84ea988b35335acc9bbc770fa1.tar.gz/sha512/78525582a46a6baf8d33df7b622e55cf244439afcd7192ba55489c1bc18393d1237d2903d517c610484bf9e2a7338ad31435a9cbf70889d6bcf87c40cec829e5 mmtk_julia.v0.30.3+1.x86_64-linux-gnu.tar.gz/md5/631b204574da7062802dac501a4b711f mmtk_julia.v0.30.3+1.x86_64-linux-gnu.tar.gz/sha512/daaed59d08fc49621479ed638dea0aac0cba123986e486571447e8e21e9a098776ce2e87fbd92ddea276782fc44621f23d40fa213296b28e1d4480553c7de4f7 +mmtk_julia-c9e046baf3a0d52fe75d6c8b28f6afd69b045d95.tar.gz/md5/73a8fbea71edce30a39a30f31969dd8e +mmtk_julia-c9e046baf3a0d52fe75d6c8b28f6afd69b045d95.tar.gz/sha512/374848b7696b565dea66daa208830581f92c1fcb0138e7a7ab88564402e94bc79c54b6ed370ec68473e31e2bd411bf82c97793796c31d39aafbbfffea9c05588 +mmtk_julia.v0.30.4+0.x86_64-linux-gnu.tar.gz/md5/8cdeb14fd69945f64308be49f6912f9c +mmtk_julia.v0.30.4+0.x86_64-linux-gnu.tar.gz/sha512/3692502f65dec8c0971b56b9bf8178641892b390d520cbcd69880d75b7500e6341534d87882246e68998f590f824ec54c18f4b8fb4aa09b8f313de065c48450e diff --git a/deps/mmtk_julia.version b/deps/mmtk_julia.version index cb1e8064f9825..684197bbe3e4e 100644 --- a/deps/mmtk_julia.version +++ b/deps/mmtk_julia.version @@ -1,6 +1,6 @@ MMTK_JULIA_BRANCH = master -MMTK_JULIA_SHA1 = f07d66aafc86af84ea988b35335acc9bbc770fa1 +MMTK_JULIA_SHA1 = c9e046baf3a0d52fe75d6c8b28f6afd69b045d95 MMTK_JULIA_GIT_URL := https://github.com/mmtk/mmtk-julia.git -MMTK_JULIA_TAR_URL = https://github.com/mmtk/mmtk-julia/archive/refs/tags/v0.30.3.tar.gz -MMTK_JULIA_JLL_VER := 0.30.3+1 +MMTK_JULIA_TAR_URL = https://github.com/mmtk/mmtk-julia/archive/refs/tags/v0.30.4.tar.gz +MMTK_JULIA_JLL_VER := 0.30.4+0 MMTK_JULIA_JLL_NAME := mmtk_julia diff --git a/src/gc-mmtk.c b/src/gc-mmtk.c index 5ec1e34cc1acd..2f261a2e8e2fd 100644 --- a/src/gc-mmtk.c +++ b/src/gc-mmtk.c @@ -64,11 +64,37 @@ void jl_gc_init(void) { arraylist_new(&to_finalize, 0); arraylist_new(&finalizer_list_marked, 0); - + gc_num.interval = default_collect_interval; gc_num.allocd = 0; gc_num.max_pause = 0; gc_num.max_memory = 0; + // Necessary if we want to use Julia heap resizing heuristics + uint64_t mem_reserve = 250*1024*1024; // LLVM + other libraries need some amount of memory + uint64_t min_heap_size_hint = mem_reserve + 1*1024*1024; + uint64_t hint = jl_options.heap_size_hint; + + // check if heap size specified on command line + if (jl_options.heap_size_hint == 0) { + char *cp = getenv(HEAP_SIZE_HINT); + if (cp) + hint = parse_heap_size_hint(cp, "JULIA_HEAP_SIZE_HINT=\"[]\""); + } +#ifdef _P64 + if (hint == 0) { + uint64_t constrained_mem = uv_get_constrained_memory(); + if (constrained_mem > 0 && constrained_mem < uv_get_total_memory()) + hint = constrained_mem; + } +#endif + if (hint) { + if (hint < min_heap_size_hint) + hint = min_heap_size_hint; + jl_gc_set_max_memory(hint - mem_reserve); + } + + // MMTK supports setting the heap size using the + // MMTK_MIN_HSIZE and MMTK_MAX_HSIZE environment variables long long min_heap_size; long long max_heap_size; char* min_size_def = getenv("MMTK_MIN_HSIZE"); @@ -77,7 +103,8 @@ void jl_gc_init(void) { char* max_size_def = getenv("MMTK_MAX_HSIZE"); char* max_size_gb = getenv("MMTK_MAX_HSIZE_G"); - // default min heap currently set as Julia's default_collect_interval + // If min and max values are not specified, set them to 0 here + // and use stock heuristics as defined in the binding if (min_size_def != NULL) { char *p; double min_size = strtod(min_size_def, &p); @@ -87,10 +114,9 @@ void jl_gc_init(void) { double min_size = strtod(min_size_gb, &p); min_heap_size = (long) 1024 * 1024 * 1024 * min_size; } else { - min_heap_size = default_collect_interval; + min_heap_size = 0; } - // default max heap currently set as 70% the free memory in the system if (max_size_def != NULL) { char *p; double max_size = strtod(max_size_def, &p); @@ -100,7 +126,7 @@ void jl_gc_init(void) { double max_size = strtod(max_size_gb, &p); max_heap_size = (long) 1024 * 1024 * 1024 * max_size; } else { - max_heap_size = uv_get_free_memory() * 70 / 100; + max_heap_size = 0; } // Assert that the number of stock GC threads is 0; MMTK uses the number of threads in jl_options.ngcthreads @@ -159,7 +185,17 @@ void jl_free_thread_gc_state(struct _jl_tls_states_t *ptls) { } JL_DLLEXPORT void jl_gc_set_max_memory(uint64_t max_mem) { - // MMTk currently does not allow setting the heap size at runtime +#ifdef _P32 + max_mem = max_mem < MAX32HEAP ? max_mem : MAX32HEAP; +#endif + max_total_memory = max_mem; +} + +JL_DLLEXPORT uint64_t jl_gc_get_max_memory(void) +{ + // FIXME: We should return the max heap size set in MMTk + // when not using Julia's heap resizing heuristics + return max_total_memory; } STATIC_INLINE void maybe_collect(jl_ptls_t ptls) @@ -415,12 +451,6 @@ JL_DLLEXPORT void jl_gc_get_total_bytes(int64_t *bytes) JL_NOTSAFEPOINT *bytes = (num.total_allocd + num.deferred_alloc + num.allocd); } -JL_DLLEXPORT uint64_t jl_gc_get_max_memory(void) -{ - // FIXME: should probably return MMTk's heap size - return max_total_memory; -} - // These are needed to collect MMTk statistics from a Julia program using ccall JL_DLLEXPORT void (jl_mmtk_harness_begin)(void) { From cc3e7b67d6af2eaf4ff5d52d57a0bc63c5ec5da7 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Mon, 27 Jan 2025 13:25:59 -0500 Subject: [PATCH 242/342] Add option to use `@spawn :samepool` for using the same threadpool as the caller (#57109) --- NEWS.md | 2 ++ base/threadingconstructs.jl | 16 ++++++++++++---- test/threadpool_use.jl | 9 +++++++++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index 71014e1e57695..3aa74034ead54 100644 --- a/NEWS.md +++ b/NEWS.md @@ -23,6 +23,8 @@ New language features - actual running time for the task (`Base.Experimental.task_running_time_ns`), and - wall-time for the task (`Base.Experimental.task_wall_time_ns`). - Support for Unicode 16 ([#56925]). +- `Threads.@spawn` now takes a `:samepool` argument to specify the same threadpool as the caller. + `Threads.@spawn :samepool foo()` which is shorthand for `Threads.@spawn Threads.threadpool() foo()` ([#57109]) Language changes ---------------- diff --git a/base/threadingconstructs.jl b/base/threadingconstructs.jl index 3d86e203ef72e..b83f47ef7c8cd 100644 --- a/base/threadingconstructs.jl +++ b/base/threadingconstructs.jl @@ -440,10 +440,11 @@ function _spawn_set_thrpool(t::Task, tp::Symbol) end """ - Threads.@spawn [:default|:interactive] expr + Threads.@spawn [:default|:interactive|:samepool] expr Create a [`Task`](@ref) and [`schedule`](@ref) it to run on any available -thread in the specified threadpool (`:default` if unspecified). The task is +thread in the specified threadpool: `:default`, `:interactive`, or `:samepool` +to use the same as the caller. `:default` is used if unspecified. The task is allocated to a thread once one becomes available. To wait for the task to finish, call [`wait`](@ref) on the result of this macro, or call [`fetch`](@ref) to wait and then obtain its return value. @@ -468,6 +469,9 @@ the variable's value in the current task. !!! compat "Julia 1.9" A threadpool may be specified as of Julia 1.9. +!!! compat "Julia 1.12" + The same threadpool may be specified as of Julia 1.12. + # Examples ```julia-repl julia> t() = println("Hello from ", Threads.threadid()); @@ -486,7 +490,7 @@ macro spawn(args...) ttype, ex = args if ttype isa QuoteNode ttype = ttype.value - if ttype !== :interactive && ttype !== :default + if !in(ttype, (:interactive, :default, :samepool)) throw(ArgumentError(LazyString("unsupported threadpool in @spawn: ", ttype))) end tp = QuoteNode(ttype) @@ -507,7 +511,11 @@ macro spawn(args...) let $(letargs...) local task = Task($thunk) task.sticky = false - _spawn_set_thrpool(task, $(esc(tp))) + local tp = $(esc(tp)) + if tp == :samepool + tp = Threads.threadpool() + end + _spawn_set_thrpool(task, tp) if $(Expr(:islocal, var)) put!($var, task) end diff --git a/test/threadpool_use.jl b/test/threadpool_use.jl index 7523991fdf6a7..e76d50c7a3fd1 100644 --- a/test/threadpool_use.jl +++ b/test/threadpool_use.jl @@ -9,6 +9,15 @@ using Base.Threads @test fetch(Threads.@spawn Threads.threadpool()) === :default @test fetch(Threads.@spawn :default Threads.threadpool()) === :default @test fetch(Threads.@spawn :interactive Threads.threadpool()) === :interactive +@test fetch(Threads.@spawn :samepool Threads.threadpool()) === Threads.threadpool() +@sync for tp in [:interactive, :default] + Threads.@spawn tp begin + @test fetch(Threads.@spawn :samepool Threads.threadpool()) === Threads.threadpool() + end +end +wait(Threads.@spawn :interactive begin + @test fetch(Threads.@spawn :samepool Threads.threadpool()) === Threads.threadpool() +end) tp = :default @test fetch(Threads.@spawn tp Threads.threadpool()) === :default tp = :interactive From c19a6bb4c2512a33ee6cee52aa2e4175227cecb8 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Mon, 27 Jan 2025 14:56:43 -0500 Subject: [PATCH 243/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?Distributed=20stdlib=20from=20c613685=20to=208890288=20(#57169)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: IanButterworth <1694067+IanButterworth@users.noreply.github.com> --- .../md5 | 1 + .../sha512 | 1 + .../md5 | 1 - .../sha512 | 1 - stdlib/Distributed.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/Distributed-8890288f01a3b4c2b64c87d98409bc9d865f506e.tar.gz/md5 create mode 100644 deps/checksums/Distributed-8890288f01a3b4c2b64c87d98409bc9d865f506e.tar.gz/sha512 delete mode 100644 deps/checksums/Distributed-c6136853451677f1957bec20ecce13419cde3a12.tar.gz/md5 delete mode 100644 deps/checksums/Distributed-c6136853451677f1957bec20ecce13419cde3a12.tar.gz/sha512 diff --git a/deps/checksums/Distributed-8890288f01a3b4c2b64c87d98409bc9d865f506e.tar.gz/md5 b/deps/checksums/Distributed-8890288f01a3b4c2b64c87d98409bc9d865f506e.tar.gz/md5 new file mode 100644 index 0000000000000..3b640d12f3344 --- /dev/null +++ b/deps/checksums/Distributed-8890288f01a3b4c2b64c87d98409bc9d865f506e.tar.gz/md5 @@ -0,0 +1 @@ +7405afe10033da0431c8fd920a8cbbbf diff --git a/deps/checksums/Distributed-8890288f01a3b4c2b64c87d98409bc9d865f506e.tar.gz/sha512 b/deps/checksums/Distributed-8890288f01a3b4c2b64c87d98409bc9d865f506e.tar.gz/sha512 new file mode 100644 index 0000000000000..e9003e31edcba --- /dev/null +++ b/deps/checksums/Distributed-8890288f01a3b4c2b64c87d98409bc9d865f506e.tar.gz/sha512 @@ -0,0 +1 @@ +ad3498cfee95bcd088e47c15eb2707f47ced9493881ec356cbeb22f66207406d23a3e3b27e70a00be7c2c755c6651f54f5378ef42bf4d1312c84d589010aab7b diff --git a/deps/checksums/Distributed-c6136853451677f1957bec20ecce13419cde3a12.tar.gz/md5 b/deps/checksums/Distributed-c6136853451677f1957bec20ecce13419cde3a12.tar.gz/md5 deleted file mode 100644 index e1c0f9e87b7c7..0000000000000 --- a/deps/checksums/Distributed-c6136853451677f1957bec20ecce13419cde3a12.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -98b8b8bc0ea4bf24c4b2986a5b7ae3e9 diff --git a/deps/checksums/Distributed-c6136853451677f1957bec20ecce13419cde3a12.tar.gz/sha512 b/deps/checksums/Distributed-c6136853451677f1957bec20ecce13419cde3a12.tar.gz/sha512 deleted file mode 100644 index ed816ebc21e97..0000000000000 --- a/deps/checksums/Distributed-c6136853451677f1957bec20ecce13419cde3a12.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -4043933825bf716f2733f8e90632de34a95a437f3b31cda92edd510ffee208f8e374ec3c5922c8142342ae21b4ec4cbd1ecd4036b9057056a12c86169632ac7b diff --git a/stdlib/Distributed.version b/stdlib/Distributed.version index 4a7ab49defed2..13d49b7a093de 100644 --- a/stdlib/Distributed.version +++ b/stdlib/Distributed.version @@ -1,4 +1,4 @@ DISTRIBUTED_BRANCH = master -DISTRIBUTED_SHA1 = c6136853451677f1957bec20ecce13419cde3a12 +DISTRIBUTED_SHA1 = 8890288f01a3b4c2b64c87d98409bc9d865f506e DISTRIBUTED_GIT_URL := https://github.com/JuliaLang/Distributed.jl DISTRIBUTED_TAR_URL = https://api.github.com/repos/JuliaLang/Distributed.jl/tarball/$1 From 779b750e858effcdafe0b39357493d22de2fa404 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Mon, 27 Jan 2025 19:06:12 -0500 Subject: [PATCH 244/342] Use faster timeout on cmdlineargs test that relies on timeout (#57164) --- test/cmdlineargs.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index ec7a51e804d3f..efcdf52b68093 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -798,7 +798,10 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no` # --worker takes default / custom as argument (default/custom arguments # tested in test/parallel.jl) - @test errors_not_signals(`$exename --worker=true`) + # shorten the worker timeout as this test relies on it timing out + withenv("JULIA_WORKER_TIMEOUT" => "10") do + @test errors_not_signals(`$exename --worker=true`) + end # --trace-compile let From d5523b6698e88d540486098a336ec0de9934b138 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Mon, 27 Jan 2025 20:14:47 -0500 Subject: [PATCH 245/342] typeinfer: Enqueue CIs for `ccallable` entrypoints (#57158) This is another step in the long-term direction to have type-inference fully-explore the code graph we want to emit, largely side-stepping the vestigial `jl_type_infer` paths that we still have in type-inference for ccallable (and OpaqueClosure) This is needed for `juliac`, since the trim checks in codegen check if code was enqueued in the workqueue as expected. --------- Co-authored-by: Jameson Nash --- Compiler/src/typeinfer.jl | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index e3896870d82b8..dd6a55bfc9f1c 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -1280,8 +1280,20 @@ function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim:: ci isa CodeInstance && !use_const_api(ci) && push!(tocompile, ci) end elseif item isa SimpleVector - push!(codeinfos, item[1]::Type) - push!(codeinfos, item[2]::Type) + (rt::Type, sig::Type) = item + # make a best-effort attempt to enqueue the relevant code for the ccallable + ptr = ccall(:jl_get_specialization1, + #= MethodInstance =# Ptr{Cvoid}, (Any, Csize_t, Cint), + sig, this_world, #= mt_cache =# 0) + if ptr !== C_NULL + mi = unsafe_pointer_to_objref(ptr) + ci = typeinf_ext(interp, mi, SOURCE_MODE_NOT_REQUIRED) + ci isa CodeInstance && !use_const_api(ci) && push!(tocompile, ci) + end + # additionally enqueue the ccallable entrypoint / adapter, which implicitly + # invokes the above ci + push!(codeinfos, rt) + push!(codeinfos, sig) end end while !isempty(tocompile) From fbe865657942da7d73cc02f76064f9ba9cdef56c Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Mon, 27 Jan 2025 22:43:54 -0500 Subject: [PATCH 246/342] Default to 1 interactive thread (#57087) --- NEWS.md | 7 ++ base/channels.jl | 3 +- doc/src/manual/faq.md | 6 +- doc/src/manual/methods.md | 4 +- doc/src/manual/multi-threading.md | 24 +++++- src/jloptions.c | 25 +++--- src/threading.c | 13 +-- stdlib/REPL/test/replcompletions.jl | 4 +- test/gcext/gcext-test.jl | 2 +- test/gcext/gcext.c | 7 ++ test/threads.jl | 21 ++++- test/threads_exec.jl | 122 ++++++++++++++-------------- 12 files changed, 143 insertions(+), 95 deletions(-) diff --git a/NEWS.md b/NEWS.md index 3aa74034ead54..796fe9647fff0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -29,6 +29,13 @@ New language features Language changes ---------------- + - Julia now defaults to 1 "interactive" thread, in addition to the 1 "default" worker thread. i.e. `-t1,1` + This means in default configuration the main task and repl (when in interactive mode), which both run on + thread 1, now run within the `interactive` threadpool. Also the libuv IO loop runs on thread 1, + helping efficient utilization of the "default" worker threadpool, which is what `Threads.@threads` and a bare + `Threads.@spawn` uses. Use `0` to disable the interactive thread i.e. `-t1,0` or `JULIA_NUM_THREADS=1,0`, or + `-tauto,0` etc. The zero is explicitly required to disable it, `-t2` will set the equivalent of `-t2,1` ([#57087]) + - When methods are replaced with exactly equivalent ones, the old method is no longer deleted implicitly simultaneously, although the new method does take priority and become more specific than the old method. Thus if the new diff --git a/base/channels.jl b/base/channels.jl index 527c22b3d45fd..ef508bd40e3ed 100644 --- a/base/channels.jl +++ b/base/channels.jl @@ -130,8 +130,7 @@ julia> chnl = Channel{Char}(1, spawn=true) do ch for c in "hello world" put!(ch, c) end - end -Channel{Char}(1) (2 items available) + end; julia> String(collect(chnl)) "hello world" diff --git a/doc/src/manual/faq.md b/doc/src/manual/faq.md index 2673ca7532acf..178a674e46643 100644 --- a/doc/src/manual/faq.md +++ b/doc/src/manual/faq.md @@ -941,7 +941,7 @@ While the streaming I/O API is synchronous, the underlying implementation is ful Consider the printed output from the following: -```jldoctest +``` julia> @sync for i in 1:3 Threads.@spawn write(stdout, string(i), " Foo ", " Bar ") end @@ -954,7 +954,7 @@ yields to other tasks while waiting for that part of the I/O to complete. `print` and `println` "lock" the stream during a call. Consequently changing `write` to `println` in the above example results in: -```jldoctest +``` julia> @sync for i in 1:3 Threads.@spawn println(stdout, string(i), " Foo ", " Bar ") end @@ -965,7 +965,7 @@ julia> @sync for i in 1:3 You can lock your writes with a `ReentrantLock` like this: -```jldoctest +``` julia> l = ReentrantLock(); julia> @sync for i in 1:3 diff --git a/doc/src/manual/methods.md b/doc/src/manual/methods.md index e448c62465b0d..45d22e08aaffe 100644 --- a/doc/src/manual/methods.md +++ b/doc/src/manual/methods.md @@ -615,7 +615,7 @@ Start some other operations that use `f(x)`: julia> g(x) = f(x) g (generic function with 1 method) -julia> t = Threads.@spawn f(wait()); yield(); +julia> t = @async f(wait()); yield(); ``` Now we add some new methods to `f(x)`: @@ -640,7 +640,7 @@ julia> g(1) julia> fetch(schedule(t, 1)) "original definition" -julia> t = Threads.@spawn f(wait()); yield(); +julia> t = @async f(wait()); yield(); julia> fetch(schedule(t, 1)) "definition for Int" diff --git a/doc/src/manual/multi-threading.md b/doc/src/manual/multi-threading.md index 209e2ffe1da56..ec470f867cc47 100644 --- a/doc/src/manual/multi-threading.md +++ b/doc/src/manual/multi-threading.md @@ -5,11 +5,13 @@ of Julia multi-threading features. ## Starting Julia with multiple threads -By default, Julia starts up with a single thread of execution. This can be verified by using the -command [`Threads.nthreads()`](@ref): +By default, Julia starts up with 2 threads of execution; 1 worker thread and 1 interactive thread. +This can be verified by using the command [`Threads.nthreads()`](@ref): ```jldoctest -julia> Threads.nthreads() +julia> Threads.nthreads(:default) +1 +julia> Threads.nthreads(:interactive) 1 ``` @@ -22,6 +24,9 @@ The number of threads can either be specified as an integer (`--threads=4`) or a (`--threads=auto`), where `auto` tries to infer a useful default number of threads to use (see [Command-line Options](@ref command-line-interface) for more details). +See [threadpools](@ref man-threadpools) for how to control how many `:default` and `:interactive` threads are in +each threadpool. + !!! compat "Julia 1.5" The `-t`/`--threads` command line argument requires at least Julia 1.5. In older versions you must use the environment variable instead. @@ -29,6 +34,10 @@ The number of threads can either be specified as an integer (`--threads=4`) or a !!! compat "Julia 1.7" Using `auto` as value of the environment variable [`JULIA_NUM_THREADS`](@ref JULIA_NUM_THREADS) requires at least Julia 1.7. In older versions, this value is ignored. + +!!! compat "Julia 1.12" + Starting by default with 1 interactive thread, as well as the 1 worker thread, was made as such in Julia 1.12 + Lets start Julia with 4 threads: ```bash @@ -96,10 +105,17 @@ using Base.Threads Interactive tasks should avoid performing high latency operations, and if they are long duration tasks, should yield frequently. -Julia may be started with one or more threads reserved to run interactive tasks: +By default Julia starts with one interactive thread reserved to run interactive tasks, but that number can +be controlled with: ```bash $ julia --threads 3,1 +julia> Threads.nthreads(:interactive) +1 + +$ julia --threads 3,0 +julia> Threads.nthreads(:interactive) +0 ``` The environment variable [`JULIA_NUM_THREADS`](@ref JULIA_NUM_THREADS) can also be used similarly: diff --git a/src/jloptions.c b/src/jloptions.c index 2c5a9074eb465..ac515bea19845 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -623,8 +623,13 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) break; case 't': // threads errno = 0; - jl_options.nthreadpools = 1; - long nthreads = -1, nthreadsi = 0; + jl_options.nthreadpools = 2; + // By default: + // default threads = -1 (== "auto") + long nthreads = -1; + // interactive threads = 1, or 0 if generating output + long nthreadsi = jl_generating_output() ? 0 : 1; + if (!strncmp(optarg, "auto", 4)) { jl_options.nthreads = -1; if (optarg[4] == ',') { @@ -633,10 +638,9 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) else { errno = 0; nthreadsi = strtol(&optarg[5], &endptr, 10); - if (errno != 0 || endptr == &optarg[5] || *endptr != 0 || nthreadsi < 1 || nthreadsi >= INT16_MAX) - jl_errorf("julia: -t,--threads=auto,; m must be an integer >= 1"); + if (errno != 0 || endptr == &optarg[5] || *endptr != 0 || nthreadsi < 0 || nthreadsi >= INT16_MAX) + jl_errorf("julia: -t,--threads=auto,; m must be an integer >= 0"); } - jl_options.nthreadpools++; } } else { @@ -650,17 +654,18 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) errno = 0; char *endptri; nthreadsi = strtol(&endptr[1], &endptri, 10); - if (errno != 0 || endptri == &endptr[1] || *endptri != 0 || nthreadsi < 1 || nthreadsi >= INT16_MAX) - jl_errorf("julia: -t,--threads=,; n and m must be integers >= 1"); + // Allow 0 for interactive + if (errno != 0 || endptri == &endptr[1] || *endptri != 0 || nthreadsi < 0 || nthreadsi >= INT16_MAX) + jl_errorf("julia: -t,--threads=,; m must be an integer ≥ 0"); + if (nthreadsi == 0) + jl_options.nthreadpools = 1; } - jl_options.nthreadpools++; } jl_options.nthreads = nthreads + nthreadsi; } int16_t *ntpp = (int16_t *)malloc_s(jl_options.nthreadpools * sizeof(int16_t)); ntpp[0] = (int16_t)nthreads; - if (jl_options.nthreadpools == 2) - ntpp[1] = (int16_t)nthreadsi; + ntpp[1] = (int16_t)nthreadsi; jl_options.nthreads_per_pool = ntpp; break; case 'p': // procs diff --git a/src/threading.c b/src/threading.c index ab63114fc9c8f..a51916cdcd8d8 100644 --- a/src/threading.c +++ b/src/threading.c @@ -698,15 +698,15 @@ void jl_init_threading(void) // and `jl_n_threads_per_pool`. jl_n_threadpools = 2; int16_t nthreads = JULIA_NUM_THREADS; - int16_t nthreadsi = 0; + // if generating output default to 0 interactive threads, otherwise default to 1 + int16_t nthreadsi = jl_generating_output() ? 0 : 1; char *endptr, *endptri; if (jl_options.nthreads != 0) { // --threads specified nthreads = jl_options.nthreads_per_pool[0]; if (nthreads < 0) nthreads = jl_effective_threads(); - if (jl_options.nthreadpools == 2) - nthreadsi = jl_options.nthreads_per_pool[1]; + nthreadsi = (jl_options.nthreadpools == 1) ? 0 : jl_options.nthreads_per_pool[1]; } else if ((cp = getenv(NUM_THREADS_NAME))) { // ENV[NUM_THREADS_NAME] specified if (!strncmp(cp, "auto", 4)) { @@ -722,13 +722,16 @@ void jl_init_threading(void) } if (*cp == ',') { cp++; - if (!strncmp(cp, "auto", 4)) + if (!strncmp(cp, "auto", 4)) { nthreadsi = 1; + cp += 4; + } else { errno = 0; nthreadsi = strtol(cp, &endptri, 10); if (errno != 0 || endptri == cp || nthreadsi < 0) - nthreadsi = 0; + nthreadsi = 1; + cp = endptri; } } } diff --git a/stdlib/REPL/test/replcompletions.jl b/stdlib/REPL/test/replcompletions.jl index 2c8d48cc232cf..77d056b63655d 100644 --- a/stdlib/REPL/test/replcompletions.jl +++ b/stdlib/REPL/test/replcompletions.jl @@ -1187,7 +1187,7 @@ let s, c, r REPL.REPLCompletions.next_cache_update = 0 end c,r = test_scomplete(s) - wait(REPL.REPLCompletions.PATH_cache_task::Task) # wait for caching to complete + timedwait(()->REPL.REPLCompletions.next_cache_update != 0, 5) # wait for caching to complete c,r = test_scomplete(s) @test "tmp-executable" in c @test r == 1:9 @@ -1221,7 +1221,7 @@ let s, c, r REPL.REPLCompletions.next_cache_update = 0 end c,r = test_scomplete(s) - wait(REPL.REPLCompletions.PATH_cache_task::Task) # wait for caching to complete + timedwait(()->REPL.REPLCompletions.next_cache_update != 0, 5) # wait for caching to complete c,r = test_scomplete(s) @test ["repl-completion"] == c @test s[r] == "repl-completio" diff --git a/test/gcext/gcext-test.jl b/test/gcext/gcext-test.jl index 81637392e3c5d..86b6ad1a2ce59 100644 --- a/test/gcext/gcext-test.jl +++ b/test/gcext/gcext-test.jl @@ -31,7 +31,7 @@ end # @test success(p) errlines = fetch(err_task) lines = fetch(out_task) - @test length(errlines) == 0 + @test isempty(errlines) # @test length(lines) == 6 @test length(lines) == 5 @test checknum(lines[2], r"([0-9]+) full collections", n -> n >= 10) diff --git a/test/gcext/gcext.c b/test/gcext/gcext.c index d5bf91ec8c9ab..3da44a388a5b8 100644 --- a/test/gcext/gcext.c +++ b/test/gcext/gcext.c @@ -600,6 +600,13 @@ int main() jl_gc_set_cb_notify_external_alloc(alloc_bigval, 1); jl_gc_set_cb_notify_external_free(free_bigval, 1); + // single threaded mode + // Note: with -t1,1 a signal 10 occurs in task_scanner + jl_options.nthreadpools = 1; + jl_options.nthreads = 1; + int16_t ntpp[] = {jl_options.nthreads}; + jl_options.nthreads_per_pool = ntpp; + jl_init(); if (jl_gc_enable_conservative_gc_support() < 0) abort(); diff --git a/test/threads.jl b/test/threads.jl index 43fbea1e351a2..a1da408252fc4 100644 --- a/test/threads.jl +++ b/test/threads.jl @@ -72,11 +72,24 @@ let e = Event(true), started1 = Event(true), started2 = Event(true), done = Even end end -let cmd = `$(Base.julia_cmd()) --depwarn=error --rr-detach --startup-file=no threads_exec.jl` - for test_nthreads in (1, 2, 4, 4) # run once to try single-threaded mode, then try a couple times to trigger bad races + +let cmd1 = `$(Base.julia_cmd()) --depwarn=error --rr-detach --startup-file=no threads_exec.jl`, + cmd2 = `$(Base.julia_cmd()) --depwarn=error --rr-detach --startup-file=no -e 'print(Threads.threadpoolsize(:default), ",", Threads.threadpoolsize(:interactive))'` + for (test_nthreads, test_nthreadsi) in ( + (1, 0), + (1, 1), + (2, 0), + (2, 1), + (4, 0), + (4, 0)) # try a couple times to trigger bad races new_env = copy(ENV) - new_env["JULIA_NUM_THREADS"] = string(test_nthreads) - run(pipeline(setenv(cmd, new_env), stdout = stdout, stderr = stderr)) + new_env["JULIA_NUM_THREADS"] = string(test_nthreads, ",", test_nthreadsi) + run(pipeline(setenv(cmd1, new_env), stdout = stdout, stderr = stderr)) + threads_config = "$test_nthreads,$test_nthreadsi" + # threads set via env var + @test chomp(read(setenv(cmd2, new_env), String)) == threads_config + # threads set via -t + @test chomp(read(`$cmd2 -t$test_nthreads,$test_nthreadsi`, String)) == threads_config end end diff --git a/test/threads_exec.jl b/test/threads_exec.jl index 65e5ef57c911b..7091893908cb3 100644 --- a/test/threads_exec.jl +++ b/test/threads_exec.jl @@ -31,10 +31,11 @@ Timer(t -> killjob("KILLING BY THREAD TEST WATCHDOG\n"), 1200) @testset """threads_exec.jl with JULIA_NUM_THREADS == $(ENV["JULIA_NUM_THREADS"])""" begin @test Threads.threadid() == 1 -@test 1 <= threadpoolsize() <= Threads.maxthreadid() +@test threadpool() in (:interactive, :default) # thread 1 could be in the interactive pool +@test 1 <= threadpoolsize(:default) <= Threads.maxthreadid() # basic lock check -if threadpoolsize() > 1 +if threadpoolsize(:default) > 1 let lk = SpinLock() c1 = Base.Event() c2 = Base.Event() @@ -56,7 +57,18 @@ end # threading constructs -let a = zeros(Int, 2 * threadpoolsize()) +@testset "@threads and @spawn threadpools" begin + @threads for i in 1:1 + @test threadpool() == :default + end + @test fetch(Threads.@spawn threadpool()) == :default + @test fetch(Threads.@spawn :default threadpool()) == :default + if threadpoolsize(:interactive) > 0 + @test fetch(Threads.@spawn :interactive threadpool()) == :interactive + end +end + +let a = zeros(Int, 2 * threadpoolsize(:default)) @threads for i = 1:length(a) @sync begin @async begin @@ -76,7 +88,7 @@ end # parallel loop with parallel atomic addition function threaded_loop(a, r, x) - counter = Threads.Atomic{Int}(min(threadpoolsize(), length(r))) + counter = Threads.Atomic{Int}(min(threadpoolsize(:default), length(r))) @threads for i in r # synchronize the start given that each partition is started sequentially, # meaning that without the wait, if the loop is too fast the iteration can happen in order @@ -429,7 +441,7 @@ end for T in intersect((Int32, Int64, Float32, Float64), Base.Threads.atomictypes) var = Atomic{T}() nloops = 1000 - di = threadpoolsize() + di = threadpoolsize(:default) @threads for i in 1:di test_atomic_cas!(var, i:di:nloops) end @@ -519,13 +531,13 @@ function test_thread_cfunction() @test cfs[1] == cf1 @test cfs[2] == cf(fs[2]) @test length(unique(cfs)) == 1000 - ok = zeros(Int, threadpoolsize()) + ok = zeros(Int, threadpoolsize(:default)) @threads :static for i in 1:10000 i = mod1(i, 1000) fi = fs[i] cfi = cf(fi) GC.@preserve cfi begin - ok[threadid()] += (cfi === cfs[i]) + ok[threadid() - threadpoolsize(:interactive)] += (cfi === cfs[i]) end end @test sum(ok) == 10000 @@ -534,20 +546,6 @@ if cfunction_closure test_thread_cfunction() end -function test_thread_range() - a = zeros(Int, threadpoolsize()) - @threads for i in 1:threadid() - a[i] = 1 - end - for i in 1:threadid() - @test a[i] == 1 - end - for i in (threadid() + 1):threadpoolsize() - @test a[i] == 0 - end -end -test_thread_range() - # Thread safety of `jl_load_and_lookup`. function test_load_and_lookup_18020(n) @threads for i in 1:n @@ -582,17 +580,17 @@ test_nested_loops() function test_thread_too_few_iters() x = Atomic() - a = zeros(Int, threadpoolsize()+2) - threaded_loop(a, 1:threadpoolsize()-1, x) - found = zeros(Bool, threadpoolsize()+2) - for i=1:threadpoolsize()-1 + a = zeros(Int, threadpoolsize(:default)+2) + threaded_loop(a, 1:threadpoolsize(:default)-1, x) + found = zeros(Bool, threadpoolsize(:default)+2) + for i=1:threadpoolsize(:default)-1 found[a[i]] = true end - @test x[] == threadpoolsize()-1 + @test x[] == threadpoolsize(:default)-1 # Next test checks that all loop iterations ran, # and were unique (via pigeon-hole principle). - @test !(false in found[1:threadpoolsize()-1]) - @test !(true in found[threadpoolsize():end]) + @test !(false in found[1:threadpoolsize(:default)-1]) + @test !(true in found[threadpoolsize(:default):end]) end test_thread_too_few_iters() @@ -734,10 +732,10 @@ function _atthreads_with_error(a, err) end a end -@test_throws CompositeException _atthreads_with_error(zeros(threadpoolsize()), true) -let a = zeros(threadpoolsize()) +@test_throws CompositeException _atthreads_with_error(zeros(threadpoolsize(:default)), true) +let a = zeros(threadpoolsize(:default)) _atthreads_with_error(a, false) - @test a == [1:threadpoolsize();] + @test a == [threadpoolsize(:interactive) .+ (1:threadpoolsize(:default));] end # static schedule @@ -748,11 +746,11 @@ function _atthreads_static_schedule(n) end return ids end -@test _atthreads_static_schedule(threadpoolsize()) == 1:threadpoolsize() -@test _atthreads_static_schedule(1) == [1;] +@test _atthreads_static_schedule(threadpoolsize(:default)) == threadpoolsize(:interactive) .+ (1:threadpoolsize(:default)) +@test _atthreads_static_schedule(1) == [threadpoolsize(:interactive) + 1;] @test_throws( "`@threads :static` cannot be used concurrently or nested", - @threads(for i = 1:1; _atthreads_static_schedule(threadpoolsize()); end), + @threads(for i = 1:1; _atthreads_static_schedule(threadpoolsize(:default)); end), ) # dynamic schedule @@ -765,35 +763,35 @@ function _atthreads_dynamic_schedule(n) end return inc[], flags end -@test _atthreads_dynamic_schedule(threadpoolsize()) == (threadpoolsize(), ones(threadpoolsize())) +@test _atthreads_dynamic_schedule(threadpoolsize(:default)) == (threadpoolsize(:default), ones(threadpoolsize(:default))) @test _atthreads_dynamic_schedule(1) == (1, ones(1)) @test _atthreads_dynamic_schedule(10) == (10, ones(10)) -@test _atthreads_dynamic_schedule(threadpoolsize() * 2) == (threadpoolsize() * 2, ones(threadpoolsize() * 2)) +@test _atthreads_dynamic_schedule(threadpoolsize(:default) * 2) == (threadpoolsize(:default) * 2, ones(threadpoolsize(:default) * 2)) # nested dynamic schedule function _atthreads_dynamic_dynamic_schedule() inc = Threads.Atomic{Int}(0) - Threads.@threads :dynamic for _ = 1:threadpoolsize() - Threads.@threads :dynamic for _ = 1:threadpoolsize() + Threads.@threads :dynamic for _ = 1:threadpoolsize(:default) + Threads.@threads :dynamic for _ = 1:threadpoolsize(:default) Threads.atomic_add!(inc, 1) end end return inc[] end -@test _atthreads_dynamic_dynamic_schedule() == threadpoolsize() * threadpoolsize() +@test _atthreads_dynamic_dynamic_schedule() == threadpoolsize(:default) * threadpoolsize(:default) function _atthreads_static_dynamic_schedule() - ids = zeros(Int, threadpoolsize()) + ids = zeros(Int, threadpoolsize(:default)) inc = Threads.Atomic{Int}(0) - Threads.@threads :static for i = 1:threadpoolsize() + Threads.@threads :static for i = 1:threadpoolsize(:default) ids[i] = Threads.threadid() - Threads.@threads :dynamic for _ = 1:threadpoolsize() + Threads.@threads :dynamic for _ = 1:threadpoolsize(:default) Threads.atomic_add!(inc, 1) end end return ids, inc[] end -@test _atthreads_static_dynamic_schedule() == (1:threadpoolsize(), threadpoolsize() * threadpoolsize()) +@test _atthreads_static_dynamic_schedule() == (threadpoolsize(:interactive) .+ (1:threadpoolsize(:default)), threadpoolsize(:default) * threadpoolsize(:default)) # errors inside @threads :dynamic function _atthreads_dynamic_with_error(a) @@ -802,7 +800,7 @@ function _atthreads_dynamic_with_error(a) end a end -@test_throws "user error in the loop body" _atthreads_dynamic_with_error(zeros(threadpoolsize())) +@test_throws "user error in the loop body" _atthreads_dynamic_with_error(zeros(threadpoolsize(:default))) #### # :greedy @@ -817,57 +815,57 @@ function _atthreads_greedy_schedule(n) end return inc[], flags end -@test _atthreads_greedy_schedule(threadpoolsize()) == (threadpoolsize(), ones(threadpoolsize())) +@test _atthreads_greedy_schedule(threadpoolsize(:default)) == (threadpoolsize(:default), ones(threadpoolsize(:default))) @test _atthreads_greedy_schedule(1) == (1, ones(1)) @test _atthreads_greedy_schedule(10) == (10, ones(10)) -@test _atthreads_greedy_schedule(threadpoolsize() * 2) == (threadpoolsize() * 2, ones(threadpoolsize() * 2)) +@test _atthreads_greedy_schedule(threadpoolsize(:default) * 2) == (threadpoolsize(:default) * 2, ones(threadpoolsize(:default) * 2)) # nested greedy schedule function _atthreads_greedy_greedy_schedule() inc = Threads.Atomic{Int}(0) - Threads.@threads :greedy for _ = 1:threadpoolsize() - Threads.@threads :greedy for _ = 1:threadpoolsize() + Threads.@threads :greedy for _ = 1:threadpoolsize(:default) + Threads.@threads :greedy for _ = 1:threadpoolsize(:default) Threads.atomic_add!(inc, 1) end end return inc[] end -@test _atthreads_greedy_greedy_schedule() == threadpoolsize() * threadpoolsize() +@test _atthreads_greedy_greedy_schedule() == threadpoolsize(:default) * threadpoolsize(:default) function _atthreads_greedy_dynamic_schedule() inc = Threads.Atomic{Int}(0) - Threads.@threads :greedy for _ = 1:threadpoolsize() - Threads.@threads :dynamic for _ = 1:threadpoolsize() + Threads.@threads :greedy for _ = 1:threadpoolsize(:default) + Threads.@threads :dynamic for _ = 1:threadpoolsize(:default) Threads.atomic_add!(inc, 1) end end return inc[] end -@test _atthreads_greedy_dynamic_schedule() == threadpoolsize() * threadpoolsize() +@test _atthreads_greedy_dynamic_schedule() == threadpoolsize(:default) * threadpoolsize(:default) function _atthreads_dymamic_greedy_schedule() inc = Threads.Atomic{Int}(0) - Threads.@threads :dynamic for _ = 1:threadpoolsize() - Threads.@threads :greedy for _ = 1:threadpoolsize() + Threads.@threads :dynamic for _ = 1:threadpoolsize(:default) + Threads.@threads :greedy for _ = 1:threadpoolsize(:default) Threads.atomic_add!(inc, 1) end end return inc[] end -@test _atthreads_dymamic_greedy_schedule() == threadpoolsize() * threadpoolsize() +@test _atthreads_dymamic_greedy_schedule() == threadpoolsize(:default) * threadpoolsize(:default) function _atthreads_static_greedy_schedule() - ids = zeros(Int, threadpoolsize()) + ids = zeros(Int, threadpoolsize(:default)) inc = Threads.Atomic{Int}(0) - Threads.@threads :static for i = 1:threadpoolsize() + Threads.@threads :static for i = 1:threadpoolsize(:default) ids[i] = Threads.threadid() - Threads.@threads :greedy for _ = 1:threadpoolsize() + Threads.@threads :greedy for _ = 1:threadpoolsize(:default) Threads.atomic_add!(inc, 1) end end return ids, inc[] end -@test _atthreads_static_greedy_schedule() == (1:threadpoolsize(), threadpoolsize() * threadpoolsize()) +@test _atthreads_static_greedy_schedule() == (threadpoolsize(:interactive) .+ (1:threadpoolsize(:default)), threadpoolsize(:default) * threadpoolsize(:default)) # errors inside @threads :greedy function _atthreads_greedy_with_error(a) @@ -876,7 +874,7 @@ function _atthreads_greedy_with_error(a) end a end -@test_throws "user error in the loop body" _atthreads_greedy_with_error(zeros(threadpoolsize())) +@test_throws "user error in the loop body" _atthreads_greedy_with_error(zeros(threadpoolsize(:default))) #### # multi-argument loop @@ -1109,7 +1107,7 @@ function check_sync_end_race() nnotscheduled += y === :notscheduled end # Useful for tuning the test: - @debug "`check_sync_end_race` done" threadpoolsize() ncompleted nnotscheduled nerror + @debug "`check_sync_end_race` done" threadpoolsize(:default) ncompleted nnotscheduled nerror finally done[] = true end @@ -1123,7 +1121,7 @@ end # issue #41546, thread-safe package loading @testset "package loading" begin - ntasks = max(threadpoolsize(), 4) + ntasks = max(threadpoolsize(:default), 4) ch = Channel{Bool}(ntasks) barrier = Base.Event() old_act_proj = Base.ACTIVE_PROJECT[] From eff8ba4c18022896321a8062cd1eb476f4221375 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Tue, 28 Jan 2025 00:46:23 -0500 Subject: [PATCH 247/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?Distributed=20stdlib=20from=208890288=20to=2051e5297=20(#57175)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../md5 | 1 + .../sha512 | 1 + .../md5 | 1 - .../sha512 | 1 - stdlib/Distributed.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/Distributed-51e52978481835413d15b589919aba80dd85f890.tar.gz/md5 create mode 100644 deps/checksums/Distributed-51e52978481835413d15b589919aba80dd85f890.tar.gz/sha512 delete mode 100644 deps/checksums/Distributed-8890288f01a3b4c2b64c87d98409bc9d865f506e.tar.gz/md5 delete mode 100644 deps/checksums/Distributed-8890288f01a3b4c2b64c87d98409bc9d865f506e.tar.gz/sha512 diff --git a/deps/checksums/Distributed-51e52978481835413d15b589919aba80dd85f890.tar.gz/md5 b/deps/checksums/Distributed-51e52978481835413d15b589919aba80dd85f890.tar.gz/md5 new file mode 100644 index 0000000000000..cdf885890db7c --- /dev/null +++ b/deps/checksums/Distributed-51e52978481835413d15b589919aba80dd85f890.tar.gz/md5 @@ -0,0 +1 @@ +bf358a22ed4aa0d57b8672ef81fb2b44 diff --git a/deps/checksums/Distributed-51e52978481835413d15b589919aba80dd85f890.tar.gz/sha512 b/deps/checksums/Distributed-51e52978481835413d15b589919aba80dd85f890.tar.gz/sha512 new file mode 100644 index 0000000000000..171fd2fdbf512 --- /dev/null +++ b/deps/checksums/Distributed-51e52978481835413d15b589919aba80dd85f890.tar.gz/sha512 @@ -0,0 +1 @@ +399ab073d8c8cd1404e2e89ce2753486c782aa18646d56d8508c0a929c6a312e8bac2c791eddc01966f99cec1af34e56bbdccd8d75196b26f0b1bbb1fa8bd9ac diff --git a/deps/checksums/Distributed-8890288f01a3b4c2b64c87d98409bc9d865f506e.tar.gz/md5 b/deps/checksums/Distributed-8890288f01a3b4c2b64c87d98409bc9d865f506e.tar.gz/md5 deleted file mode 100644 index 3b640d12f3344..0000000000000 --- a/deps/checksums/Distributed-8890288f01a3b4c2b64c87d98409bc9d865f506e.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -7405afe10033da0431c8fd920a8cbbbf diff --git a/deps/checksums/Distributed-8890288f01a3b4c2b64c87d98409bc9d865f506e.tar.gz/sha512 b/deps/checksums/Distributed-8890288f01a3b4c2b64c87d98409bc9d865f506e.tar.gz/sha512 deleted file mode 100644 index e9003e31edcba..0000000000000 --- a/deps/checksums/Distributed-8890288f01a3b4c2b64c87d98409bc9d865f506e.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -ad3498cfee95bcd088e47c15eb2707f47ced9493881ec356cbeb22f66207406d23a3e3b27e70a00be7c2c755c6651f54f5378ef42bf4d1312c84d589010aab7b diff --git a/stdlib/Distributed.version b/stdlib/Distributed.version index 13d49b7a093de..be52c0d684b50 100644 --- a/stdlib/Distributed.version +++ b/stdlib/Distributed.version @@ -1,4 +1,4 @@ DISTRIBUTED_BRANCH = master -DISTRIBUTED_SHA1 = 8890288f01a3b4c2b64c87d98409bc9d865f506e +DISTRIBUTED_SHA1 = 51e52978481835413d15b589919aba80dd85f890 DISTRIBUTED_GIT_URL := https://github.com/JuliaLang/Distributed.jl DISTRIBUTED_TAR_URL = https://api.github.com/repos/JuliaLang/Distributed.jl/tarball/$1 From 856031880e7a223b6bf5c0875d843b88c0359495 Mon Sep 17 00:00:00 2001 From: Nick Robinson Date: Tue, 28 Jan 2025 14:30:58 +0000 Subject: [PATCH 248/342] Loosen type restriction on `Ryu.writeshortest` (#57172) `Ryu.writeshortest` is documented to have a method that "allows passing in a byte buffer", just like `Ryu.writefixed` and `Ryu.writeexp`, but unlike those functions `writeshortest` is type constrained to `::Vector{UInt8}`. This PR loosens that to `::AbstractVector{UInt8}`, to allow the "byte buffer" to e.g. be a `Memory` rather than a `Vector`. I've added tests and updated the docstrings for all three functions to ensure that they're not just restricted to `Vector{UInt8}`. This change was prompted by our private codebase hitting `MethodError: no method matching writeshortest(::Memory{UInt8}, ::Int64, ::Float64, ...)` when trying it out with Julia v1.12.0-DEV. (cc @quinnj -- i think you added this method originally, but i couldn't see any reason why e.g. Memory shouldn't be allowed now we have it) --- base/ryu/Ryu.jl | 6 +++--- base/ryu/shortest.jl | 2 +- test/ryu.jl | 51 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/base/ryu/Ryu.jl b/base/ryu/Ryu.jl index e44e240baafda..86b9a64c002d5 100644 --- a/base/ryu/Ryu.jl +++ b/base/ryu/Ryu.jl @@ -19,7 +19,7 @@ neededdigits(::Type{Float16}) = 9 + 5 + 9 """ Ryu.writeshortest(x, plus=false, space=false, hash=true, precision=-1, expchar=UInt8('e'), padexp=false, decchar=UInt8('.'), typed=false, compact=false) - Ryu.writeshortest(buf::Vector{UInt8}, pos::Int, x, args...) + Ryu.writeshortest(buf::AbstractVector{UInt8}, pos::Int, x, args...) Convert a float value `x` into its "shortest" decimal string, which can be parsed back to the same value. This function allows achieving the `%g` printf format. @@ -53,7 +53,7 @@ end """ Ryu.writefixed(x, precision, plus=false, space=false, hash=false, decchar=UInt8('.'), trimtrailingzeros=false) - Ryu.writefixed(buf::Vector{UInt8}, pos::Int, x, args...) + Ryu.writefixed(buf::AbstractVector{UInt8}, pos::Int, x, args...) Convert a float value `x` into a "fixed" size decimal string of the provided precision. This function allows achieving the `%f` printf format. @@ -81,7 +81,7 @@ end """ Ryu.writeexp(x, precision, plus=false, space=false, hash=false, expchar=UInt8('e'), decchar=UInt8('.'), trimtrailingzeros=false) - Ryu.writeexp(buf::Vector{UInt8}, pos::Int, x, args...) + Ryu.writeexp(buf::AbstractVector{UInt8}, pos::Int, x, args...) Convert a float value `x` into a scientific notation decimal string. This function allows achieving the `%e` printf format. diff --git a/base/ryu/shortest.jl b/base/ryu/shortest.jl index 32aa993467e7a..c1ec648bfacdd 100644 --- a/base/ryu/shortest.jl +++ b/base/ryu/shortest.jl @@ -224,7 +224,7 @@ integer. If a `maxsignif` argument is provided, then `b < maxsignif`. return b, e10 end -function writeshortest(buf::Vector{UInt8}, pos, x::T, +function writeshortest(buf::AbstractVector{UInt8}, pos, x::T, plus=false, space=false, hash=true, precision=-1, expchar=UInt8('e'), padexp=false, decchar=UInt8('.'), typed=false, compact=false) where {T} diff --git a/test/ryu.jl b/test/ryu.jl index 4acd2fd08df50..05eedef9a0da2 100644 --- a/test/ryu.jl +++ b/test/ryu.jl @@ -370,6 +370,23 @@ end end # Float16 +@testset "writeshortest(::AbstractVector, pos, ...)" begin + @testset for Vec in (Vector{UInt8}, Memory{UInt8}) + buf = Vec(undef, 4) + @test Ryu.writeshortest(buf, 1, -0.0) == 5 + @test String(buf) == "-0.0" + + buf = Vec(undef, 100) + xx = 4.7223665f21 + expected = "4.7223665e21" + start_pos = 42 + nwritten = length(expected) + end_pos = start_pos + nwritten + @test Ryu.writeshortest(buf, start_pos, xx) == end_pos + @test String(buf[start_pos:end_pos-1]) == expected + end +end + @testset "Ryu.writefixed" begin @testset "Basic" begin @test Ryu.writefixed(todouble(false, 1234, 99999), 0) == @@ -563,6 +580,23 @@ end # Float16 @test Ryu.writefixed(-100.0+eps(-100.0), 0, false, false, true, UInt8('.'), false) == "-100." @test Ryu.writefixed(100.0-eps(100.0), 1, false, false, true, UInt8('.'), false) == "100.0" @test Ryu.writefixed(-100.0+eps(-100.0), 1, false, false, true, UInt8('.'), false) == "-100.0" + + @testset "writefixed(::AbstractVector, pos, ...)" begin + @testset for Vec in (Vector{UInt8}, Memory{UInt8}) + buf = Vec(undef, 6) + @test Ryu.writefixed(buf, 1, 0.0, 4) == 7 + @test String(buf) == "0.0000" + + buf = Vec(undef, 100) + xx = 1729.142857142857 + prec = 8 + start_pos = 42 + nwritten = 4 + 1 + prec + end_pos = start_pos + nwritten + @test Ryu.writefixed(buf, start_pos, xx, prec) == end_pos + @test String(buf[start_pos:end_pos-1]) == "1729.14285714" + end + end end # fixed @testset "Ryu.writeexp" begin @@ -761,6 +795,23 @@ end @test Ryu.writeexp(2.0, 1, false, false, false, UInt8('e'), UInt8('.'), true) == "2e+00" end +@testset "writeexp(::AbstractVector, pos, ...)" begin + @testset for Vec in (Vector{UInt8}, Memory{UInt8}) + buf = Vec(undef, 10) + @test Ryu.writeexp(buf, 1, 0.0, 4) == 11 + @test String(buf) == "0.0000e+00" + + buf = Vec(undef, 100) + xx = 1729.142857142857 + prec = 8 + start_pos = 42 + nwritten = 1 + 1 + prec + 4 + end_pos = start_pos + nwritten + @test Ryu.writeexp(buf, start_pos, xx, prec) == end_pos + @test String(buf[start_pos:end_pos-1]) == "1.72914286e+03" + end +end + end # exp @testset "compact" begin From 575d8e805d2b0b2cc2213b7745f3a90cef190b0c Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Tue, 28 Jan 2025 10:12:29 -0500 Subject: [PATCH 249/342] Add `Timer` args to struct and add show method (#57081) --- NEWS.md | 1 + base/asyncevent.jl | 44 ++++++++++++++++++++++++++++++++++++++++++-- test/channels.jl | 10 ++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 796fe9647fff0..1a3ba07021bad 100644 --- a/NEWS.md +++ b/NEWS.md @@ -128,6 +128,7 @@ New library features certain compiler plugin workflows ([#56660]). * `sort` now supports `NTuple`s ([#54494]) * `map!(f, A)` now stores the results in `A`, like `map!(f, A, A)`. or `A .= f.(A)` ([#40632]). +* `Timer` now has readable `timeout` and `interval` properties, and a more descriptive show method ([#57081]) Standard library changes ------------------------ diff --git a/base/asyncevent.jl b/base/asyncevent.jl index 8c708455976e2..8297626ee0f97 100644 --- a/base/asyncevent.jl +++ b/base/asyncevent.jl @@ -74,7 +74,24 @@ Create a timer that wakes up tasks waiting for it (by calling [`wait`](@ref) on Waiting tasks are woken after an initial delay of at least `delay` seconds, and then repeating after at least `interval` seconds again elapse. If `interval` is equal to `0`, the timer is only triggered once. When the timer is closed (by [`close`](@ref)) waiting tasks are woken with an error. Use -[`isopen`](@ref) to check whether a timer is still active. +[`isopen`](@ref) to check whether a timer is still active. Use `t.timeout` and `t.interval` to read +the setup conditions of a `Timer` `t`. + +```julia-repl +julia> t = Timer(1.0; interval=0.5) +Timer (open, timeout: 1.0 s, interval: 0.5 s) @0x000000010f4e6e90 + +julia> isopen(t) +true + +julia> t.timeout +1.0 + +julia> close(t) + +julia> isopen(t) +false +``` !!! note `interval` is subject to accumulating time skew. If you need precise events at a particular @@ -84,12 +101,17 @@ once. When the timer is closed (by [`close`](@ref)) waiting tasks are woken with A `Timer` requires yield points to update its state. For instance, `isopen(t::Timer)` cannot be used to timeout a non-yielding while loop. +!!! compat "Julia 1.12 + The `timeout` and `interval` readable properties were added in Julia 1.12. + """ mutable struct Timer @atomic handle::Ptr{Cvoid} cond::ThreadSynchronizer @atomic isopen::Bool @atomic set::Bool + timeout_ms::UInt64 + interval_ms::UInt64 function Timer(timeout::Real; interval::Real = 0.0) timeout ≥ 0 || throw(ArgumentError("timer cannot have negative timeout of $timeout seconds")) @@ -99,7 +121,7 @@ mutable struct Timer intervalms = ceil(UInt64, interval * 1000) loop = eventloop() - this = new(Libc.malloc(_sizeof_uv_timer), ThreadSynchronizer(), true, false) + this = new(Libc.malloc(_sizeof_uv_timer), ThreadSynchronizer(), true, false, timeoutms, intervalms) associate_julia_struct(this.handle, this) iolock_begin() err = ccall(:uv_timer_init, Cint, (Ptr{Cvoid}, Ptr{Cvoid}), loop, this) @@ -114,6 +136,24 @@ mutable struct Timer return this end end +function getproperty(t::Timer, f::Symbol) + if f == :timeout + t.timeout_ms == 0 && return 0.0 + return (t.timeout_ms - 1) / 1000 # remove the +1ms compensation from the constructor + elseif f == :interval + return t.interval_ms / 1000 + else + return getfield(t, f) + end +end +propertynames(::Timer) = (:handle, :cond, :isopen, :set, :timeout, :timeout_ms, :interval, :interval_ms) + +function show(io::IO, t::Timer) + state = isopen(t) ? "open" : "closed" + interval = t.interval + interval_str = interval > 0 ? ", interval: $(t.interval) s" : "" + print(io, "Timer ($state, timeout: $(t.timeout) s$interval_str) @0x$(string(convert(UInt, pointer_from_objref(t)), base = 16, pad = Sys.WORD_SIZE>>2))") +end unsafe_convert(::Type{Ptr{Cvoid}}, t::Timer) = t.handle unsafe_convert(::Type{Ptr{Cvoid}}, async::AsyncCondition) = async.handle diff --git a/test/channels.jl b/test/channels.jl index d654bc63be586..f646b41cfa1a0 100644 --- a/test/channels.jl +++ b/test/channels.jl @@ -621,6 +621,16 @@ let a = Ref(0) @test a[] == 1 end +@testset "Timer properties" begin + t = Timer(1.0, interval = 0.5) + @test t.timeout == 1.0 + @test t.interval == 0.5 + close(t) + @test !isopen(t) + @test t.timeout == 1.0 + @test t.interval == 0.5 +end + # trying to `schedule` a finished task let t = @async nothing wait(t) From 7a97bc91cf7d4223fd05940b322774476f5913a7 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Tue, 28 Jan 2025 15:09:53 -0500 Subject: [PATCH 250/342] interpreter: pop GC frames when leaving multiple `:enter` blocks (#57186) Resolves https://github.com/JuliaLang/julia/issues/56062 --- src/interpreter.c | 8 +++++++- test/scopedvalues.jl | 13 +++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/interpreter.c b/src/interpreter.c index 338853b56f692..35c70a9ead2f1 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -540,6 +540,9 @@ 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; if (!jl_setjmp(__eh.eh_ctx, 1)) { @@ -606,8 +609,11 @@ static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, size_t ip, // equivalent to jl_pop_handler(hand_n_leave), longjmping // to the :enter code above instead, which handles cleanup jl_handler_t *eh = ct->eh; - while (--hand_n_leave > 0) + while (--hand_n_leave > 0) { + // pop GC frames for any skipped handlers + ct->gcstack = eh->gcstack; eh = eh->prev; + } // leave happens during normal control flow, but we must // longjmp to pop the eval_body call for each enter. s->continue_at = next_ip; diff --git a/test/scopedvalues.jl b/test/scopedvalues.jl index 174bc690ac0a2..e9b36d80fc2c4 100644 --- a/test/scopedvalues.jl +++ b/test/scopedvalues.jl @@ -182,3 +182,16 @@ end @test Core.current_scope() === nothing end nothrow_scope() + +# https://github.com/JuliaLang/julia/issues/56062 +@testset "issue #56062" begin + ts = Int[] + try + @with begin + return + end + catch err + finally + push!(ts, 2) + end +end From 989b32b6e2483a16bf2abe291defde19a2cb94d7 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Tue, 28 Jan 2025 19:50:02 -0500 Subject: [PATCH 251/342] CI: Be noisy about cache being bad. Check hash of downloaded busybox executable (#57174) --- test/spawn.jl | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/test/spawn.jl b/test/spawn.jl index 0356cf9871424..099f0670ce5f7 100644 --- a/test/spawn.jl +++ b/test/spawn.jl @@ -4,7 +4,7 @@ # Cross Platform tests for spawn. # ################################### -using Random, Sockets +using Random, Sockets, SHA using Downloads: Downloads, download valgrind_off = ccall(:jl_running_on_valgrind, Cint, ()) == 0 @@ -21,6 +21,8 @@ sleepcmd = `sleep` lscmd = `ls` havebb = false +busybox_hash_correct(file) = bytes2hex(open(SHA.sha256, file)) == "ed2f95da9555268e93c7af52feb48e148534ee518b9128f65dda9a2767b61b9e" + function _tryonce_download_from_cache(desired_url::AbstractString) cache_url = "https://cache.julialang.org/$(desired_url)" cache_output_filename = joinpath(mktempdir(), "busybox") @@ -32,9 +34,14 @@ function _tryonce_download_from_cache(desired_url::AbstractString) ) if cache_response isa Downloads.Response if Downloads.status_ok(cache_response.proto, cache_response.status) - return cache_output_filename + if busybox_hash_correct(cache_output_filename) + return cache_output_filename + else + @warn "The busybox executable downloaded from the cache has an incorrect hash" cache_output_filename bytes2hex(open(SHA.sha256, cache_output_filename)) + end end end + @warn "Could not download from cache at $cache_url, falling back to primary source at $desired_url" return Downloads.download(desired_url; timeout = 60) end @@ -46,7 +53,11 @@ function download_from_cache(desired_url::AbstractString) end if Sys.iswindows() - busybox = download_from_cache("https://frippery.org/files/busybox/busybox.exe") + # See https://frippery.org/files/busybox/ + # latest as of 2024-09-20 18:08 + busybox = download_from_cache("https://frippery.org/files/busybox/busybox-w32-FRP-5467-g9376eebd8.exe") + busybox_hash_correct(busybox) || error("The busybox executable downloaded has an incorrect hash") + havebb = try # use busybox-w32 on windows, if available success(`$busybox`) true From f209eba244d55afbf7aeff298434deba4fcbe30a Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Wed, 29 Jan 2025 03:08:35 +0100 Subject: [PATCH 252/342] bpart: Start enforcing min_world for global variable definitions (#57150) This is the analog of #57102 for global variables. Unlike for consants, there is no automatic global backdate mechanism. The reasoning for this is that global variables can be declared at any time, unlike constants which can only be decalared once their value is available. As a result code patterns using `Core.eval` to declare globals are rarer and likely incorrect. --- Compiler/test/abioverride.jl | 2 +- base/docs/Docs.jl | 17 ++++-- base/exports.jl | 1 + base/loading.jl | 2 +- src/builtins.c | 10 ++-- src/codegen.cpp | 103 ++++----------------------------- src/jl_exported_funcs.inc | 1 + src/julia-syntax.scm | 11 +++- src/julia.h | 3 +- src/module.c | 44 +++++++------- src/toplevel.c | 107 ++++++++++++++++++++--------------- stdlib/REPL/src/REPL.jl | 28 ++++++--- stdlib/REPL/test/repl.jl | 14 ++--- sysimage.mk | 1 + test/core.jl | 1 + test/precompile.jl | 2 +- test/worlds.jl | 29 ++++++---- 17 files changed, 175 insertions(+), 201 deletions(-) diff --git a/Compiler/test/abioverride.jl b/Compiler/test/abioverride.jl index 49907ea8e4c63..feb992b27ee43 100644 --- a/Compiler/test/abioverride.jl +++ b/Compiler/test/abioverride.jl @@ -46,7 +46,7 @@ let world = Base.tls_world_age() global new_ci = Core.CodeInstance(Core.ABIOverride(Tuple{typeof(myplus), Int}, mi), #=owner=#SecondArgConstOverride(1), new_source.rettype, Any#=new_source.exctype is missing=#, #=inferred_const=#nothing, #=code=#nothing, #=const_flags=#Int32(0), - new_source.min_world, new_source.max_world, #=new_source.ipo_purity_bits is missing=#UInt32(0), + new_source.min_world, typemax(UInt), #=new_source.ipo_purity_bits is missing=#UInt32(0), #=analysis_results=#nothing, new_source.debuginfo, new_source.edges) # Poke the CI into the global cache diff --git a/base/docs/Docs.jl b/base/docs/Docs.jl index 61c0cf71e70c2..061a94bffd9cf 100644 --- a/base/docs/Docs.jl +++ b/base/docs/Docs.jl @@ -75,18 +75,23 @@ const META = gensym(:meta) const METAType = IdDict{Any,Any} function meta(m::Module; autoinit::Bool=true) - if !isdefined(m, META) || getfield(m, META) === nothing - autoinit ? initmeta(m) : return nothing + if !isdefinedglobal(m, META) + return autoinit ? invokelatest(initmeta, m) : nothing end - return getfield(m, META)::METAType + # TODO: This `invokelatest` is not technically required, but because + # of the automatic constant backdating is currently required to avoid + # a warning. + return invokelatest(getglobal, m, META)::METAType end function initmeta(m::Module) - if !isdefined(m, META) || getfield(m, META) === nothing - Core.eval(m, :($META = $(METAType()))) + if !isdefinedglobal(m, META) + val = METAType() + Core.eval(m, :(const $META = $val)) push!(modules, m) + return val end - nothing + return getglobal(m, META) end function signature!(tv::Vector{Any}, expr::Expr) diff --git a/base/exports.jl b/base/exports.jl index 56cd58ce269e7..d81067478dd55 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -818,6 +818,7 @@ export @invoke, invokelatest, @invokelatest, + @world, # loading source files __precompile__, diff --git a/base/loading.jl b/base/loading.jl index 240406292246b..57d69f49483c9 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -1389,7 +1389,7 @@ function register_restored_modules(sv::SimpleVector, pkg::PkgId, path::String) restored = sv[1]::Vector{Any} for M in restored M = M::Module - if isdefined(M, Base.Docs.META) && getfield(M, Base.Docs.META) !== nothing + if isdefinedglobal(M, Base.Docs.META) push!(Base.Docs.modules, M) end if is_root_module(M) diff --git a/src/builtins.c b/src/builtins.c index 90d8a0d453e20..f67ef65d35356 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1395,7 +1395,7 @@ JL_CALLABLE(jl_f_setglobal) jl_atomic_error("setglobal!: module binding cannot be written non-atomically"); else if (order >= jl_memory_order_seq_cst) jl_fence(); - jl_binding_t *b = jl_get_binding_wr(mod, var, 0); + jl_binding_t *b = jl_get_binding_wr(mod, var); jl_checked_assignment(b, mod, var, args[2]); // release store if (order >= jl_memory_order_seq_cst) jl_fence(); @@ -1430,7 +1430,7 @@ JL_CALLABLE(jl_f_swapglobal) if (order == jl_memory_order_notatomic) jl_atomic_error("swapglobal!: module binding cannot be written non-atomically"); // is seq_cst already, no fence needed - jl_binding_t *b = jl_get_binding_wr(mod, var, 0); + jl_binding_t *b = jl_get_binding_wr(mod, var); return jl_checked_swap(b, mod, var, args[2]); } @@ -1448,7 +1448,7 @@ JL_CALLABLE(jl_f_modifyglobal) JL_TYPECHK(modifyglobal!, symbol, (jl_value_t*)var); if (order == jl_memory_order_notatomic) jl_atomic_error("modifyglobal!: module binding cannot be written non-atomically"); - jl_binding_t *b = jl_get_binding_wr(mod, var, 0); + jl_binding_t *b = jl_get_binding_wr(mod, var); // is seq_cst already, no fence needed return jl_checked_modify(b, mod, var, args[2], args[3]); } @@ -1477,7 +1477,7 @@ JL_CALLABLE(jl_f_replaceglobal) jl_atomic_error("replaceglobal!: module binding cannot be written non-atomically"); if (failure_order == jl_memory_order_notatomic) jl_atomic_error("replaceglobal!: module binding cannot be accessed non-atomically"); - jl_binding_t *b = jl_get_binding_wr(mod, var, 0); + jl_binding_t *b = jl_get_binding_wr(mod, var); // is seq_cst already, no fence needed return jl_checked_replace(b, mod, var, args[2], args[3]); } @@ -1506,7 +1506,7 @@ JL_CALLABLE(jl_f_setglobalonce) jl_atomic_error("setglobalonce!: module binding cannot be written non-atomically"); if (failure_order == jl_memory_order_notatomic) jl_atomic_error("setglobalonce!: module binding cannot be accessed non-atomically"); - jl_binding_t *b = jl_get_binding_wr(mod, var, 0); + jl_binding_t *b = jl_get_binding_wr(mod, var); // is seq_cst already, no fence needed jl_value_t *old = jl_checked_assignonce(b, mod, var, args[2]); return old == NULL ? jl_true : jl_false; diff --git a/src/codegen.cpp b/src/codegen.cpp index 19ee1e9161152..e9e4275672c7e 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -930,12 +930,12 @@ static const auto jlgetbindingorerror_func = new JuliaFunction<>{ }, nullptr, }; -static const auto jlgetbindingwrorerror_func = new JuliaFunction<>{ - XSTR(jl_get_binding_wr), +static const auto jlcheckbpwritable_func = new JuliaFunction<>{ + XSTR(jl_check_binding_currently_writable), [](LLVMContext &C) { auto T_pjlvalue = JuliaType::get_pjlvalue_ty(C); - return FunctionType::get(T_pjlvalue, - {T_pjlvalue, T_pjlvalue, getInt32Ty(C)}, false); + return FunctionType::get(getVoidTy(C), + {T_pjlvalue, T_pjlvalue, T_pjlvalue}, false); }, nullptr, }; @@ -2098,8 +2098,6 @@ static Type *julia_type_to_llvm(jl_codectx_t &ctx, jl_value_t *jt, bool *isboxed static jl_returninfo_t get_specsig_function(jl_codectx_t &ctx, Module *M, Value *fval, StringRef name, jl_value_t *sig, jl_value_t *jlrettype, bool is_opaque_closure, bool gcstack_arg, ArrayRef ArgNames=None, unsigned nreq=0); static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaval = -1); -static Value *global_binding_pointer(jl_codectx_t &ctx, jl_module_t *m, jl_sym_t *s, - jl_binding_t **pbnd, bool assign, bool alloc); static jl_cgval_t emit_checked_var(jl_codectx_t &ctx, Value *bp, jl_sym_t *name, jl_value_t *scope, bool isvol, MDNode *tbaa); static jl_cgval_t emit_sparam(jl_codectx_t &ctx, size_t i); static Value *emit_condition(jl_codectx_t &ctx, const jl_cgval_t &condV, const Twine &msg); @@ -3498,19 +3496,17 @@ static jl_cgval_t emit_globalop(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *s bool issetglobal, bool isreplaceglobal, bool isswapglobal, bool ismodifyglobal, bool issetglobalonce, const jl_cgval_t *modifyop, bool alloc) { - jl_binding_t *bnd = NULL; - Value *bp = global_binding_pointer(ctx, mod, sym, &bnd, true, alloc); + jl_binding_t *bnd = jl_get_module_binding(mod, sym, 1); jl_binding_partition_t *bpart = jl_get_binding_partition_all(bnd, ctx.min_world, ctx.max_world); - if (bp == NULL) - return jl_cgval_t(); + Value *bp = julia_binding_gv(ctx, bnd); if (bpart) { jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - if (!jl_bkind_is_some_constant(decode_restriction_kind(pku))) { + if (decode_restriction_kind(pku) == BINDING_KIND_GLOBAL) { jl_value_t *ty = decode_restriction_value(pku); if (ty != nullptr) { const std::string fname = issetglobal ? "setglobal!" : isreplaceglobal ? "replaceglobal!" : isswapglobal ? "swapglobal!" : ismodifyglobal ? "modifyglobal!" : "setglobalonce!"; if (!ismodifyglobal) { - // TODO: use typeassert in jl_check_binding_wr too + // TODO: use typeassert in jl_check_binding_assign_value too emit_typecheck(ctx, rval, ty, "typeassert"); rval = update_julia_type(ctx, rval, ty); if (rval.typ == jl_bottom_type) @@ -3545,6 +3541,8 @@ static jl_cgval_t emit_globalop(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *s } Value *m = literal_pointer_val(ctx, (jl_value_t*)mod); Value *s = literal_pointer_val(ctx, (jl_value_t*)sym); + ctx.builder.CreateCall(prepare_call(jlcheckbpwritable_func), + { bp, m, s }); if (issetglobal) { ctx.builder.CreateCall(prepare_call(jlcheckassign_func), { bp, m, s, mark_callee_rooted(ctx, boxed(ctx, rval)) }); @@ -5991,85 +5989,6 @@ static void emit_hasnofield_error_ifnot(jl_codectx_t &ctx, Value *ok, jl_datatyp ctx.builder.SetInsertPoint(ifok); } -// returns a jl_ppvalue_t location for the global variable m.s -// if the reference currently bound or assign == true, -// pbnd will also be assigned with the binding address -static Value *global_binding_pointer(jl_codectx_t &ctx, jl_module_t *m, jl_sym_t *s, - jl_binding_t **pbnd, bool assign, bool alloc) -{ - jl_binding_t *b = jl_get_module_binding(m, s, 1); - jl_binding_partition_t *bpart = jl_get_binding_partition_all(b, ctx.min_world, ctx.max_world); - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - if (assign) { - if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) - // not yet declared - b = NULL; - } - else { - if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) { - // try to look this up now - b = jl_get_binding(m, s); - bpart = jl_get_binding_partition_all(b, ctx.min_world, ctx.max_world); - } - pku = jl_walk_binding_inplace_all(&b, &bpart, ctx.min_world, ctx.max_world); - } - if (!b || !bpart) { - // var not found. switch to delayed lookup. - Constant *initnul = Constant::getNullValue(ctx.types().T_pjlvalue); - GlobalVariable *bindinggv = new GlobalVariable(*ctx.f->getParent(), ctx.types().T_pjlvalue, - false, GlobalVariable::PrivateLinkage, initnul, "jl_binding_ptr"); // LLVM has bugs with nameless globals - LoadInst *cachedval = ctx.builder.CreateAlignedLoad(ctx.types().T_pjlvalue, bindinggv, Align(sizeof(void*))); - setName(ctx.emission_context, cachedval, jl_symbol_name(m->name) + StringRef(".") + jl_symbol_name(s) + ".cached"); - cachedval->setOrdering(AtomicOrdering::Unordered); - BasicBlock *have_val = BasicBlock::Create(ctx.builder.getContext(), "found"); - BasicBlock *not_found = BasicBlock::Create(ctx.builder.getContext(), "notfound"); - BasicBlock *currentbb = ctx.builder.GetInsertBlock(); - auto iscached = ctx.builder.CreateICmpNE(cachedval, initnul); - setName(ctx.emission_context, iscached, "iscached"); - ctx.builder.CreateCondBr(iscached, have_val, not_found); - not_found->insertInto(ctx.f); - ctx.builder.SetInsertPoint(not_found); - Value *bval = nullptr; - if (assign) { - bval = ctx.builder.CreateCall(prepare_call(jlgetbindingwrorerror_func), - { literal_pointer_val(ctx, (jl_value_t*)m), - literal_pointer_val(ctx, (jl_value_t*)s), - ConstantInt::get(getInt32Ty(ctx.builder.getContext()), alloc)}); - } else { - bval = ctx.builder.CreateCall(prepare_call(jlgetbindingorerror_func), - { literal_pointer_val(ctx, (jl_value_t*)m), - literal_pointer_val(ctx, (jl_value_t*)s)}); - } - setName(ctx.emission_context, bval, jl_symbol_name(m->name) + StringRef(".") + jl_symbol_name(s) + ".found"); - ctx.builder.CreateAlignedStore(bval, bindinggv, Align(sizeof(void*)))->setOrdering(AtomicOrdering::Release); - ctx.builder.CreateBr(have_val); - have_val->insertInto(ctx.f); - ctx.builder.SetInsertPoint(have_val); - PHINode *p = ctx.builder.CreatePHI(ctx.types().T_pjlvalue, 2); - p->addIncoming(cachedval, currentbb); - p->addIncoming(bval, not_found); - setName(ctx.emission_context, p, jl_symbol_name(m->name) + StringRef(".") + jl_symbol_name(s)); - return p; - } - if (assign) { - if (decode_restriction_kind(pku) != BINDING_KIND_GLOBAL && !jl_bkind_is_some_guard(decode_restriction_kind(pku))) { - // this will fail at runtime, so defer to the runtime to create the error - ctx.builder.CreateCall(prepare_call(jlgetbindingwrorerror_func), - { literal_pointer_val(ctx, (jl_value_t*)m), - literal_pointer_val(ctx, (jl_value_t*)s), - ConstantInt::get(getInt32Ty(ctx.builder.getContext()), alloc) }); - CreateTrap(ctx.builder); - return NULL; - } - } - else { - if (b->deprecated) - cg_bdw(ctx, s, b); - } - *pbnd = b; - return julia_binding_gv(ctx, b); -} - static jl_cgval_t emit_checked_var(jl_codectx_t &ctx, Value *bp, jl_sym_t *name, jl_value_t *scope, bool isvol, MDNode *tbaa) { LoadInst *v = ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, bp, Align(sizeof(void*))); @@ -10184,7 +10103,7 @@ static void init_jit_functions(void) add_named_global(jltypeerror_func, &jl_type_error); add_named_global(jlcheckassign_func, &jl_checked_assignment); add_named_global(jlgetbindingorerror_func, &jl_get_binding_or_error); - add_named_global(jlgetbindingwrorerror_func, &jl_get_binding_wr); + add_named_global(jlcheckbpwritable_func, &jl_check_binding_currently_writable); add_named_global(jlboundp_func, &jl_boundp); for (auto it : builtin_func_map()) add_named_global(it.second, it.first); diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index c1b29a091511b..9e221420aa9f4 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -196,6 +196,7 @@ XX(jl_get_binding_for_method_def) \ XX(jl_get_binding_or_error) \ XX(jl_get_binding_wr) \ + XX(jl_check_binding_currently_writable) \ XX(jl_get_cpu_name) \ XX(jl_get_cpu_features) \ XX(jl_cpu_has_fma) \ diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 57f67755df692..97d76e7762a9e 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -4626,6 +4626,8 @@ f(x) = yt(x) (if (globalref? lhs) (begin (emit `(global ,lhs)) + (if (null? (cadr lam)) + (emit `(latestworld))) (emit `(call (top setglobal!) ,(cadr lhs) (inert ,(caddr lhs)) ,rhs))) (emit `(= ,lhs ,rhs)))) (define (emit-assignment lhs rhs) @@ -4944,13 +4946,16 @@ f(x) = yt(x) #f)) ((global) ; keep global declarations as statements (if value (error "misplaced \"global\" declaration")) - (emit e)) + (emit e) + (if (null? (cadr lam)) + (emit `(latestworld)))) ((globaldecl) (if value (error "misplaced \"global\" declaration")) - (if (atom? (caddr e)) (emit e) + (if (atom? (caddr e)) (begin (emit e) (emit `(latestworld))) (let ((rr (make-ssavalue))) (emit `(= ,rr ,(caddr e))) - (emit `(globaldecl ,(cadr e) ,rr))))) + (emit `(globaldecl ,(cadr e) ,rr)) + (emit `(latestworld))))) ((local-def) #f) ((local) #f) ((moved-local) diff --git a/src/julia.h b/src/julia.h index f36133088119f..a5f56ad580335 100644 --- a/src/julia.h +++ b/src/julia.h @@ -2001,7 +2001,8 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_or_error(jl_module_t *m, jl_sym_t *var JL_DLLEXPORT jl_value_t *jl_module_globalref(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT jl_value_t *jl_get_binding_type(jl_module_t *m, jl_sym_t *var); // get binding for assignment -JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, int alloc); +JL_DLLEXPORT void jl_check_binding_currently_writable(jl_binding_t *b, jl_module_t *m, jl_sym_t *s); +JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var); JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var); JL_DLLEXPORT int jl_boundp(jl_module_t *m, jl_sym_t *var, int allow_import); JL_DLLEXPORT int jl_defines_or_exports_p(jl_module_t *m, jl_sym_t *var); diff --git a/src/module.c b/src/module.c index f4c56e19efa61..2630db2dbfd94 100644 --- a/src/module.c +++ b/src/module.c @@ -279,38 +279,42 @@ extern void check_safe_newbinding(jl_module_t *m, jl_sym_t *var) static jl_module_t *jl_binding_dbgmodule(jl_binding_t *b, jl_module_t *m, jl_sym_t *var) JL_GLOBALLY_ROOTED; -// get binding for assignment -JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, int alloc) +// Checks that the binding in general is currently writable, but does not perform any checks on the +// value to be written into the binding. +JL_DLLEXPORT void jl_check_binding_currently_writable(jl_binding_t *b, jl_module_t *m, jl_sym_t *s) { - jl_binding_t *b = jl_get_module_binding(m, var, 1); jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); retry: if (decode_restriction_kind(pku) != BINDING_KIND_GLOBAL && !jl_bkind_is_some_constant(decode_restriction_kind(pku))) { if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) { if (decode_restriction_kind(pku) != BINDING_KIND_DECLARED) { - check_safe_newbinding(m, var); - if (!alloc) - jl_errorf("Global %s.%s does not exist and cannot be assigned.\n" - "Note: Julia 1.9 and 1.10 inadvertently omitted this error check (#56933).\n" - "Hint: Declare it using `global %s` inside `%s` before attempting assignment.", - jl_symbol_name(m->name), jl_symbol_name(var), - jl_symbol_name(var), jl_symbol_name(m->name)); + jl_errorf("Global %s.%s does not exist and cannot be assigned.\n" + "Note: Julia 1.9 and 1.10 inadvertently omitted this error check (#56933).\n" + "Hint: Declare it using `global %s` inside `%s` before attempting assignment.", + jl_symbol_name(m->name), jl_symbol_name(s), + jl_symbol_name(s), jl_symbol_name(m->name)); } jl_ptr_kind_union_t new_pku = encode_restriction((jl_value_t*)jl_any_type, BINDING_KIND_GLOBAL); if (!jl_atomic_cmpswap(&bpart->restriction, &pku, new_pku)) goto retry; jl_gc_wb_knownold(bpart, jl_any_type); } else { - jl_module_t *from = jl_binding_dbgmodule(b, m, var); + jl_module_t *from = jl_binding_dbgmodule(b, m, s); if (from == m) jl_errorf("cannot assign a value to imported variable %s.%s", - jl_symbol_name(from->name), jl_symbol_name(var)); + jl_symbol_name(from->name), jl_symbol_name(s)); else jl_errorf("cannot assign a value to imported variable %s.%s from module %s", - jl_symbol_name(from->name), jl_symbol_name(var), jl_symbol_name(m->name)); + jl_symbol_name(from->name), jl_symbol_name(s), jl_symbol_name(m->name)); } } +} + +JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var) +{ + jl_binding_t *b = jl_get_module_binding(m, var, 1); + jl_check_binding_currently_writable(b, m, var); return b; } @@ -1066,7 +1070,7 @@ JL_DLLEXPORT jl_value_t *jl_get_global(jl_module_t *m, jl_sym_t *var) JL_DLLEXPORT void jl_set_global(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT) { - jl_binding_t *bp = jl_get_binding_wr(m, var, 0); + jl_binding_t *bp = jl_get_binding_wr(m, var); jl_checked_assignment(bp, m, var, val); } @@ -1186,7 +1190,9 @@ void jl_binding_deprecation_warning(jl_module_t *m, jl_sym_t *s, jl_binding_t *b } } -jl_value_t *jl_check_binding_wr(jl_binding_t *b JL_PROPAGATES_ROOT, jl_module_t *mod, jl_sym_t *var, jl_value_t *rhs JL_MAYBE_UNROOTED, int reassign) +// For a generally writable binding (checked using jl_check_binding_currently_writable in this world age), check whether +// we can actually write the value `rhs` to it. +jl_value_t *jl_check_binding_assign_value(jl_binding_t *b JL_PROPAGATES_ROOT, jl_module_t *mod, jl_sym_t *var, jl_value_t *rhs JL_MAYBE_UNROOTED) { JL_GC_PUSH1(&rhs); // callee-rooted jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); @@ -1219,7 +1225,7 @@ jl_value_t *jl_check_binding_wr(jl_binding_t *b JL_PROPAGATES_ROOT, jl_module_t JL_DLLEXPORT void jl_checked_assignment(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *rhs) { - if (jl_check_binding_wr(b, mod, var, rhs, 1) != NULL) { + if (jl_check_binding_assign_value(b, mod, var, rhs) != NULL) { jl_atomic_store_release(&b->value, rhs); jl_gc_wb(b, rhs); } @@ -1227,7 +1233,7 @@ JL_DLLEXPORT void jl_checked_assignment(jl_binding_t *b, jl_module_t *mod, jl_sy JL_DLLEXPORT jl_value_t *jl_checked_swap(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *rhs) { - jl_check_binding_wr(b, mod, var, rhs, 0); + jl_check_binding_assign_value(b, mod, var, rhs); jl_value_t *old = jl_atomic_exchange(&b->value, rhs); jl_gc_wb(b, rhs); if (__unlikely(old == NULL)) @@ -1237,7 +1243,7 @@ JL_DLLEXPORT jl_value_t *jl_checked_swap(jl_binding_t *b, jl_module_t *mod, jl_s JL_DLLEXPORT jl_value_t *jl_checked_replace(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *expected, jl_value_t *rhs) { - jl_value_t *ty = jl_check_binding_wr(b, mod, var, rhs, 0); + jl_value_t *ty = jl_check_binding_assign_value(b, mod, var, rhs); return replace_value(ty, &b->value, (jl_value_t*)b, expected, rhs, 1, mod, var); } @@ -1256,7 +1262,7 @@ JL_DLLEXPORT jl_value_t *jl_checked_modify(jl_binding_t *b, jl_module_t *mod, jl JL_DLLEXPORT jl_value_t *jl_checked_assignonce(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *rhs ) { - jl_check_binding_wr(b, mod, var, rhs, 0); + jl_check_binding_assign_value(b, mod, var, rhs); jl_value_t *old = NULL; if (jl_atomic_cmpswap(&b->value, &old, rhs)) jl_gc_wb(b, rhs); diff --git a/src/toplevel.c b/src/toplevel.c index 30e78bf813fc8..35ad001ac4b4b 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -302,38 +302,6 @@ static jl_value_t *jl_eval_dot_expr(jl_module_t *m, jl_value_t *x, jl_value_t *f return args[0]; } -void jl_binding_set_type(jl_binding_t *b, jl_module_t *mod, jl_sym_t *sym, jl_value_t *ty) -{ - jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - jl_ptr_kind_union_t new_pku = encode_restriction(ty, BINDING_KIND_GLOBAL); - while (1) { - if (decode_restriction_kind(pku) != BINDING_KIND_GLOBAL) { - if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) { - if (jl_atomic_cmpswap(&bpart->restriction, &pku, new_pku)) - break; - continue; - } else { - jl_errorf("cannot set type for imported global %s.%s.", - jl_symbol_name(mod->name), jl_symbol_name(sym)); - } - } - if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) { - jl_errorf("cannot set type for imported constant %s.%s.", - jl_symbol_name(mod->name), jl_symbol_name(sym)); - } - jl_value_t *old_ty = decode_restriction_value(pku); - JL_GC_PROMISE_ROOTED(old_ty); - if (!jl_types_equal(ty, old_ty)) { - jl_errorf("cannot set type for global %s.%s. It already has a value or is already set to a different type.", - jl_symbol_name(mod->name), jl_symbol_name(sym)); - } - if (jl_atomic_cmpswap(&bpart->restriction, &pku, new_pku)) - break; - } - jl_gc_wb(bpart, ty); -} - extern void check_safe_newbinding(jl_module_t *m, jl_sym_t *var); void jl_declare_global(jl_module_t *m, jl_value_t *arg, jl_value_t *set_type) { // create uninitialized mutable binding for "global x" decl sometimes or probably @@ -349,17 +317,49 @@ void jl_declare_global(jl_module_t *m, jl_value_t *arg, jl_value_t *set_type) { gm = m; gs = (jl_sym_t*)arg; } + JL_LOCK(&world_counter_lock); + size_t new_world = jl_atomic_load_relaxed(&jl_world_counter) + 1; jl_binding_t *b = jl_get_module_binding(gm, gs, 1); - jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - while (decode_restriction_kind(pku) == BINDING_KIND_GUARD || decode_restriction_kind(pku) == BINDING_KIND_FAILED) { - check_safe_newbinding(gm, gs); - if (jl_atomic_cmpswap(&bpart->restriction, &pku, encode_restriction(NULL, BINDING_KIND_DECLARED))) - break; - } - if (set_type) { - jl_binding_set_type(b, gm, gs, set_type); + jl_binding_partition_t *bpart = NULL; + jl_ptr_kind_union_t new_pku = encode_restriction(set_type, set_type == NULL ? BINDING_KIND_DECLARED : BINDING_KIND_GLOBAL); + while (1) { + bpart = jl_get_binding_partition(b, new_world); + jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); + if (decode_restriction_kind(pku) != BINDING_KIND_GLOBAL) { + if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) { + if (decode_restriction_kind(pku) == BINDING_KIND_DECLARED && !set_type) + goto done; + check_safe_newbinding(gm, gs); + if (jl_atomic_cmpswap(&bpart->restriction, &pku, new_pku)) { + break; + } + continue; + } else if (set_type) { + if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) { + jl_errorf("cannot set type for imported constant %s.%s.", + jl_symbol_name(gm->name), jl_symbol_name(gs)); + } else { + jl_errorf("cannot set type for imported global %s.%s.", + jl_symbol_name(gm->name), jl_symbol_name(gs)); + } + } + } + if (!set_type) + goto done; + jl_value_t *old_ty = decode_restriction_value(pku); + JL_GC_PROMISE_ROOTED(old_ty); + if (!jl_types_equal(set_type, old_ty)) { + jl_errorf("cannot set type for global %s.%s. It already has a value or is already set to a different type.", + jl_symbol_name(gm->name), jl_symbol_name(gs)); + } + goto done; } + if (set_type) + jl_gc_wb(bpart, set_type); + bpart->min_world = new_world; + jl_atomic_store_release(&jl_world_counter, new_world); +done: + JL_UNLOCK(&world_counter_lock); } void jl_eval_global_expr(jl_module_t *m, jl_expr_t *ex, int set_type) @@ -751,7 +751,8 @@ JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val3( jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); int did_warn = 0; while (1) { - if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) { + enum jl_partition_kind kind = decode_restriction_kind(pku); + if (jl_bkind_is_some_constant(kind)) { if (!val) { break; } @@ -789,9 +790,24 @@ JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val3( continue; } jl_gc_wb(bpart, val); - int needs_backdate = bpart->min_world == 0 && new_world && val; + size_t prev_min_world = bpart->min_world; bpart->min_world = new_world; - if (needs_backdate) { + int need_backdate = 0; + if (new_world && val) { + if (prev_min_world == 0) { + need_backdate = 1; + } else if (kind == BINDING_KIND_DECLARED) { + jl_binding_partition_t *prev_bpart = jl_get_binding_partition(b, prev_min_world-1); + jl_ptr_kind_union_t prev_pku = jl_atomic_load_relaxed(&prev_bpart->restriction); + if (prev_bpart->min_world == 0 && decode_restriction_kind(prev_pku) == BINDING_KIND_GUARD) { + // Just keep it simple and use one backdated const entry for both previous guard partition + // ranges. + jl_atomic_store_relaxed(&prev_bpart->max_world, new_world-1); + need_backdate = 1; + } + } + } + if (need_backdate) { jl_declare_constant_val3(b, mod, var, val, BINDING_KIND_BACKDATED_CONST, 0); } } @@ -1094,9 +1110,8 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val else { // use interpreter assert(thk); - if (has_opaque) { + if (has_opaque) jl_resolve_definition_effects_in_ir((jl_array_t*)thk->code, m, NULL, 0); - } size_t world = jl_atomic_load_acquire(&jl_world_counter); ct->world_age = world; result = jl_interpret_toplevel_thunk(m, thk); diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index f83fa867748af..699024c1723a4 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -44,8 +44,8 @@ function UndefVarError_hint(io::IO, ex::UndefVarError) "with the module it should come from.") elseif kind === Base.BINDING_KIND_GUARD print(io, "\nSuggestion: check for spelling errors or missing imports.") - else - print(io, "\nSuggestion: this global was defined as `$(bpart.restriction.globalref)` but not assigned a value.") + elseif Base.is_some_imported(kind) + print(io, "\nSuggestion: this global was defined as `$(Base.partition_restriction(bpart).globalref)` but not assigned a value.") end elseif scope === :static_parameter print(io, "\nSuggestion: run Test.detect_unbound_args to detect method arguments that do not fully constrain a type parameter.") @@ -1884,16 +1884,26 @@ function get_usings!(usings, ex) return usings end +function create_global_out!(mod) + if !isdefinedglobal(mod, :Out) + out = Dict{Int, Any}() + @eval mod begin + const Out = $(out) + export Out + end + return out + end + return getglobal(mod, Out) +end + function capture_result(n::Ref{Int}, @nospecialize(x)) n = n[] mod = Base.MainInclude - if !isdefined(mod, :Out) - @eval mod global Out - @eval mod export Out - setglobal!(mod, :Out, Dict{Int, Any}()) - end - if x !== getglobal(mod, :Out) && x !== nothing # remove this? - getglobal(mod, :Out)[n] = x + # TODO: This invokelatest is only required due to backdated constants + # and should be removed after + out = isdefinedglobal(mod, :Out) ? invokelatest(getglobal, mod, :Out) : invokelatest(create_global_out!, mod) + if x !== out && x !== nothing # remove this? + out[n] = x end nothing end diff --git a/stdlib/REPL/test/repl.jl b/stdlib/REPL/test/repl.jl index 8944fd76f31de..018cf9c36430e 100644 --- a/stdlib/REPL/test/repl.jl +++ b/stdlib/REPL/test/repl.jl @@ -752,11 +752,11 @@ fake_repl() do stdin_write, stdout_read, repl # Test removal of prefix in single statement paste sendrepl2("\e[200~julia> A = 2\e[201~\n") - @test Main.A == 2 + @test @world(Main.A, ∞) == 2 # Test removal of prefix in single statement paste sendrepl2("\e[200~In [12]: A = 2.2\e[201~\n") - @test Main.A == 2.2 + @test @world(Main.A, ∞) == 2.2 # Test removal of prefix in multiple statement paste sendrepl2("""\e[200~ @@ -768,7 +768,7 @@ fake_repl() do stdin_write, stdout_read, repl julia> A = 3\e[201~ """) - @test Main.A == 3 + @test @world(Main.A, ∞) == 3 @test @invokelatest(Main.foo(4)) @test @invokelatest(Main.T17599(3)).a == 3 @test !@invokelatest(Main.foo(2)) @@ -780,12 +780,12 @@ fake_repl() do stdin_write, stdout_read, repl julia> A = 4 4\e[201~ """) - @test Main.A == 4 + @test @world(Main.A, ∞) == 4 @test @invokelatest(Main.goo(4)) == 5 # Test prefix removal only active in bracket paste mode sendrepl2("julia = 4\n julia> 3 && (A = 1)\n") - @test Main.A == 1 + @test @world(Main.A, ∞) == 1 # Test that indentation corresponding to the prompt is removed s = sendrepl2("""\e[200~julia> begin\n α=1\n β=2\n end\n\e[201~""") @@ -820,8 +820,8 @@ fake_repl() do stdin_write, stdout_read, repl julia> B = 2 2\e[201~ """) - @test Main.A == 1 - @test Main.B == 2 + @test @world(Main.A, ∞) == 1 + @test @world(Main.B, ∞) == 2 end # redirect_stdout # Close repl diff --git a/sysimage.mk b/sysimage.mk index 571e2da003346..ae6ce8699f417 100644 --- a/sysimage.mk +++ b/sysimage.mk @@ -39,6 +39,7 @@ COMPILER_SRCS := $(addprefix $(JULIAHOME)/, \ base/error.jl \ base/essentials.jl \ base/expr.jl \ + base/exports.jl \ base/generator.jl \ base/int.jl \ base/indices.jl \ diff --git a/test/core.jl b/test/core.jl index 3886e6728df10..5e2677f0f075f 100644 --- a/test/core.jl +++ b/test/core.jl @@ -8233,6 +8233,7 @@ end let M = @__MODULE__ Core.eval(M, :(global a_typed_global)) @test Core.eval(M, :(global a_typed_global::$(Tuple{Union{Integer,Nothing}}))) === nothing + @Core.latestworld @test Core.get_binding_type(M, :a_typed_global) === Tuple{Union{Integer,Nothing}} @test Core.eval(M, :(global a_typed_global::$(Tuple{Union{Integer,Nothing}}))) === nothing @test Core.eval(M, :(global a_typed_global::$(Union{Tuple{Integer},Tuple{Nothing}}))) === nothing diff --git a/test/precompile.jl b/test/precompile.jl index f5a412b416ddc..a9516231ff8d7 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -1969,7 +1969,7 @@ precompile_test_harness("Issue #50538") do load_path """ module I50538 const newglobal = try - Base.newglobal = false + eval(Expr(:global, GlobalRef(Base, :newglobal))) catch ex ex isa ErrorException || rethrow() ex diff --git a/test/worlds.jl b/test/worlds.jl index 025aaba6cea4f..48fb6593d3a37 100644 --- a/test/worlds.jl +++ b/test/worlds.jl @@ -107,7 +107,7 @@ end g265() = [f265(x) for x in 1:3.] wc265 = get_world_counter() wc265_41332a = Task(tls_world_age) -@test tls_world_age() == wc265 +@test tls_world_age() == wc265 + 2 (function () global wc265_41332b = Task(tls_world_age) @eval f265(::Any) = 1.0 @@ -115,24 +115,24 @@ wc265_41332a = Task(tls_world_age) global wc265_41332d = Task(tls_world_age) nothing end)() -@test wc265 + 4 == get_world_counter() == tls_world_age() +@test wc265 + 10 == get_world_counter() == tls_world_age() schedule(wc265_41332a) schedule(wc265_41332b) schedule(wc265_41332c) schedule(wc265_41332d) -@test wc265 == fetch(wc265_41332a) -@test wc265 + 2 == fetch(wc265_41332b) -@test wc265 + 4 == fetch(wc265_41332c) -@test wc265 + 2 == fetch(wc265_41332d) +@test wc265 + 1 == fetch(wc265_41332a) +@test wc265 + 8 == fetch(wc265_41332b) +@test wc265 + 10 == fetch(wc265_41332c) +@test wc265 + 8 == fetch(wc265_41332d) chnls, tasks = Base.channeled_tasks(2, wfunc) t265 = tasks[1] wc265 = get_world_counter() @test put_n_take!(get_world_counter, ()) == wc265 -@test put_n_take!(tls_world_age, ()) == wc265 +@test put_n_take!(tls_world_age, ()) + 3 == wc265 f265(::Int) = 1 @test put_n_take!(get_world_counter, ()) == wc265 + 1 == get_world_counter() == tls_world_age() -@test put_n_take!(tls_world_age, ()) == wc265 +@test put_n_take!(tls_world_age, ()) + 3 == wc265 @test g265() == Int[1, 1, 1] @test Core.Compiler.return_type(f265, Tuple{Any,}) == Union{Float64, Int} @@ -162,12 +162,12 @@ let ex = t265.exception @test ex isa MethodError @test ex.f == h265 @test ex.args == () - @test ex.world == wc265 + @test ex.world == wc265-3 str = sprint(showerror, ex) wc = get_world_counter() cmps = """ MethodError: no method matching h265() - The applicable method may be too new: running in world age $wc265, while current world is $wc.""" + The applicable method may be too new: running in world age $(wc265-3), while current world is $wc.""" @test startswith(str, cmps) cmps = "\n h265() (method too new to be called from this world context.)\n $loc_h265" @test occursin(cmps, str) @@ -500,3 +500,12 @@ end end @test_throws ErrorException("Generated function result with `edges == nothing` and `max_world == typemax(UInt)` must have `min_world == 1`") generated_no_edges() + +# Test that backdating of constants is working for structs +before_backdate_age = Base.tls_world_age() +struct FooBackdated + x::Vector{FooBackdated} + + FooBackdated() = new(FooBackdated[]) +end +@test Base.invoke_in_world(before_backdate_age, isdefined, @__MODULE__, :FooBackdated) From e65af91a3d36c7635abb7284ee9b7c2e1aac89c3 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Wed, 29 Jan 2025 15:15:24 -0500 Subject: [PATCH 253/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?Pkg=20stdlib=20from=20bc9fb21b1=20to=206091533bc=20(#57194)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: Pkg URL: https://github.com/JuliaLang/Pkg.jl.git Stdlib branch: master Julia branch: master Old commit: bc9fb21b1 New commit: 6091533bc Julia version: 1.12.0-DEV Pkg version: 1.12.0 Bump invoked by: @KristofferC Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaLang/Pkg.jl/compare/bc9fb21b1f2d72038491eff938673fc5fbc99445...6091533bc93c722591d3e7ee53d26012cb4d5aa4 ``` $ git log --oneline bc9fb21b1..6091533bc 6091533bc fix ambiguity in apps `rm` (#4144) ecdf6aa38 rename rot13 app in test to avoid name conflicts on systems where such a binary is already installed (#4143) a3626bf29 add `PREV_ENV_PATH` to globals getting reset and move the reset to before precompilation is finished instead of `__init__` (#4142) 938e9b24e app support in Pkg (#3772) df1931a93 Use copy_test_packages in some places, and ensure that the copied test package is user writable. This allows running the Pkg tests as part of Base.runtests of an installed Julia installation, where sources might be readonly. (#4136) 2609a9411 don't set up callbacks if using cli git (#4128) ``` Co-authored-by: KristofferC <1282691+KristofferC@users.noreply.github.com> --- .../Pkg-6091533bc93c722591d3e7ee53d26012cb4d5aa4.tar.gz/md5 | 1 + .../Pkg-6091533bc93c722591d3e7ee53d26012cb4d5aa4.tar.gz/sha512 | 1 + .../Pkg-bc9fb21b1f2d72038491eff938673fc5fbc99445.tar.gz/md5 | 1 - .../Pkg-bc9fb21b1f2d72038491eff938673fc5fbc99445.tar.gz/sha512 | 1 - stdlib/Pkg.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/Pkg-6091533bc93c722591d3e7ee53d26012cb4d5aa4.tar.gz/md5 create mode 100644 deps/checksums/Pkg-6091533bc93c722591d3e7ee53d26012cb4d5aa4.tar.gz/sha512 delete mode 100644 deps/checksums/Pkg-bc9fb21b1f2d72038491eff938673fc5fbc99445.tar.gz/md5 delete mode 100644 deps/checksums/Pkg-bc9fb21b1f2d72038491eff938673fc5fbc99445.tar.gz/sha512 diff --git a/deps/checksums/Pkg-6091533bc93c722591d3e7ee53d26012cb4d5aa4.tar.gz/md5 b/deps/checksums/Pkg-6091533bc93c722591d3e7ee53d26012cb4d5aa4.tar.gz/md5 new file mode 100644 index 0000000000000..b1012dffefbf6 --- /dev/null +++ b/deps/checksums/Pkg-6091533bc93c722591d3e7ee53d26012cb4d5aa4.tar.gz/md5 @@ -0,0 +1 @@ +26699bf323c07c7491d3c106219de6da diff --git a/deps/checksums/Pkg-6091533bc93c722591d3e7ee53d26012cb4d5aa4.tar.gz/sha512 b/deps/checksums/Pkg-6091533bc93c722591d3e7ee53d26012cb4d5aa4.tar.gz/sha512 new file mode 100644 index 0000000000000..2ed6fcd7c5f46 --- /dev/null +++ b/deps/checksums/Pkg-6091533bc93c722591d3e7ee53d26012cb4d5aa4.tar.gz/sha512 @@ -0,0 +1 @@ +1466dca4e49800b94d65ce59c3e2c75308545282a00720c964b34e0cde5e06aced80361c236a9ada81d35ebcc2692f8e6e84db507342d8055ba501fc1291c0a2 diff --git a/deps/checksums/Pkg-bc9fb21b1f2d72038491eff938673fc5fbc99445.tar.gz/md5 b/deps/checksums/Pkg-bc9fb21b1f2d72038491eff938673fc5fbc99445.tar.gz/md5 deleted file mode 100644 index 5180b5f916d1b..0000000000000 --- a/deps/checksums/Pkg-bc9fb21b1f2d72038491eff938673fc5fbc99445.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -2332986e216728bc85e364994f2ed910 diff --git a/deps/checksums/Pkg-bc9fb21b1f2d72038491eff938673fc5fbc99445.tar.gz/sha512 b/deps/checksums/Pkg-bc9fb21b1f2d72038491eff938673fc5fbc99445.tar.gz/sha512 deleted file mode 100644 index 04bc79171c734..0000000000000 --- a/deps/checksums/Pkg-bc9fb21b1f2d72038491eff938673fc5fbc99445.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -99bf03f921ae79767009dbd68a94a7119513b2454d5c9832b157bc1e092a35a6b90cb7a5d81346a7d927f9b0275328582098ca6b8b376b4a406ddf0b3167a280 diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 4240c77105583..c5e38c1fe6487 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = master -PKG_SHA1 = bc9fb21b1f2d72038491eff938673fc5fbc99445 +PKG_SHA1 = 6091533bc93c722591d3e7ee53d26012cb4d5aa4 PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 From c172a646a33a7a500f7fbfff3475c4348bf5b376 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 30 Jan 2025 07:49:07 +0800 Subject: [PATCH 254/342] Change JuliaSyntaxHighlighting UUID (#56852) TLDR; I made a silly mistake a while back, and this seems like the least bad option. ----- Unfortunately during development of the backported version of this stdlib, to avoid potential sysimage issues the UUID was temporarilly changed and I forgot to change it back. This mistake lead to the backport/compat verison of the package having a different UUID from the in-tree stdlib. Beyond this being an embarassing mistake, it's also a pain because it means that we now have incorrect/invalid manifests. A small mercy is that 1.12 hasn't been released yet, so the discrepancy currently only affects people using development Julia versions. Changing the UUID here will require these people to regenerate their manifests, but this seems like the lesser of two evils. Appologies for the hassle all. Co-authored-by: Chengyu Han --- .../md5 | 1 - .../sha512 | 1 - .../md5 | 1 + .../sha512 | 1 + doc/Manifest.toml | 2 +- stdlib/JuliaSyntaxHighlighting.version | 2 +- stdlib/Manifest.toml | 2 +- stdlib/Markdown/Project.toml | 2 +- stdlib/Project.toml | 2 +- stdlib/REPL/Project.toml | 2 +- 10 files changed, 8 insertions(+), 8 deletions(-) delete mode 100644 deps/checksums/JuliaSyntaxHighlighting-19bd57b89c648592155156049addf67e0638eab1.tar.gz/md5 delete mode 100644 deps/checksums/JuliaSyntaxHighlighting-19bd57b89c648592155156049addf67e0638eab1.tar.gz/sha512 create mode 100644 deps/checksums/JuliaSyntaxHighlighting-eb8097c5f1dbfca80b5e6664af031ff1fe0904af.tar.gz/md5 create mode 100644 deps/checksums/JuliaSyntaxHighlighting-eb8097c5f1dbfca80b5e6664af031ff1fe0904af.tar.gz/sha512 diff --git a/deps/checksums/JuliaSyntaxHighlighting-19bd57b89c648592155156049addf67e0638eab1.tar.gz/md5 b/deps/checksums/JuliaSyntaxHighlighting-19bd57b89c648592155156049addf67e0638eab1.tar.gz/md5 deleted file mode 100644 index a86f3fe9c5561..0000000000000 --- a/deps/checksums/JuliaSyntaxHighlighting-19bd57b89c648592155156049addf67e0638eab1.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -401bb32ca43a8460d6790ee80e695bb5 diff --git a/deps/checksums/JuliaSyntaxHighlighting-19bd57b89c648592155156049addf67e0638eab1.tar.gz/sha512 b/deps/checksums/JuliaSyntaxHighlighting-19bd57b89c648592155156049addf67e0638eab1.tar.gz/sha512 deleted file mode 100644 index 6e54aef5fd34f..0000000000000 --- a/deps/checksums/JuliaSyntaxHighlighting-19bd57b89c648592155156049addf67e0638eab1.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -db2c732d3343f5a8770b3516cdd900587d497feab2259a937d354fac436ab3cb099b0401fb4e05817e75744fb9877ab69b1e4879d8a710b33b69c95b7e58d961 diff --git a/deps/checksums/JuliaSyntaxHighlighting-eb8097c5f1dbfca80b5e6664af031ff1fe0904af.tar.gz/md5 b/deps/checksums/JuliaSyntaxHighlighting-eb8097c5f1dbfca80b5e6664af031ff1fe0904af.tar.gz/md5 new file mode 100644 index 0000000000000..2b717077de398 --- /dev/null +++ b/deps/checksums/JuliaSyntaxHighlighting-eb8097c5f1dbfca80b5e6664af031ff1fe0904af.tar.gz/md5 @@ -0,0 +1 @@ +73d1db780528e93c4b756a2182bacfc2 diff --git a/deps/checksums/JuliaSyntaxHighlighting-eb8097c5f1dbfca80b5e6664af031ff1fe0904af.tar.gz/sha512 b/deps/checksums/JuliaSyntaxHighlighting-eb8097c5f1dbfca80b5e6664af031ff1fe0904af.tar.gz/sha512 new file mode 100644 index 0000000000000..dac11d46691a9 --- /dev/null +++ b/deps/checksums/JuliaSyntaxHighlighting-eb8097c5f1dbfca80b5e6664af031ff1fe0904af.tar.gz/sha512 @@ -0,0 +1 @@ +a994a3a9af8188f4c5985b91c8dc3e449b101eb4e56c4f9bccd69a528bd13fa919cc0cd39f101afa3d4245ad3b8e6691ca539969fefa0868e4b1f256d6ffa49e diff --git a/doc/Manifest.toml b/doc/Manifest.toml index e91958808828e..481b7240c0caf 100644 --- a/doc/Manifest.toml +++ b/doc/Manifest.toml @@ -101,7 +101,7 @@ version = "0.21.4" [[deps.JuliaSyntaxHighlighting]] deps = ["StyledStrings"] -uuid = "dc6e5ff7-fb65-4e79-a425-ec3bc9c03011" +uuid = "ac6e5ff7-fb65-4e79-a425-ec3bc9c03011" version = "1.12.0" [[deps.LazilyInitializedFields]] diff --git a/stdlib/JuliaSyntaxHighlighting.version b/stdlib/JuliaSyntaxHighlighting.version index 2a409c721d32b..ab3b0e930eb48 100644 --- a/stdlib/JuliaSyntaxHighlighting.version +++ b/stdlib/JuliaSyntaxHighlighting.version @@ -1,4 +1,4 @@ JULIASYNTAXHIGHLIGHTING_BRANCH = main -JULIASYNTAXHIGHLIGHTING_SHA1 = 19bd57b89c648592155156049addf67e0638eab1 +JULIASYNTAXHIGHLIGHTING_SHA1 = eb8097c5f1dbfca80b5e6664af031ff1fe0904af JULIASYNTAXHIGHLIGHTING_GIT_URL := https://github.com/julialang/JuliaSyntaxHighlighting.jl.git JULIASYNTAXHIGHLIGHTING_TAR_URL = https://api.github.com/repos/julialang/JuliaSyntaxHighlighting.jl/tarball/$1 diff --git a/stdlib/Manifest.toml b/stdlib/Manifest.toml index f029a210320cc..b149532d7b203 100644 --- a/stdlib/Manifest.toml +++ b/stdlib/Manifest.toml @@ -67,7 +67,7 @@ version = "1.11.0" [[deps.JuliaSyntaxHighlighting]] deps = ["StyledStrings"] -uuid = "dc6e5ff7-fb65-4e79-a425-ec3bc9c03011" +uuid = "ac6e5ff7-fb65-4e79-a425-ec3bc9c03011" version = "1.12.0" [[deps.LLD_jll]] diff --git a/stdlib/Markdown/Project.toml b/stdlib/Markdown/Project.toml index a48a3d1f0b345..1d5962c80803d 100644 --- a/stdlib/Markdown/Project.toml +++ b/stdlib/Markdown/Project.toml @@ -4,7 +4,7 @@ version = "1.11.0" [deps] Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" -JuliaSyntaxHighlighting = "dc6e5ff7-fb65-4e79-a425-ec3bc9c03011" +JuliaSyntaxHighlighting = "ac6e5ff7-fb65-4e79-a425-ec3bc9c03011" StyledStrings = "f489334b-da3d-4c2e-b8f0-e476e12c162b" [extras] diff --git a/stdlib/Project.toml b/stdlib/Project.toml index 92996cf017d0d..1e03a0f474490 100644 --- a/stdlib/Project.toml +++ b/stdlib/Project.toml @@ -12,7 +12,7 @@ FileWatching = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" Future = "9fa8497b-333b-5362-9e8d-4d0656e87820" GMP_jll = "781609d7-10c4-51f6-84f2-b8444358ff6d" InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" -JuliaSyntaxHighlighting = "dc6e5ff7-fb65-4e79-a425-ec3bc9c03011" +JuliaSyntaxHighlighting = "ac6e5ff7-fb65-4e79-a425-ec3bc9c03011" LLD_jll = "d55e3150-da41-5e91-b323-ecfd1eec6109" LLVMLibUnwind_jll = "47c5dbc3-30ba-59ef-96a6-123e260183d9" LazyArtifacts = "4af54fe1-eca0-43a8-85a7-787d91b784e3" diff --git a/stdlib/REPL/Project.toml b/stdlib/REPL/Project.toml index f60a6a4766093..5ee3849f507f2 100644 --- a/stdlib/REPL/Project.toml +++ b/stdlib/REPL/Project.toml @@ -4,7 +4,7 @@ version = "1.11.0" [deps] InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" -JuliaSyntaxHighlighting = "dc6e5ff7-fb65-4e79-a425-ec3bc9c03011" +JuliaSyntaxHighlighting = "ac6e5ff7-fb65-4e79-a425-ec3bc9c03011" Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" Sockets = "6462fe0b-24de-5631-8697-dd941f90decc" StyledStrings = "f489334b-da3d-4c2e-b8f0-e476e12c162b" From 683c5e7ec4977f3c77e29fb47a13cc4c78cdf595 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 30 Jan 2025 00:28:48 -0500 Subject: [PATCH 255/342] move forward edges stripping code to correct place (#57197) Fixes a regression in the size of stripped binaries. --- src/staticdata.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/staticdata.c b/src/staticdata.c index ff352cd8c152f..b5d6fb7cdd62a 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -2623,7 +2623,6 @@ static void strip_specializations_(jl_method_instance_t *mi) if (inferred && inferred != jl_nothing) { if (jl_options.strip_ir) { record_field_change((jl_value_t**)&codeinst->inferred, jl_nothing); - record_field_change((jl_value_t**)&codeinst->edges, (jl_value_t*)jl_emptysvec); } else if (jl_options.strip_metadata) { jl_value_t *stripped = strip_codeinfo_meta(mi->def.method, inferred, codeinst); @@ -2632,6 +2631,8 @@ static void strip_specializations_(jl_method_instance_t *mi) } } } + if (jl_options.strip_ir) + record_field_change((jl_value_t**)&codeinst->edges, (jl_value_t*)jl_emptysvec); if (jl_options.strip_metadata) record_field_change((jl_value_t**)&codeinst->debuginfo, (jl_value_t*)jl_nulldebuginfo); codeinst = jl_atomic_load_relaxed(&codeinst->next); From 9777a33824c1f954dc334ad3de7618b173998eb6 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Thu, 30 Jan 2025 07:55:51 -0500 Subject: [PATCH 256/342] codegen (stubs): report success when registering `@ccallable` (#57200) This is required to be able to load a sysimage with ccallable entrypoints without `libjulia-codegen.so` --- src/codegen-stubs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/codegen-stubs.c b/src/codegen-stubs.c index 5e243ddda28c9..6b547251eaab8 100644 --- a/src/codegen-stubs.c +++ b/src/codegen-stubs.c @@ -73,7 +73,10 @@ JL_DLLEXPORT uint32_t jl_get_LLVM_VERSION_fallback(void) JL_DLLEXPORT int jl_compile_extern_c_fallback(LLVMOrcThreadSafeModuleRef llvmmod, void *params, void *sysimg, jl_value_t *declrt, jl_value_t *sigt) { - return 0; + // Assume we were able to register the ccallable with the JIT. The + // fact that we didn't is not observable since we cannot compile + // anything else. + return 1; } JL_DLLEXPORT void jl_teardown_codegen_fallback(void) JL_NOTSAFEPOINT From 3e08cb1b99e28bc2131bfbb840c5c23619c0bf15 Mon Sep 17 00:00:00 2001 From: Chengyu Han Date: Fri, 31 Jan 2025 00:00:46 +0800 Subject: [PATCH 257/342] deps: update JuliaSyntax to v1.0.0 (#57188) This pr: - Update JuliaSyntax to v1.0.0 - Update JuliaSyntaxHighlighting to latest Note: `JuliaSyntax.jl` contains some breaking changes in v1.0.0, so we need to update `JuliaSyntaxHighlighting.jl` at the same time. Close #57166 --- deps/JuliaSyntax.version | 2 +- .../md5 | 1 + .../sha512 | 1 + .../md5 | 1 - .../sha512 | 1 - .../md5 | 1 + .../sha512 | 1 + .../md5 | 1 - .../sha512 | 1 - stdlib/JuliaSyntaxHighlighting.version | 2 +- test/syntax.jl | 16 +++++++++------- 11 files changed, 15 insertions(+), 13 deletions(-) create mode 100644 deps/checksums/JuliaSyntax-2e965a159dd9f87d216d2d50ecbd2ed4f9af2c5a.tar.gz/md5 create mode 100644 deps/checksums/JuliaSyntax-2e965a159dd9f87d216d2d50ecbd2ed4f9af2c5a.tar.gz/sha512 delete mode 100644 deps/checksums/JuliaSyntax-dfd1d69b153eb119873035e62993a109b27192f0.tar.gz/md5 delete mode 100644 deps/checksums/JuliaSyntax-dfd1d69b153eb119873035e62993a109b27192f0.tar.gz/sha512 create mode 100644 deps/checksums/JuliaSyntaxHighlighting-2680c8bde1aa274f25d7a434c645f16b3a1ee731.tar.gz/md5 create mode 100644 deps/checksums/JuliaSyntaxHighlighting-2680c8bde1aa274f25d7a434c645f16b3a1ee731.tar.gz/sha512 delete mode 100644 deps/checksums/JuliaSyntaxHighlighting-eb8097c5f1dbfca80b5e6664af031ff1fe0904af.tar.gz/md5 delete mode 100644 deps/checksums/JuliaSyntaxHighlighting-eb8097c5f1dbfca80b5e6664af031ff1fe0904af.tar.gz/sha512 diff --git a/deps/JuliaSyntax.version b/deps/JuliaSyntax.version index 86f94135884a0..a7d31b7c16403 100644 --- a/deps/JuliaSyntax.version +++ b/deps/JuliaSyntax.version @@ -1,4 +1,4 @@ JULIASYNTAX_BRANCH = main -JULIASYNTAX_SHA1 = dfd1d69b153eb119873035e62993a109b27192f0 +JULIASYNTAX_SHA1 = 2e965a159dd9f87d216d2d50ecbd2ed4f9af2c5a 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-2e965a159dd9f87d216d2d50ecbd2ed4f9af2c5a.tar.gz/md5 b/deps/checksums/JuliaSyntax-2e965a159dd9f87d216d2d50ecbd2ed4f9af2c5a.tar.gz/md5 new file mode 100644 index 0000000000000..96f356f3faaec --- /dev/null +++ b/deps/checksums/JuliaSyntax-2e965a159dd9f87d216d2d50ecbd2ed4f9af2c5a.tar.gz/md5 @@ -0,0 +1 @@ +40d7bcc6e5741d50a457ace2ca8b2c0c diff --git a/deps/checksums/JuliaSyntax-2e965a159dd9f87d216d2d50ecbd2ed4f9af2c5a.tar.gz/sha512 b/deps/checksums/JuliaSyntax-2e965a159dd9f87d216d2d50ecbd2ed4f9af2c5a.tar.gz/sha512 new file mode 100644 index 0000000000000..fd7770cdeaa75 --- /dev/null +++ b/deps/checksums/JuliaSyntax-2e965a159dd9f87d216d2d50ecbd2ed4f9af2c5a.tar.gz/sha512 @@ -0,0 +1 @@ +b9429b90a28460ef0272cd42a5c221629c6d60221ed088ae3e591cc3d8dbdec32788074397419e58b611bda7df32c7379ec7fafeead7056ed9665591474cec5d diff --git a/deps/checksums/JuliaSyntax-dfd1d69b153eb119873035e62993a109b27192f0.tar.gz/md5 b/deps/checksums/JuliaSyntax-dfd1d69b153eb119873035e62993a109b27192f0.tar.gz/md5 deleted file mode 100644 index 51b30461d3905..0000000000000 --- a/deps/checksums/JuliaSyntax-dfd1d69b153eb119873035e62993a109b27192f0.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -e58559668aabb0fa96d598970c4d648e diff --git a/deps/checksums/JuliaSyntax-dfd1d69b153eb119873035e62993a109b27192f0.tar.gz/sha512 b/deps/checksums/JuliaSyntax-dfd1d69b153eb119873035e62993a109b27192f0.tar.gz/sha512 deleted file mode 100644 index 63a513ec9ae63..0000000000000 --- a/deps/checksums/JuliaSyntax-dfd1d69b153eb119873035e62993a109b27192f0.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -59e22f7db63a383beadf96a68d4db6ae173d61be6d766ea1792b3a3bd70125f73dd4df9e55bad4c66363aa0b6ff6ea5259d3c91abf42f5fe34446e3fa076cc87 diff --git a/deps/checksums/JuliaSyntaxHighlighting-2680c8bde1aa274f25d7a434c645f16b3a1ee731.tar.gz/md5 b/deps/checksums/JuliaSyntaxHighlighting-2680c8bde1aa274f25d7a434c645f16b3a1ee731.tar.gz/md5 new file mode 100644 index 0000000000000..30284ccf352d4 --- /dev/null +++ b/deps/checksums/JuliaSyntaxHighlighting-2680c8bde1aa274f25d7a434c645f16b3a1ee731.tar.gz/md5 @@ -0,0 +1 @@ +187f155c32a79f57a89e31e672d2d8c5 diff --git a/deps/checksums/JuliaSyntaxHighlighting-2680c8bde1aa274f25d7a434c645f16b3a1ee731.tar.gz/sha512 b/deps/checksums/JuliaSyntaxHighlighting-2680c8bde1aa274f25d7a434c645f16b3a1ee731.tar.gz/sha512 new file mode 100644 index 0000000000000..bdce410b84d69 --- /dev/null +++ b/deps/checksums/JuliaSyntaxHighlighting-2680c8bde1aa274f25d7a434c645f16b3a1ee731.tar.gz/sha512 @@ -0,0 +1 @@ +69347af996d77b88b5e5b6e44ff046e9197775a66802a0da6fb5fcbf9e5ca533566955c8435bc25490f6ca0c002b4c1effcddaf932b7eb91e00a8f99554b7b8d diff --git a/deps/checksums/JuliaSyntaxHighlighting-eb8097c5f1dbfca80b5e6664af031ff1fe0904af.tar.gz/md5 b/deps/checksums/JuliaSyntaxHighlighting-eb8097c5f1dbfca80b5e6664af031ff1fe0904af.tar.gz/md5 deleted file mode 100644 index 2b717077de398..0000000000000 --- a/deps/checksums/JuliaSyntaxHighlighting-eb8097c5f1dbfca80b5e6664af031ff1fe0904af.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -73d1db780528e93c4b756a2182bacfc2 diff --git a/deps/checksums/JuliaSyntaxHighlighting-eb8097c5f1dbfca80b5e6664af031ff1fe0904af.tar.gz/sha512 b/deps/checksums/JuliaSyntaxHighlighting-eb8097c5f1dbfca80b5e6664af031ff1fe0904af.tar.gz/sha512 deleted file mode 100644 index dac11d46691a9..0000000000000 --- a/deps/checksums/JuliaSyntaxHighlighting-eb8097c5f1dbfca80b5e6664af031ff1fe0904af.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -a994a3a9af8188f4c5985b91c8dc3e449b101eb4e56c4f9bccd69a528bd13fa919cc0cd39f101afa3d4245ad3b8e6691ca539969fefa0868e4b1f256d6ffa49e diff --git a/stdlib/JuliaSyntaxHighlighting.version b/stdlib/JuliaSyntaxHighlighting.version index ab3b0e930eb48..14eb1cedf49a4 100644 --- a/stdlib/JuliaSyntaxHighlighting.version +++ b/stdlib/JuliaSyntaxHighlighting.version @@ -1,4 +1,4 @@ JULIASYNTAXHIGHLIGHTING_BRANCH = main -JULIASYNTAXHIGHLIGHTING_SHA1 = eb8097c5f1dbfca80b5e6664af031ff1fe0904af +JULIASYNTAXHIGHLIGHTING_SHA1 = 2680c8bde1aa274f25d7a434c645f16b3a1ee731 JULIASYNTAXHIGHLIGHTING_GIT_URL := https://github.com/julialang/JuliaSyntaxHighlighting.jl.git JULIASYNTAXHIGHLIGHTING_TAR_URL = https://api.github.com/repos/julialang/JuliaSyntaxHighlighting.jl/tarball/$1 diff --git a/test/syntax.jl b/test/syntax.jl index aaeeea7aec161..f29dd4978d309 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -377,8 +377,8 @@ add_method_to_glob_fn!() @test_parseerror "function finally() end" # PR #16170 -@test Meta.lower(Main, Meta.parse("true(x) = x")) == Expr(:error, "invalid function name \"true\"") -@test Meta.lower(Main, Meta.parse("false(x) = x")) == Expr(:error, "invalid function name \"false\"") +@test Meta.lower(Main, Meta.parse("true(x) = x")) == Expr(:error, "\"true\" is not a valid function argument name") +@test Meta.lower(Main, Meta.parse("false(x) = x")) == Expr(:error, "\"false\" is not a valid function argument name") # issue #16355 @test Meta.lower(Main, :(f(d:Int...) = nothing)) == Expr(:error, "\"d:Int\" is not a valid function argument name") @@ -925,8 +925,8 @@ g21054(>:) = >:2 @test g21054(-) == -2 # issue #21168 -@test Meta.lower(Main, :(a.[1])) == Expr(:error, "invalid syntax \"a.[1]\"") -@test Meta.lower(Main, :(a.{1})) == Expr(:error, "invalid syntax \"a.{1}\"") +@test_broken Meta.lower(Main, :(a.[1])) == Expr(:error, "invalid syntax \"a.[1]\"") +@test_broken Meta.lower(Main, :(a.{1})) == Expr(:error, "invalid syntax \"a.{1}\"") # Issue #21225 let abstr = Meta.parse("abstract type X end") @@ -1496,8 +1496,8 @@ end # issue #26739 let exc = try Core.eval(@__MODULE__, :(sin.[1])) catch exc ; exc end - @test exc isa ErrorException - @test startswith(exc.msg, "syntax: invalid syntax \"sin.[1]\"") + @test_broken exc isa ErrorException + @test_broken startswith(exc.msg, "syntax: invalid syntax \"sin.[1]\"") end # issue #26873 @@ -2454,7 +2454,9 @@ end @test_throws MethodError @m37134()(1.0) == 62 macro n37134() - :($(esc(Expr(:tuple, Expr(:..., :x))))->$(esc(:x))) + quote + ((x...,)) -> (x) + end |> esc end @test @n37134()(2,1) === (2,1) From cf4ab8336468f73bbc768187864586bedbd59342 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Thu, 30 Jan 2025 16:15:48 -0500 Subject: [PATCH 258/342] REPL: fix test that fails locally via `Pkg.test` (#57202) Via `Base.runtests` it seems stdlibs are generally available in test environments. In `Pkg.test` they must be in the test env, which Profile isn't, so this failed locally. All REPL tests pass locally with this. --- stdlib/REPL/test/docview.jl | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/stdlib/REPL/test/docview.jl b/stdlib/REPL/test/docview.jl index c81715ad69921..8c92d9b3b1d95 100644 --- a/stdlib/REPL/test/docview.jl +++ b/stdlib/REPL/test/docview.jl @@ -29,8 +29,22 @@ end end @testset "non-loaded packages in doc search" begin - str = get_help_io("Profile") - @test occursin("Couldn't find Profile, but a loadable package with that name exists.", str) + temp_package = mktempdir() + write(joinpath(temp_package, "Project.toml"), + """ + name = "FooPackage" + uuid = "2e6e0b2d-0e7f-4b7f-9f3b-6f3f3f3f3f3f" + """) + mkpath(joinpath(temp_package, "src")) + write(joinpath(temp_package, "src", "FooPackage.jl"), + """ + module FooPackage + end + """) + push!(LOAD_PATH, temp_package) + str = get_help_io("FooPackage") + @test occursin("Couldn't find FooPackage, but a loadable package with that name exists.", str) + @test pop!(LOAD_PATH) == temp_package end @testset "Check @var_str also completes to var\"\" in REPL.doc_completions()" begin From 2a9c1336d7c89955f60cf6619810ed4150d70ac9 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Fri, 31 Jan 2025 06:57:36 -0500 Subject: [PATCH 259/342] juliac: add pre-compilation step to build pipeline (#57207) This is required to avoid obscure loading / package errors during the trimming build process. --- contrib/juliac.jl | 95 +++++++++++++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 37 deletions(-) diff --git a/contrib/juliac.jl b/contrib/juliac.jl index 20d56615c6357..3d1a3ef13fe79 100644 --- a/contrib/juliac.jl +++ b/contrib/juliac.jl @@ -1,8 +1,7 @@ # Julia compiler wrapper script # NOTE: The interface and location of this script are considered unstable/experimental -cmd = Base.julia_cmd() -cmd = `$cmd --startup-file=no --history-file=no` +julia_cmd = `$(Base.julia_cmd()) --startup-file=no --history-file=no` output_type = nothing # exe, sharedlib, sysimage outname = nothing file = nothing @@ -55,9 +54,9 @@ isnothing(outname) && error("No output file specified") isnothing(file) && error("No input file specified") absfile = abspath(file) -cflags = readchomp(`$(cmd) $(joinpath(Sys.BINDIR, Base.DATAROOTDIR,"julia", "julia-config.jl")) --cflags `) +cflags = readchomp(`$(julia_cmd) $(joinpath(Sys.BINDIR, Base.DATAROOTDIR,"julia", "julia-config.jl")) --cflags `) cflags = Base.shell_split(cflags) -allflags = readchomp(`$(cmd) $(joinpath(Sys.BINDIR, Base.DATAROOTDIR,"julia", "julia-config.jl")) --allflags`) +allflags = readchomp(`$(julia_cmd) $(joinpath(Sys.BINDIR, Base.DATAROOTDIR,"julia", "julia-config.jl")) --allflags`) allflags = Base.shell_split(allflags) tmpdir = mktempdir(cleanup=false) initsrc_path = joinpath(tmpdir, "init.c") @@ -65,45 +64,67 @@ init_path = joinpath(tmpdir, "init.a") img_path = joinpath(tmpdir, "img.a") bc_path = joinpath(tmpdir, "img-bc.a") -open(initsrc_path, "w") do io - print(io, """ - #include - __attribute__((constructor)) void static_init(void) { - if (jl_is_initialized()) - return; - julia_init(JL_IMAGE_IN_MEMORY); - jl_exception_clear(); - } - """) -end -cmd = addenv(`$cmd --project=$(Base.active_project()) --output-o $img_path --output-incremental=no --strip-ir --strip-metadata $julia_args $(joinpath(@__DIR__,"juliac-buildscript.jl")) $absfile $output_type $add_ccallables`, "OPENBLAS_NUM_THREADS" => 1, "JULIA_NUM_THREADS" => 1) -verbose && println("Running: $cmd") -if !success(pipeline(cmd; stdout, stderr)) - println(stderr, "\nFailed to compile $file") - exit(1) +function precompile_env() + # Pre-compile the environment + # (otherwise obscure error messages will occur) + cmd = addenv(`$julia_cmd --project=$(Base.active_project()) -e "using Pkg; Pkg.precompile()"`) + verbose && println("Running: $cmd") + if !success(pipeline(cmd; stdout, stderr)) + println(stderr, "\nError encountered during pre-compilation of environment.") + exit(1) + end end -run(`cc $(cflags) -g -c -o $init_path $initsrc_path`) +function compile_products() + # Compile the Julia code + cmd = addenv(`$julia_cmd --project=$(Base.active_project()) --output-o $img_path --output-incremental=no --strip-ir --strip-metadata $julia_args $(joinpath(@__DIR__,"juliac-buildscript.jl")) $absfile $output_type $add_ccallables`, "OPENBLAS_NUM_THREADS" => 1, "JULIA_NUM_THREADS" => 1) + verbose && println("Running: $cmd") + if !success(pipeline(cmd; stdout, stderr)) + println(stderr, "\nFailed to compile $file") + exit(1) + end -if output_type == "--output-lib" || output_type == "--output-sysimage" - of, ext = splitext(outname) - soext = "." * Base.BinaryPlatforms.platform_dlext() - if ext == "" - outname = of * soext + # Compile the initialization code + open(initsrc_path, "w") do io + print(io, """ + #include + __attribute__((constructor)) void static_init(void) { + if (jl_is_initialized()) + return; + julia_init(JL_IMAGE_IN_MEMORY); + jl_exception_clear(); + } + """) end + run(`cc $(cflags) -g -c -o $init_path $initsrc_path`) end -julia_libs = Base.shell_split(Base.isdebugbuild() ? "-ljulia-debug -ljulia-internal-debug" : "-ljulia -ljulia-internal") -try - if output_type == "--output-lib" - run(`cc $(allflags) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $init_path $(julia_libs)`) - elseif output_type == "--output-sysimage" - run(`cc $(allflags) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $(julia_libs)`) - else - run(`cc $(allflags) -o $outname -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $init_path $(julia_libs)`) +function link_products() + global outname + if output_type == "--output-lib" || output_type == "--output-sysimage" + of, ext = splitext(outname) + soext = "." * Base.BinaryPlatforms.platform_dlext() + if ext == "" + outname = of * soext + end + end + + julia_libs = Base.shell_split(Base.isdebugbuild() ? "-ljulia-debug -ljulia-internal-debug" : "-ljulia -ljulia-internal") + try + if output_type == "--output-lib" + run(`cc $(allflags) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $init_path $(julia_libs)`) + elseif output_type == "--output-sysimage" + run(`cc $(allflags) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $(julia_libs)`) + else + run(`cc $(allflags) -o $outname -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $init_path $(julia_libs)`) + end + catch e + println("\nCompilation failed: ", e) + exit(1) end -catch - println("\nCompilation failed.") - exit(1) end + +precompile_env() +compile_products() +link_products() From 162cfb3b46d95c96965b0d8df41f1f65ff560840 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Fri, 31 Jan 2025 07:00:43 -0500 Subject: [PATCH 260/342] juliac: add `invokelatest_gr` override to juliac-buildscript.jl (#57205) This extends the existing `invokelatest` hack to treat the current world as the latest world for globalref lookups. Since this came up, @Keno can you confirm that any world-age-affecting operations on bindings still require `eval()`? Are there any imports / assignments / etc. that might bump the world age by changing a binding? --- contrib/juliac-buildscript.jl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/contrib/juliac-buildscript.jl b/contrib/juliac-buildscript.jl index 0303e95f448b5..c23b679272b1e 100644 --- a/contrib/juliac-buildscript.jl +++ b/contrib/juliac-buildscript.jl @@ -38,6 +38,14 @@ end @inline function invokelatest(f::F, args...; kwargs...) where F return f(args...; kwargs...) end + @inline function invokelatest_gr(gr::GlobalRef, @nospecialize args...; kwargs...) + @inline + kwargs = merge(NamedTuple(), kwargs) + if isempty(kwargs) + return apply_gr(gr, args...) + end + return apply_gr_kw(kwargs, gr, args...) + end function sprint(f::F, args::Vararg{Any,N}; context=nothing, sizehint::Integer=0) where {F<:Function,N} s = IOBuffer(sizehint=sizehint) if context isa Tuple From dbcdf735ff9ca016ad07725381bcfbc352fdac1b Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Fri, 31 Jan 2025 08:03:56 -0500 Subject: [PATCH 261/342] add interactive pool size to `Base.runtests` report (#57215) --- test/runtests.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index f0c5e1b94c376..1872c888333da 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -120,7 +120,8 @@ cd(@__DIR__) do Running parallel tests with: getpid() = $(getpid()) nworkers() = $(nworkers()) - nthreads() = $(Threads.threadpoolsize()) + nthreads(:interactive) = $(Threads.threadpoolsize(:interactive)) + nthreads(:default) = $(Threads.threadpoolsize(:default)) Sys.CPU_THREADS = $(Sys.CPU_THREADS) Sys.total_memory() = $(Base.format_bytes(Sys.total_memory())) Sys.free_memory() = $(Base.format_bytes(Sys.free_memory())) From 3952c2cc8ebbd0513e3c53844116d77755036608 Mon Sep 17 00:00:00 2001 From: Jakob Nybo Nissen Date: Fri, 31 Jan 2025 14:18:48 +0100 Subject: [PATCH 262/342] Add `@inline` to Base.reinterpret (#57078) Reinterpret contains quite a bit of code to handle padding, and so doesn't usually inline for structs. However, it frequently compiles down to a noop, making an inline unusually valuable. --- base/essentials.jl | 1 + base/reinterpretarray.jl | 39 ++++++++++++++++++++++++--------------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/base/essentials.jl b/base/essentials.jl index 58e4ce1125093..5db7a5f6fb0d9 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -726,6 +726,7 @@ julia> reinterpret(Tuple{UInt16, UInt8}, (0x01, 0x0203)) """ function reinterpret(::Type{Out}, x) where {Out} + @inline if isprimitivetype(Out) && isprimitivetype(typeof(x)) return bitcast(Out, x) end diff --git a/base/reinterpretarray.jl b/base/reinterpretarray.jl index d31f3ebb5dd2d..4feb14539f9dc 100644 --- a/base/reinterpretarray.jl +++ b/base/reinterpretarray.jl @@ -871,25 +871,34 @@ end return out[] else # mismatched padding - GC.@preserve in out begin - ptr_in = unsafe_convert(Ptr{In}, in) - ptr_out = unsafe_convert(Ptr{Out}, out) + return _reinterpret_padding(Out, x) + end +end - if fieldcount(In) > 0 && ispacked(Out) - _copytopacked!(ptr_out, ptr_in) - elseif fieldcount(Out) > 0 && ispacked(In) - _copyfrompacked!(ptr_out, ptr_in) - else - packed = Ref{NTuple{inpackedsize, UInt8}}() - GC.@preserve packed begin - ptr_packed = unsafe_convert(Ptr{NTuple{inpackedsize, UInt8}}, packed) - _copytopacked!(ptr_packed, ptr_in) - _copyfrompacked!(ptr_out, ptr_packed) - end +# If the code reaches this part, it needs to handle padding and is unlikely +# to compile to a noop. Therefore, we don't forcibly inline it. +function _reinterpret_padding(::Type{Out}, x::In) where {Out, In} + inpackedsize = packedsize(In) + in = Ref{In}(x) + out = Ref{Out}() + GC.@preserve in out begin + ptr_in = unsafe_convert(Ptr{In}, in) + ptr_out = unsafe_convert(Ptr{Out}, out) + + if fieldcount(In) > 0 && ispacked(Out) + _copytopacked!(ptr_out, ptr_in) + elseif fieldcount(Out) > 0 && ispacked(In) + _copyfrompacked!(ptr_out, ptr_in) + else + packed = Ref{NTuple{inpackedsize, UInt8}}() + GC.@preserve packed begin + ptr_packed = unsafe_convert(Ptr{NTuple{inpackedsize, UInt8}}, packed) + _copytopacked!(ptr_packed, ptr_in) + _copyfrompacked!(ptr_out, ptr_packed) end end - return out[] end + return out[] end From dbe19e49d9e7770856cdf88e492f22ec7827820d Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 31 Jan 2025 09:36:24 -0500 Subject: [PATCH 263/342] staticdata: Insert backedges recursively (#57212) In the new edges scheme, when we perform constant propagation, we create a dummy CodeInstance that is not inserted into the specializations cache, but instead simply serves as a container for all edges that were encountered during the constant propagation. These CodeInstances are not part of either the internal or external edges list collected during pkgimage generation. As such, while we were verifying edges recursively and would thus catch an invalidation prior to package image reload, we were failing to also insert backedges for these CodeInstance. We were thus failing to invalidate such methods if the method was redefined after re-load of the package image. Fix that by moving the storing of the backedges to the end of the validation code, so that it too happens recursively. --- base/staticdata.jl | 39 +++++++++++++++++---------------------- test/precompile.jl | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 22 deletions(-) diff --git a/base/staticdata.jl b/base/staticdata.jl index 79d81788cc16a..345769e479380 100644 --- a/base/staticdata.jl +++ b/base/staticdata.jl @@ -39,26 +39,16 @@ function _insert_backedges(edges::Vector{Any}, stack::Vector{CodeInstance}, visi verify_method_graph(codeinst, stack, visiting) minvalid = codeinst.min_world maxvalid = codeinst.max_world - if maxvalid ≥ minvalid - if get_world_counter() == maxvalid - # if this callee is still valid, add all the backedges - Base.Compiler.store_backedges(codeinst, codeinst.edges) - end - if get_world_counter() == maxvalid - maxvalid = typemax(UInt) - @atomic :monotonic codeinst.max_world = maxvalid - end - if external - caller = get_ci_mi(codeinst) - @assert isdefined(codeinst, :inferred) # See #53586, #53109 - inferred = @ccall jl_rettype_inferred( - codeinst.owner::Any, caller::Any, minvalid::UInt, maxvalid::UInt)::Any - if inferred !== nothing - # We already got a code instance for this world age range from - # somewhere else - we don't need this one. - else - @ccall jl_mi_cache_insert(caller::Any, codeinst::Any)::Cvoid - end + if maxvalid ≥ minvalid && external + caller = get_ci_mi(codeinst) + @assert isdefined(codeinst, :inferred) # See #53586, #53109 + inferred = @ccall jl_rettype_inferred( + codeinst.owner::Any, caller::Any, minvalid::UInt, maxvalid::UInt)::Any + if inferred !== nothing + # We already got a code instance for this world age range from + # somewhere else - we don't need this one. + else + @ccall jl_mi_cache_insert(caller::Any, codeinst::Any)::Cvoid end end end @@ -196,9 +186,14 @@ function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visi while length(stack) ≥ depth child = pop!(stack) if maxworld ≠ 0 - @atomic :monotonic child.min_world = minworld + @atomic :monotonic child.min_world = minworld + end + if maxworld == current_world + Base.Compiler.store_backedges(child, child.edges) + @atomic :monotonic child.max_world = typemax(UInt) + else + @atomic :monotonic child.max_world = maxworld end - @atomic :monotonic child.max_world = maxworld @assert visiting[child] == length(stack) + 1 delete!(visiting, child) invalidations = _jl_debug_method_invalidation[] diff --git a/test/precompile.jl b/test/precompile.jl index a9516231ff8d7..194f88719642e 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -2222,4 +2222,37 @@ precompile_test_harness("No package module") do load_path String(take!(io))) end +precompile_test_harness("Constprop CodeInstance invalidation") do load_path + write(joinpath(load_path, "DefineTheMethod.jl"), + """ + module DefineTheMethod + export the_method + the_method_val(::Val{x}) where {x} = x + the_method_val(::Val{1}) = 0xdeadbeef + the_method_val(::Val{2}) = 2 + the_method_val(::Val{3}) = 3 + the_method_val(::Val{4}) = 4 + the_method_val(::Val{5}) = 5 + Base.@constprop :aggressive the_method(x) = the_method_val(Val{x}()) + the_method(2) + end + """) + Base.compilecache(Base.PkgId("DefineTheMethod")) + write(joinpath(load_path, "CallTheMethod.jl"), + """ + module CallTheMethod + using DefineTheMethod + call_the_method() = the_method(1) + call_the_method() + end + """) + Base.compilecache(Base.PkgId("CallTheMethod")) + @eval using DefineTheMethod + @eval using CallTheMethod + @eval DefineTheMethod.the_method_val(::Val{1}) = Int(0) + invokelatest() do + @test Int(0) == CallTheMethod.call_the_method() + end +end + finish_precompile_test!() From 0b9525bf81a1727e18d3342a6da7f8505bc447f5 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Fri, 31 Jan 2025 12:08:26 -0500 Subject: [PATCH 264/342] REPL: generate tab completion hints on a worker thread to not block typing (#57192) --- stdlib/REPL/src/LineEdit.jl | 110 ++++++++++++++++++++++++------------ stdlib/REPL/src/REPL.jl | 10 ++-- 2 files changed, 79 insertions(+), 41 deletions(-) diff --git a/stdlib/REPL/src/LineEdit.jl b/stdlib/REPL/src/LineEdit.jl index e15807f645119..0f9979d768af3 100644 --- a/stdlib/REPL/src/LineEdit.jl +++ b/stdlib/REPL/src/LineEdit.jl @@ -77,9 +77,12 @@ mutable struct MIState last_action::Symbol current_action::Symbol async_channel::Channel{Function} + line_modify_lock::Base.ReentrantLock + hint_generation_lock::Base.ReentrantLock + n_keys_pressed::Int end -MIState(i, mod, c, a, m) = MIState(i, mod, mod, c, a, m, String[], 0, Char[], 0, :none, :none, Channel{Function}()) +MIState(i, mod, c, a, m) = MIState(i, mod, mod, c, a, m, String[], 0, Char[], 0, :none, :none, Channel{Function}(), Base.ReentrantLock(), Base.ReentrantLock(), 0) const BufferLike = Union{MIState,ModeState,IOBuffer} const State = Union{MIState,ModeState} @@ -400,47 +403,82 @@ function complete_line_named(args...; kwargs...)::Tuple{Vector{NamedCompletion}, end end -function check_for_hint(s::MIState) +# checks for a hint and shows it if appropriate. +# to allow the user to type even if hint generation is slow, the +# hint is generated on a worker thread, and only shown if the user hasn't +# pressed a key since the hint generation was requested +function check_show_hint(s::MIState) st = state(s) + + this_key_i = s.n_keys_pressed + next_key_pressed() = @lock s.line_modify_lock s.n_keys_pressed > this_key_i + function lock_clear_hint() + @lock s.line_modify_lock begin + next_key_pressed() || s.aborted || clear_hint(st) && refresh_line(s) + end + end + if !options(st).hint_tab_completes || !eof(buffer(st)) # only generate hints if enabled and at the end of the line # TODO: maybe show hints for insertions at other positions # Requires making space for them earlier in refresh_multi_line - return clear_hint(st) + lock_clear_hint() + return end - - named_completions, partial, should_complete = try - complete_line_named(st.p.complete, st, s.active_module; hint = true) - catch - @debug "error completing line for hint" exception=current_exceptions() - return clear_hint(st) - end - completions = map(x -> x.completion, named_completions) - - isempty(completions) && return clear_hint(st) - # Don't complete for single chars, given e.g. `x` completes to `xor` - if length(partial) > 1 && should_complete - singlecompletion = length(completions) == 1 - p = singlecompletion ? completions[1] : common_prefix(completions) - if singlecompletion || p in completions # i.e. complete `@time` even though `@time_imports` etc. exists - # The completion `p` and the input `partial` may not share the same initial - # characters, for instance when completing to subscripts or superscripts. - # So, in general, make sure that the hint starts at the correct position by - # incrementing its starting position by as many characters as the input. - startind = 1 # index of p from which to start providing the hint - maxind = ncodeunits(p) - for _ in partial - startind = nextind(p, startind) - startind > maxind && break + t_completion = Threads.@spawn :default begin + named_completions, partial, should_complete = nothing, nothing, nothing + + # only allow one task to generate hints at a time and check around lock + # if the user has pressed a key since the hint was requested, to skip old completions + next_key_pressed() && return + @lock s.hint_generation_lock begin + next_key_pressed() && return + named_completions, partial, should_complete = try + complete_line_named(st.p.complete, st, s.active_module; hint = true) + catch + lock_clear_hint() + return end - if startind ≤ maxind # completion on a complete name returns itself so check that there's something to hint - hint = p[startind:end] - st.hint = hint - return true + end + next_key_pressed() && return + + completions = map(x -> x.completion, named_completions) + if isempty(completions) + lock_clear_hint() + return + end + # Don't complete for single chars, given e.g. `x` completes to `xor` + if length(partial) > 1 && should_complete + singlecompletion = length(completions) == 1 + p = singlecompletion ? completions[1] : common_prefix(completions) + if singlecompletion || p in completions # i.e. complete `@time` even though `@time_imports` etc. exists + # The completion `p` and the input `partial` may not share the same initial + # characters, for instance when completing to subscripts or superscripts. + # So, in general, make sure that the hint starts at the correct position by + # incrementing its starting position by as many characters as the input. + startind = 1 # index of p from which to start providing the hint + maxind = ncodeunits(p) + for _ in partial + startind = nextind(p, startind) + startind > maxind && break + end + if startind ≤ maxind # completion on a complete name returns itself so check that there's something to hint + hint = p[startind:end] + next_key_pressed() && return + @lock s.line_modify_lock begin + if !s.aborted + state(s).hint = hint + refresh_line(s) + end + end + return + end end end + lock_clear_hint() end - return clear_hint(st) + Base.errormonitor(t_completion) + return end function clear_hint(s::ModeState) @@ -2569,7 +2607,7 @@ AnyDict( "^_" => (s::MIState,o...)->edit_undo!(s), "\e_" => (s::MIState,o...)->edit_redo!(s), # Show hints at what tab complete would do by default - "*" => (s::MIState,data,c::StringLike)->(edit_insert(s, c); check_for_hint(s) && refresh_line(s)), + "*" => (s::MIState,data,c::StringLike)->(edit_insert(s, c); check_show_hint(s)), "^U" => (s::MIState,o...)->edit_kill_line_backwards(s), "^K" => (s::MIState,o...)->edit_kill_line_forwards(s), "^Y" => (s::MIState,o...)->edit_yank(s), @@ -2875,10 +2913,9 @@ keymap_data(ms::MIState, m::ModalInterface) = keymap_data(state(ms), mode(ms)) function prompt!(term::TextTerminal, prompt::ModalInterface, s::MIState = init_state(term, prompt)) Base.reseteof(term) - l = Base.ReentrantLock() t1 = Threads.@spawn :interactive while true wait(s.async_channel) - status = @lock l begin + status = @lock s.line_modify_lock begin fcn = take!(s.async_channel) fcn(s) end @@ -2893,7 +2930,8 @@ function prompt!(term::TextTerminal, prompt::ModalInterface, s::MIState = init_s # and we want to not block typing when the repl task thread is busy t2 = Threads.@spawn :interactive while true eof(term) || peek(term) # wait before locking but don't consume - @lock l begin + @lock s.line_modify_lock begin + s.n_keys_pressed += 1 kmap = keymap(s, prompt) fcn = match_input(kmap, s) kdata = keymap_data(s, prompt) diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index 699024c1723a4..cc4f4f00cf8f6 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -1431,7 +1431,7 @@ function setup_interface( end else edit_insert(s, ';') - LineEdit.check_for_hint(s) && LineEdit.refresh_line(s) + LineEdit.check_show_hint(s) end end, '?' => function (s::MIState,o...) @@ -1442,7 +1442,7 @@ function setup_interface( end else edit_insert(s, '?') - LineEdit.check_for_hint(s) && LineEdit.refresh_line(s) + LineEdit.check_show_hint(s) end end, ']' => function (s::MIState,o...) @@ -1465,8 +1465,8 @@ function setup_interface( transition(s, mode) do LineEdit.state(s, mode).input_buffer = buf end - if !isempty(s) && @invokelatest(LineEdit.check_for_hint(s)) - @invokelatest(LineEdit.refresh_line(s)) + if !isempty(s) + @invokelatest(LineEdit.check_show_hint(s)) end break end @@ -1479,7 +1479,7 @@ function setup_interface( Base.errormonitor(t_replswitch) else edit_insert(s, ']') - LineEdit.check_for_hint(s) && LineEdit.refresh_line(s) + LineEdit.check_show_hint(s) end end, From cba19bf8e3ab7f0d509351e0185d60c148facd5b Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Fri, 31 Jan 2025 17:46:03 -0500 Subject: [PATCH 265/342] contrib: add `--relative-rpath` option to `juliac.jl` (#57199) This flag is useful when you'd like to deploy the generated library / executable across machines. This will tell the linker to look for the required libraries (`libjulia*.so`, `libopenblas`, etc.) in an adjacent `julia/` directory. We'll eventually use PackageCompiler to help bundle all the required libraries together, but for now this at least gets the lookup setup correctly in the created `.so` / binary. --------- Co-authored-by: Gabriel Baraldi --- contrib/julia-config.jl | 57 ++++++++++++++++++++++++----------------- contrib/juliac.jl | 36 ++++++++++++++++++++++---- 2 files changed, 65 insertions(+), 28 deletions(-) diff --git a/contrib/julia-config.jl b/contrib/julia-config.jl index 8b1eb55cbe4f4..6794834834d25 100755 --- a/contrib/julia-config.jl +++ b/contrib/julia-config.jl @@ -45,8 +45,8 @@ function includeDir() return abspath(Sys.BINDIR, Base.INCLUDEDIR, "julia") end -function ldflags(doframework) - doframework && return "-F$(shell_escape(frameworkDir()))" +function ldflags(; framework::Bool=false) + framework && return "-F$(shell_escape(frameworkDir()))" fl = "-L$(shell_escape(libDir()))" if Sys.iswindows() fl = fl * " -Wl,--stack,8388608" @@ -56,27 +56,40 @@ function ldflags(doframework) return fl end -function ldlibs(doframework) +function ldrpath() + libname = if Base.isdebugbuild() + "julia-debug" + else + "julia" + end + return "-Wl,-rpath,$(shell_escape(private_libDir())) -Wl,-rpath,$(shell_escape(libDir())) -l$libname" +end + +function ldlibs(; framework::Bool=false, rpath::Bool=true) # Return "Julia" for the framework even if this is a debug build. # If the user wants the debug framework, DYLD_IMAGE_SUFFIX=_debug # should be used (refer to man 1 dyld). - doframework && return "-framework $(Base.DARWIN_FRAMEWORK_NAME)" + framework && return "-framework $(Base.DARWIN_FRAMEWORK_NAME)" libname = if Base.isdebugbuild() "julia-debug" else "julia" end if Sys.isunix() - return "-L$(shell_escape(private_libDir())) -Wl,-rpath,$(shell_escape(libDir())) -Wl,-rpath,$(shell_escape(private_libDir())) -l$libname" + if rpath + return "-L$(shell_escape(private_libDir())) $(ldrpath())" + else + return "-L$(shell_escape(private_libDir()))" + end else return "-l$libname -lopenlibm" end end -function cflags(doframework) +function cflags(; framework::Bool=false) flags = IOBuffer() print(flags, "-std=gnu11") - if doframework + if framework include = shell_escape(frameworkDir()) print(flags, " -F", include) else @@ -89,8 +102,8 @@ function cflags(doframework) return String(take!(flags)) end -function allflags(doframework) - return "$(cflags(doframework)) $(ldflags(doframework)) $(ldlibs(doframework))" +function allflags(; framework::Bool=false, rpath::Bool=true) + return "$(cflags(; framework)) $(ldflags(; framework)) $(ldlibs(; framework, rpath))" end function check_args(args) @@ -102,31 +115,29 @@ function check_args(args) end function check_framework_flag(args) - doframework = "--framework" in args - if doframework && !Base.DARWIN_FRAMEWORK + framework = "--framework" in args + if framework && !Base.DARWIN_FRAMEWORK println(stderr, "NOTICE: Ignoring --framework because Julia is not packaged as a framework.") return false - elseif !doframework && Base.DARWIN_FRAMEWORK + elseif !framework && Base.DARWIN_FRAMEWORK println(stderr, "NOTICE: Consider using --framework because Julia is packaged as a framework.") return false end - return doframework + return framework end -function main() - check_args(ARGS) - doframework = check_framework_flag(ARGS) - for args in ARGS +function (@main)(args) + check_args(args) + framework = check_framework_flag(args) + for args in args if args == "--ldflags" - println(ldflags(doframework)) + println(ldflags(; framework)) elseif args == "--cflags" - println(cflags(doframework)) + println(cflags(; framework)) elseif args == "--ldlibs" - println(ldlibs(doframework)) + println(ldlibs(; framework)) elseif args == "--allflags" - println(allflags(doframework)) + println(allflags(; framework)) end end end - -main() diff --git a/contrib/juliac.jl b/contrib/juliac.jl index 3d1a3ef13fe79..8b413fccd6231 100644 --- a/contrib/juliac.jl +++ b/contrib/juliac.jl @@ -1,11 +1,16 @@ # Julia compiler wrapper script # NOTE: The interface and location of this script are considered unstable/experimental +module JuliaConfig + include(joinpath(@__DIR__, "julia-config.jl")) +end + julia_cmd = `$(Base.julia_cmd()) --startup-file=no --history-file=no` output_type = nothing # exe, sharedlib, sysimage outname = nothing file = nothing add_ccallables = false +relative_rpath = false verbose = false help = findfirst(x->x == "--help", ARGS) @@ -15,6 +20,7 @@ if help !== nothing Usage: julia juliac.jl [--output-exe | --output-lib | --output-sysimage] [options] --experimental --trim= Only output code statically determined to be reachable --compile-ccallable Include all methods marked `@ccallable` in output + --relative-rpath Configure the library / executable to lookup all required libraries in an adjacent "julia/" folder --verbose Request verbose output """) exit(0) @@ -36,6 +42,8 @@ let i = 1 global add_ccallables = true elseif arg == "--verbose" global verbose = true + elseif arg == "--relative-rpath" + global relative_rpath = true elseif startswith(arg, "--trim") || arg == "--experimental" # forwarded args push!(julia_args, arg) @@ -53,11 +61,27 @@ end isnothing(outname) && error("No output file specified") isnothing(file) && error("No input file specified") +function get_rpath(; relative::Bool = false) + if relative + if Sys.isapple() + return "-Wl,-rpath,'@loader_path/julia/' -Wl,-rpath,'@loader_path/'" + elseif Sys.islinux() + return "-Wl,-rpath,'\$ORIGIN/julia/' -Wl,-rpath,'\$ORIGIN/'" + else + error("unimplemented") + end + else + return JuliaConfig.ldrpath() + end +end + absfile = abspath(file) -cflags = readchomp(`$(julia_cmd) $(joinpath(Sys.BINDIR, Base.DATAROOTDIR,"julia", "julia-config.jl")) --cflags `) +cflags = JuliaConfig.cflags(; framework=false) cflags = Base.shell_split(cflags) -allflags = readchomp(`$(julia_cmd) $(joinpath(Sys.BINDIR, Base.DATAROOTDIR,"julia", "julia-config.jl")) --allflags`) +allflags = JuliaConfig.allflags(; framework=false, rpath=false) allflags = Base.shell_split(allflags) +rpath = get_rpath(; relative = relative_rpath) +rpath = Base.shell_split(rpath) tmpdir = mktempdir(cleanup=false) initsrc_path = joinpath(tmpdir, "init.c") init_path = joinpath(tmpdir, "init.a") @@ -113,12 +137,14 @@ function link_products() julia_libs = Base.shell_split(Base.isdebugbuild() ? "-ljulia-debug -ljulia-internal-debug" : "-ljulia -ljulia-internal") try if output_type == "--output-lib" - run(`cc $(allflags) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $init_path $(julia_libs)`) + cmd2 = `cc $(allflags) $(rpath) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $init_path $(julia_libs)` elseif output_type == "--output-sysimage" - run(`cc $(allflags) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $(julia_libs)`) + cmd2 = `cc $(allflags) $(rpath) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $(julia_libs)` else - run(`cc $(allflags) -o $outname -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $init_path $(julia_libs)`) + cmd2 = `cc $(allflags) $(rpath) -o $outname -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $init_path $(julia_libs)` end + verbose && println("Running: $cmd2") + run(cmd2) catch e println("\nCompilation failed: ", e) exit(1) From 9a278a21650561c79a6b8e6158873cabefdcc2c1 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Fri, 31 Jan 2025 23:36:22 -0500 Subject: [PATCH 266/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?LinearAlgebra=20stdlib=20from=20da6d052=20to=2057e9a0d=20(#5717?= =?UTF-8?q?7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: LinearAlgebra URL: https://github.com/JuliaLang/LinearAlgebra.jl.git Stdlib branch: master Julia branch: master Old commit: da6d052 New commit: 57e9a0d Julia version: 1.12.0-DEV LinearAlgebra version: 1.12.0 Bump invoked by: @ViralBShah Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaLang/LinearAlgebra.jl/compare/da6d0521347daf5e42b3d09cdb757d4488528c7b...57e9a0d19f7a0042e0ef536fe5ae5fc35c61a6f1 ``` $ git log --oneline da6d052..57e9a0d 57e9a0d Reduce allocations and improve performance in `syevr!` (#1176) 8bb9f6b fix error messages (#1171) 97a712f Update .ci/Manifest.toml (#1179) ``` Co-authored-by: ViralBShah <744411+ViralBShah@users.noreply.github.com> Co-authored-by: Viral B. Shah --- .../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-57e9a0d19f7a0042e0ef536fe5ae5fc35c61a6f1.tar.gz/md5 create mode 100644 deps/checksums/LinearAlgebra-57e9a0d19f7a0042e0ef536fe5ae5fc35c61a6f1.tar.gz/sha512 delete mode 100644 deps/checksums/LinearAlgebra-da6d0521347daf5e42b3d09cdb757d4488528c7b.tar.gz/md5 delete mode 100644 deps/checksums/LinearAlgebra-da6d0521347daf5e42b3d09cdb757d4488528c7b.tar.gz/sha512 diff --git a/deps/checksums/LinearAlgebra-57e9a0d19f7a0042e0ef536fe5ae5fc35c61a6f1.tar.gz/md5 b/deps/checksums/LinearAlgebra-57e9a0d19f7a0042e0ef536fe5ae5fc35c61a6f1.tar.gz/md5 new file mode 100644 index 0000000000000..cf0897401a9b8 --- /dev/null +++ b/deps/checksums/LinearAlgebra-57e9a0d19f7a0042e0ef536fe5ae5fc35c61a6f1.tar.gz/md5 @@ -0,0 +1 @@ +a2c4227b17fe589791261081710add05 diff --git a/deps/checksums/LinearAlgebra-57e9a0d19f7a0042e0ef536fe5ae5fc35c61a6f1.tar.gz/sha512 b/deps/checksums/LinearAlgebra-57e9a0d19f7a0042e0ef536fe5ae5fc35c61a6f1.tar.gz/sha512 new file mode 100644 index 0000000000000..3aebc8a8bd7b5 --- /dev/null +++ b/deps/checksums/LinearAlgebra-57e9a0d19f7a0042e0ef536fe5ae5fc35c61a6f1.tar.gz/sha512 @@ -0,0 +1 @@ +08fd85a63a08aae079c835f139845f5155fbb5d96444e8ed4cd1a696921e30ec842e6013e486e32d7ffe19d598ff1abb084e0a13fecdecc17546a76f16357a4a diff --git a/deps/checksums/LinearAlgebra-da6d0521347daf5e42b3d09cdb757d4488528c7b.tar.gz/md5 b/deps/checksums/LinearAlgebra-da6d0521347daf5e42b3d09cdb757d4488528c7b.tar.gz/md5 deleted file mode 100644 index 1771370455266..0000000000000 --- a/deps/checksums/LinearAlgebra-da6d0521347daf5e42b3d09cdb757d4488528c7b.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -810a9f842ee40d03e55c698130620963 diff --git a/deps/checksums/LinearAlgebra-da6d0521347daf5e42b3d09cdb757d4488528c7b.tar.gz/sha512 b/deps/checksums/LinearAlgebra-da6d0521347daf5e42b3d09cdb757d4488528c7b.tar.gz/sha512 deleted file mode 100644 index f696212eda4fc..0000000000000 --- a/deps/checksums/LinearAlgebra-da6d0521347daf5e42b3d09cdb757d4488528c7b.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -4197a863c0f5052f0b85f1c04b6f42f71bf35af572f507dbc475e868a7c057bebd11f8258451b7d0a728012f238abfd88943fe80b83df63728af2fcc01199604 diff --git a/stdlib/LinearAlgebra.version b/stdlib/LinearAlgebra.version index e877475771829..6bdb43b93bfa8 100644 --- a/stdlib/LinearAlgebra.version +++ b/stdlib/LinearAlgebra.version @@ -1,4 +1,4 @@ LINEARALGEBRA_BRANCH = master -LINEARALGEBRA_SHA1 = da6d0521347daf5e42b3d09cdb757d4488528c7b +LINEARALGEBRA_SHA1 = 57e9a0d19f7a0042e0ef536fe5ae5fc35c61a6f1 LINEARALGEBRA_GIT_URL := https://github.com/JuliaLang/LinearAlgebra.jl.git LINEARALGEBRA_TAR_URL = https://api.github.com/repos/JuliaLang/LinearAlgebra.jl/tarball/$1 From 832f0847ca1674e82b3576281e89b8cd2195f7d1 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Sat, 1 Feb 2025 16:36:00 -0300 Subject: [PATCH 267/342] Don't delete inferred code from external interpreters (#57224) We were deleting code from external abstract interpreters since https://github.com/JuliaLang/julia/commit/bdf8219ee80557ea6035b421b00d91b1174234f2. Fixes https://github.com/JuliaGPU/CUDA.jl/issues/2637. Not sure how to write tests for this :( --------- Co-authored-by: Jeff Bezanson --- src/staticdata.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/staticdata.c b/src/staticdata.c index b5d6fb7cdd62a..ba9c6ed8c1bea 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -939,6 +939,7 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_ record_field_change((jl_value_t**)&ci->inferred, jl_nothing); } else if (native_functions && // don't delete any code if making a ji file + (ci->owner == jl_nothing) && // don't delete code for external interpreters !effects_foldable(jl_atomic_load_relaxed(&ci->ipo_purity_bits)) && // don't delete code we may want for irinterp jl_ir_inlining_cost(inferred) == UINT16_MAX) { // don't delete inlineable code // delete the code now: if we thought it was worth keeping, it would have been converted to object code From cee26a35c1b16407ce624f9f0e154a41ca60d8e8 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Sun, 2 Feb 2025 01:29:55 +0100 Subject: [PATCH 268/342] allow passing custom julia arguments in `runtests` (#56716) The `propagate_project` kwarg can be removed after current users (LinearAlgebra.jl) switches to it. This is to allow moving buildkite yaml logic into Julia where it is easier to write. --------- Co-authored-by: Alex Arslan --- base/util.jl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/base/util.jl b/base/util.jl index c01ff697e64e3..39ca793a7c3f5 100644 --- a/base/util.jl +++ b/base/util.jl @@ -678,7 +678,7 @@ end """ Base.runtests(tests=["all"]; ncores=ceil(Int, Sys.CPU_THREADS / 2), - exit_on_error=false, revise=false, propagate_project=true, [seed]) + exit_on_error=false, revise=false, propagate_project=true, [seed], [julia_args::Cmd]) Run the Julia unit tests listed in `tests`, which can be either a string or an array of strings, using `ncores` processors. If `exit_on_error` is `false`, when one test @@ -689,12 +689,14 @@ to the standard libraries before running the tests. If `propagate_project` is true the current project is propagated to the test environment. If a seed is provided via the keyword argument, it is used to seed the global RNG in the context where the tests are run; otherwise the seed is chosen randomly. +The argument `julia_args` can be used to pass custom `julia` command line flags to the test process. """ function runtests(tests = ["all"]; ncores::Int = ceil(Int, Sys.CPU_THREADS / 2), exit_on_error::Bool=false, revise::Bool=false, propagate_project::Bool=false, - seed::Union{BitInteger,Nothing}=nothing) + seed::Union{BitInteger,Nothing}=nothing, + julia_args::Cmd=``) if isa(tests,AbstractString) tests = split(tests) end @@ -710,7 +712,7 @@ function runtests(tests = ["all"]; ncores::Int = ceil(Int, Sys.CPU_THREADS / 2), delete!(ENV2, "JULIA_PROJECT") project_flag = propagate_project ? `--project` : `` try - run(setenv(`$(julia_cmd()) $project_flag $(joinpath(Sys.BINDIR, + run(setenv(`$(julia_cmd()) $julia_args $project_flag $(joinpath(Sys.BINDIR, Base.DATAROOTDIR, "julia", "test", "runtests.jl")) $tests`, ENV2)) nothing catch From dbc6681820890485db259a2b32e81c8f5975cd64 Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Sun, 2 Feb 2025 06:03:38 +0530 Subject: [PATCH 269/342] Specialize common reductions for ranges with `init` specified (#56896) The idea is that since ranges have `O(1)` reductions such as `minimum`, `maximum` and `sum` defined, we may reuse the implementations in the corresponding reductions with `init` specified, instead of hitting slow fallback implementations. for example, after this, ```julia julia> @btime maximum($(Ref(1:10000))[], init=typemin(Int)) 2.344 ns (0 allocations: 0 bytes) 10000 ``` whereas, on master, this is `O(N)` as it loops over each element. The specific use case is to avoid hitting slow fallbacks in a change like https://github.com/JuliaLinearAlgebra/BlockBandedMatrices.jl/pull/218/files. --- base/reduce.jl | 7 +++++++ test/ranges.jl | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/base/reduce.jl b/base/reduce.jl index 25466eed4a105..60bff3acb52ed 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -1155,3 +1155,10 @@ function _simple_count(::typeof(identity), x::Array{Bool}, init::T=0) where {T} end return n end + +# A few common reductions for ranges with init specified +for (fred, f) in ((maximum, max), (minimum, min), (sum, add_sum)) + @eval function _foldl_impl(op::typeof(BottomRF($f)), init, r::AbstractRange) + isempty(r) ? init : op(init, $fred(r)) + end +end diff --git a/test/ranges.jl b/test/ranges.jl index 89134be897ddd..ba54f6cebcd7d 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -1554,8 +1554,8 @@ end (range(10, stop=20, length=5), 1, 5), (range(10.3, step=-2, length=7), 7, 1), ] - @test minimum(r) === r[imin] - @test maximum(r) === r[imax] + @test minimum(r) === minimum(r, init=typemax(eltype(r))) === r[imin] + @test maximum(r) === maximum(r, init=typemin(eltype(r))) === r[imax] @test imin === argmin(r) @test imax === argmax(r) @test extrema(r) === (r[imin], r[imax]) From e485be85a0152d1ebfd2928d5370831701c93982 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sun, 2 Feb 2025 02:22:59 -0500 Subject: [PATCH 270/342] bpart: Start tracking backedges for bindings (#57213) This PR adds limited backedge support for Bindings. There are two classes of bindings that get backedges: 1. Cross-module `GlobalRef` bindings (new in this PR) 2. Any globals accesses through intrinsics (i.e. those with forward edges from #57009) This is a time/space trade-off for invalidation. As a result of the first category, invalidating a binding now only needs to scan all the methods defined in the same module as the binding. At the same time, it is anticipated that most binding references are to bindings in the same module, keeping the list of bindings that need explicit (back)edges small. --- Compiler/src/Compiler.jl | 2 +- Compiler/src/abstractinterpretation.jl | 24 +++-- Compiler/src/bootstrap.jl | 2 +- Compiler/src/ssair/verify.jl | 5 +- Compiler/src/stmtinfo.jl | 8 +- Compiler/src/typeinfer.jl | 3 +- Compiler/test/ssair.jl | 2 +- base/Base.jl | 4 + base/Base_compiler.jl | 2 - base/invalidation.jl | 142 +++++++++++++++++-------- base/iterators.jl | 6 +- base/loading.jl | 4 +- base/staticdata.jl | 49 ++++++--- src/init.c | 1 + src/jltypes.c | 10 +- src/julia.h | 1 + src/julia_internal.h | 5 +- src/method.c | 20 ++-- src/module.c | 29 ++++- src/staticdata.c | 28 +++-- src/toplevel.c | 7 +- stdlib/REPL/src/REPLCompletions.jl | 1 + test/rebinding.jl | 68 +++++++++++- 23 files changed, 311 insertions(+), 112 deletions(-) diff --git a/Compiler/src/Compiler.jl b/Compiler/src/Compiler.jl index b83dc0b5970e1..0fc7bd6e328e7 100644 --- a/Compiler/src/Compiler.jl +++ b/Compiler/src/Compiler.jl @@ -67,7 +67,7 @@ using Base: @_foldable_meta, @_gc_preserve_begin, @_gc_preserve_end, @nospeciali partition_restriction, quoted, rename_unionall, rewrap_unionall, specialize_method, structdiff, tls_world_age, unconstrain_vararg_length, unionlen, uniontype_layout, uniontypes, unsafe_convert, unwrap_unionall, unwrapva, vect, widen_diagonal, - _uncompressed_ir + _uncompressed_ir, maybe_add_binding_backedge! using Base.Order import Base: ==, _topmod, append!, convert, copy, copy!, findall, first, get, get!, diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index dbd7e76615116..fe7cc1dbf5680 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -208,6 +208,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(fun end if const_edge !== nothing edge = const_edge + update_valid_age!(sv, world_range(const_edge)) end end @@ -2330,6 +2331,7 @@ function abstract_invoke(interp::AbstractInterpreter, arginfo::ArgInfo, si::Stmt end if const_edge !== nothing edge = const_edge + update_valid_age!(sv, world_range(const_edge)) end end rt = from_interprocedural!(interp, rt, sv, arginfo′, sig) @@ -2396,8 +2398,9 @@ function abstract_eval_getglobal(interp::AbstractInterpreter, sv::AbsIntState, s if M isa Const && s isa Const M, s = M.val, s.val if M isa Module && s isa Symbol - (ret, bpart) = abstract_eval_globalref(interp, GlobalRef(M, s), saw_latestworld, sv) - return CallMeta(ret, bpart === nothing ? NoCallInfo() : GlobalAccessInfo(bpart)) + gr = GlobalRef(M, s) + (ret, bpart) = abstract_eval_globalref(interp, gr, saw_latestworld, sv) + return CallMeta(ret, bpart === nothing ? NoCallInfo() : GlobalAccessInfo(convert(Core.Binding, gr), bpart)) end return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo()) elseif !hasintersect(widenconst(M), Module) || !hasintersect(widenconst(s), Symbol) @@ -2475,8 +2478,9 @@ function abstract_eval_setglobal!(interp::AbstractInterpreter, sv::AbsIntState, if isa(M, Const) && isa(s, Const) M, s = M.val, s.val if M isa Module && s isa Symbol - (rt, exct), partition = global_assignment_rt_exct(interp, sv, saw_latestworld, GlobalRef(M, s), v) - return CallMeta(rt, exct, Effects(setglobal!_effects, nothrow=exct===Bottom), GlobalAccessInfo(partition)) + gr = GlobalRef(M, s) + (rt, exct), partition = global_assignment_rt_exct(interp, sv, saw_latestworld, gr, v) + return CallMeta(rt, exct, Effects(setglobal!_effects, nothrow=exct===Bottom), GlobalAccessInfo(convert(Core.Binding, gr), partition)) end return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo()) end @@ -2564,14 +2568,15 @@ function abstract_eval_replaceglobal!(interp::AbstractInterpreter, sv::AbsIntSta M, s = M.val, s.val M isa Module || return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo()) s isa Symbol || return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo()) - partition = abstract_eval_binding_partition!(interp, GlobalRef(M, s), sv) + gr = GlobalRef(M, s) + partition = abstract_eval_binding_partition!(interp, gr, sv) rte = abstract_eval_partition_load(interp, partition) if binding_kind(partition) == BINDING_KIND_GLOBAL T = partition_restriction(partition) end exct = Union{rte.exct, global_assignment_binding_rt_exct(interp, partition, v)[2]} effects = merge_effects(rte.effects, Effects(setglobal!_effects, nothrow=exct===Bottom)) - sg = CallMeta(Any, exct, effects, GlobalAccessInfo(partition)) + sg = CallMeta(Any, exct, effects, GlobalAccessInfo(convert(Core.Binding, gr), partition)) else sg = abstract_eval_setglobal!(interp, sv, saw_latestworld, M, s, v) end @@ -2791,6 +2796,7 @@ function abstract_call_opaque_closure(interp::AbstractInterpreter, end if const_edge !== nothing edge = const_edge + update_valid_age!(sv, world_range(const_edge)) end end end @@ -3225,7 +3231,8 @@ function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, mod::Module, end effects = EFFECTS_TOTAL - partition = lookup_binding_partition!(interp, GlobalRef(mod, sym), sv) + gr = GlobalRef(mod, sym) + partition = lookup_binding_partition!(interp, gr, sv) if allow_import !== true && is_some_imported(binding_kind(partition)) if allow_import === false rt = Const(false) @@ -3243,7 +3250,7 @@ function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, mod::Module, effects = Effects(generic_isdefinedglobal_effects, nothrow=true) end end - return CallMeta(RTEffects(rt, Union{}, effects), GlobalAccessInfo(partition)) + return CallMeta(RTEffects(rt, Union{}, effects), GlobalAccessInfo(convert(Core.Binding, gr), partition)) end function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, @nospecialize(M), @nospecialize(s), @nospecialize(allow_import_arg), @nospecialize(order_arg), saw_latestworld::Bool, sv::AbsIntState) @@ -3454,6 +3461,7 @@ end world_range(ir::IRCode) = ir.valid_worlds world_range(ci::CodeInfo) = WorldRange(ci.min_world, ci.max_world) +world_range(ci::CodeInstance) = WorldRange(ci.min_world, ci.max_world) world_range(compact::IncrementalCompact) = world_range(compact.ir) function force_binding_resolution!(g::GlobalRef, world::UInt) diff --git a/Compiler/src/bootstrap.jl b/Compiler/src/bootstrap.jl index 26fcfde5f256f..c35de48cd20f5 100644 --- a/Compiler/src/bootstrap.jl +++ b/Compiler/src/bootstrap.jl @@ -91,6 +91,6 @@ function activate!(; reflection=true, codegen=false) Base.REFLECTION_COMPILER[] = Compiler end if codegen - activate_codegen!() + bootstrap!() end end diff --git a/Compiler/src/ssair/verify.jl b/Compiler/src/ssair/verify.jl index 779a28afe9f56..2d6d59cc4e22b 100644 --- a/Compiler/src/ssair/verify.jl +++ b/Compiler/src/ssair/verify.jl @@ -67,7 +67,10 @@ function check_op(ir::IRCode, domtree::DomTree, @nospecialize(op), use_bb::Int, imported_binding = partition_restriction(bpart)::Core.Binding bpart = lookup_binding_partition(min_world(ir.valid_worlds), imported_binding) end - if !is_defined_const_binding(binding_kind(bpart)) || (bpart.max_world < max_world(ir.valid_worlds)) + if (!is_defined_const_binding(binding_kind(bpart)) || (bpart.max_world < max_world(ir.valid_worlds))) && + (op.mod !== Core) && (op.mod !== Base) + # Core and Base are excluded because the frontend uses them for intrinsics, etc. + # TODO: Decide which way to go with these. @verify_error "Unbound or partitioned GlobalRef not allowed in value position" raise_error() end diff --git a/Compiler/src/stmtinfo.jl b/Compiler/src/stmtinfo.jl index e3f8e2f56c86b..58c7c7b3fea11 100644 --- a/Compiler/src/stmtinfo.jl +++ b/Compiler/src/stmtinfo.jl @@ -489,10 +489,12 @@ Represents access to a global through runtime reflection, rather than as a manif perform such accesses. """ struct GlobalAccessInfo <: CallInfo + b::Core.Binding bpart::Core.BindingPartition end -GlobalAccessInfo(::Nothing) = NoCallInfo() -add_edges_impl(edges::Vector{Any}, info::GlobalAccessInfo) = - push!(edges, info.bpart) +GlobalAccessInfo(::Core.Binding, ::Nothing) = NoCallInfo() +function add_edges_impl(edges::Vector{Any}, info::GlobalAccessInfo) + push!(edges, info.b) +end @specialize diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index dd6a55bfc9f1c..96f58943e3255 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -544,8 +544,9 @@ function store_backedges(caller::CodeInstance, edges::SimpleVector) # ignore `Method`-edges (from e.g. failed `abstract_call_method`) i += 1 continue - elseif isa(item, Core.BindingPartition) + elseif isa(item, Core.Binding) i += 1 + maybe_add_binding_backedge!(item, caller) continue end if isa(item, CodeInstance) diff --git a/Compiler/test/ssair.jl b/Compiler/test/ssair.jl index 6100aad673040..3026202466599 100644 --- a/Compiler/test/ssair.jl +++ b/Compiler/test/ssair.jl @@ -134,7 +134,7 @@ let code = Any[ Expr(:boundscheck), Compiler.GotoIfNot(SSAValue(1), 6), # block 2 - Expr(:call, GlobalRef(Base, :size), Compiler.Argument(3)), + Expr(:call, size, Compiler.Argument(3)), Compiler.ReturnNode(), # block 3 Core.PhiNode(), diff --git a/base/Base.jl b/base/Base.jl index 379347f027f69..fde41a5f19f37 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -31,6 +31,10 @@ let os = ccall(:jl_get_UNAME, Any, ()) end end +# subarrays +include("subarray.jl") +include("views.jl") + # numeric operations include("hashing.jl") include("rounding.jl") diff --git a/base/Base_compiler.jl b/base/Base_compiler.jl index abeec81f0c028..8cc7096ee26a7 100644 --- a/base/Base_compiler.jl +++ b/base/Base_compiler.jl @@ -231,8 +231,6 @@ include("indices.jl") include("genericmemory.jl") include("array.jl") include("abstractarray.jl") -include("subarray.jl") -include("views.jl") include("baseext.jl") include("c.jl") diff --git a/base/invalidation.jl b/base/invalidation.jl index 5abb0b74ad884..d9a0bd95c5159 100644 --- a/base/invalidation.jl +++ b/base/invalidation.jl @@ -35,9 +35,6 @@ function foreach_module_mtable(visit, m::Module, world::UInt) visit(mt) || return false end end - elseif isa(v, Module) && v !== m && parentmodule(v) === m && _nameof(v) === name - # this is the original/primary binding for the submodule - foreach_module_mtable(visit, v, world) || return false elseif isa(v, Core.MethodTable) && v.module === m && v.name === name # this is probably an external method table here, so let's # assume so as there is no way to precisely distinguish them @@ -48,49 +45,46 @@ function foreach_module_mtable(visit, m::Module, world::UInt) return true end -function foreach_reachable_mtable(visit, world::UInt) - visit(TYPE_TYPE_MT) || return - visit(NONFUNCTION_MT) || return - for mod in loaded_modules_array() - foreach_module_mtable(visit, mod, world) +function foreachgr(visit, src::CodeInfo) + stmts = src.code + for i = 1:length(stmts) + stmt = stmts[i] + isa(stmt, GlobalRef) && visit(stmt) + for ur in Compiler.userefs(stmt) + arg = ur[] + isa(arg, GlobalRef) && visit(arg) + end end end -function should_invalidate_code_for_globalref(gr::GlobalRef, src::CodeInfo) - found_any = false - labelchangemap = nothing +function anygr(visit, src::CodeInfo) stmts = src.code - isgr(g::GlobalRef) = gr.mod == g.mod && gr.name === g.name - isgr(g) = false for i = 1:length(stmts) stmt = stmts[i] - if isgr(stmt) - found_any = true + if isa(stmt, GlobalRef) + visit(stmt) && return true continue end for ur in Compiler.userefs(stmt) arg = ur[] - # If any of the GlobalRefs in this stmt match the one that - # we are about, we need to move out all GlobalRefs to preserve - # effect order, in case we later invalidate a different GR - if isa(arg, GlobalRef) - if isgr(arg) - @assert !isa(stmt, PhiNode) - found_any = true - break - end - end + isa(arg, GlobalRef) && visit(arg) && return true end end - return found_any + return false +end + +function should_invalidate_code_for_globalref(gr::GlobalRef, src::CodeInfo) + isgr(g::GlobalRef) = gr.mod == g.mod && gr.name === g.name + isgr(g) = false + return anygr(isgr, src) end -function scan_edge_list(ci::Core.CodeInstance, bpart::Core.BindingPartition) +function scan_edge_list(ci::Core.CodeInstance, binding::Core.Binding) isdefined(ci, :edges) || return false edges = ci.edges i = 1 while i <= length(edges) - if isassigned(edges, i) && edges[i] === bpart + if isassigned(edges, i) && edges[i] === binding return true end i += 1 @@ -98,33 +92,91 @@ function scan_edge_list(ci::Core.CodeInstance, bpart::Core.BindingPartition) return false end +function invalidate_method_for_globalref!(gr::GlobalRef, method::Method, invalidated_bpart::Core.BindingPartition, new_max_world::UInt) + if isdefined(method, :source) + src = _uncompressed_ir(method) + binding = convert(Core.Binding, gr) + old_stmts = src.code + invalidate_all = should_invalidate_code_for_globalref(gr, src) + for mi in specializations(method) + isdefined(mi, :cache) || continue + ci = mi.cache + while true + if ci.max_world > new_max_world && (invalidate_all || scan_edge_list(ci, binding)) + ccall(:jl_invalidate_code_instance, Cvoid, (Any, UInt), ci, new_max_world) + end + isdefined(ci, :next) || break + ci = ci.next + end + end + end +end + function invalidate_code_for_globalref!(gr::GlobalRef, invalidated_bpart::Core.BindingPartition, new_max_world::UInt) try valid_in_valuepos = false - foreach_reachable_mtable(new_max_world) do mt::Core.MethodTable + foreach_module_mtable(gr.mod, new_max_world) do mt::Core.MethodTable for method in MethodList(mt) - if isdefined(method, :source) - src = _uncompressed_ir(method) - old_stmts = src.code - invalidate_all = should_invalidate_code_for_globalref(gr, src) - for mi in specializations(method) - isdefined(mi, :cache) || continue - ci = mi.cache - while true - if ci.max_world > new_max_world && (invalidate_all || scan_edge_list(ci, invalidated_bpart)) - ccall(:jl_invalidate_code_instance, Cvoid, (Any, UInt), ci, new_max_world) - end - isdefined(ci, :next) || break - ci = ci.next - end - end - end + invalidate_method_for_globalref!(gr, method, invalidated_bpart, new_max_world) end return true end + b = convert(Core.Binding, gr) + if isdefined(b, :backedges) + for edge in b.backedges + if isa(edge, CodeInstance) + ccall(:jl_invalidate_code_instance, Cvoid, (Any, UInt), edge, new_max_world) + else + invalidate_method_for_globalref!(gr, edge::Method, invalidated_bpart, new_max_world) + end + end + end catch err bt = catch_backtrace() invokelatest(Base.println, "Internal Error during invalidation:") invokelatest(Base.display_error, err, bt) end end + +gr_needs_backedge_in_module(gr::GlobalRef, mod::Module) = gr.mod !== mod + +# N.B.: This needs to match jl_maybe_add_binding_backedge +function maybe_add_binding_backedge!(b::Core.Binding, edge::Union{Method, CodeInstance}) + method = isa(edge, Method) ? edge : edge.def.def::Method + gr_needs_backedge_in_module(b.globalref, method.module) || return + if !isdefined(b, :backedges) + b.backedges = Any[] + end + !isempty(b.backedges) && b.backedges[end] === edge && return + push!(b.backedges, edge) +end + +function binding_was_invalidated(b::Core.Binding) + # At least one partition is required for invalidation + !isdefined(b, :partitions) && return false + b.partitions.min_world > unsafe_load(cglobal(:jl_require_world, UInt)) +end + +function scan_new_method!(methods_with_invalidated_source::IdSet{Method}, method::Method) + isdefined(method, :source) || return + src = _uncompressed_ir(method) + mod = method.module + foreachgr(src) do gr::GlobalRef + b = convert(Core.Binding, gr) + binding_was_invalidated(b) && push!(methods_with_invalidated_source, method) + maybe_add_binding_backedge!(b, method) + end +end + +function scan_new_methods(extext_methods::Vector{Any}, internal_methods::Vector{Any}) + methods_with_invalidated_source = IdSet{Method}() + for method in internal_methods + if isa(method, Method) + scan_new_method!(methods_with_invalidated_source, method) + end + end + for tme::Core.TypeMapEntry in extext_methods + scan_new_method!(methods_with_invalidated_source, tme.func::Method) + end + return methods_with_invalidated_source +end diff --git a/base/iterators.jl b/base/iterators.jl index c6278e6284d70..d6367ed8d996e 100644 --- a/base/iterators.jl +++ b/base/iterators.jl @@ -20,7 +20,7 @@ using .Base: using Core: @doc using .Base: - cld, fld, SubArray, view, resize!, IndexCartesian + cld, fld, resize!, IndexCartesian using .Base.Checked: checked_mul import .Base: @@ -1327,7 +1327,7 @@ eltype(::Type{PartitionIterator{T}}) where {T} = Vector{eltype(T)} # Arrays use a generic `view`-of-a-`vec`, so we cannot exactly predict what we'll get back eltype(::Type{PartitionIterator{T}}) where {T<:AbstractArray} = AbstractVector{eltype(T)} # But for some common implementations in Base we know the answer exactly -eltype(::Type{PartitionIterator{T}}) where {T<:Vector} = SubArray{eltype(T), 1, T, Tuple{UnitRange{Int}}, true} +eltype(::Type{PartitionIterator{T}}) where {T<:Vector} = Base.SubArray{eltype(T), 1, T, Tuple{UnitRange{Int}}, true} IteratorEltype(::Type{PartitionIterator{T}}) where {T} = IteratorEltype(T) IteratorEltype(::Type{PartitionIterator{T}}) where {T<:AbstractArray} = EltypeUnknown() @@ -1353,7 +1353,7 @@ end function iterate(itr::PartitionIterator{<:AbstractArray}, state = firstindex(itr.c)) state > lastindex(itr.c) && return nothing r = min(state + itr.n - 1, lastindex(itr.c)) - return @inbounds view(itr.c, state:r), r + 1 + return @inbounds Base.view(itr.c, state:r), r + 1 end struct IterationCutShort; end diff --git a/base/loading.jl b/base/loading.jl index 57d69f49483c9..826e4116405ef 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -1293,7 +1293,9 @@ function _include_from_serialized(pkg::PkgId, path::String, ocachepath::Union{No edges = sv[3]::Vector{Any} ext_edges = sv[4]::Union{Nothing,Vector{Any}} - StaticData.insert_backedges(edges, ext_edges) + extext_methods = sv[5]::Vector{Any} + internal_methods = sv[6]::Vector{Any} + StaticData.insert_backedges(edges, ext_edges, extext_methods, internal_methods) restored = register_restored_modules(sv, pkg, path) diff --git a/base/staticdata.jl b/base/staticdata.jl index 345769e479380..a4a40b9af0a7c 100644 --- a/base/staticdata.jl +++ b/base/staticdata.jl @@ -22,21 +22,22 @@ end # Restore backedges to external targets # `edges` = [caller1, ...], the list of worklist-owned code instances internally # `ext_ci_list` = [caller1, ...], the list of worklist-owned code instances externally -function insert_backedges(edges::Vector{Any}, ext_ci_list::Union{Nothing,Vector{Any}}) +function insert_backedges(edges::Vector{Any}, ext_ci_list::Union{Nothing,Vector{Any}}, extext_methods::Vector{Any}, internal_methods::Vector{Any}) # determine which CodeInstance objects are still valid in our image # to enable any applicable new codes + methods_with_invalidated_source = Base.scan_new_methods(extext_methods, internal_methods) stack = CodeInstance[] visiting = IdDict{CodeInstance,Int}() - _insert_backedges(edges, stack, visiting) + _insert_backedges(edges, stack, visiting, methods_with_invalidated_source) if ext_ci_list !== nothing - _insert_backedges(ext_ci_list, stack, visiting, #=external=#true) + _insert_backedges(ext_ci_list, stack, visiting, methods_with_invalidated_source, #=external=#true) end end -function _insert_backedges(edges::Vector{Any}, stack::Vector{CodeInstance}, visiting::IdDict{CodeInstance,Int}, external::Bool=false) +function _insert_backedges(edges::Vector{Any}, stack::Vector{CodeInstance}, visiting::IdDict{CodeInstance,Int}, mwis::IdSet{Method}, external::Bool=false) for i = 1:length(edges) codeinst = edges[i]::CodeInstance - verify_method_graph(codeinst, stack, visiting) + verify_method_graph(codeinst, stack, visiting, mwis) minvalid = codeinst.min_world maxvalid = codeinst.max_world if maxvalid ≥ minvalid && external @@ -54,9 +55,9 @@ function _insert_backedges(edges::Vector{Any}, stack::Vector{CodeInstance}, visi end end -function verify_method_graph(codeinst::CodeInstance, stack::Vector{CodeInstance}, visiting::IdDict{CodeInstance,Int}) +function verify_method_graph(codeinst::CodeInstance, stack::Vector{CodeInstance}, visiting::IdDict{CodeInstance,Int}, mwis::IdSet{Method}) @assert isempty(stack); @assert isempty(visiting); - child_cycle, minworld, maxworld = verify_method(codeinst, stack, visiting) + child_cycle, minworld, maxworld = verify_method(codeinst, stack, visiting, mwis) @assert child_cycle == 0 @assert isempty(stack); @assert isempty(visiting); nothing @@ -66,7 +67,7 @@ end # - Visit the entire call graph, starting from edges[idx] to determine if that method is valid # - Implements Tarjan's SCC (strongly connected components) algorithm, simplified to remove the count variable # and slightly modified with an early termination option once the computation reaches its minimum -function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visiting::IdDict{CodeInstance,Int}) +function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visiting::IdDict{CodeInstance,Int}, mwis::IdSet{Method}) world = codeinst.min_world let max_valid2 = codeinst.max_world if max_valid2 ≠ WORLD_AGE_REVALIDATION_SENTINEL @@ -75,7 +76,8 @@ function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visi end current_world = get_world_counter() local minworld::UInt, maxworld::UInt = 1, current_world - @assert get_ci_mi(codeinst).def isa Method + def = get_ci_mi(codeinst).def + @assert def isa Method if haskey(visiting, codeinst) return visiting[codeinst], minworld, maxworld end @@ -84,6 +86,14 @@ function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visi visiting[codeinst] = depth # TODO JL_TIMING(VERIFY_IMAGE, VERIFY_Methods) callees = codeinst.edges + # Check for invalidation of the implicit edges from GlobalRef in the Method source + if def in mwis + maxworld = 0 + invalidations = _jl_debug_method_invalidation[] + if invalidations !== nothing + push!(invalidations, def, "method_globalref", codeinst, nothing) + end + end # verify current edges if isempty(callees) # quick return: no edges to verify (though we probably shouldn't have gotten here from WORLD_AGE_REVALIDATION_SENTINEL) @@ -96,10 +106,6 @@ function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visi local min_valid2::UInt, max_valid2::UInt edge = callees[j] @assert !(edge isa Method) # `Method`-edge isn't allowed for the optimized one-edge format - if edge isa Core.BindingPartition - j += 1 - continue - end if edge isa CodeInstance edge = get_ci_mi(edge) end @@ -112,6 +118,21 @@ function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visi min_valid2, max_valid2, matches = verify_call(sig, callees, j+2, edge, world) j += 2 + edge edge = sig + elseif edge isa Core.Binding + j += 1 + min_valid2 = minworld + max_valid2 = maxworld + if !Base.binding_was_invalidated(edge) + if isdefined(edge, :partitions) + min_valid2 = edge.partitions.min_world + max_valid2 = edge.partitions.max_world + end + else + # Binding was previously invalidated + min_valid2 = 1 + max_valid2 = 0 + end + matches = nothing else callee = callees[j+1] if callee isa Core.MethodTable # skip the legacy edge (missing backedge) @@ -156,7 +177,7 @@ function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visi end callee = edge local min_valid2::UInt, max_valid2::UInt - child_cycle, min_valid2, max_valid2 = verify_method(callee, stack, visiting) + child_cycle, min_valid2, max_valid2 = verify_method(callee, stack, visiting, mwis) if minworld < min_valid2 minworld = min_valid2 end diff --git a/src/init.c b/src/init.c index f383a8f4620be..aada2c75ed7a6 100644 --- a/src/init.c +++ b/src/init.c @@ -910,6 +910,7 @@ static NOINLINE void _finish_julia_init(JL_IMAGE_SEARCH rel, jl_ptls_t ptls, jl_ jl_n_threads_per_pool[JL_THREADPOOL_ID_INTERACTIVE] = 0; jl_n_threads_per_pool[JL_THREADPOOL_ID_DEFAULT] = 1; } else { + jl_current_task->world_age = jl_atomic_load_acquire(&jl_world_counter); post_image_load_hooks(); } jl_start_threads(); diff --git a/src/jltypes.c b/src/jltypes.c index b478ce7ea98fd..b94922ce9cf54 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3271,12 +3271,13 @@ void jl_init_types(void) JL_GC_DISABLED jl_binding_type = jl_new_datatype(jl_symbol("Binding"), core, jl_any_type, jl_emptysvec, - jl_perm_symsvec(4, "globalref", "value", "partitions", "flags"), - jl_svec(4, jl_any_type/*jl_globalref_type*/, jl_any_type, jl_binding_partition_type, jl_uint8_type), + jl_perm_symsvec(5, "globalref", "value", "partitions", "backedges", "flags"), + jl_svec(5, jl_any_type/*jl_globalref_type*/, jl_any_type, jl_binding_partition_type, + jl_any_type, jl_uint8_type), jl_emptysvec, 0, 1, 0); - const static uint32_t binding_atomicfields[] = { 0x0005 }; // Set fields 1, 3 as atomic + const static uint32_t binding_atomicfields[] = { 0x0005 }; // Set fields 2, 3 as atomic jl_binding_type->name->atomicfields = binding_atomicfields; - const static uint32_t binding_constfields[] = { 0x0002 }; // Set fields 2 as constant + const static uint32_t binding_constfields[] = { 0x0001 }; // Set fields 1 as constant jl_binding_type->name->constfields = binding_constfields; jl_globalref_type = @@ -3856,6 +3857,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_svecset(jl_code_instance_type->types, 15, jl_voidpointer_type); jl_svecset(jl_code_instance_type->types, 16, jl_voidpointer_type); jl_svecset(jl_binding_type->types, 0, jl_globalref_type); + jl_svecset(jl_binding_type->types, 3, jl_array_any_type); jl_svecset(jl_binding_partition_type->types, 3, jl_binding_partition_type); jl_compute_field_offsets(jl_datatype_type); diff --git a/src/julia.h b/src/julia.h index a5f56ad580335..a80a69049ccb2 100644 --- a/src/julia.h +++ b/src/julia.h @@ -696,6 +696,7 @@ typedef struct _jl_binding_t { jl_globalref_t *globalref; // cached GlobalRef for this binding _Atomic(jl_value_t*) value; _Atomic(jl_binding_partition_t*) partitions; + jl_array_t *backedges; uint8_t did_print_backdate_admonition:1; uint8_t exportp:1; // `public foo` sets `publicp`, `export foo` sets both `publicp` and `exportp` uint8_t publicp:1; // exportp without publicp is not allowed. diff --git a/src/julia_internal.h b/src/julia_internal.h index a838b75e506a2..8d09861ba9cd5 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -719,8 +719,9 @@ jl_value_t *jl_code_or_ci_for_interpreter(jl_method_instance_t *lam JL_PROPAGATE int jl_code_requires_compiler(jl_code_info_t *src, int include_force_compile); jl_code_info_t *jl_new_code_info_from_ir(jl_expr_t *ast); JL_DLLEXPORT jl_code_info_t *jl_new_code_info_uninit(void); -JL_DLLEXPORT void jl_resolve_definition_effects_in_ir(jl_array_t *stmts, jl_module_t *m, jl_svec_t *sparam_vals, - int binding_effects); +JL_DLLEXPORT void jl_resolve_definition_effects_in_ir(jl_array_t *stmts, jl_module_t *m, jl_svec_t *sparam_vals, jl_value_t *binding_edge, + int binding_effects); +JL_DLLEXPORT void jl_maybe_add_binding_backedge(jl_globalref_t *gr, jl_module_t *defining_module, jl_value_t *edge); int get_next_edge(jl_array_t *list, int i, jl_value_t** invokesig, jl_code_instance_t **caller) JL_NOTSAFEPOINT; int set_next_edge(jl_array_t *list, int i, jl_value_t *invokesig, jl_code_instance_t *caller); diff --git a/src/method.c b/src/method.c index 4b39de9aa67e1..a79c46d9dab42 100644 --- a/src/method.c +++ b/src/method.c @@ -41,12 +41,16 @@ static void check_c_types(const char *where, jl_value_t *rt, jl_value_t *at) // Resolve references to non-locally-defined variables to become references to global // variables in `module` (unless the rvalue is one of the type parameters in `sparam_vals`). -static jl_value_t *resolve_definition_effects(jl_value_t *expr, jl_module_t *module, jl_svec_t *sparam_vals, +static jl_value_t *resolve_definition_effects(jl_value_t *expr, jl_module_t *module, jl_svec_t *sparam_vals, jl_value_t *binding_edge, int binding_effects, int eager_resolve) { if (jl_is_symbol(expr)) { jl_error("Found raw symbol in code returned from lowering. Expected all symbols to have been resolved to GlobalRef or slots."); } + if (jl_is_globalref(expr)) { + jl_maybe_add_binding_backedge((jl_globalref_t*)expr, module, binding_edge); + return expr; + } if (!jl_is_expr(expr)) { return expr; } @@ -60,10 +64,10 @@ static jl_value_t *resolve_definition_effects(jl_value_t *expr, jl_module_t *mod } // These exprs are not fully linearized if (e->head == jl_assign_sym) { - jl_exprargset(e, 1, resolve_definition_effects(jl_exprarg(e, 1), module, sparam_vals, binding_effects, eager_resolve)); + jl_exprargset(e, 1, resolve_definition_effects(jl_exprarg(e, 1), module, sparam_vals, binding_edge, binding_effects, eager_resolve)); return expr; } else if (e->head == jl_new_opaque_closure_sym) { - jl_exprargset(e, 4, resolve_definition_effects(jl_exprarg(e, 4), module, sparam_vals, binding_effects, eager_resolve)); + jl_exprargset(e, 4, resolve_definition_effects(jl_exprarg(e, 4), module, sparam_vals, binding_edge, binding_effects, eager_resolve)); return expr; } size_t nargs = jl_array_nrows(e->args); @@ -202,13 +206,13 @@ static jl_value_t *resolve_definition_effects(jl_value_t *expr, jl_module_t *mod return expr; } -JL_DLLEXPORT void jl_resolve_definition_effects_in_ir(jl_array_t *stmts, jl_module_t *m, jl_svec_t *sparam_vals, +JL_DLLEXPORT void jl_resolve_definition_effects_in_ir(jl_array_t *stmts, jl_module_t *m, jl_svec_t *sparam_vals, jl_value_t *binding_edge, int binding_effects) { size_t i, l = jl_array_nrows(stmts); for (i = 0; i < l; i++) { jl_value_t *stmt = jl_array_ptr_ref(stmts, i); - jl_array_ptr_set(stmts, i, resolve_definition_effects(stmt, m, sparam_vals, binding_effects, 0)); + jl_array_ptr_set(stmts, i, resolve_definition_effects(stmt, m, sparam_vals, binding_edge, binding_effects, 0)); } } @@ -622,7 +626,7 @@ JL_DLLEXPORT jl_code_info_t *jl_expand_and_resolve(jl_value_t *ex, jl_module_t * JL_GC_PUSH1(&func); if (jl_is_code_info(func)) { jl_array_t *stmts = (jl_array_t*)func->code; - jl_resolve_definition_effects_in_ir(stmts, module, sparam_vals, 1); + jl_resolve_definition_effects_in_ir(stmts, module, sparam_vals, NULL, 1); } JL_GC_POP(); return func; @@ -702,7 +706,7 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *mi, size_t if (jl_is_code_info(ex)) { func = (jl_code_info_t*)ex; jl_array_t *stmts = (jl_array_t*)func->code; - jl_resolve_definition_effects_in_ir(stmts, def->module, mi->sparam_vals, 1); + jl_resolve_definition_effects_in_ir(stmts, def->module, mi->sparam_vals, NULL, 1); } else { // Lower the user's expression and resolve references to the type parameters @@ -925,7 +929,7 @@ JL_DLLEXPORT void jl_method_set_source(jl_method_t *m, jl_code_info_t *src) } } else { - st = resolve_definition_effects(st, m->module, sparam_vars, 1, 0); + st = resolve_definition_effects(st, m->module, sparam_vars, (jl_value_t*)m, 1, 0); } jl_array_ptr_set(copy, i, st); } diff --git a/src/module.c b/src/module.c index 2630db2dbfd94..6ff43da5f9fc4 100644 --- a/src/module.c +++ b/src/module.c @@ -238,6 +238,7 @@ static jl_binding_t *new_binding(jl_module_t *mod, jl_sym_t *name) jl_atomic_store_relaxed(&b->value, NULL); jl_atomic_store_relaxed(&b->partitions, NULL); b->globalref = NULL; + b->backedges = NULL; b->exportp = 0; b->publicp = 0; b->deprecated = 0; @@ -245,7 +246,6 @@ static jl_binding_t *new_binding(jl_module_t *mod, jl_sym_t *name) JL_GC_PUSH1(&b); b->globalref = jl_new_globalref(mod, name, b); jl_gc_wb(b, b->globalref); - jl_atomic_store_relaxed(&b->partitions, NULL); JL_GC_POP(); return b; } @@ -1099,6 +1099,33 @@ void jl_invalidate_binding_refs(jl_globalref_t *ref, jl_binding_partition_t *inv JL_GC_POP(); } +// Called for all GlobalRefs found in lowered code. Adds backedges for cross-module +// GlobalRefs. +JL_DLLEXPORT void jl_maybe_add_binding_backedge(jl_globalref_t *gr, jl_module_t *defining_module, jl_value_t *edge) +{ + if (!edge) + return; + // N.B.: The logic for evaluating whether a backedge is required must + // match the invalidation logic. + if (gr->mod == defining_module) { + // No backedge required - invalidation will forward scan + return; + } + jl_binding_t *b = gr->binding; + if (!b) + b = jl_get_module_binding(gr->mod, gr->name, 1); + if (!b->backedges) { + b->backedges = jl_alloc_vec_any(0); + jl_gc_wb(b, b->backedges); + } else if (jl_array_len(b->backedges) > 0 && + jl_array_ptr_ref(b->backedges, jl_array_len(b->backedges)-1) == edge) { + // Optimization: Deduplicate repeated insertion of the same edge (e.g. during + // definition of a method that contains many references to the same global) + return; + } + jl_array_ptr_1d_push(b->backedges, edge); +} + JL_DLLEXPORT void jl_disable_binding(jl_globalref_t *gr) { jl_binding_t *b = gr->binding; diff --git a/src/staticdata.c b/src/staticdata.c index ba9c6ed8c1bea..cb1dc54d26d50 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -1676,16 +1676,24 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED write_uint(f, decode_restriction_kind(pku)); #endif size_t max_world = jl_atomic_load_relaxed(&bpart->max_world); - if (max_world == ~(size_t)0) { - // Still valid. Will be considered primordial after re-load. - // We could consider updating min_world to the loaded world, but - // there doesn't appear to be much point. - write_uint(f, 0); - write_uint(f, max_world); + if (s->incremental) { + if (max_world == ~(size_t)0) { + // Still valid. Will be considered to be defined in jl_require_world + // after reload, which is the first world before new code runs. + // We use this as a quick check to determine whether a binding was + // invalidated. If a binding was first defined in or before + // jl_require_world, then we can assume that all precompile processes + // will have seen it consistently. + write_uint(f, jl_require_world); + write_uint(f, max_world); + } else { + // The world will not be reachable after loading + write_uint(f, 1); + write_uint(f, 0); + } } else { - // The world will not be reachable after loading - write_uint(f, 1); - write_uint(f, 0); + write_uint(f, bpart->min_world); + write_uint(f, max_world); } write_pointerfield(s, (jl_value_t*)jl_atomic_load_relaxed(&bpart->next)); #ifdef _P64 @@ -4141,7 +4149,7 @@ static jl_value_t *jl_restore_package_image_from_stream(void* pkgimage_handle, i extext_methods, method_roots_list, cachesizes_sv); } else { - restored = (jl_value_t*)jl_svec(4, restored, init_order, edges, ext_edges); + restored = (jl_value_t*)jl_svec(6, restored, init_order, edges, ext_edges, extext_methods, internal_methods); } } } diff --git a/src/toplevel.c b/src/toplevel.c index 35ad001ac4b4b..cdd390b9b49ed 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -1097,7 +1097,7 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val jl_get_module_compile(m) != JL_OPTIONS_COMPILE_MIN)) { // use codegen mfunc = jl_method_instance_for_thunk(thk, m); - jl_resolve_definition_effects_in_ir((jl_array_t*)thk->code, m, NULL, 0); + jl_resolve_definition_effects_in_ir((jl_array_t*)thk->code, m, NULL, NULL, 0); // Don't infer blocks containing e.g. method definitions, since it's probably not worthwhile. size_t world = jl_atomic_load_acquire(&jl_world_counter); ct->world_age = world; @@ -1110,8 +1110,9 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val else { // use interpreter assert(thk); - if (has_opaque) - jl_resolve_definition_effects_in_ir((jl_array_t*)thk->code, m, NULL, 0); + if (has_opaque) { + jl_resolve_definition_effects_in_ir((jl_array_t*)thk->code, m, NULL, NULL, 0); + } size_t world = jl_atomic_load_acquire(&jl_world_counter); ct->world_age = world; result = jl_interpret_toplevel_thunk(m, thk); diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index 26ad6651cd880..eadc2672dd29b 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -726,6 +726,7 @@ function resolve_toplevel_symbols!(src::Core.CodeInfo, mod::Module) #=jl_array_t *stmts=# src.code::Any, #=jl_module_t *m=# mod::Any, #=jl_svec_t *sparam_vals=# Core.svec()::Any, + #=jl_value_t *binding_edge=# C_NULL::Ptr{Cvoid}, #=int binding_effects=# 0::Int)::Cvoid return src end diff --git a/test/rebinding.jl b/test/rebinding.jl index 10da27ce3ad8f..ed8e96ba30c62 100644 --- a/test/rebinding.jl +++ b/test/rebinding.jl @@ -2,7 +2,6 @@ module Rebinding using Test - make_foo() = Foo(1) @test Base.binding_kind(@__MODULE__, :Foo) == Base.BINDING_KIND_GUARD @@ -41,10 +40,73 @@ module Rebinding Base.delete_binding(@__MODULE__, :delete_me) @test_throws UndefVarError f_return_delete_me() + # + foreign module + module NotTheDefinitionModule + const delete_me_other = 2 + end + @eval f_return_delete_me_foreign_module() = $(GlobalRef(NotTheDefinitionModule, :delete_me_other)) + @test f_return_delete_me_foreign_module() == 2 + Base.delete_binding(NotTheDefinitionModule, :delete_me_other) + @test_throws UndefVarError f_return_delete_me_foreign_module() + ## + via indirect access - const delete_me = 2 + const delete_me = 3 f_return_delete_me_indirect() = getglobal(@__MODULE__, :delete_me) - @test f_return_delete_me_indirect() == 2 + @test f_return_delete_me_indirect() == 3 Base.delete_binding(@__MODULE__, :delete_me) @test_throws UndefVarError f_return_delete_me_indirect() end + +module RebindingPrecompile + using Test + include("precompile_utils.jl") + + precompile_test_harness("rebinding precompile") do load_path + # Test that the system doesn't accidentally forget to revalidate a method without backedges + write(joinpath(load_path, "LotsOfBindingsToDelete.jl"), + """ + module LotsOfBindingsToDelete + const delete_me_1 = 1 + const delete_me_2 = 2 + const delete_me_3 = 3 + const delete_me_4 = 4 + end + """) + Base.compilecache(Base.PkgId("LotsOfBindingsToDelete")) + write(joinpath(load_path, "UseTheBindings.jl"), + """ + module UseTheBindings + using LotsOfBindingsToDelete + @eval f_use_bindings1() = \$(GlobalRef(LotsOfBindingsToDelete, :delete_me_1)) + @eval f_use_bindings2() = \$(GlobalRef(LotsOfBindingsToDelete, :delete_me_2)) + f_use_bindings3() = LotsOfBindingsToDelete.delete_me_3 + f_use_bindings4() = LotsOfBindingsToDelete.delete_me_4 + # Code Instances for each of these + @assert (f_use_bindings1(), f_use_bindings2(), f_use_bindings3(), f_use_bindings4()) == + (1, 2, 3, 4) + end + """) + Base.compilecache(Base.PkgId("UseTheBindings")) + @eval using LotsOfBindingsToDelete + # Delete some bindings before loading the dependent package + Base.delete_binding(LotsOfBindingsToDelete, :delete_me_1) + Base.delete_binding(LotsOfBindingsToDelete, :delete_me_3) + # Load the dependent package + @eval using UseTheBindings + invokelatest() do + @test_throws UndefVarError UseTheBindings.f_use_bindings1() + @test UseTheBindings.f_use_bindings2() == 2 + @test_throws UndefVarError UseTheBindings.f_use_bindings3() + @test UseTheBindings.f_use_bindings4() == 4 + # Delete remaining bindings + Base.delete_binding(LotsOfBindingsToDelete, :delete_me_2) + Base.delete_binding(LotsOfBindingsToDelete, :delete_me_4) + invokelatest() do + @test_throws UndefVarError UseTheBindings.f_use_bindings2() + @test_throws UndefVarError UseTheBindings.f_use_bindings4() + end + end + end + + finish_precompile_test!() +end From 12698af99f2502227aba611f0107b1dc3a6872d2 Mon Sep 17 00:00:00 2001 From: Neven Sajko <4944410+nsajko@users.noreply.github.com> Date: Sun, 2 Feb 2025 20:23:17 +0100 Subject: [PATCH 271/342] test foldability inference of basic iterator functions like `eltype` (#56838) Co-authored-by: Max Horn --- test/iterators.jl | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/test/iterators.jl b/test/iterators.jl index 06f08cff4f6ad..df4fa63b433b8 100644 --- a/test/iterators.jl +++ b/test/iterators.jl @@ -998,6 +998,57 @@ end @test (@inferred Base.IteratorSize(zip(1:5, (1,2,3)) )) == Base.HasLength() # for zip of ::HasShape and ::HasLength end +@testset "foldability inference" begin + functions = (eltype, Base.IteratorSize, Base.IteratorEltype) + helper(type::UnionAll) = (type{n} for n ∈ 1:10) # helper for trying with multiple iterator counts + iterator_types = ( # each element here takes an iterator type as first parameter + Base.Generator, + Iterators.Reverse, + Iterators.Enumerate, + Iterators.Filter{F, I} where {I, F}, + Iterators.Accumulate{F, I} where {I, F}, + Iterators.Rest, + Iterators.Count, + Iterators.Take, + Iterators.Drop, + Iterators.TakeWhile, + Iterators.DropWhile, + Iterators.Cycle, + Iterators.Repeated, + Iterators.PartitionIterator, + Iterators.Stateful, + helper(Iterators.ProductIterator{Tuple{Vararg{I, N}}} where {N, I})..., + ) + iterator_types_extra = ( + iterator_types..., + helper(Iterators.Zip{Tuple{Vararg{I, N}}} where {N, I})..., + helper(Iterators.Flatten{Tuple{Vararg{I, N}}} where {N, I})..., + ) + simple_types = (Vector, NTuple, NamedTuple{X, Y} where {X, Y <: NTuple}) + example_type = Tuple{Bool, Int8, Vararg{Int16, 20}} + function test_foldability_inference(f, S::Type) + @test Core.Compiler.is_foldable(Base.infer_effects(f, Tuple{S})) + @test Core.Compiler.is_foldable(Base.infer_effects(f, Tuple{Type{<:S}})) + end + @testset "concrete" begin # weaker test, only checks foldability for certain concrete types + @testset "f: $f" for f ∈ functions + for U ∈ iterator_types_extra + test_foldability_inference(f, U{example_type}) + end + end + end + @testset "nonconcrete" begin # stronger test, checks foldability for large families of types + @testset "f: $f" for f ∈ functions + for V ∈ simple_types + test_foldability_inference(f, V) # sanity check + for U ∈ iterator_types + test_foldability_inference(f, U{<:V}) + end + end + end + end +end + @testset "proper partition for non-1-indexed vector" begin @test partition(IdentityUnitRange(11:19), 5) |> collect == [11:15,16:19] # IdentityUnitRange end From ce507a7e70603631b7c9e242528c1b611f918b01 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sun, 2 Feb 2025 21:46:58 -0500 Subject: [PATCH 272/342] Refactor generated function implementation to provide bindings/method (#57230) This PR refactors the generated function implementation in multiple ways: 1. Rather than allocating a new LineNumber node to pass to the generator, we just pass the original method from which this LineNumberNode was constructed. This has been a bit of a longer-standing annoyance of mine, since the generator needs to know properties of the original method to properly interpret the return value from the generator, but this information was only available on the C side. 2. Move the handling of `Expr` returns fully into Julia. Right not things were a bit split with the julia code post-processing an `Expr` return, but then handing it back to C for lowering. By moving it fully into Julia, we can keep the C-side interface simpler by always getting a `CodeInfo`. With these refactorings done, amend the post-processing code to provide binding edges for `Expr` returns. Ordinarily, bindings in lowered code do not need edges, because we will scan the lowered code of the method to find them. However, generated functions are different, because we do not in general have the lowered code available. To still give them binding edges, we simply scan through the post-lowered code and all of the bindings we find into the edges array. I will note that both of these will require minor adjustments to `@generated` functions that use the CodeInfo interface (N.B.: this interface is not considered stable and we've broken it in almost every release so far). In particular, the following adjustments need to be made: 1. Adjusting the `source` argument to the new `Method` ABI 2. If necessary, adding any edges that correspond to GlobalRefs used - the code will treat the returned CodeInfo mostly opaquely and (unlike in the `Expr` case) will not automatically compute these edges. --- base/Base_compiler.jl | 2 +- base/boot.jl | 21 ------------------ base/expr.jl | 43 ++++++++++++++++++++++++++++++++++++ base/invalidation.jl | 22 ++++++++++--------- src/jl_exported_funcs.inc | 1 - src/julia_internal.h | 1 + src/method.c | 46 ++++++++------------------------------- src/module.c | 25 ++++++++++++--------- test/rebinding.jl | 7 ++++++ test/staged.jl | 6 ++--- 10 files changed, 91 insertions(+), 83 deletions(-) diff --git a/base/Base_compiler.jl b/base/Base_compiler.jl index 8cc7096ee26a7..4ec6bae171d8f 100644 --- a/base/Base_compiler.jl +++ b/base/Base_compiler.jl @@ -234,13 +234,13 @@ include("abstractarray.jl") include("baseext.jl") include("c.jl") -include("ntuple.jl") include("abstractset.jl") include("bitarray.jl") include("bitset.jl") include("abstractdict.jl") include("iddict.jl") include("idset.jl") +include("ntuple.jl") include("iterators.jl") using .Iterators: zip, enumerate, only using .Iterators: Flatten, Filter, product # for generators diff --git a/base/boot.jl b/base/boot.jl index 9b386f90d4abe..e50d74659d399 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -777,27 +777,6 @@ struct GeneratedFunctionStub spnames::SimpleVector end -# invoke and wrap the results of @generated expression -function (g::GeneratedFunctionStub)(world::UInt, source::LineNumberNode, @nospecialize args...) - # args is (spvals..., argtypes...) - body = g.gen(args...) - file = source.file - file isa Symbol || (file = :none) - lam = Expr(:lambda, Expr(:argnames, g.argnames...).args, - Expr(:var"scope-block", - Expr(:block, - source, - Expr(:meta, :push_loc, file, :var"@generated body"), - Expr(:return, body), - Expr(:meta, :pop_loc)))) - spnames = g.spnames - if spnames === svec() - return lam - else - return Expr(Symbol("with-static-parameters"), lam, spnames...) - end -end - # If the generator is a subtype of this trait, inference caches the generated unoptimized # code, sacrificing memory space to improve the performance of subsequent inferences. # This tradeoff is not appropriate in general cases (e.g., for `GeneratedFunctionStub`s diff --git a/base/expr.jl b/base/expr.jl index 84078829f77ed..d71723ee26f1f 100644 --- a/base/expr.jl +++ b/base/expr.jl @@ -1654,3 +1654,46 @@ end function quoted(@nospecialize(x)) return is_self_quoting(x) ? x : QuoteNode(x) end + +# Implementation of generated functions +function generated_body_to_codeinfo(ex::Expr, defmod::Module, isva::Bool) + ci = ccall(:jl_expand, Any, (Any, Any), ex, defmod) + if !isa(ci, CodeInfo) + if isa(ci, Expr) && ci.head === :error + error("syntax: $(ci.args[1])") + end + error("The function body AST defined by this @generated function is not pure. This likely means it contains a closure, a comprehension or a generator.") + end + ci.isva = isva + code = ci.code + bindings = IdSet{Core.Binding}() + for i = 1:length(code) + stmt = code[i] + if isa(stmt, GlobalRef) + push!(bindings, convert(Core.Binding, stmt)) + end + end + if !isempty(bindings) + ci.edges = Core.svec(bindings...) + end + return ci +end + +# invoke and wrap the results of @generated expression +function (g::Core.GeneratedFunctionStub)(world::UInt, source::Method, @nospecialize args...) + # args is (spvals..., argtypes...) + body = g.gen(args...) + file = source.file + file isa Symbol || (file = :none) + lam = Expr(:lambda, Expr(:argnames, g.argnames...).args, + Expr(:var"scope-block", + Expr(:block, + LineNumberNode(Int(source.line), source.file), + Expr(:meta, :push_loc, file, :var"@generated body"), + Expr(:return, body), + Expr(:meta, :pop_loc)))) + spnames = g.spnames + return generated_body_to_codeinfo(spnames === Core.svec() ? lam : Expr(Symbol("with-static-parameters"), lam, spnames...), + typename(typeof(g.gen)).module, + source.isva) +end diff --git a/base/invalidation.jl b/base/invalidation.jl index d9a0bd95c5159..36b867ede2868 100644 --- a/base/invalidation.jl +++ b/base/invalidation.jl @@ -93,26 +93,28 @@ function scan_edge_list(ci::Core.CodeInstance, binding::Core.Binding) end function invalidate_method_for_globalref!(gr::GlobalRef, method::Method, invalidated_bpart::Core.BindingPartition, new_max_world::UInt) + invalidate_all = false + binding = convert(Core.Binding, gr) if isdefined(method, :source) src = _uncompressed_ir(method) - binding = convert(Core.Binding, gr) old_stmts = src.code invalidate_all = should_invalidate_code_for_globalref(gr, src) - for mi in specializations(method) - isdefined(mi, :cache) || continue - ci = mi.cache - while true - if ci.max_world > new_max_world && (invalidate_all || scan_edge_list(ci, binding)) - ccall(:jl_invalidate_code_instance, Cvoid, (Any, UInt), ci, new_max_world) - end - isdefined(ci, :next) || break - ci = ci.next + end + for mi in specializations(method) + isdefined(mi, :cache) || continue + ci = mi.cache + while true + if ci.max_world > new_max_world && (invalidate_all || scan_edge_list(ci, binding)) + ccall(:jl_invalidate_code_instance, Cvoid, (Any, UInt), ci, new_max_world) end + isdefined(ci, :next) || break + ci = ci.next end end end function invalidate_code_for_globalref!(gr::GlobalRef, invalidated_bpart::Core.BindingPartition, new_max_world::UInt) + b = convert(Core.Binding, gr) try valid_in_valuepos = false foreach_module_mtable(gr.mod, new_max_world) do mt::Core.MethodTable diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index 9e221420aa9f4..4d1ab94644e39 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -127,7 +127,6 @@ XX(jl_exit_on_sigint) \ XX(jl_exit_threaded_region) \ XX(jl_expand) \ - XX(jl_expand_and_resolve) \ XX(jl_expand_stmt) \ XX(jl_expand_stmt_with_loc) \ XX(jl_expand_with_loc) \ diff --git a/src/julia_internal.h b/src/julia_internal.h index 8d09861ba9cd5..9817c8cc8263b 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -722,6 +722,7 @@ JL_DLLEXPORT jl_code_info_t *jl_new_code_info_uninit(void); JL_DLLEXPORT void jl_resolve_definition_effects_in_ir(jl_array_t *stmts, jl_module_t *m, jl_svec_t *sparam_vals, jl_value_t *binding_edge, int binding_effects); JL_DLLEXPORT void jl_maybe_add_binding_backedge(jl_globalref_t *gr, jl_module_t *defining_module, jl_value_t *edge); +JL_DLLEXPORT void jl_add_binding_backedge(jl_binding_t *b, jl_value_t *edge); int get_next_edge(jl_array_t *list, int i, jl_value_t** invokesig, jl_code_instance_t **caller) JL_NOTSAFEPOINT; int set_next_edge(jl_array_t *list, int i, jl_value_t *invokesig, jl_code_instance_t *caller); diff --git a/src/method.c b/src/method.c index a79c46d9dab42..8a14eb00182b1 100644 --- a/src/method.c +++ b/src/method.c @@ -604,8 +604,7 @@ static jl_value_t *jl_call_staged(jl_method_t *def, jl_value_t *generator, size_t totargs = 2 + n_sparams + def->nargs; JL_GC_PUSHARGS(gargs, totargs); gargs[0] = jl_box_ulong(world); - gargs[1] = jl_box_long(def->line); - gargs[1] = jl_new_struct(jl_linenumbernode_type, gargs[1], def->file); + gargs[1] = (jl_value_t*)def; memcpy(&gargs[2], jl_svec_data(sparam_vals), n_sparams * sizeof(void*)); memcpy(&gargs[2 + n_sparams], args, (def->nargs - def->isva) * sizeof(void*)); if (def->isva) @@ -615,23 +614,6 @@ static jl_value_t *jl_call_staged(jl_method_t *def, jl_value_t *generator, return code; } -// Lower `ex` into Julia IR, and (if it expands into a CodeInfo) resolve global-variable -// references in light of the provided type parameters. -// Like `jl_expand`, if there is an error expanding the provided expression, the return value -// will be an error expression (an `Expr` with `error_sym` as its head), which should be eval'd -// in the caller's context. -JL_DLLEXPORT jl_code_info_t *jl_expand_and_resolve(jl_value_t *ex, jl_module_t *module, - jl_svec_t *sparam_vals) { - jl_code_info_t *func = (jl_code_info_t*)jl_expand((jl_value_t*)ex, module); - JL_GC_PUSH1(&func); - if (jl_is_code_info(func)) { - jl_array_t *stmts = (jl_array_t*)func->code; - jl_resolve_definition_effects_in_ir(stmts, module, sparam_vals, NULL, 1); - } - JL_GC_POP(); - return func; -} - JL_DLLEXPORT jl_code_instance_t *jl_cached_uninferred(jl_code_instance_t *codeinst, size_t world) { for (; codeinst; codeinst = jl_atomic_load_relaxed(&codeinst->next)) { @@ -703,25 +685,12 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *mi, size_t ex = jl_call_staged(def, generator, world, mi->sparam_vals, jl_svec_data(ttdt->parameters), jl_nparams(ttdt)); // do some post-processing - if (jl_is_code_info(ex)) { - func = (jl_code_info_t*)ex; - jl_array_t *stmts = (jl_array_t*)func->code; - jl_resolve_definition_effects_in_ir(stmts, def->module, mi->sparam_vals, NULL, 1); - } - else { - // Lower the user's expression and resolve references to the type parameters - func = jl_expand_and_resolve(ex, def->module, mi->sparam_vals); - if (!jl_is_code_info(func)) { - if (jl_is_expr(func) && ((jl_expr_t*)func)->head == jl_error_sym) { - ct->ptls->in_pure_callback = 0; - jl_toplevel_eval(def->module, (jl_value_t*)func); - } - jl_error("The function body AST defined by this @generated function is not pure. This likely means it contains a closure, a comprehension or a generator."); - } - // TODO: This should ideally be in the lambda expression, - // but currently our isva determination is non-syntactic - func->isva = def->isva; + if (!jl_is_code_info(ex)) { + jl_error("As of Julia 1.12, generated functions must return `CodeInfo`. See `Base.generated_body_to_codeinfo`."); } + func = (jl_code_info_t*)ex; + jl_array_t *stmts = (jl_array_t*)func->code; + jl_resolve_definition_effects_in_ir(stmts, def->module, mi->sparam_vals, NULL, 1); ex = NULL; // If this generated function has an opaque closure, cache it for @@ -778,6 +747,9 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *mi, size_t if (jl_is_method_instance(kind)) { jl_method_instance_add_backedge((jl_method_instance_t*)kind, jl_nothing, ci); } + else if (jl_is_binding(kind)) { + jl_add_binding_backedge((jl_binding_t*)kind, (jl_value_t*)ci); + } else if (jl_is_mtable(kind)) { assert(i < l); ex = data[i++]; diff --git a/src/module.c b/src/module.c index 6ff43da5f9fc4..b2a4018519fca 100644 --- a/src/module.c +++ b/src/module.c @@ -1099,6 +1099,20 @@ void jl_invalidate_binding_refs(jl_globalref_t *ref, jl_binding_partition_t *inv JL_GC_POP(); } +JL_DLLEXPORT void jl_add_binding_backedge(jl_binding_t *b, jl_value_t *edge) +{ + if (!b->backedges) { + b->backedges = jl_alloc_vec_any(0); + jl_gc_wb(b, b->backedges); + } else if (jl_array_len(b->backedges) > 0 && + jl_array_ptr_ref(b->backedges, jl_array_len(b->backedges)-1) == edge) { + // Optimization: Deduplicate repeated insertion of the same edge (e.g. during + // definition of a method that contains many references to the same global) + return; + } + jl_array_ptr_1d_push(b->backedges, edge); +} + // Called for all GlobalRefs found in lowered code. Adds backedges for cross-module // GlobalRefs. JL_DLLEXPORT void jl_maybe_add_binding_backedge(jl_globalref_t *gr, jl_module_t *defining_module, jl_value_t *edge) @@ -1114,16 +1128,7 @@ JL_DLLEXPORT void jl_maybe_add_binding_backedge(jl_globalref_t *gr, jl_module_t jl_binding_t *b = gr->binding; if (!b) b = jl_get_module_binding(gr->mod, gr->name, 1); - if (!b->backedges) { - b->backedges = jl_alloc_vec_any(0); - jl_gc_wb(b, b->backedges); - } else if (jl_array_len(b->backedges) > 0 && - jl_array_ptr_ref(b->backedges, jl_array_len(b->backedges)-1) == edge) { - // Optimization: Deduplicate repeated insertion of the same edge (e.g. during - // definition of a method that contains many references to the same global) - return; - } - jl_array_ptr_1d_push(b->backedges, edge); + jl_add_binding_backedge(b, edge); } JL_DLLEXPORT void jl_disable_binding(jl_globalref_t *gr) diff --git a/test/rebinding.jl b/test/rebinding.jl index ed8e96ba30c62..aee866facaf02 100644 --- a/test/rebinding.jl +++ b/test/rebinding.jl @@ -55,6 +55,13 @@ module Rebinding @test f_return_delete_me_indirect() == 3 Base.delete_binding(@__MODULE__, :delete_me) @test_throws UndefVarError f_return_delete_me_indirect() + + # + via generated function + const delete_me = 4 + @generated f_generated_return_delete_me() = return :(delete_me) + @test f_generated_return_delete_me() == 4 + Base.delete_binding(@__MODULE__, :delete_me) + @test_throws UndefVarError f_generated_return_delete_me() end module RebindingPrecompile diff --git a/test/staged.jl b/test/staged.jl index 6cb99950a7bb2..f3dbdcd73d811 100644 --- a/test/staged.jl +++ b/test/staged.jl @@ -381,7 +381,7 @@ let @test length(ir.cfg.blocks) == 1 end -function generate_lambda_ex(world::UInt, source::LineNumberNode, +function generate_lambda_ex(world::UInt, source::Method, argnames, spnames, @nospecialize body) stub = Core.GeneratedFunctionStub(identity, Core.svec(argnames...), Core.svec(spnames...)) return stub(world, source, body) @@ -389,7 +389,7 @@ end # Test that `Core.CachedGenerator` works as expected struct Generator54916 <: Core.CachedGenerator end -function (::Generator54916)(world::UInt, source::LineNumberNode, args...) +function (::Generator54916)(world::UInt, source::Method, args...) return generate_lambda_ex(world, source, (:doit54916, :func, :arg), (), :(func(arg))) end @@ -432,7 +432,7 @@ function overdubbee54341(a, b) a + b end const overdubee_codeinfo54341 = code_lowered(overdubbee54341, Tuple{Any, Any})[1] -function overdub_generator54341(world::UInt, source::LineNumberNode, selftype, fargtypes) +function overdub_generator54341(world::UInt, source::Method, selftype, fargtypes) if length(fargtypes) != 2 return generate_lambda_ex(world, source, (:overdub54341, :args), (), :(error("Wrong number of arguments"))) From 2317c2310e2154f793a2ea801445625b37d5070b Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Sun, 2 Feb 2025 22:18:05 -0500 Subject: [PATCH 273/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?LinearAlgebra=20stdlib=20from=2057e9a0d=20to=20c9ad828=20(#5723?= =?UTF-8?q?4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: LinearAlgebra URL: https://github.com/JuliaLang/LinearAlgebra.jl.git Stdlib branch: master Julia branch: master Old commit: 57e9a0d New commit: c9ad828 Julia version: 1.12.0-DEV LinearAlgebra version: 1.12.0 Bump invoked by: @ViralBShah Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaLang/LinearAlgebra.jl/compare/57e9a0d19f7a0042e0ef536fe5ae5fc35c61a6f1...c9ad82820ab59c57e0f982aa9c7c8611380e28e2 ``` $ git log --oneline 57e9a0d..c9ad828 c9ad828 Fix #1164 - flaky posv test (#1166) 106da87 Merge branch 'master' into vs/1164 443aa0f update manifest from JuliaSyntaxHighlighting UUID change (#1188) 0ce073c update manifest from JuliaSyntaxHighlighting UUID change e05561b Merge branch 'master' into vs/1164 55eddfc Fix structure test for strided matrices (#1184) 1a0135a Let `cond` of an empty square matrix return zero (#1169) 7542f75 Fix test 6f2c5df Fix structure test for strided matrices 697ee4f Fix #1164 ``` Co-authored-by: ViralBShah <744411+ViralBShah@users.noreply.github.com> Co-authored-by: Viral B. Shah --- .../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-57e9a0d19f7a0042e0ef536fe5ae5fc35c61a6f1.tar.gz/md5 delete mode 100644 deps/checksums/LinearAlgebra-57e9a0d19f7a0042e0ef536fe5ae5fc35c61a6f1.tar.gz/sha512 create mode 100644 deps/checksums/LinearAlgebra-c9ad82820ab59c57e0f982aa9c7c8611380e28e2.tar.gz/md5 create mode 100644 deps/checksums/LinearAlgebra-c9ad82820ab59c57e0f982aa9c7c8611380e28e2.tar.gz/sha512 diff --git a/deps/checksums/LinearAlgebra-57e9a0d19f7a0042e0ef536fe5ae5fc35c61a6f1.tar.gz/md5 b/deps/checksums/LinearAlgebra-57e9a0d19f7a0042e0ef536fe5ae5fc35c61a6f1.tar.gz/md5 deleted file mode 100644 index cf0897401a9b8..0000000000000 --- a/deps/checksums/LinearAlgebra-57e9a0d19f7a0042e0ef536fe5ae5fc35c61a6f1.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -a2c4227b17fe589791261081710add05 diff --git a/deps/checksums/LinearAlgebra-57e9a0d19f7a0042e0ef536fe5ae5fc35c61a6f1.tar.gz/sha512 b/deps/checksums/LinearAlgebra-57e9a0d19f7a0042e0ef536fe5ae5fc35c61a6f1.tar.gz/sha512 deleted file mode 100644 index 3aebc8a8bd7b5..0000000000000 --- a/deps/checksums/LinearAlgebra-57e9a0d19f7a0042e0ef536fe5ae5fc35c61a6f1.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -08fd85a63a08aae079c835f139845f5155fbb5d96444e8ed4cd1a696921e30ec842e6013e486e32d7ffe19d598ff1abb084e0a13fecdecc17546a76f16357a4a diff --git a/deps/checksums/LinearAlgebra-c9ad82820ab59c57e0f982aa9c7c8611380e28e2.tar.gz/md5 b/deps/checksums/LinearAlgebra-c9ad82820ab59c57e0f982aa9c7c8611380e28e2.tar.gz/md5 new file mode 100644 index 0000000000000..9f3191a5d97c5 --- /dev/null +++ b/deps/checksums/LinearAlgebra-c9ad82820ab59c57e0f982aa9c7c8611380e28e2.tar.gz/md5 @@ -0,0 +1 @@ +02594da939439696ad60bf415d357c2b diff --git a/deps/checksums/LinearAlgebra-c9ad82820ab59c57e0f982aa9c7c8611380e28e2.tar.gz/sha512 b/deps/checksums/LinearAlgebra-c9ad82820ab59c57e0f982aa9c7c8611380e28e2.tar.gz/sha512 new file mode 100644 index 0000000000000..61f11a324d196 --- /dev/null +++ b/deps/checksums/LinearAlgebra-c9ad82820ab59c57e0f982aa9c7c8611380e28e2.tar.gz/sha512 @@ -0,0 +1 @@ +13a999588218736e54d11b7537e778215fdc18b515fd595c30d9d7ac21c5f1bc030d000ada14b56b49b7e6ab179bcdfcad2d46819eb3c0e3d8add1a4bbd83232 diff --git a/stdlib/LinearAlgebra.version b/stdlib/LinearAlgebra.version index 6bdb43b93bfa8..6d882da545f2a 100644 --- a/stdlib/LinearAlgebra.version +++ b/stdlib/LinearAlgebra.version @@ -1,4 +1,4 @@ LINEARALGEBRA_BRANCH = master -LINEARALGEBRA_SHA1 = 57e9a0d19f7a0042e0ef536fe5ae5fc35c61a6f1 +LINEARALGEBRA_SHA1 = c9ad82820ab59c57e0f982aa9c7c8611380e28e2 LINEARALGEBRA_GIT_URL := https://github.com/JuliaLang/LinearAlgebra.jl.git LINEARALGEBRA_TAR_URL = https://api.github.com/repos/JuliaLang/LinearAlgebra.jl/tarball/$1 From 4bc3206dc2a2b3cb6fa0efd6ce49ea8b6eedbc16 Mon Sep 17 00:00:00 2001 From: Lilith Orion Hafner Date: Sun, 2 Feb 2025 23:43:16 -0600 Subject: [PATCH 274/342] Define publicity at a per-binding level, not per-symbol (#57094) Symbols don't belong to modules and can't be marked public. The statement `public Fix` in Base does not make the symbol `:Fix` public everywhere. My package's `Package.Fix` may still be private. It's bindings that are marked this way: https://github.com/JuliaLang/julia/blob/fa9478b5178052ef00690732fe363601182b6922/src/julia.h#L695-L705 --- NEWS.md | 2 +- doc/src/manual/faq.md | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/NEWS.md b/NEWS.md index 1a3ba07021bad..53643ee2c0954 100644 --- a/NEWS.md +++ b/NEWS.md @@ -56,7 +56,7 @@ Language changes behavior. Infinite loops that actually do things (e.g. have side effects or sleep) were never and are still not undefined behavior. ([#52999]) - - It is now an error to mark a symbol as both `public` and `export`ed. + - It is now an error to mark a binding as both `public` and `export`ed. ([#53664]) Compiler/Runtime improvements diff --git a/doc/src/manual/faq.md b/doc/src/manual/faq.md index 178a674e46643..be4f331cd6233 100644 --- a/doc/src/manual/faq.md +++ b/doc/src/manual/faq.md @@ -23,22 +23,22 @@ On the other hand, language *interoperability* is extremely useful: we want to e ### How does Julia define its public API? Julia's public [API](https://en.wikipedia.org/wiki/API) is the behavior described in -documentation of public symbols from `Base` and the standard libraries. Functions, +documentation of public bindings from `Base` and the standard libraries. Functions, types, and constants are not part of the public API if they are not public, even if they have docstrings or are described in the documentation. Further, only the documented -behavior of public symbols is part of the public API. Undocumented behavior of public -symbols is internal. +behavior of public bindings is part of the public API. Undocumented behavior of public +bindings is internal. -Public symbols are those marked with either `public foo` or `export foo`. +Public bindings are those marked with either `public foo` or `export foo`. In other words: -- Documented behavior of public symbols is part of the public API. -- Undocumented behavior of public symbols is not part of the public API. -- Documented behavior of private symbols is not part of the public API. -- Undocumented behavior of private symbols is not part of the public API. +- Documented behavior of public bindings is part of the public API. +- Undocumented behavior of public bindings is not part of the public API. +- Documented behavior of private bindings is not part of the public API. +- Undocumented behavior of private bindings is not part of the public API. -You can get a complete list of the public symbols from a module with `names(MyModule)`. +You can get a complete list of the public bindings from a module with `names(MyModule)`. Package authors are encouraged to define their public API similarly. @@ -253,7 +253,7 @@ the variables `A` and `x` were distinct bindings referring to the same mutable ` ### Can I use `using` or `import` inside a function? No, you are not allowed to have a `using` or `import` statement inside a function. If you want -to import a module but only use its symbols inside a specific function or set of functions, you +to import a module but only use its bindings inside a specific function or set of functions, you have two options: 1. Use `import`: @@ -261,13 +261,13 @@ have two options: ```julia import Foo function bar(...) - # ... refer to Foo symbols via Foo.baz ... + # ... refer to Foo bindings via Foo.baz ... end ``` This loads the module `Foo` and defines a variable `Foo` that refers to the module, but does not - import any of the other symbols from the module into the current namespace. You refer to the - `Foo` symbols by their qualified names `Foo.bar` etc. + import any of the other bindings from the module into the current namespace. You refer to the + `Foo` bindings by their qualified names `Foo.bar` etc. 2. Wrap your function in a module: ```julia @@ -281,7 +281,7 @@ have two options: using Bar ``` - This imports all the symbols from `Foo`, but only inside the module `Bar`. + This imports all the bindings from `Foo`, but only inside the module `Bar`. ### What does the `...` operator do? From fea26ddecb8a6c404f0c501228bf17c9b384d686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Belmant?= Date: Mon, 3 Feb 2025 16:00:24 +0100 Subject: [PATCH 275/342] Optimizer: Update SROA def-uses after DCE (#57201) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/JuliaLang/julia/issues/57141. Given the function ```julia julia> function _f() ref = Ref{Any}() ref[] = 3 @assert isdefined(ref, :x) inner = Returns(ref) x = inner() (x, ref[]) end _f (generic function with 1 method) julia> f() = first(_f()) f (generic function with 1 method) ``` Here is before: ```julia julia> @code_typed f() CodeInfo( 1 ─ %1 = %new(Base.RefValue{Any})::Base.RefValue{Any} └── goto #3 2 ─ unreachable 3 ─ return %1 ) => Base.RefValue{Any} ``` Here is after this PR: ```julia julia> @code_typed f() CodeInfo( 1 ─ %1 = %new(Base.RefValue{Any})::Base.RefValue{Any} │ builtin Base.setfield!(%1, :x, 3)::Int64 │ %3 = builtin Main.isdefined(%1, :x)::Bool └── goto #3 if not %3 2 ─ goto #4 3 ─ %6 = invoke Base.AssertionError("isdefined(ref, :x)"::String)::AssertionError │ builtin Base.throw(%6)::Union{} └── unreachable 4 ─ return %1 ) => Base.RefValue{Any} ``` The elimination of `setfield!` was due to a use still being recorded for `ref[]` in the def-use data while DCE eliminated this `getindex` call (by virtue of not using the second tuple element in the result). --------- Co-authored-by: Cédric Belmant Co-authored-by: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> --- Compiler/src/ssair/passes.jl | 4 ++++ Compiler/test/irpasses.jl | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/Compiler/src/ssair/passes.jl b/Compiler/src/ssair/passes.jl index ff333b9b0a129..c9b3d5515caa3 100644 --- a/Compiler/src/ssair/passes.jl +++ b/Compiler/src/ssair/passes.jl @@ -1511,6 +1511,10 @@ function sroa_pass!(ir::IRCode, inlining::Union{Nothing,InliningState}=nothing) used_ssas[x.id] -= 1 end ir = complete(compact) + # remove any use that has been optimized away by the DCE + for (intermediaries, defuse) in values(defuses) + filter!(x -> ir[SSAValue(x.idx)][:stmt] !== nothing, defuse.uses) + end sroa_mutables!(ir, defuses, used_ssas, lazydomtree, inlining) return ir else diff --git a/Compiler/test/irpasses.jl b/Compiler/test/irpasses.jl index 27b6d75f86c93..0d0b0e4daf83e 100644 --- a/Compiler/test/irpasses.jl +++ b/Compiler/test/irpasses.jl @@ -2030,3 +2030,15 @@ let code = Any[ ir = Compiler.domsort_ssa!(ir, domtree) Compiler.verify_ir(ir) end + +# https://github.com/JuliaLang/julia/issues/57141 +# don't eliminate `setfield!` when the field is to be used +let src = code_typed1(()) do + ref = Ref{Any}() + ref[] = 0 + @assert isdefined(ref, :x) + inner() = ref[] + 1 + (inner(), ref[]) + end + @test count(iscall((src, setfield!)), src.code) == 1 +end From 67e992de49f49359927b9b3fb808be69ca12cede Mon Sep 17 00:00:00 2001 From: Sam Schweigel <33556084+xal-0@users.noreply.github.com> Date: Mon, 3 Feb 2025 12:37:48 -0800 Subject: [PATCH 276/342] Runtime intrinsics: fix fpext and fptrunc behaviour on Float16/BFloat16 (#57160) This makes two changes `fpext` and `fptrunc` to match the behaviour specified in their error strings: -`fpext` works when converting from Float16 => Float16, -`fptrunc` is prevented from truncating Float16 => Float16 Both are re-written to make it explicit what conversions are possible, and how they are done. Closes #57130. --------- Co-authored-by: Jameson Nash --- Compiler/src/tfuncs.jl | 14 ++++ Compiler/test/effects.jl | 11 +++ src/intrinsics.cpp | 23 ++++--- src/runtime_intrinsics.c | 145 ++++++++++++++++++++++++--------------- test/intrinsics.jl | 130 ++++++++++++++++++++++++++++++++--- 5 files changed, 250 insertions(+), 73 deletions(-) diff --git a/Compiler/src/tfuncs.jl b/Compiler/src/tfuncs.jl index 74c8026ca0cf5..50b88bb0222ce 100644 --- a/Compiler/src/tfuncs.jl +++ b/Compiler/src/tfuncs.jl @@ -2454,6 +2454,9 @@ const _SPECIAL_BUILTINS = Any[ Core._apply_iterate, ] +# Types compatible with fpext/fptrunc +const CORE_FLOAT_TYPES = Union{Core.BFloat16, Float16, Float32, Float64} + function isdefined_effects(𝕃::AbstractLattice, argtypes::Vector{Any}) # consistent if the first arg is immutable na = length(argtypes) @@ -2867,6 +2870,17 @@ function intrinsic_exct(𝕃::AbstractLattice, f::IntrinsicFunction, argtypes::V if !(isprimitivetype(ty) && isprimitivetype(xty)) return ErrorException end + + # fpext and fptrunc have further restrictions on the allowed types. + if f === Intrinsics.fpext && + !(ty <: CORE_FLOAT_TYPES && xty <: CORE_FLOAT_TYPES && Core.sizeof(ty) > Core.sizeof(xty)) + return ErrorException + end + if f === Intrinsics.fptrunc && + !(ty <: CORE_FLOAT_TYPES && xty <: CORE_FLOAT_TYPES && Core.sizeof(ty) < Core.sizeof(xty)) + return ErrorException + end + return Union{} end diff --git a/Compiler/test/effects.jl b/Compiler/test/effects.jl index a7a1d18159137..b8a841b6b74b7 100644 --- a/Compiler/test/effects.jl +++ b/Compiler/test/effects.jl @@ -1384,3 +1384,14 @@ end |> Compiler.is_nothrow @test Base.infer_effects() do @ccall unsafecall()::Cvoid end == Compiler.EFFECTS_UNKNOWN + +# fpext +@test Compiler.intrinsic_nothrow(Core.Intrinsics.fpext, Any[Type{Float32}, Float16]) +@test Compiler.intrinsic_nothrow(Core.Intrinsics.fpext, Any[Type{Float64}, Float16]) +@test Compiler.intrinsic_nothrow(Core.Intrinsics.fpext, Any[Type{Float64}, Float32]) +@test !Compiler.intrinsic_nothrow(Core.Intrinsics.fpext, Any[Type{Float16}, Float16]) +@test !Compiler.intrinsic_nothrow(Core.Intrinsics.fpext, Any[Type{Float16}, Float32]) +@test !Compiler.intrinsic_nothrow(Core.Intrinsics.fpext, Any[Type{Float32}, Float32]) +@test !Compiler.intrinsic_nothrow(Core.Intrinsics.fpext, Any[Type{Float32}, Float64]) +@test !Compiler.intrinsic_nothrow(Core.Intrinsics.fpext, Any[Type{Int32}, Float16]) +@test !Compiler.intrinsic_nothrow(Core.Intrinsics.fpext, Any[Type{Float32}, Int16]) diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 7b5aa7c397129..e4dc2459e8db6 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -672,16 +672,23 @@ static jl_cgval_t generic_cast( uint32_t nb = jl_datatype_size(jlto); Type *to = bitstype_to_llvm((jl_value_t*)jlto, ctx.builder.getContext(), true); Type *vt = bitstype_to_llvm(v.typ, ctx.builder.getContext(), true); - if (toint) - to = INTT(to, DL); - else - to = FLOATT(to); - if (fromint) - vt = INTT(vt, DL); - else - vt = FLOATT(vt); + + // fptrunc fpext depend on the specific floating point format to work + // correctly, and so do not pun their argument types. + if (!(f == fpext || f == fptrunc)) { + if (toint) + to = INTT(to, DL); + else + to = FLOATT(to); + if (fromint) + vt = INTT(vt, DL); + else + vt = FLOATT(vt); + } + if (!to || !vt) return emit_runtime_call(ctx, f, argv, 2); + Value *from = emit_unbox(ctx, vt, v, v.typ); if (!CastInst::castIsValid(Op, from, to)) return emit_runtime_call(ctx, f, argv, 2); diff --git a/src/runtime_intrinsics.c b/src/runtime_intrinsics.c index 49d510cc48c34..f5b281f9e92ed 100644 --- a/src/runtime_intrinsics.c +++ b/src/runtime_intrinsics.c @@ -161,8 +161,11 @@ static inline uint16_t float_to_half(float param) JL_NOTSAFEPOINT uint32_t f; memcpy(&f, ¶m, sizeof(float)); if (isnan(param)) { - uint32_t t = 0x8000 ^ (0x8000 & ((uint16_t)(f >> 0x10))); - return t ^ ((uint16_t)(f >> 0xd)); + // Match the behaviour of arm64's fcvt or x86's vcvtps2ph by quieting + // all NaNs (avoids creating infinities), preserving the sign, and using + // the upper bits of the payload. + // sign exp quiet payload + return (f>>16 & 0x8000) | 0x7c00 | 0x0200 | (f>>13 & 0x03ff); } int i = ((f & ~0x007fffff) >> 23); uint8_t sh = shifttable[i]; @@ -761,33 +764,25 @@ static inline void name(unsigned osize, jl_value_t *ty, void *pa, void *pr) JL_N OP(ty, (c_type*)pr, a); \ } -#define un_fintrinsic_half(OP, name) \ -static inline void name(unsigned osize, jl_value_t *ty, void *pa, void *pr) JL_NOTSAFEPOINT \ -{ \ - uint16_t a = *(uint16_t*)pa; \ - float A = half_to_float(a); \ - if (osize == 16) { \ - float R; \ - OP(ty, &R, A); \ - *(uint16_t*)pr = float_to_half(R); \ - } else { \ - OP(ty, (uint16_t*)pr, A); \ - } \ -} +#define un_fintrinsic_half(OP, name) \ + static inline void name(unsigned osize, jl_value_t *ty, void *pa, void *pr) \ + JL_NOTSAFEPOINT \ + { \ + uint16_t a = *(uint16_t *)pa; \ + float R, A = half_to_float(a); \ + OP(ty, &R, A); \ + *(uint16_t *)pr = float_to_half(R); \ + } -#define un_fintrinsic_bfloat(OP, name) \ -static inline void name(unsigned osize, jl_value_t *ty, void *pa, void *pr) JL_NOTSAFEPOINT \ -{ \ - uint16_t a = *(uint16_t*)pa; \ - float A = bfloat_to_float(a); \ - if (osize == 16) { \ - float R; \ - OP(ty, &R, A); \ - *(uint16_t*)pr = float_to_bfloat(R); \ - } else { \ - OP(ty, (uint16_t*)pr, A); \ - } \ -} +#define un_fintrinsic_bfloat(OP, name) \ + static inline void name(unsigned osize, jl_value_t *ty, void *pa, void *pr) \ + JL_NOTSAFEPOINT \ + { \ + uint16_t a = *(uint16_t *)pa; \ + float R, A = bfloat_to_float(a); \ + OP(ty, &R, A); \ + *(uint16_t *)pr = float_to_bfloat(R); \ + } // float or integer inputs // OP::Function macro(inputa, inputb) @@ -1629,32 +1624,74 @@ cvt_iintrinsic(LLVMUItoFP, uitofp) cvt_iintrinsic(LLVMFPtoSI, fptosi) cvt_iintrinsic(LLVMFPtoUI, fptoui) -#define fptrunc(tr, pr, a) \ - if (!(osize < 8 * sizeof(a))) \ - jl_error("fptrunc: output bitsize must be < input bitsize"); \ - else if (osize == 16) { \ - if ((jl_datatype_t*)tr == jl_float16_type) \ - *(uint16_t*)pr = float_to_half(a); \ - else /*if ((jl_datatype_t*)tr == jl_bfloat16_type)*/ \ - *(uint16_t*)pr = float_to_bfloat(a); \ - } \ - else if (osize == 32) \ - *(float*)pr = a; \ - else if (osize == 64) \ - *(double*)pr = a; \ - else \ - jl_error("fptrunc: runtime floating point intrinsics are not implemented for bit sizes other than 16, 32 and 64"); -#define fpext(tr, pr, a) \ - if (!(osize >= 8 * sizeof(a))) \ - jl_error("fpext: output bitsize must be >= input bitsize"); \ - if (osize == 32) \ - *(float*)pr = a; \ - else if (osize == 64) \ - *(double*)pr = a; \ - else \ - jl_error("fpext: runtime floating point intrinsics are not implemented for bit sizes other than 32 and 64"); -un_fintrinsic_withtype(fptrunc,fptrunc) -un_fintrinsic_withtype(fpext,fpext) +#define fintrinsic_read_float16(p) half_to_float(*(uint16_t *)p) +#define fintrinsic_read_bfloat16(p) bfloat_to_float(*(uint16_t *)p) +#define fintrinsic_read_float32(p) *(float *)p +#define fintrinsic_read_float64(p) *(double *)p + +#define fintrinsic_write_float16(p, x) *(uint16_t *)p = float_to_half(x) +#define fintrinsic_write_bfloat16(p, x) *(uint16_t *)p = float_to_bfloat(x) +#define fintrinsic_write_float32(p, x) *(float *)p = x +#define fintrinsic_write_float64(p, x) *(double *)p = x + +/* + * aty: Type of value argument (input) + * pa: Pointer to value argument data + * ty: Type argument (output) + * pr: Pointer to result data + */ + +static inline void fptrunc(jl_datatype_t *aty, void *pa, jl_datatype_t *ty, void *pr) +{ + unsigned isize = jl_datatype_size(aty), osize = jl_datatype_size(ty); + if (!(osize < isize)) { + jl_error("fptrunc: output bitsize must be < input bitsize"); + return; + } + +#define fptrunc_convert(in, out) \ + else if (aty == jl_##in##_type && ty == jl_##out##_type) \ + fintrinsic_write_##out(pr, fintrinsic_read_##in(pa)) + + if (0) + ; + fptrunc_convert(float32, float16); + fptrunc_convert(float64, float16); + fptrunc_convert(float32, bfloat16); + fptrunc_convert(float64, bfloat16); + fptrunc_convert(float64, float32); + else + jl_error("fptrunc: runtime floating point intrinsics are not implemented for bit sizes other than 16, 32 and 64"); +#undef fptrunc_convert +} + +static inline void fpext(jl_datatype_t *aty, void *pa, jl_datatype_t *ty, void *pr) +{ + unsigned isize = jl_datatype_size(aty), osize = jl_datatype_size(ty); + if (!(osize > isize)) { + jl_error("fpext: output bitsize must be > input bitsize"); + return; + } + +#define fpext_convert(in, out) \ + else if (aty == jl_##in##_type && ty == jl_##out##_type) \ + fintrinsic_write_##out(pr, fintrinsic_read_##in(pa)) + + if (0) + ; + fpext_convert(float16, float32); + fpext_convert(float16, float64); + fpext_convert(bfloat16, float32); + fpext_convert(bfloat16, float64); + fpext_convert(float32, float64); + else + jl_error("fptrunc: runtime floating point intrinsics are not implemented for bit sizes other than 16, 32 and 64"); +#undef fpext_convert +} + +cvt_iintrinsic(fptrunc, fptrunc) +cvt_iintrinsic(fpext, fpext) + // checked arithmetic /** diff --git a/test/intrinsics.jl b/test/intrinsics.jl index bc1838ce2c68b..c3e9bb1680d48 100644 --- a/test/intrinsics.jl +++ b/test/intrinsics.jl @@ -18,9 +18,24 @@ truncbool(u) = reinterpret(UInt8, reinterpret(Bool, u)) @testset "runtime intrinsics" begin @test Core.Intrinsics.add_int(1, 1) == 2 @test Core.Intrinsics.sub_int(1, 1) == 0 - @test_throws ErrorException("fpext: output bitsize must be >= input bitsize") Core.Intrinsics.fpext(Int32, 0x0000_0000_0000_0000) + + @test_throws ErrorException("fpext: output bitsize must be > input bitsize") Core.Intrinsics.fpext(Float32, 1.0) + @test_throws ErrorException("fpext: output bitsize must be > input bitsize") Core.Intrinsics.fpext(Float32, 1.0) + @test_throws ErrorException("fptrunc: output bitsize must be < input bitsize") Core.Intrinsics.fptrunc(Int32, 0x0000_0000) @test_throws ErrorException("fptrunc: output bitsize must be < input bitsize") Core.Intrinsics.fptrunc(Int64, 0x0000_0000) + @test_throws ErrorException("fptrunc: output bitsize must be < input bitsize") Core.Intrinsics.fptrunc(Float16, Float16(1.0)) + @test_throws ErrorException("fptrunc: output bitsize must be < input bitsize") Core.Intrinsics.fptrunc(Core.BFloat16, Float16(1.0)) + @test_throws ErrorException("fptrunc: output bitsize must be < input bitsize") Core.Intrinsics.fptrunc(Float32, Float16(1.0)) + @test_throws ErrorException("fptrunc: output bitsize must be < input bitsize") Core.Intrinsics.fptrunc(Float32, 1.0f0) + @test_throws ErrorException("fptrunc: output bitsize must be < input bitsize") Core.Intrinsics.fptrunc(Float64, 1.0) + + let bf16_1 = Core.Intrinsics.bitcast(Core.BFloat16, 0x3f80) + @test_throws ErrorException("fptrunc: output bitsize must be < input bitsize") Core.Intrinsics.fptrunc(Core.BFloat16, bf16_1) + @test_throws ErrorException("fptrunc: output bitsize must be < input bitsize") Core.Intrinsics.fptrunc(Float16, bf16_1) + @test_throws ErrorException("fptrunc: output bitsize must be < input bitsize") Core.Intrinsics.fptrunc(Float32, bf16_1) + end + @test_throws ErrorException("ZExt: output bitsize must be > input bitsize") Core.Intrinsics.zext_int(Int8, 0x00) @test_throws ErrorException("SExt: output bitsize must be > input bitsize") Core.Intrinsics.sext_int(Int8, 0x00) @test_throws ErrorException("ZExt: output bitsize must be > input bitsize") Core.Intrinsics.zext_int(Int8, 0x0000) @@ -87,16 +102,57 @@ function compiled_conv(::Type{T}, x) where T t = Core.Intrinsics.trunc_int(T, x) z = Core.Intrinsics.zext_int(typeof(x), t) s = Core.Intrinsics.sext_int(typeof(x), t) - fpt = Core.Intrinsics.fptrunc(T, x) - fpe = Core.Intrinsics.fpext(typeof(x), fpt) - return (t, z, s, fpt, fpe) + return (t, z, s) end @test compiled_conv(UInt32, Int64(0x8000_0000)) == - (0x80000000, Int64(0x80000000), -Int64(0x80000000), 0x00000000, 0) + (0x80000000, Int64(0x80000000), -Int64(0x80000000)) @test compiled_conv(UInt32, UInt64(0xC000_BA98_8765_4321)) == - (0x87654321, 0x0000000087654321, 0xffffffff87654321, 0xc005d4c4, 0xc000ba9880000000) + (0x87654321, 0x0000000087654321, 0xffffffff87654321) @test_throws ErrorException compiled_conv(Bool, im) +function compiled_fptrunc(::Type{T}, x) where T + return Core.Intrinsics.fptrunc(T, x) + +end +# 1.234 +# 0 01111111 00111011111001110110110 +# float32 0 01111111 00111011111001110110110 +# float16 0 01111 0011101111 (truncated/rtz) +# float16 0 01111 0011110000 (round-to-nearest) +# bfloat16 0 01111111 0011110 (round-to-nearest) +@test compiled_fptrunc(Float16, 1.234) === reinterpret(Float16, 0b0_01111_0011110000) +# On arm64, LLVM gives an assertion failure when compiling this: +# LLVM ERROR: Cannot select: 0x106c8e570: bf16 = fp_round 0x106c8df50, TargetConstant:i64<0>, intrinsics.jl:114 +# 0x106c8df50: f64,ch = CopyFromReg 0x104545960, Register:f64 %1 +# 0x106c8dee0: f64 = Register %1 +# 0x106c8e3b0: i64 = TargetConstant<0> +# In function: julia_compiled_fptrunc_3480 +# @test compiled_fptrunc(Core.BFloat16, 1.234) === reinterpret(Core.BFloat16, 0b0_01111111_0011110) +@test compiled_fptrunc(Float32, 1.234) === 1.234f0 +@test_throws ErrorException compiled_fptrunc(Float64, 1.234f0) +@test_throws ErrorException compiled_fptrunc(Int32, 1.234) +@test_throws ErrorException compiled_fptrunc(Float32, 1234) + +function compiled_fpext(::Type{T}, x) where T + return Core.Intrinsics.fpext(T, x) +end +# 1.234 +# float16 0 01111 0011110000 +# 0 01111111 00111100000000000000000 = 1.234375 + +# 1.234 +# float32 0 01111111 00111011111001110110110 +# float64 0 01111111111 0011101111100111011011000000000000000000000000000000 +# 3be76c +@test compiled_fpext(Float32, reinterpret(Float16, 0b0_01111_0011110000)) === 1.234375f0 +@test compiled_fpext(Float64, reinterpret(Float16, 0b0_01111_0011110000)) === 1.234375 +@test compiled_fpext(Float64, 1.234f0) === 0x1.3be76cp0 +@test_throws ErrorException compiled_fpext(Float16, Float16(1.0)) +@test_throws ErrorException compiled_fpext(Float16, 1.0f0) +@test_throws ErrorException compiled_fpext(Float32, 1.0f0) +@test_throws ErrorException compiled_fpext(Float32, 1.0) +@test_throws ErrorException compiled_fpext(Float64, 1.0) + let f = Core.Intrinsics.ashr_int @test f(Int8(-17), 1) == -9 @test f(Int32(-1), 33) == -1 @@ -143,7 +199,19 @@ macro test_intrinsic(intr, args...) $intr($(inputs...)) end @test f() === Base.invokelatest($intr, $(inputs...)) - @test f() == $output + @test f() === $output + end +end + +macro test_intrinsic_pred(intr, args...) + p = args[end] + inputs = args[1:end-1] + quote + function f() + $intr($(inputs...)) + end + @test $(p)(Base.invokelatest($intr, $(inputs...))) + @test $(p)(f()) end end @@ -151,7 +219,6 @@ end # unary @test_intrinsic Core.Intrinsics.abs_float Float64(-3.3) Float64(3.3) @test_intrinsic Core.Intrinsics.neg_float Float64(3.3) Float64(-3.3) - @test_intrinsic Core.Intrinsics.fpext Float64 Float64(3.3) Float64(3.3) # binary @test_intrinsic Core.Intrinsics.add_float Float64(3.3) Float64(2) Float64(5.3) @@ -184,7 +251,6 @@ end # unary @test_intrinsic Core.Intrinsics.abs_float Float32(-3.3) Float32(3.3) @test_intrinsic Core.Intrinsics.neg_float Float32(3.3) Float32(-3.3) - @test_intrinsic Core.Intrinsics.fpext Float32 Float32(3.3) Float32(3.3) @test_intrinsic Core.Intrinsics.fpext Float64 Float32(3.3) 3.299999952316284 @test_intrinsic Core.Intrinsics.fptrunc Float32 Float64(3.3) Float32(3.3) @@ -215,18 +281,60 @@ end @test_intrinsic Core.Intrinsics.fptoui UInt Float32(3.3) UInt(3) end +function f16(sign, exp, sig) + x = (sign&1)<<15 | (exp&((1<<5)-1))<<10 | sig&((1<<10)-1) + return reinterpret(Float16, UInt16(x)) +end +function f32(sign, exp, sig) + x = (sign&1)<<31 | (exp&((1<<8)-1))<<23 | sig&((1<<23)-1) + return reinterpret(Float32, UInt32(x)) +end +function f64(sign, exp, sig) + x = Int64(sign&1)<<31 | Int64(exp&((1<<11)-1))<<52 | sig&((Int64(1)<<52)-1) + return reinterpret(Float64, UInt64(x)) +end + @testset "Float16 intrinsics" begin # unary @test_intrinsic Core.Intrinsics.abs_float Float16(-3.3) Float16(3.3) @test_intrinsic Core.Intrinsics.neg_float Float16(3.3) Float16(-3.3) # See - #broken @test_intrinsic Core.Intrinsics.fpext Float16 Float16(3.3) Float16(3.3) - @test_broken Core.Intrinsics.fpext(Float16, Float16(3.3)) === Float16(3.3) @test_intrinsic Core.Intrinsics.fpext Float32 Float16(3.3) 3.3007812f0 @test_intrinsic Core.Intrinsics.fpext Float64 Float16(3.3) 3.30078125 @test_intrinsic Core.Intrinsics.fptrunc Float16 Float32(3.3) Float16(3.3) @test_intrinsic Core.Intrinsics.fptrunc Float16 Float64(3.3) Float16(3.3) + # float_to_half/bfloat_to_float special cases + @test_intrinsic Core.Intrinsics.fptrunc Float16 Inf32 Inf16 + @test_intrinsic Core.Intrinsics.fptrunc Float16 -Inf32 -Inf16 + @test_intrinsic Core.Intrinsics.fptrunc Float16 Inf64 Inf16 + @test_intrinsic Core.Intrinsics.fptrunc Float16 -Inf64 -Inf16 + + # LLVM gives us three things that may happen to NaNs in an fptrunc on + # "normal" platforms (x86, ARM): + # - Return a canonical NaN (quiet, all-zero payload) + # - Copy high bits of payload to output, and: + # - Set the quiet bit + # - Leave the quiet bit as-is. This option isn't possible if doing so + # would result in an infinity (all-zero payload and quiet bit clear) + # + # We'll just test a NaN is returned at all. + # + # Refer to #49353 and https://llvm.org/docs/LangRef.html#floatnan + + # Canonical NaN + @test_intrinsic_pred Core.Intrinsics.fptrunc Float16 NaN32 isnan + @test_intrinsic_pred Core.Intrinsics.fptrunc Float16 NaN isnan + # Quiet NaN + @test_intrinsic_pred Core.Intrinsics.fptrunc Float16 f32(0, 0xff, 1<<22 | 1<<13) isnan + @test_intrinsic_pred Core.Intrinsics.fptrunc Float16 f64(0, 0x7ff, Int64(1)<<51 | Int64(1)<<42) isnan + # Signalling NaN that can be propagated to Float16 + @test_intrinsic_pred Core.Intrinsics.fptrunc Float16 f32(0, 0xff, 1<<13) isnan + @test_intrinsic_pred Core.Intrinsics.fptrunc Float16 f64(0, 0x7ff, Int64(1)<<42) isnan + # Signalling NaN that cannot be propagated to Float16 + @test_intrinsic_pred Core.Intrinsics.fptrunc Float16 f32(0, 0xff, 1) isnan + @test_intrinsic_pred Core.Intrinsics.fptrunc Float16 f64(0, 0x7ff, 1) isnan + # binary @test_intrinsic Core.Intrinsics.add_float Float16(3.3) Float16(2) Float16(5.3) @test_intrinsic Core.Intrinsics.sub_float Float16(3.3) Float16(2) Float16(1.301) From e592169fb58644f0a80a9d799550b6dd61196478 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Mon, 3 Feb 2025 15:47:04 -0500 Subject: [PATCH 277/342] REPL: Query `libuv` for virtual terminal support (#57132) The query-and-restore logic here was pretty flawed: - it had no way to guarantee when the "default" mode is available to query, so it could easily save a "bad" mode - it did not ensure / check whether the "default" mode is compatible with the output generated by REPL (esp. ASCII escape codes / color) - it persisted the "default" mode from pre-compilation to runtime, causing https://github.com/JuliaLang/julia/issues/56073 With this PR, `ENABLE_VIRTUAL_TERMINAL_PROCESSING` is the only flag that we're agnostic about. It was added relatively recently (Windows 10 version 1511), and `libuv` has support to emulate its behavior when it's not available natively. We query `libuv` directly to ask whether it is expecting to emulate, rather than measuring the console mode at some random point in time. Otherwise this PR resets ENABLE_PROCESSED_OUTPUT and ENABLE_WRAP_AT_EOL_OUTPUT always, since we output ASCII control sequences unconditionally. Resolves https://github.com/JuliaLang/julia/issues/56073. --- stdlib/REPL/src/LineEdit.jl | 60 +++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/stdlib/REPL/src/LineEdit.jl b/stdlib/REPL/src/LineEdit.jl index 0f9979d768af3..1075aa648b926 100644 --- a/stdlib/REPL/src/LineEdit.jl +++ b/stdlib/REPL/src/LineEdit.jl @@ -595,10 +595,19 @@ function refresh_multi_line(termbuf::TerminalBuffer, terminal::UnixTerminal, buf line_pos = buf_pos regstart, regstop = region(buf) written = 0 + @static if Sys.iswindows() + writer = Terminals.pipe_writer(terminal) + if writer isa Base.TTY && !Base.ispty(writer)::Bool + _reset_console_mode(writer.handle) + end + end # Write out the prompt string lindent = write_prompt(termbuf, prompt, hascolor(terminal))::Int # Count the '\n' at the end of the line if the terminal emulator does (specific to DOS cmd prompt) - miscountnl = @static Sys.iswindows() ? (isa(Terminals.pipe_reader(terminal), Base.TTY) && !(Base.ispty(Terminals.pipe_reader(terminal)))::Bool) : false + miscountnl = @static if Sys.iswindows() + reader = Terminals.pipe_reader(terminal) + reader isa Base.TTY && !Base.ispty(reader)::Bool + else false end # Now go through the buffer line by line seek(buf, 0) @@ -1676,34 +1685,39 @@ end # not leave the console mode in a corrupt state. # FIXME: remove when pseudo-tty are implemented for child processes if Sys.iswindows() -function _console_mode() - hOutput = ccall(:GetStdHandle, stdcall, Ptr{Cvoid}, (UInt32,), -11 % UInt32) # STD_OUTPUT_HANDLE - dwMode = Ref{UInt32}() - ccall(:GetConsoleMode, stdcall, Int32, (Ref{Cvoid}, Ref{UInt32}), hOutput, dwMode) - return dwMode[] -end -const default_console_mode_ref = Ref{UInt32}() -const default_console_mode_assigned = Ref(false) -function get_default_console_mode() - if default_console_mode_assigned[] == false - default_console_mode_assigned[] = true - default_console_mode_ref[] = _console_mode() - end - return default_console_mode_ref[] -end -function _reset_console_mode() - mode = _console_mode() - if mode !== get_default_console_mode() - hOutput = ccall(:GetStdHandle, stdcall, Ptr{Cvoid}, (UInt32,), -11 % UInt32) # STD_OUTPUT_HANDLE - ccall(:SetConsoleMode, stdcall, Int32, (Ptr{Cvoid}, UInt32), hOutput, default_console_mode_ref[]) + +#= Get/SetConsoleMode flags =# +const ENABLE_PROCESSED_OUTPUT = UInt32(0x0001) +const ENABLE_WRAP_AT_EOL_OUTPUT = UInt32(0x0002) +const ENABLE_VIRTUAL_TERMINAL_PROCESSING = UInt32(0x0004) +const DISABLE_NEWLINE_AUTO_RETURN = UInt32(0x0008) +const ENABLE_LVB_GRID_WORLDWIDE = UInt32(0x0010) + +#= libuv flags =# +const UV_TTY_SUPPORTED = 0 +const UV_TTY_UNSUPPORTED = 1 + +function _reset_console_mode(handle::Ptr{Cvoid}) + # Query libuv to see whether it expects the console to support virtual terminal sequences + vterm_state = Ref{Cint}() + ccall(:uv_tty_get_vterm_state, Cint, (Ref{Cint},), vterm_state) + + mode::UInt32 = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT + if vterm_state[] == UV_TTY_SUPPORTED + mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING end - nothing + + # Expected to fail (benignly) with ERROR_INVALID_HANDLE if the provided handle does not + # allow setting the console mode + ccall(:SetConsoleMode, stdcall, Int32, (Ptr{Cvoid}, UInt32), handle, mode) + + return nothing end + end # returns the width of the written prompt function write_prompt(terminal::Union{IO, AbstractTerminal}, s::Union{AbstractString,Function}, color::Bool) - @static Sys.iswindows() && _reset_console_mode() promptstr = prompt_string(s)::String write(terminal, promptstr) return textwidth(promptstr) From a358f58eee5b7c27227f6acd895f2a701171486f Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Mon, 3 Feb 2025 18:51:35 -0500 Subject: [PATCH 278/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?Pkg=20stdlib=20from=206091533bc=20to=207aeec766c=20(#57244)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Pkg-6091533bc93c722591d3e7ee53d26012cb4d5aa4.tar.gz/md5 | 1 - .../Pkg-6091533bc93c722591d3e7ee53d26012cb4d5aa4.tar.gz/sha512 | 1 - .../Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/md5 | 1 + .../Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/sha512 | 1 + stdlib/Pkg.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/Pkg-6091533bc93c722591d3e7ee53d26012cb4d5aa4.tar.gz/md5 delete mode 100644 deps/checksums/Pkg-6091533bc93c722591d3e7ee53d26012cb4d5aa4.tar.gz/sha512 create mode 100644 deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/md5 create mode 100644 deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/sha512 diff --git a/deps/checksums/Pkg-6091533bc93c722591d3e7ee53d26012cb4d5aa4.tar.gz/md5 b/deps/checksums/Pkg-6091533bc93c722591d3e7ee53d26012cb4d5aa4.tar.gz/md5 deleted file mode 100644 index b1012dffefbf6..0000000000000 --- a/deps/checksums/Pkg-6091533bc93c722591d3e7ee53d26012cb4d5aa4.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -26699bf323c07c7491d3c106219de6da diff --git a/deps/checksums/Pkg-6091533bc93c722591d3e7ee53d26012cb4d5aa4.tar.gz/sha512 b/deps/checksums/Pkg-6091533bc93c722591d3e7ee53d26012cb4d5aa4.tar.gz/sha512 deleted file mode 100644 index 2ed6fcd7c5f46..0000000000000 --- a/deps/checksums/Pkg-6091533bc93c722591d3e7ee53d26012cb4d5aa4.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -1466dca4e49800b94d65ce59c3e2c75308545282a00720c964b34e0cde5e06aced80361c236a9ada81d35ebcc2692f8e6e84db507342d8055ba501fc1291c0a2 diff --git a/deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/md5 b/deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/md5 new file mode 100644 index 0000000000000..2574fca7dbe2b --- /dev/null +++ b/deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/md5 @@ -0,0 +1 @@ +d3e705f029ba3d81bd0725c2cb0b2e46 diff --git a/deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/sha512 b/deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/sha512 new file mode 100644 index 0000000000000..54276d232add9 --- /dev/null +++ b/deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/sha512 @@ -0,0 +1 @@ +ef8c37b056fb6dfc3c8b1b542d65d6ffdfdc1f41a08da5307ad1c3e7ce9fe0030ac4132c9d30af0e850964842d9b330e2f950bb49dd6dd0fd5b30592f8173477 diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index c5e38c1fe6487..63845886099aa 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = master -PKG_SHA1 = 6091533bc93c722591d3e7ee53d26012cb4d5aa4 +PKG_SHA1 = 7aeec766cf637e2bc2af161eba8abd3a4b68d025 PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 From a3e4f0daeda492951163073dd963a4e3d3871a62 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Mon, 3 Feb 2025 19:33:56 -0500 Subject: [PATCH 279/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?LinearAlgebra=20stdlib=20from=20c9ad828=20to=20e7da19f=20(#5724?= =?UTF-8?q?7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: ViralBShah <744411+ViralBShah@users.noreply.github.com> --- .../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-c9ad82820ab59c57e0f982aa9c7c8611380e28e2.tar.gz/md5 delete mode 100644 deps/checksums/LinearAlgebra-c9ad82820ab59c57e0f982aa9c7c8611380e28e2.tar.gz/sha512 create mode 100644 deps/checksums/LinearAlgebra-e7da19f2764ba36bd0a9eb8ec67dddce19d87114.tar.gz/md5 create mode 100644 deps/checksums/LinearAlgebra-e7da19f2764ba36bd0a9eb8ec67dddce19d87114.tar.gz/sha512 diff --git a/deps/checksums/LinearAlgebra-c9ad82820ab59c57e0f982aa9c7c8611380e28e2.tar.gz/md5 b/deps/checksums/LinearAlgebra-c9ad82820ab59c57e0f982aa9c7c8611380e28e2.tar.gz/md5 deleted file mode 100644 index 9f3191a5d97c5..0000000000000 --- a/deps/checksums/LinearAlgebra-c9ad82820ab59c57e0f982aa9c7c8611380e28e2.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -02594da939439696ad60bf415d357c2b diff --git a/deps/checksums/LinearAlgebra-c9ad82820ab59c57e0f982aa9c7c8611380e28e2.tar.gz/sha512 b/deps/checksums/LinearAlgebra-c9ad82820ab59c57e0f982aa9c7c8611380e28e2.tar.gz/sha512 deleted file mode 100644 index 61f11a324d196..0000000000000 --- a/deps/checksums/LinearAlgebra-c9ad82820ab59c57e0f982aa9c7c8611380e28e2.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -13a999588218736e54d11b7537e778215fdc18b515fd595c30d9d7ac21c5f1bc030d000ada14b56b49b7e6ab179bcdfcad2d46819eb3c0e3d8add1a4bbd83232 diff --git a/deps/checksums/LinearAlgebra-e7da19f2764ba36bd0a9eb8ec67dddce19d87114.tar.gz/md5 b/deps/checksums/LinearAlgebra-e7da19f2764ba36bd0a9eb8ec67dddce19d87114.tar.gz/md5 new file mode 100644 index 0000000000000..b49f2365717a1 --- /dev/null +++ b/deps/checksums/LinearAlgebra-e7da19f2764ba36bd0a9eb8ec67dddce19d87114.tar.gz/md5 @@ -0,0 +1 @@ +f9258e97e2f478f66a4e63ed008a6953 diff --git a/deps/checksums/LinearAlgebra-e7da19f2764ba36bd0a9eb8ec67dddce19d87114.tar.gz/sha512 b/deps/checksums/LinearAlgebra-e7da19f2764ba36bd0a9eb8ec67dddce19d87114.tar.gz/sha512 new file mode 100644 index 0000000000000..4873f3162c8be --- /dev/null +++ b/deps/checksums/LinearAlgebra-e7da19f2764ba36bd0a9eb8ec67dddce19d87114.tar.gz/sha512 @@ -0,0 +1 @@ +3ed43673c69b8ee549bf5b63d9a6d814f9638269fc0b12d7f7c735581757f1627a3dcd1f242f8fde2cbde1509b43d261191a9a0bb019e22759cb019936ae949e diff --git a/stdlib/LinearAlgebra.version b/stdlib/LinearAlgebra.version index 6d882da545f2a..96c00ca746651 100644 --- a/stdlib/LinearAlgebra.version +++ b/stdlib/LinearAlgebra.version @@ -1,4 +1,4 @@ LINEARALGEBRA_BRANCH = master -LINEARALGEBRA_SHA1 = c9ad82820ab59c57e0f982aa9c7c8611380e28e2 +LINEARALGEBRA_SHA1 = e7da19f2764ba36bd0a9eb8ec67dddce19d87114 LINEARALGEBRA_GIT_URL := https://github.com/JuliaLang/LinearAlgebra.jl.git LINEARALGEBRA_TAR_URL = https://api.github.com/repos/JuliaLang/LinearAlgebra.jl/tarball/$1 From 0c1e800dbdcf76b24cf3ab2bc9861a587e7c1fb5 Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Tue, 4 Feb 2025 05:20:41 -0500 Subject: [PATCH 280/342] Add timing when `PRECOMPILE_TRACE_COMPILE` is set (#57251) --- base/loading.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/base/loading.jl b/base/loading.jl index 826e4116405ef..47741da26a1b2 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -3078,7 +3078,10 @@ function create_expr_cache(pkg::PkgId, input::String, output::String, output_o:: cpu_target = nothing end push!(opts, "--output-ji", output) - isassigned(PRECOMPILE_TRACE_COMPILE) && push!(opts, "--trace-compile=$(PRECOMPILE_TRACE_COMPILE[])") + if isassigned(PRECOMPILE_TRACE_COMPILE) + push!(opts, "--trace-compile=$(PRECOMPILE_TRACE_COMPILE[])") + push!(opts, "--trace-compile-timing") + end io = open(pipeline(addenv(`$(julia_cmd(;cpu_target)::Cmd) $(flags) From 79ce1685e94a19edadd21544bce973cfd06cb168 Mon Sep 17 00:00:00 2001 From: Dilum Aluthge Date: Tue, 4 Feb 2025 05:35:34 -0500 Subject: [PATCH 281/342] Set `VERSION` to `1.13.0-DEV` (#56970) After this PR has been merged, the `release-1.12` branch will be created off of the commit immediately prior to this commit. --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index f6c25a3020b69..181a714af3a79 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.12.0-DEV +1.13.0-DEV From a52de835af96c2f5f3939fa3342d985e613f5a30 Mon Sep 17 00:00:00 2001 From: Nicolau Leal Werneck Date: Tue, 4 Feb 2025 15:49:59 +0100 Subject: [PATCH 282/342] Add reference to time_ns in time (#57142) I couldn't find `time_ns` when I was looking for it, nice to make clear the "monotonic" clock is also available in Base. --- base/libc.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/base/libc.jl b/base/libc.jl index 7364f6e6677fe..fc0cc774cab7a 100644 --- a/base/libc.jl +++ b/base/libc.jl @@ -288,6 +288,8 @@ time(tm::TmStruct) = Float64(ccall(:mktime, Int, (Ref{TmStruct},), tm)) time() -> Float64 Get the system time in seconds since the epoch, with fairly high (typically, microsecond) resolution. + +See also [`time_ns`](@ref). """ time() = ccall(:jl_clock_now, Float64, ()) From daf865e8605344764c1f26b5fc4412f100888791 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Tue, 4 Feb 2025 11:42:09 -0500 Subject: [PATCH 283/342] Handle `waitpid` race condition when `SIGCHLD` is set to `SIG_IGN` (#57241) The `fork()` we do here relies on `SIGCHLD` to make sure that we don't race against the child. This is easy to see in an embedding application that dynamically links `libjulia`: ```c int main(int argc, char *argv[]) { signal(SIGCHLD, SIG_IGN); void *handle = dlopen("path/to/libjulia.so", RTLD_LAZY); return 0; } ``` Without this change, this fails with an error message: ``` Error during libstdcxxprobe in parent process: waitpid: No child processes ``` Resolves #57240 --- cli/loader_lib.c | 12 +++++++++--- test/embedding/Makefile | 14 +++++++++++--- test/embedding/libdl_embedding.c | 12 ++++++++++++ 3 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 test/embedding/libdl_embedding.c diff --git a/cli/loader_lib.c b/cli/loader_lib.c index af2a36cfce8ab..4d75cfd9563cb 100644 --- a/cli/loader_lib.c +++ b/cli/loader_lib.c @@ -349,10 +349,16 @@ static char *libstdcxxprobe(void) pid_t npid = waitpid(pid, &wstatus, 0); if (npid == -1) { if (errno == EINTR) continue; - if (errno != EINTR) { - perror("Error during libstdcxxprobe in parent process:\nwaitpid"); - exit(1); + if (errno == ECHILD) { + // SIGCHLD is set to SIG_IGN or has flag SA_NOCLDWAIT, so the child + // did not become a zombie and wait for `waitpid` - it just exited. + // + // Assume that it exited successfully and use whatever libpath we + // got out of the pipe, if any. + break; } + perror("Error during libstdcxxprobe in parent process:\nwaitpid"); + exit(1); } else if (!WIFEXITED(wstatus)) { const char *err_str = "Error during libstdcxxprobe in parent process:\n" diff --git a/test/embedding/Makefile b/test/embedding/Makefile index df31c3735c9de..4be4974e864cd 100644 --- a/test/embedding/Makefile +++ b/test/embedding/Makefile @@ -21,6 +21,7 @@ EXE := $(suffix $(abspath $(JULIA))) # get compiler and linker flags. (see: `contrib/julia-config.jl`) JULIA_CONFIG := $(JULIA) -e 'include(joinpath(Sys.BINDIR, Base.DATAROOTDIR, "julia", "julia-config.jl"))' -- +JULIA_LIBDIR := $(shell $(JULIA) -e 'println(joinpath(Sys.BINDIR, "..", "lib"))' --) CPPFLAGS_ADD := CFLAGS_ADD = $(shell $(JULIA_CONFIG) --cflags) LDFLAGS_ADD = -lm $(shell $(JULIA_CONFIG) --ldflags --ldlibs) @@ -29,8 +30,8 @@ DEBUGFLAGS += -g #============================================================================= -release: $(BIN)/embedding$(EXE) -debug: $(BIN)/embedding-debug$(EXE) +release: $(BIN)/embedding$(EXE) $(BIN)/libdl-embedding$(EXE) +debug: $(BIN)/embedding-debug$(EXE) $(BIN)/libdl-embedding$(EXE) $(BIN)/embedding$(EXE): $(SRCDIR)/embedding.c $(CC) $^ -o $@ $(CPPFLAGS_ADD) $(CPPFLAGS) $(CFLAGS_ADD) $(CFLAGS) $(LDFLAGS_ADD) $(LDFLAGS) @@ -38,6 +39,12 @@ $(BIN)/embedding$(EXE): $(SRCDIR)/embedding.c $(BIN)/embedding-debug$(EXE): $(SRCDIR)/embedding.c $(CC) $^ -o $@ $(CPPFLAGS_ADD) $(CPPFLAGS) $(CFLAGS_ADD) $(CFLAGS) $(LDFLAGS_ADD) $(LDFLAGS) $(DEBUGFLAGS) +$(BIN)/libdl-embedding$(EXE): $(SRCDIR)/libdl_embedding.c + $(CC) $^ -o $@ $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -ldl -DLIBJULIA_PATH=\"$(JULIA_LIBDIR)/libjulia.so\" + +$(BIN)/libdl-embedding-debug$(EXE): $(SRCDIR)/libdl_embedding.c + $(CC) $^ -o $@ $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(DEBUGFLAGS) -ldl -DLIBJULIA_PATH=\"$(JULIA_LIBDIR)/libjulia.so\" + ifneq ($(abspath $(BIN)),$(abspath $(SRCDIR))) # for demonstration purposes, our demo code is also installed # in $BIN, although this would likely not be typical @@ -45,7 +52,8 @@ $(BIN)/LocalModule.jl: $(SRCDIR)/LocalModule.jl cp $< $@ endif -check: $(BIN)/embedding$(EXE) $(BIN)/LocalModule.jl +check: $(BIN)/embedding$(EXE) $(BIN)/libdl-embedding$(EXE) $(BIN)/LocalModule.jl + $(BIN)/libdl-embedding$(EXE) # run w/o error $(JULIA) --depwarn=error $(SRCDIR)/embedding-test.jl $< @echo SUCCESS diff --git a/test/embedding/libdl_embedding.c b/test/embedding/libdl_embedding.c new file mode 100644 index 0000000000000..6cd040d5f9abf --- /dev/null +++ b/test/embedding/libdl_embedding.c @@ -0,0 +1,12 @@ +#include +#include +#include + +int main(int argc, char *argv[]) +{ + // This test doesn't do much yet, except check + // https://github.com/JuliaLang/julia/issues/57240 + signal(SIGCHLD, SIG_IGN); + void *handle = dlopen(LIBJULIA_PATH, RTLD_LAZY); + return 0; +} From 2f0a5239f00697914128e7bb7b58f7dadec0d519 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 4 Feb 2025 13:39:13 -0500 Subject: [PATCH 284/342] restore non-freebsd-unix fix for profiling (#57249) Restores #57035, undo #57089 for non-FreeBSD. While I suggested doing this change for all platforms, I forgot that means non-FreeBSD platforms become vulnerable again to the very deadlock problems that #57035 was required to prevent. That fix seems to not be viable on FreeBSD due to known libc implementation problems on that platform. However, upon closer inspection of the questionable design implementation decisions they seem to have made here, the platform is likely not currently vulnerable to this libunwind bug in the first place: https://github.com/lattera/freebsd/blob/master/libexec/rtld-elf/rtld_lock.c#L120 --- src/signals-unix.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/signals-unix.c b/src/signals-unix.c index c730f27f16def..1f4ad647a87af 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -310,14 +310,34 @@ int exc_reg_is_write_fault(uintptr_t esr) { #include #include +#ifndef _OS_FREEBSD_ +typedef struct { + void (*f)(void*) JL_NOTSAFEPOINT; + void *ctx; +} callback_t; +static int with_dl_iterate_phdr_lock(struct dl_phdr_info *info, size_t size, void *data) +{ + jl_lock_profile(); + callback_t *callback = (callback_t*)data; + callback->f(callback->ctx); + jl_unlock_profile(); + return 1; // only call this once +} +#endif + void jl_with_stackwalk_lock(void (*f)(void*), void *ctx) { - sigset_t sset, oset; - sigemptyset(&sset); - sigaddset(&sset, SIGUSR2); - pthread_sigmask(SIG_BLOCK, &sset, &oset); +#ifndef _OS_FREEBSD_ + callback_t callback = {f, ctx}; + dl_iterate_phdr(with_dl_iterate_phdr_lock, &callback); +#else + // FreeBSD makes the questionable decisions to use a terrible implementation of a spin + // lock and to block all signals while a lock is held. However, that also means it is + // not currently vulnerable to this libunwind bug that other platforms can encounter. + jl_lock_profile(); f(ctx); - pthread_sigmask(SIG_SETMASK, &oset, NULL); + jl_unlock_profile(); +#endif } #if defined(_OS_LINUX_) && (defined(_CPU_X86_64_) || defined(_CPU_X86_)) From ffc96bc7e14a80b22f3a7bbfd4fc60adaa120f1a Mon Sep 17 00:00:00 2001 From: Jacob Quinn Date: Tue, 4 Feb 2025 13:55:11 -0700 Subject: [PATCH 285/342] Ensure read/readavailable for BufferStream are threadsafe (#57211) It looks like these methods were just missed while overloading for BufferStream. There's also `readbytes!` where the current implementation will fallback to the `LibuvStream` implementation that is currently not threadsafe. What's the best approach there since the implementation is quite a bit more involved? Just duplicate the code but for BufferStream? Should we take the BufferStream lock and invoke the LibuvStream method? Open to ideas there. Also open to suggestions for having tests here? Not easy to simulate the data race of writing and calling readavailable. The fix here will unblock https://github.com/JuliaWeb/HTTP.jl/pull/1213 (I'll probably do some compat shim there until this is fully released). Thanks to @oscardssmith for rubber ducking this issue with me. Probably most helpfully reviewed by @vtjnash. --------- Co-authored-by: Jameson Nash --- base/stream.jl | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/base/stream.jl b/base/stream.jl index e81f65685df72..33d884018d5ad 100644 --- a/base/stream.jl +++ b/base/stream.jl @@ -1559,6 +1559,64 @@ function wait_readnb(s::BufferStream, nb::Int) end end +function readavailable(this::BufferStream) + bytes = lock(this.cond) do + wait_readnb(this, 1) + buf = this.buffer + @assert buf.seekable == false + take!(buf) + end + return bytes +end + +function read(stream::BufferStream) + bytes = lock(stream.cond) do + wait_close(stream) + take!(stream.buffer) + end + return bytes +end + +function readbytes!(s::BufferStream, a::Vector{UInt8}, nb::Int) + sbuf = s.buffer + @assert sbuf.seekable == false + @assert sbuf.maxsize >= nb + + function wait_locked(s, buf, nb) + while bytesavailable(buf) < nb + s.readerror === nothing || throw(s.readerror) + isopen(s) || break + s.status != StatusEOF || break + wait_readnb(s, nb) + end + end + + bytes = lock(s.cond) do + if nb <= SZ_UNBUFFERED_IO # Under this limit we are OK with copying the array from the stream's buffer + wait_locked(s, sbuf, nb) + end + if bytesavailable(sbuf) >= nb + nread = readbytes!(sbuf, a, nb) + else + initsize = length(a) + newbuf = PipeBuffer(a, maxsize=nb) + newbuf.size = newbuf.offset # reset the write pointer to the beginning + nread = try + s.buffer = newbuf + write(newbuf, sbuf) + wait_locked(s, newbuf, nb) + bytesavailable(newbuf) + finally + s.buffer = sbuf + end + _take!(a, _unsafe_take!(newbuf)) + length(a) >= initsize || resize!(a, initsize) + end + return nread + end + return bytes +end + show(io::IO, s::BufferStream) = print(io, "BufferStream(bytes waiting=", bytesavailable(s.buffer), ", isopen=", isopen(s), ")") function readuntil(s::BufferStream, c::UInt8; keep::Bool=false) From 30cb68ef75c85061fb75c16653c2584089bcc9b6 Mon Sep 17 00:00:00 2001 From: Em Chu <61633163+mlechu@users.noreply.github.com> Date: Tue, 4 Feb 2025 21:39:05 -0800 Subject: [PATCH 286/342] Fix printing of `var"keyword"` identifiers (issue #56936) (#57268) Fixes #56936. One quirk this change would introduce is that `:((1:10)[end])` will be shown as `:((1:10)[var"end"])`, which is not ideal, but still correct. It would make sense to fix this at the same time we fix `(let var"end" = 1; (1:10)[var"end"]; end) == 10` being true. I'll open a separate issue for this. --- base/show.jl | 10 ++++++++-- test/show.jl | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/base/show.jl b/base/show.jl index 42788f05eceb5..27f0596e32e82 100644 --- a/base/show.jl +++ b/base/show.jl @@ -1757,9 +1757,15 @@ function show_enclosed_list(io::IO, op, items, sep, cl, indent, prec=0, quote_le print(io, cl) end +const keyword_syms = Set([ + :baremodule, :begin, :break, :catch, :const, :continue, :do, :else, :elseif, + :end, :export, :false, :finally, :for, :function, :global, :if, :import, + :let, :local, :macro, :module, :public, :quote, :return, :struct, :true, + :try, :using, :while ]) + function is_valid_identifier(sym) - return isidentifier(sym) || ( - _isoperator(sym) && + return (isidentifier(sym) && !(sym in keyword_syms)) || + (_isoperator(sym) && !(sym in (Symbol("'"), :(::), :?)) && !is_syntactic_operator(sym) ) diff --git a/test/show.jl b/test/show.jl index 75f04c1e02096..3057fcc3026e0 100644 --- a/test/show.jl +++ b/test/show.jl @@ -2356,9 +2356,9 @@ end # begin/end indices @weak_test_repr "a[begin, end, (begin; end)]" -@test repr(Base.remove_linenums!(:(a[begin, end, (begin; end)]))) == ":(a[begin, end, (begin;\n end)])" +@test_broken repr(Base.remove_linenums!(:(a[begin, end, (begin; end)]))) == ":(a[begin, end, (begin;\n end)])" @weak_test_repr "a[begin, end, let x=1; (x+1;); end]" -@test repr(Base.remove_linenums!(:(a[begin, end, let x=1; (x+1;); end]))) == +@test_broken repr(Base.remove_linenums!(:(a[begin, end, let x=1; (x+1;); end]))) == ":(a[begin, end, let x = 1\n begin\n x + 1\n end\n end])" @test_repr "a[(bla;)]" @test_repr "a[(;;)]" @@ -2795,3 +2795,9 @@ Base.setindex!(d::NoLengthDict, v, k) = d.dict[k] = v @test contains(str, "NoLengthDict") @test contains(str, "1 => 2") end + +# Issue 56936 +@testset "code printing of var\"keyword\" identifiers" begin + @test_repr """:(var"do" = 1)""" + @weak_test_repr """:(let var"let" = 1; var"let"; end)""" +end From 99fd5d9a92190e826bc462d5739e7be948a3bf44 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Wed, 5 Feb 2025 08:24:14 -0500 Subject: [PATCH 287/342] edit NEWS for v1.12 (#57262) --- NEWS.md | 310 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 172 insertions(+), 138 deletions(-) diff --git a/NEWS.md b/NEWS.md index 53643ee2c0954..403d832ee6f68 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,83 +4,74 @@ Julia v1.12 Release Notes New language features --------------------- -- New option `--trim` creates smaller binaries by removing code that was not proven to be reachable from - the entry points. Entry points can be marked using `Base.Experimental.entrypoint` ([#55047]). -- A new keyword argument `usings::Bool` has been added to `names`. By using this, we can now - find all the names available in module `A` by `names(A; all=true, imported=true, usings=true)`. ([#54609]) -- the `@atomic(...)` macro family supports now the reference assignment syntax, e.g. - `@atomic :monotonic v[3] += 4` modifies `v[3]` atomically with monotonic ordering semantics. ([#54707]) +* New option `--trim` creates smaller binaries by removing code that was not proven to be reachable from + entry points. Entry points can be marked using `Base.Experimental.entrypoint` ([#55047]). +* 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`, + which modifies `v[3]` atomically with monotonic ordering semantics ([#54707]). The supported syntax allows - - atomic fetch (`x = @atomic v[3]`), - - atomic set (`@atomic v[3] = 4`), - - atomic modify (`@atomic v[3] += 2`), - - atomic set once (`@atomiconce v[3] = 2`), - - atomic swap (`x = @atomicswap v[3] = 2`), and - - atomic replace (`x = @atomicreplace v[3] 2=>5`). -- New option `--task-metrics=yes` to enable the collection of per-task timing information, - which can also be enabled/disabled at runtime with `Base.Experimental.task_metrics(::Bool)`. ([#56320]) + * atomic fetch (`x = @atomic v[3]`), + * atomic set (`@atomic v[3] = 4`), + * atomic modify (`@atomic v[3] += 2`), + * atomic set once (`@atomiconce v[3] = 2`), + * atomic swap (`x = @atomicswap v[3] = 2`), and + * atomic replace (`x = @atomicreplace v[3] 2=>5`). +* New option `--task-metrics=yes` to enable the collection of per-task timing information, + which can also be enabled/disabled at runtime with `Base.Experimental.task_metrics(::Bool)` ([#56320]). The available metrics are: - - actual running time for the task (`Base.Experimental.task_running_time_ns`), and - - wall-time for the task (`Base.Experimental.task_wall_time_ns`). -- Support for Unicode 16 ([#56925]). -- `Threads.@spawn` now takes a `:samepool` argument to specify the same threadpool as the caller. - `Threads.@spawn :samepool foo()` which is shorthand for `Threads.@spawn Threads.threadpool() foo()` ([#57109]) + * actual running time for the task (`Base.Experimental.task_running_time_ns`), and + * wall-time for the task (`Base.Experimental.task_wall_time_ns`). +* Support for Unicode 16 ([#56925]). +* `Threads.@spawn` now takes a `:samepool` argument to specify the same threadpool as the caller. + `Threads.@spawn :samepool foo()` which is shorthand for `Threads.@spawn Threads.threadpool() foo()` ([#57109]). Language changes ---------------- - - Julia now defaults to 1 "interactive" thread, in addition to the 1 "default" worker thread. i.e. `-t1,1` +* Julia now defaults to 1 "interactive" thread, in addition to the 1 default "worker" thread. i.e. `-t1,1`. This means in default configuration the main task and repl (when in interactive mode), which both run on - thread 1, now run within the `interactive` threadpool. Also the libuv IO loop runs on thread 1, - helping efficient utilization of the "default" worker threadpool, which is what `Threads.@threads` and a bare - `Threads.@spawn` uses. Use `0` to disable the interactive thread i.e. `-t1,0` or `JULIA_NUM_THREADS=1,0`, or - `-tauto,0` etc. The zero is explicitly required to disable it, `-t2` will set the equivalent of `-t2,1` ([#57087]) - - - When methods are replaced with exactly equivalent ones, the old method is no - longer deleted implicitly simultaneously, although the new method does take - priority and become more specific than the old method. Thus if the new - method is deleted later, the old method will resume operating. This can be - useful to mocking frameworks (such as in SparseArrays, Pluto, and Mocking, - among others), as they do not need to explicitly restore the old method. - While inference and compilation still must be repeated with this, it also - may pave the way for inference to be able to intelligently re-use the old - results, once the new method is deleted. ([#53415]) - - - Macro expansion will no longer eagerly recurse into `Expr(:toplevel)` - expressions returned from macros. Instead, macro expansion of `:toplevel` - expressions will be delayed until evaluation time. This allows a later - expression within a given `:toplevel` expression to make use of macros - defined earlier in the same `:toplevel` expression. ([#53515]) - - - Trivial infinite loops (like `while true; end`) are no longer undefined - behavior. Infinite loops that actually do things (e.g. have side effects - or sleep) were never and are still not undefined behavior. ([#52999]) - - - It is now an error to mark a binding as both `public` and `export`ed. - ([#53664]) + thread 1, now run within the `interactive` threadpool. The libuv IO loop also runs on thread 1, + helping efficient utilization of the worker threadpool used by `Threads.@spawn`. Pass `0` to disable the + interactive thread i.e. `-t1,0` or `JULIA_NUM_THREADS=1,0`, or `-tauto,0` etc. The zero is explicitly + required to disable it, `-t2` will set the equivalent of `-t2,1` ([#57087]). +* When a method is replaced with an exactly equivalent one, the old method is not deleted. Instead, the + new method takes priority and becomes more specific than the old method. Thus if the new method is deleted + later, the old method will resume operating. This can be useful in mocking frameworks (as in SparseArrays, + Pluto, and Mocking, among others), as they do not need to explicitly restore the old method. + At this time, inference and compilation must be repeated in this situation, but we may eventually be + able to re-use the old results ([#53415]). +* Macro expansion will no longer eagerly recurse into `Expr(:toplevel)` expressions returned from macros. + Instead, macro expansion of `:toplevel` expressions will be delayed until evaluation time. This allows a + later expression within a given `:toplevel` expression to make use of macros defined earlier in the same + `:toplevel` expression ([#53515]). +* Trivial infinite loops (like `while true; end`) are no longer undefined behavior. Infinite loops that + do things (e.g. have side effects or sleep) were never and are still not undefined behavior ([#52999]). +* It is now an error to mark a binding as both `public` and `export`ed ([#53664]). +* Errors during `getfield` now raise a new `FieldError` exception type instead of the generic + `ErrorException` ([#54504]). Compiler/Runtime improvements ----------------------------- -- Generated LLVM IR now uses actual pointer types instead of passing pointers as integers. +* Generated LLVM IR now uses pointer types instead of passing pointers as integers. This affects `llvmcall`: Inline LLVM IR should be updated to use `i8*` or `ptr` instead of `i32` or `i64`, and remove unneeded `ptrtoint`/`inttoptr` conversions. For compatibility, - IR with integer pointers is still supported, but generates a deprecation warning. ([#53687]) - -- A new exception `FieldError` is now introduced to raise/handle `getfield` exceptions. Previously `getfield` exception was captured by fallback generic exception `ErrorException`. Now that `FieldError` is more specific `getfield` related exceptions that can occur should use `FieldError` exception instead. ([#54504]) + IR with integer pointers is still supported, but generates a deprecation warning ([#53687]). Command-line option changes --------------------------- * The `-m/--module` flag can be passed to run the `main` function inside a package with a set of arguments. - This `main` function should be declared using `@main` to indicate that it is an entry point. ([#52103]) + This `main` function should be declared using `@main` to indicate that it is an entry point ([#52103]). * Enabling or disabling color text in Julia can now be controlled with the [`NO_COLOR`](https://no-color.org/) or [`FORCE_COLOR`](https://force-color.org/) environment variables. These variables are also honored by Julia's build system ([#53742], [#56346]). -* `--project=@temp` starts Julia with a temporary environment. ([#51149]) +* `--project=@temp` starts Julia with a temporary environment ([#51149]). * New `--trace-compile-timing` option to report how long each method reported by `--trace-compile` took - to compile, in ms. ([#54662]) -* `--trace-compile` now prints recompiled methods in yellow or with a trailing comment if color is not supported ([#55763]) + to compile, in ms ([#54662]). +* `--trace-compile` now prints recompiled methods in yellow or with a trailing comment if color is not + supported ([#55763]). * New `--trace-dispatch` option to report methods that are dynamically dispatched ([#55848]). Multi-threading changes @@ -90,45 +81,49 @@ Multi-threading changes a `OncePerProcess{T}` type, which allows defining a function that should be run exactly once the first time it is called, and then always return the same result value of type `T` every subsequent time afterwards. There are also `OncePerThread{T}` and `OncePerTask{T}` types for - similar usage with threads or tasks. ([#55793]) + similar usage with threads or tasks ([#55793]). Build system changes -------------------- -* There are new `Makefile`s to build Julia and LLVM using the Binary Optimization and Layout Tool (BOLT), see `contrib/bolt` and `contrib/pgo-lto-bolt` ([#54107]). +* There are new `Makefile`s to build Julia and LLVM using the Binary Optimization and Layout Tool (BOLT). + See `contrib/bolt` and `contrib/pgo-lto-bolt` ([#54107]). New library functions --------------------- -* `logrange(start, stop; length)` makes a range of constant ratio, instead of constant step ([#39071]) -* The new `isfull(c::Channel)` function can be used to check if `put!(c, some_value)` will block. ([#53159]) -* `waitany(tasks; throw=false)` and `waitall(tasks; failfast=false, throw=false)` which wait multiple tasks at once ([#53341]). +* `logrange(start, stop; length)` makes a range of constant ratio, instead of constant step ([#39071]). +* The new `isfull(c::Channel)` function can be used to check if `put!(c, some_value)` will block ([#53159]). +* `waitany(tasks; throw=false)` and `waitall(tasks; failfast=false, throw=false)` which wait for multiple tasks + at once ([#53341]). * `uuid7()` creates an RFC 9652 compliant UUID with version 7 ([#54834]). -* `insertdims(array; dims)` allows to insert singleton dimensions into an array which is the inverse operation to `dropdims`. ([#45793]) -* The new `Fix` type is a generalization of `Fix1/Fix2` for fixing a single argument ([#54653]). -* `Sys.detectwsl()` allows to testing if Julia is running inside WSL at runtime. ([#57069]) +* `insertdims(array; dims)` inserts singleton dimensions into an array --- the inverse operation of + `dropdims` ([#45793]). +* A new `Fix` type generalizes `Fix1/Fix2` for fixing a single argument ([#54653]). +* `Sys.detectwsl()` tests whether Julia is running inside WSL at runtime ([#57069]). New library features -------------------- -* `escape_string` takes additional keyword arguments `ascii=true` (to escape all - non-ASCII characters) and `fullhex=true` (to require full 4/8-digit hex numbers - for u/U escapes, e.g. for C compatibility) ([#55099]). +* `escape_string` takes additional keyword arguments `ascii=true` (to escape all non-ASCII characters) and + `fullhex=true` (to require full 4/8-digit hex numbers for u/U escapes, e.g. for C compatibility) ([#55099]). * `tempname` can now take a suffix string to allow the file name to include a suffix and include that suffix in - the uniquing checking ([#53474]) -* `RegexMatch` objects can now be used to construct `NamedTuple`s and `Dict`s ([#50988]) -* `Lockable` is now exported ([#54595]) -* `Base.require_one_based_indexing` and `Base.has_offset_axes` are now public ([#56196]) -* New `ltruncate`, `rtruncate` and `ctruncate` functions for truncating strings to text width, accounting for char widths ([#55351]) -* `isless` (and thus `cmp`, sorting, etc.) is now supported for zero-dimensional `AbstractArray`s ([#55772]) -* `invoke` now supports passing a Method instead of a type signature making this interface somewhat more flexible for certain uncommon use cases ([#56692]). -* `Timer(f, ...)` will now match the stickiness of the parent task when creating timer tasks, which can be overridden - by the new `spawn` kwarg. This avoids the issue where sticky tasks i.e. `@async` make their parent sticky ([#56745]) -* `invoke` now supports passing a CodeInstance instead of a type, which can enable -certain compiler plugin workflows ([#56660]). -* `sort` now supports `NTuple`s ([#54494]) -* `map!(f, A)` now stores the results in `A`, like `map!(f, A, A)`. or `A .= f.(A)` ([#40632]). -* `Timer` now has readable `timeout` and `interval` properties, and a more descriptive show method ([#57081]) + the uniquing checking ([#53474]). +* `RegexMatch` objects can now be used to construct `NamedTuple`s and `Dict`s ([#50988]). +* `Lockable` is now exported ([#54595]). +* `Base.require_one_based_indexing` and `Base.has_offset_axes` are now public ([#56196]). +* New `ltruncate`, `rtruncate` and `ctruncate` functions for truncating strings to text width, accounting for + char widths ([#55351]). +* `isless` (and thus `cmp`, sorting, etc.) is now supported for zero-dimensional `AbstractArray`s ([#55772]). +* `invoke` now supports passing a `Method` instead of a type signature ([#56692]). +* `invoke` now supports passing a `CodeInstance` instead of a type, which can enable certain compiler plugin + workflows ([#56660]). +* `Timer(f, ...)` will now match the stickiness of the parent task when creating timer tasks, which can be + overridden by the new `spawn` keyword argument. This avoids the issue where sticky tasks (i.e. `@async`) + make their parent sticky ([#56745]). +* `Timer` now has readable `timeout` and `interval` properties, and a more descriptive `show` method ([#57081]). +* `sort` now supports `NTuple`s ([#54494]). +* `map!(f, A)` now stores the results in `A`, like `map!(f, A, A)` or `A .= f.(A)` ([#40632]). Standard library changes ------------------------ @@ -136,27 +131,23 @@ Standard library changes * `gcdx(0, 0)` now returns `(0, 0, 0)` instead of `(0, 1, 0)` ([#40989]). * `fd` returns a `RawFD` instead of an `Int` ([#55080]). -#### StyledStrings - #### JuliaSyntaxHighlighting -* A new standard library for applying syntax highlighting to Julia code, this - uses `JuliaSyntax` and `StyledStrings` to implement a `highlight` function - that creates an `AnnotatedString` with syntax highlighting applied. ([#51810]) - -#### Package Manager +* A new standard library for applying syntax highlighting to Julia code, this uses `JuliaSyntax` and + `StyledStrings` to implement a `highlight` function that creates an `AnnotatedString` with syntax highlighting + applied ([#51810]). #### LinearAlgebra * `rank` can now take a `QRPivoted` matrix to allow rank estimation via QR factorization ([#54283]). -* Added keyword argument `alg` to `eigen`, `eigen!`, `eigvals` and `eigvals!` for self-adjoint - matrix types (i.e., the type union `RealHermSymComplexHerm`) that allows one to switch - between different eigendecomposition algorithms ([#49355]). -* Added a generic version of the (unblocked) pivoted Cholesky decomposition - (callable via `cholesky[!](A, RowMaximum())`) ([#54619]). -* The number of default BLAS threads now respects process affinity, instead of - using total number of logical threads available on the system ([#55574]). -* A new function `zeroslike` is added that is used to generate the zero elements for matrix-valued banded matrices. +* Added keyword argument `alg` to `eigen`, `eigen!`, `eigvals` and `eigvals!` for self-adjoint matrix types + (i.e., the type union `RealHermSymComplexHerm`) that allows one to switch between different eigendecomposition + algorithms ([#49355]). +* Added a generic version of the (unblocked) pivoted Cholesky decomposition (callable via + `cholesky[!](A, RowMaximum())`) ([#54619]). +* The number of default BLAS threads now respects process affinity, instead of using the total number of logical + threads available on the system ([#55574]). +* A new function `zeroslike` is added that generates the zero elements for matrix-valued banded matrices. Custom array types may specialize this function to return an appropriate result ([#55252]). * The matrix multiplication `A * B` calls `matprod_dest(A, B, T::Type)` to generate the destination. This function is now public ([#55537]). @@ -164,41 +155,33 @@ Standard library changes This is now public ([#56223]). * A new function `diagview` is added that returns a view into a specific band of an `AbstractMatrix` ([#56175]). -#### Logging - -#### Printf - #### Profile -* `Profile.take_heap_snapshot` takes a new keyword argument, `redact_data::Bool`, - that is `true` by default. When set, the contents of Julia objects are not emitted - in the heap snapshot. This currently only applies to strings. ([#55326]) +* `Profile.take_heap_snapshot` takes a new keyword argument, `redact_data::Bool`, which is `true` by default. + When set, the contents of Julia objects are not emitted in the heap snapshot. This currently only applies to + strings ([#55326]). * `Profile.print()` now colors Base/Core/Package modules similarly to how they are in stacktraces. Also paths, even if truncated, are now clickable in terminals that support URI links - to take you to the specified `JULIA_EDITOR` for the given file & line number. ([#55335]) - -#### Random + to take you to the specified `JULIA_EDITOR` for the given file & line number ([#55335]). #### REPL -- Using the new `usings=true` feature of the `names()` function, REPL completions can now - complete names that have been explicitly `using`-ed. ([#54610]) -- REPL completions can now complete input lines like `[import|using] Mod: xxx|` e.g. - complete `using Base.Experimental: @op` to `using Base.Experimental: @opaque`. ([#54719]) -- the REPL will now warn if it detects a name is being accessed from a module which does not define it (nor has a submodule which defines it), - and for which the name is not public in that module. For example, `map` is defined in Base, and executing `LinearAlgebra.map` - in the REPL will now issue a warning the first time occurs. ([#54872]) -- When an object is printed automatically (by being returned in the REPL), its display is now truncated after printing 20 KiB. - This does not affect manual calls to `show`, `print`, and so forth. ([#53959]) -- Backslash completions now print the respective glyph or emoji next to each matching backslash shortcode. ([#54800]) - -#### SuiteSparse - -#### SparseArrays +* Using the new `usings=true` feature of the `names()` function, REPL completions can now + complete names visible via `using` ([#54610]). +* REPL completions can now complete input lines like `[import|using] Mod: xxx|` e.g. + complete `using Base.Experimental: @op` to `using Base.Experimental: @opaque` ([#54719]). +* The REPL will now warn if it detects a name is being accessed via a module which does not define it (nor has + a submodule which defines it), and for which the name is not public in that module. For example, `map` is + defined in Base, and executing `LinearAlgebra.map` in the REPL will now issue a warning the first time it + occurs ([#54872]). +* When the result of a REPL input is printed, the output is now truncated to 20 KiB. + This does not affect manual calls to `show`, `print`, etc. ([#53959]). +* Backslash completions now print the respective glyph or emoji next to each matching backslash shortcode ([#54800]). #### Test -* A failing `DefaultTestSet` now prints to screen the random number generator (RNG) of the failed test, to help reproducing a stochastic failure which only depends on the state of the RNG. +* A failing `DefaultTestSet` now prints to screen the random number generator (RNG) of the failed test, to help + reproducing a stochastic failure which only depends on the state of the RNG. It is also possible seed a test set by passing the `rng` keyword argument to `@testset`: ```julia using Test, Random @@ -207,35 +190,86 @@ Standard library changes end ``` -#### Dates - -#### Statistics - -#### Distributed - -#### Unicode - -#### DelimitedFiles - #### InteractiveUtils * New macros `@trace_compile` and `@trace_dispatch` for running an expression with - `--trace-compile=stderr --trace-compile-timing` and `--trace-dispatch=stderr` respectively enabled. - ([#55915]) - -Deprecated or removed ---------------------- + `--trace-compile=stderr --trace-compile-timing` and `--trace-dispatch=stderr` respectively enabled ([#55915]). External dependencies --------------------- -- The terminal info database, `terminfo`, is now vendored by default, providing a better +* The terminal info database, `terminfo`, is now vendored by default, providing a better REPL user experience when `terminfo` is not available on the system. Julia can be built - without vendoring the database using the Makefile option `WITH_TERMINFO=0`. ([#55411]) + without vendoring the database using the Makefile option `WITH_TERMINFO=0` ([#55411]). Tooling Improvements -------------------- -- A wall-time profiler is now available for users who need a sampling profiler that captures tasks regardless of their scheduling or running state. This type of profiler enables profiling of I/O-heavy tasks and helps detect areas of heavy contention in the system ([#55889]). +* A wall-time profiler is now available for users who need a sampling profiler that captures tasks regardless + of their scheduling or running state. This type of profiler enables profiling of I/O-heavy tasks and helps + detect areas of heavy contention in the system ([#55889]). +[#39071]: https://github.com/JuliaLang/julia/issues/39071 +[#40632]: https://github.com/JuliaLang/julia/issues/40632 +[#40989]: https://github.com/JuliaLang/julia/issues/40989 +[#45793]: https://github.com/JuliaLang/julia/issues/45793 +[#49355]: https://github.com/JuliaLang/julia/issues/49355 +[#50988]: https://github.com/JuliaLang/julia/issues/50988 +[#51149]: https://github.com/JuliaLang/julia/issues/51149 +[#51810]: https://github.com/JuliaLang/julia/issues/51810 +[#52103]: https://github.com/JuliaLang/julia/issues/52103 +[#52999]: https://github.com/JuliaLang/julia/issues/52999 +[#53159]: https://github.com/JuliaLang/julia/issues/53159 +[#53341]: https://github.com/JuliaLang/julia/issues/53341 +[#53415]: https://github.com/JuliaLang/julia/issues/53415 +[#53474]: https://github.com/JuliaLang/julia/issues/53474 +[#53515]: https://github.com/JuliaLang/julia/issues/53515 +[#53664]: https://github.com/JuliaLang/julia/issues/53664 +[#53687]: https://github.com/JuliaLang/julia/issues/53687 +[#53742]: https://github.com/JuliaLang/julia/issues/53742 +[#53959]: https://github.com/JuliaLang/julia/issues/53959 +[#54107]: https://github.com/JuliaLang/julia/issues/54107 +[#54283]: https://github.com/JuliaLang/julia/issues/54283 +[#54494]: https://github.com/JuliaLang/julia/issues/54494 +[#54504]: https://github.com/JuliaLang/julia/issues/54504 +[#54595]: https://github.com/JuliaLang/julia/issues/54595 +[#54609]: https://github.com/JuliaLang/julia/issues/54609 +[#54610]: https://github.com/JuliaLang/julia/issues/54610 +[#54619]: https://github.com/JuliaLang/julia/issues/54619 +[#54653]: https://github.com/JuliaLang/julia/issues/54653 +[#54662]: https://github.com/JuliaLang/julia/issues/54662 +[#54707]: https://github.com/JuliaLang/julia/issues/54707 +[#54719]: https://github.com/JuliaLang/julia/issues/54719 +[#54800]: https://github.com/JuliaLang/julia/issues/54800 +[#54834]: https://github.com/JuliaLang/julia/issues/54834 +[#54872]: https://github.com/JuliaLang/julia/issues/54872 +[#55047]: https://github.com/JuliaLang/julia/issues/55047 +[#55080]: https://github.com/JuliaLang/julia/issues/55080 +[#55099]: https://github.com/JuliaLang/julia/issues/55099 +[#55252]: https://github.com/JuliaLang/julia/issues/55252 +[#55326]: https://github.com/JuliaLang/julia/issues/55326 +[#55335]: https://github.com/JuliaLang/julia/issues/55335 +[#55351]: https://github.com/JuliaLang/julia/issues/55351 +[#55411]: https://github.com/JuliaLang/julia/issues/55411 +[#55537]: https://github.com/JuliaLang/julia/issues/55537 +[#55574]: https://github.com/JuliaLang/julia/issues/55574 +[#55763]: https://github.com/JuliaLang/julia/issues/55763 +[#55772]: https://github.com/JuliaLang/julia/issues/55772 +[#55793]: https://github.com/JuliaLang/julia/issues/55793 +[#55848]: https://github.com/JuliaLang/julia/issues/55848 +[#55889]: https://github.com/JuliaLang/julia/issues/55889 +[#55915]: https://github.com/JuliaLang/julia/issues/55915 +[#56175]: https://github.com/JuliaLang/julia/issues/56175 +[#56196]: https://github.com/JuliaLang/julia/issues/56196 +[#56223]: https://github.com/JuliaLang/julia/issues/56223 +[#56320]: https://github.com/JuliaLang/julia/issues/56320 +[#56346]: https://github.com/JuliaLang/julia/issues/56346 +[#56660]: https://github.com/JuliaLang/julia/issues/56660 +[#56692]: https://github.com/JuliaLang/julia/issues/56692 +[#56745]: https://github.com/JuliaLang/julia/issues/56745 +[#56925]: https://github.com/JuliaLang/julia/issues/56925 +[#57069]: https://github.com/JuliaLang/julia/issues/57069 +[#57081]: https://github.com/JuliaLang/julia/issues/57081 +[#57087]: https://github.com/JuliaLang/julia/issues/57087 +[#57109]: https://github.com/JuliaLang/julia/issues/57109 From 6ac507cd7d753ca8c1309b49a63090532076a55c Mon Sep 17 00:00:00 2001 From: Priynsh <119518987+Priynsh@users.noreply.github.com> Date: Thu, 6 Feb 2025 06:04:49 +0530 Subject: [PATCH 288/342] changed lcm and gcd implementations for when just one arg is infinite (#57067) Co-authored-by: Lilith Orion Hafner --- base/rational.jl | 14 +++++++++++-- test/rational.jl | 51 +++++++++++++++++++++++++----------------------- 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/base/rational.jl b/base/rational.jl index 69d39770b2095..b0704017beafa 100644 --- a/base/rational.jl +++ b/base/rational.jl @@ -564,8 +564,18 @@ end float(::Type{Rational{T}}) where {T<:Integer} = float(T) -gcd(x::Rational, y::Rational) = unsafe_rational(gcd(x.num, y.num), lcm(x.den, y.den)) -lcm(x::Rational, y::Rational) = unsafe_rational(lcm(x.num, y.num), gcd(x.den, y.den)) +function gcd(x::Rational, y::Rational) + if isinf(x) != isinf(y) + throw(ArgumentError("lcm is not defined between infinite and finite numbers")) + end + unsafe_rational(gcd(x.num, y.num), lcm(x.den, y.den)) +end +function lcm(x::Rational, y::Rational) + if isinf(x) != isinf(y) + throw(ArgumentError("lcm is not defined")) + end + return unsafe_rational(lcm(x.num, y.num), gcd(x.den, y.den)) +end function gcdx(x::Rational, y::Rational) c = gcd(x, y) if iszero(c.num) diff --git a/test/rational.jl b/test/rational.jl index 90b5414a6fe89..fe707cb7d3521 100644 --- a/test/rational.jl +++ b/test/rational.jl @@ -649,49 +649,49 @@ end @test lcm(a, T(0)//T(1)) === T(0)//T(1) @test gcdx(a, T(0)//T(1)) === (a, T(1), T(0)) - @test gcdx(T(1)//T(0), T(1)//T(2)) === (T(1)//T(0), T(1), T(0)) - @test gcdx(T(1)//T(2), T(1)//T(0)) === (T(1)//T(0), T(0), T(1)) - @test gcdx(T(1)//T(0), T(1)//T(1)) === (T(1)//T(0), T(1), T(0)) - @test gcdx(T(1)//T(1), T(1)//T(0)) === (T(1)//T(0), T(0), T(1)) + @test_throws ArgumentError gcdx(T(1)//T(0), T(1)//T(2)) + @test_throws ArgumentError gcdx(T(1)//T(2), T(1)//T(0)) + @test_throws ArgumentError gcdx(T(1)//T(0), T(1)//T(1)) + @test_throws ArgumentError gcdx(T(1)//T(1), T(1)//T(0)) @test gcdx(T(1)//T(0), T(1)//T(0)) === (T(1)//T(0), T(1), T(1)) - @test gcdx(T(1)//T(0), T(0)//T(1)) === (T(1)//T(0), T(1), T(0)) + @test_throws ArgumentError gcdx(T(1)//T(0), T(0)//T(1)) @test gcdx(T(0)//T(1), T(0)//T(1)) === (T(0)//T(1), T(0), T(0)) if T <: Signed - @test gcdx(T(-1)//T(0), T(1)//T(2)) === (T(1)//T(0), T(1), T(0)) - @test gcdx(T(1)//T(2), T(-1)//T(0)) === (T(1)//T(0), T(0), T(1)) - @test gcdx(T(-1)//T(0), T(1)//T(1)) === (T(1)//T(0), T(1), T(0)) - @test gcdx(T(1)//T(1), T(-1)//T(0)) === (T(1)//T(0), T(0), T(1)) + @test_throws ArgumentError gcdx(T(-1)//T(0), T(1)//T(2)) + @test_throws ArgumentError gcdx(T(1)//T(2), T(-1)//T(0)) + @test_throws ArgumentError gcdx(T(-1)//T(0), T(1)//T(1)) + @test_throws ArgumentError gcdx(T(1)//T(1), T(-1)//T(0)) @test gcdx(T(-1)//T(0), T(1)//T(0)) === (T(1)//T(0), T(1), T(1)) @test gcdx(T(1)//T(0), T(-1)//T(0)) === (T(1)//T(0), T(1), T(1)) @test gcdx(T(-1)//T(0), T(-1)//T(0)) === (T(1)//T(0), T(1), T(1)) - @test gcdx(T(-1)//T(0), T(0)//T(1)) === (T(1)//T(0), T(1), T(0)) - @test gcdx(T(0)//T(1), T(-1)//T(0)) === (T(1)//T(0), T(0), T(1)) + @test_throws ArgumentError gcdx(T(-1)//T(0), T(0)//T(1)) + @test_throws ArgumentError gcdx(T(0)//T(1), T(-1)//T(0)) end @test gcdx(T(1)//T(3), T(2)) === (T(1)//T(3), T(1), T(0)) @test lcm(T(1)//T(3), T(1)) === T(1)//T(1) - @test lcm(T(3)//T(1), T(1)//T(0)) === T(3)//T(1) - @test lcm(T(0)//T(1), T(1)//T(0)) === T(0)//T(1) + @test_throws ArgumentError lcm(T(3)//T(1), T(1)//T(0)) + @test_throws ArgumentError lcm(T(0)//T(1), T(1)//T(0)) - @test lcm(T(1)//T(0), T(1)//T(2)) === T(1)//T(2) - @test lcm(T(1)//T(2), T(1)//T(0)) === T(1)//T(2) - @test lcm(T(1)//T(0), T(1)//T(1)) === T(1)//T(1) - @test lcm(T(1)//T(1), T(1)//T(0)) === T(1)//T(1) + @test_throws ArgumentError lcm(T(1)//T(0), T(1)//T(2)) + @test_throws ArgumentError lcm(T(1)//T(2), T(1)//T(0)) + @test_throws ArgumentError lcm(T(1)//T(0), T(1)//T(1)) + @test_throws ArgumentError lcm(T(1)//T(1), T(1)//T(0)) @test lcm(T(1)//T(0), T(1)//T(0)) === T(1)//T(0) - @test lcm(T(1)//T(0), T(0)//T(1)) === T(0)//T(1) + @test_throws ArgumentError lcm(T(1)//T(0), T(0)//T(1)) @test lcm(T(0)//T(1), T(0)//T(1)) === T(0)//T(1) if T <: Signed - @test lcm(T(-1)//T(0), T(1)//T(2)) === T(1)//T(2) - @test lcm(T(1)//T(2), T(-1)//T(0)) === T(1)//T(2) - @test lcm(T(-1)//T(0), T(1)//T(1)) === T(1)//T(1) - @test lcm(T(1)//T(1), T(-1)//T(0)) === T(1)//T(1) + @test_throws ArgumentError lcm(T(-1)//T(0), T(1)//T(2)) + @test_throws ArgumentError lcm(T(1)//T(2), T(-1)//T(0)) + @test_throws ArgumentError lcm(T(-1)//T(0), T(1)//T(1)) + @test_throws ArgumentError lcm(T(1)//T(1), T(-1)//T(0)) @test lcm(T(-1)//T(0), T(1)//T(0)) === T(1)//T(0) @test lcm(T(1)//T(0), T(-1)//T(0)) === T(1)//T(0) @test lcm(T(-1)//T(0), T(-1)//T(0)) === T(1)//T(0) - @test lcm(T(-1)//T(0), T(0)//T(1)) === T(0)//T(1) - @test lcm(T(0)//T(1), T(-1)//T(0)) === T(0)//T(1) + @test_throws ArgumentError lcm(T(-1)//T(0), T(0)//T(1)) + @test_throws ArgumentError lcm(T(0)//T(1), T(-1)//T(0)) end @test gcd([T(5), T(2), T(1)//T(2)]) === T(1)//T(2) @@ -699,6 +699,9 @@ end @test lcm([T(5), T(2), T(1)//T(2)]) === T(10)//T(1) @test lcm(T(5), T(2), T(1)//T(2)) === T(10)//T(1) + + @test_throws ArgumentError gcd(T(1)//T(1), T(1)//T(0)) + @test_throws ArgumentError gcd(T(1)//T(0), T(0)//T(1)) end end From ca7cf30d6310469c335e7d2ed95c786cf8b93881 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 5 Feb 2025 23:45:19 -0500 Subject: [PATCH 289/342] cfunction: reimplement, as originally planned, for reliable performance (#57226) --- Compiler/src/typeinfer.jl | 12 +- src/aotcompile.cpp | 179 +++++++++- src/ccall.cpp | 2 + src/cgutils.cpp | 54 ++- src/codegen.cpp | 706 +++++++++++++++++++++++++------------- src/gf.c | 3 +- src/intrinsics.cpp | 3 + src/jitlayers.cpp | 124 ++++--- src/jitlayers.h | 25 ++ src/jl_exported_funcs.inc | 1 + src/julia_internal.h | 9 +- src/runtime_ccall.cpp | 130 +++++++ src/staticdata.c | 3 + 13 files changed, 926 insertions(+), 325 deletions(-) diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index 96f58943e3255..f1da2e8a75a67 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -1266,6 +1266,7 @@ function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim:: tocompile = Vector{CodeInstance}() codeinfos = [] # first compute the ABIs of everything + latest = true # whether this_world == world_counter() for this_world in reverse(sort!(worlds)) interp = NativeInterpreter(this_world) for i = 1:length(methods) @@ -1278,18 +1279,18 @@ function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim:: # then we want to compile and emit this if item.def.primary_world <= this_world <= item.def.deleted_world ci = typeinf_ext(interp, item, SOURCE_MODE_NOT_REQUIRED) - ci isa CodeInstance && !use_const_api(ci) && push!(tocompile, ci) + ci isa CodeInstance && push!(tocompile, ci) end - elseif item isa SimpleVector + elseif item isa SimpleVector && latest (rt::Type, sig::Type) = item # make a best-effort attempt to enqueue the relevant code for the ccallable ptr = ccall(:jl_get_specialization1, #= MethodInstance =# Ptr{Cvoid}, (Any, Csize_t, Cint), sig, this_world, #= mt_cache =# 0) if ptr !== C_NULL - mi = unsafe_pointer_to_objref(ptr) + mi = unsafe_pointer_to_objref(ptr)::MethodInstance ci = typeinf_ext(interp, mi, SOURCE_MODE_NOT_REQUIRED) - ci isa CodeInstance && !use_const_api(ci) && push!(tocompile, ci) + ci isa CodeInstance && push!(tocompile, ci) end # additionally enqueue the ccallable entrypoint / adapter, which implicitly # invokes the above ci @@ -1305,7 +1306,7 @@ function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim:: mi = get_ci_mi(callee) def = mi.def if use_const_api(callee) - src = codeinfo_for_const(interp, mi, code.rettype_const) + src = codeinfo_for_const(interp, mi, callee.rettype_const) elseif haskey(interp.codegen, callee) src = interp.codegen[callee] elseif isa(def, Method) && ccall(:jl_get_module_infer, Cint, (Any,), def.module) == 0 && !trim @@ -1327,6 +1328,7 @@ function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim:: println("warning: failed to get code for ", mi) end end + latest = false end return codeinfos end diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 5524518da46fa..d91da9c64cda9 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -423,7 +423,7 @@ static void resolve_workqueue(jl_codegen_params_t ¶ms, egal_set &method_root if (decls.functionObject == "jl_fptr_args") { preal_decl = decls.specFunctionObject; } - else if (decls.functionObject != "jl_fptr_sparam" && decls.functionObject != "jl_f_opaque_closure_call") { + else if (decls.functionObject != "jl_fptr_sparam" && decls.functionObject != "jl_f_opaque_closure_call" && decls.functionObject != "jl_fptr_const_return") { preal_decl = decls.specFunctionObject; preal_specsig = true; } @@ -439,6 +439,13 @@ static void resolve_workqueue(jl_codegen_params_t ¶ms, egal_set &method_root Module *mod = proto.decl->getParent(); assert(proto.decl->isDeclaration()); Function *pinvoke = nullptr; + if (preal_decl.empty() && jl_atomic_load_relaxed(&codeinst->invoke) == jl_fptr_const_return_addr) { + std::string gf_thunk_name = emit_abi_constreturn(mod, params, proto.specsig, codeinst); + preal_specsig = proto.specsig; + if (invokeName.empty()) + invokeName = "jl_fptr_const_return"; + preal_decl = mod->getNamedValue(gf_thunk_name)->getName(); + } if (preal_decl.empty()) { if (invokeName.empty() && params.params->trim) { jl_safe_printf("warning: bailed out to invoke when compiling: "); @@ -483,6 +490,7 @@ static void resolve_workqueue(jl_codegen_params_t ¶ms, egal_set &method_root ocinvokeDecl = pinvoke->getName(); assert(!ocinvokeDecl.empty()); assert(ocinvokeDecl != "jl_fptr_args"); + assert(ocinvokeDecl != "jl_fptr_const_return"); assert(ocinvokeDecl != "jl_fptr_sparam"); // merge and/or rename this prototype to the real function if (Value *specfun = mod->getNamedValue(ocinvokeDecl)) { @@ -499,6 +507,134 @@ static void resolve_workqueue(jl_codegen_params_t ¶ms, egal_set &method_root JL_GC_POP(); } +/// Link the function in the source module into the destination module if +/// needed, setting up mapping information. +/// Similar to orc::cloneFunctionDecl, but more complete for greater correctness +Function *IRLinker_copyFunctionProto(Module *DstM, Function *SF) { + // If there is no linkage to be performed or we are linking from the source, + // bring SF over, if we haven't already. + if (SF->getParent() == DstM) + return SF; + if (auto *F = DstM->getNamedValue(SF->getName())) + return cast(F); + auto *F = Function::Create(SF->getFunctionType(), SF->getLinkage(), + SF->getAddressSpace(), SF->getName(), DstM); + F->copyAttributesFrom(SF); + F->IsNewDbgInfoFormat = SF->IsNewDbgInfoFormat; + + // Remove these copied constants since they point to the source module. + F->setPersonalityFn(nullptr); + F->setPrefixData(nullptr); + F->setPrologueData(nullptr); + return F; +} + +static Function *aot_abi_converter(jl_codegen_params_t ¶ms, Module *M, jl_value_t *declrt, jl_value_t *sigt, size_t nargs, bool specsig, jl_code_instance_t *codeinst, Module *defM, StringRef func, StringRef specfunc, bool target_specsig) +{ + std::string gf_thunk_name; + if (!specfunc.empty()) { + Value *llvmtarget = IRLinker_copyFunctionProto(M, defM->getFunction(specfunc)); + gf_thunk_name = emit_abi_converter(M, params, declrt, sigt, nargs, specsig, codeinst, llvmtarget, target_specsig); + } + else { + Value *llvmtarget = func.empty() ? nullptr : IRLinker_copyFunctionProto(M, defM->getFunction(func)); + gf_thunk_name = emit_abi_dispatcher(M, params, declrt, sigt, nargs, specsig, codeinst, llvmtarget); + } + auto F = M->getFunction(gf_thunk_name); + assert(F); + return F; +} + +static void generate_cfunc_thunks(jl_codegen_params_t ¶ms, jl_compiled_functions_t &compiled_functions) +{ + DenseMap compiled_mi; + for (auto &def : compiled_functions) { + jl_code_instance_t *this_code = def.first; + jl_method_instance_t *mi = jl_get_ci_mi(this_code); + if (this_code->owner == jl_nothing && jl_atomic_load_relaxed(&this_code->max_world) == ~(size_t)0 && this_code->def == (jl_value_t*)mi) + compiled_mi[mi] = this_code; + } + size_t latestworld = jl_atomic_load_acquire(&jl_world_counter); + for (cfunc_decl_t &cfunc : params.cfuncs) { + Module *M = cfunc.theFptr->getParent(); + jl_value_t *sigt = cfunc.sigt; + JL_GC_PROMISE_ROOTED(sigt); + jl_value_t *declrt = cfunc.declrt; + JL_GC_PROMISE_ROOTED(declrt); + Function *unspec = aot_abi_converter(params, M, declrt, sigt, cfunc.nargs, cfunc.specsig, nullptr, nullptr, "", "", false); + jl_code_instance_t *codeinst = nullptr; + auto assign_fptr = [¶ms, &cfunc, &codeinst, &unspec](Function *f) { + ConstantArray *init = cast(cfunc.cfuncdata->getInitializer()); + SmallVector initvals; + for (unsigned i = 0; i < init->getNumOperands(); ++i) + initvals.push_back(init->getOperand(i)); + assert(initvals.size() == 6); + assert(initvals[0]->isNullValue()); + if (codeinst) { + Constant *llvmcodeinst = literal_pointer_val_slot(params, f->getParent(), (jl_value_t*)codeinst); + initvals[0] = llvmcodeinst; // plast_codeinst + } + assert(initvals[2]->isNullValue()); + initvals[2] = unspec; + cfunc.cfuncdata->setInitializer(ConstantArray::get(init->getType(), initvals)); + cfunc.theFptr->setInitializer(f); + }; + Module *defM = nullptr; + StringRef func; + jl_method_instance_t *mi = jl_get_specialization1((jl_tupletype_t*)sigt, latestworld, 0); + if (mi) { + auto it = compiled_mi.find(mi); + if (it != compiled_mi.end()) { + codeinst = it->second; + JL_GC_PROMISE_ROOTED(codeinst); + auto defs = compiled_functions.find(codeinst); + defM = std::get<0>(defs->second).getModuleUnlocked(); + const jl_llvm_functions_t &decls = std::get<1>(defs->second); + func = decls.functionObject; + StringRef specfunc = decls.specFunctionObject; + jl_value_t *astrt = codeinst->rettype; + if (astrt != (jl_value_t*)jl_bottom_type && + jl_type_intersection(astrt, declrt) == jl_bottom_type) { + // Do not warn if the function never returns since it is + // occasionally required by the C API (typically error callbacks) + // even though we're likely to encounter memory errors in that case + jl_printf(JL_STDERR, "WARNING: cfunction: return type of %s does not match\n", name_from_method_instance(mi)); + } + if (func == "jl_fptr_const_return") { + std::string gf_thunk_name = emit_abi_constreturn(M, params, declrt, sigt, cfunc.nargs, cfunc.specsig, codeinst->rettype_const); + auto F = M->getFunction(gf_thunk_name); + assert(F); + assign_fptr(F); + continue; + } + else if (func == "jl_fptr_args") { + assert(!specfunc.empty()); + if (!cfunc.specsig && jl_subtype(astrt, declrt)) { + assign_fptr(IRLinker_copyFunctionProto(M, defM->getFunction(specfunc))); + continue; + } + assign_fptr(aot_abi_converter(params, M, declrt, sigt, cfunc.nargs, cfunc.specsig, codeinst, defM, func, specfunc, false)); + continue; + } + else if (func == "jl_fptr_sparam" || func == "jl_f_opaque_closure_call") { + func = ""; // use jl_invoke instead for these, since we don't declare these prototypes + } + else { + assert(!specfunc.empty()); + if (jl_egal(mi->specTypes, sigt) && jl_egal(declrt, astrt)) { + assign_fptr(IRLinker_copyFunctionProto(M, defM->getFunction(specfunc))); + continue; + } + assign_fptr(aot_abi_converter(params, M, declrt, sigt, cfunc.nargs, cfunc.specsig, codeinst, defM, func, specfunc, true)); + continue; + } + } + } + Function *f = codeinst ? aot_abi_converter(params, M, declrt, sigt, cfunc.nargs, cfunc.specsig, codeinst, defM, func, "", false) : unspec; + return assign_fptr(f); + } +} + // takes the running content that has collected in the shadow module and dump it to disk // this builds the object file portion of the sysimage files for fast startup @@ -651,7 +787,11 @@ void *jl_emit_native_impl(jl_array_t *codeinfos, LLVMOrcThreadSafeModuleRef llvm orc::ThreadSafeModule result_m = jl_create_ts_module(name_from_method_instance(jl_get_ci_mi(codeinst)), params.tsctx, clone.getModuleUnlocked()->getDataLayout(), Triple(clone.getModuleUnlocked()->getTargetTriple())); - jl_llvm_functions_t decls = jl_emit_codeinst(result_m, codeinst, src, params); + jl_llvm_functions_t decls; + if (jl_atomic_load_relaxed(&codeinst->invoke) == jl_fptr_const_return_addr) + decls.functionObject = "jl_fptr_const_return"; + else + decls = jl_emit_codeinst(result_m, codeinst, src, params); record_method_roots(method_roots, jl_get_ci_mi(codeinst)); if (result_m) compiled_functions[codeinst] = {std::move(result_m), std::move(decls)}; @@ -671,6 +811,8 @@ void *jl_emit_native_impl(jl_array_t *codeinfos, LLVMOrcThreadSafeModuleRef llvm } // finally, make sure all referenced methods get fixed up, particularly if the user declined to compile them resolve_workqueue(params, method_roots, compiled_functions); + // including generating cfunction thunks + generate_cfunc_thunks(params, compiled_functions); aot_optimize_roots(params, method_roots, compiled_functions); params.temporary_roots = nullptr; JL_GC_POP(); @@ -728,9 +870,12 @@ void *jl_emit_native_impl(jl_array_t *codeinfos, LLVMOrcThreadSafeModuleRef llvm else if (func == "jl_fptr_sparam") { func_id = -2; } - else if (decls.functionObject == "jl_f_opaque_closure_call") { + else if (func == "jl_f_opaque_closure_call") { func_id = -4; } + else if (func == "jl_fptr_const_return") { + func_id = -5; + } else { //Safe b/c context is locked by params data->jl_sysimg_fvars.push_back(cast(clone.getModuleUnlocked()->getNamedValue(func))); @@ -2201,7 +2346,7 @@ extern "C" JL_DLLEXPORT_CODEGEN jl_code_info_t *jl_gdbdumpcode(jl_method_instanc // for use in reflection from Julia. // This is paired with jl_dump_function_ir and jl_dump_function_asm, either of which will free all memory allocated here extern "C" JL_DLLEXPORT_CODEGEN -void jl_get_llvmf_defn_impl(jl_llvmf_dump_t* dump, jl_method_instance_t *mi, jl_code_info_t *src, char getwrapper, char optimize, const jl_cgparams_t params) +void jl_get_llvmf_defn_impl(jl_llvmf_dump_t *dump, jl_method_instance_t *mi, jl_code_info_t *src, char getwrapper, char optimize, const jl_cgparams_t params) { // emit this function into a new llvm module dump->F = nullptr; @@ -2223,7 +2368,31 @@ void jl_get_llvmf_defn_impl(jl_llvmf_dump_t* dump, jl_method_instance_t *mi, jl_ output.imaging_mode = jl_options.image_codegen; output.temporary_roots = jl_alloc_array_1d(jl_array_any_type, 0); JL_GC_PUSH1(&output.temporary_roots); - auto decls = jl_emit_code(m, mi, src, mi->specTypes, src->rettype, output); + jl_llvm_functions_t decls = jl_emit_code(m, mi, src, mi->specTypes, src->rettype, output); + // while not required, also emit the cfunc thunks, based on the + // inferred ABIs of their targets in the current latest world, + // since otherwise it is challenging to see all relevant codes + jl_compiled_functions_t compiled_functions; + size_t latestworld = jl_atomic_load_acquire(&jl_world_counter); + for (cfunc_decl_t &cfunc : output.cfuncs) { + jl_value_t *sigt = cfunc.sigt; + JL_GC_PROMISE_ROOTED(sigt); + jl_method_instance_t *mi = jl_get_specialization1((jl_tupletype_t*)sigt, latestworld, 0); + if (mi == nullptr) + continue; + jl_code_instance_t *codeinst = jl_type_infer(mi, latestworld, SOURCE_MODE_NOT_REQUIRED); + if (codeinst == nullptr || compiled_functions.count(codeinst)) + continue; + orc::ThreadSafeModule decl_m = jl_create_ts_module("extern", ctx); + jl_llvm_functions_t decls; + if (jl_atomic_load_relaxed(&codeinst->invoke) == jl_fptr_const_return_addr) + decls.functionObject = "jl_fptr_const_return"; + else + decls = jl_emit_codedecls(decl_m, codeinst, output); + compiled_functions[codeinst] = {std::move(decl_m), std::move(decls)}; + } + generate_cfunc_thunks(output, compiled_functions); + compiled_functions.clear(); output.temporary_roots = nullptr; JL_GC_POP(); // GC the global_targets array contents now since reflection doesn't need it diff --git a/src/ccall.cpp b/src/ccall.cpp index eb64adef447f4..6c03f9532d9a8 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -1970,6 +1970,8 @@ static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs) return retval; } +static inline Constant *literal_static_pointer_val(const void *p, Type *T); + jl_cgval_t function_sig_t::emit_a_ccall( jl_codectx_t &ctx, const native_sym_arg_t &symarg, diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 98c5627578b80..39879503596fe 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -391,19 +391,17 @@ static llvm::SmallVector get_gc_roots_for(jl_codectx_t &ctx, const jl_ static void jl_temporary_root(jl_codegen_params_t &ctx, jl_value_t *val); static void jl_temporary_root(jl_codectx_t &ctx, jl_value_t *val); -static inline Constant *literal_static_pointer_val(const void *p, Type *T); -static Constant *julia_pgv(jl_codectx_t &ctx, const char *cname, void *addr) +static Constant *julia_pgv(jl_codegen_params_t ¶ms, Module *M, const char *cname, void *addr) { // emit a GlobalVariable for a jl_value_t named "cname" // store the name given so we can reuse it (facilitating merging later) // so first see if there already is a GlobalVariable for this address - GlobalVariable* &gv = ctx.emission_context.global_targets[addr]; - Module *M = jl_Module; + GlobalVariable* &gv = params.global_targets[addr]; StringRef localname; std::string gvname; if (!gv) { - uint64_t id = jl_atomic_fetch_add_relaxed(&globalUniqueGeneratedNames, 1); // TODO: use ctx.emission_context.global_targets.size() + uint64_t id = jl_atomic_fetch_add_relaxed(&globalUniqueGeneratedNames, 1); // TODO: use params.global_targets.size() raw_string_ostream(gvname) << cname << id; localname = StringRef(gvname); } @@ -413,9 +411,9 @@ static Constant *julia_pgv(jl_codectx_t &ctx, const char *cname, void *addr) gv = cast_or_null(M->getNamedValue(localname)); } if (gv == nullptr) - gv = new GlobalVariable(*M, ctx.types().T_pjlvalue, + gv = new GlobalVariable(*M, getPointerTy(M->getContext()), false, GlobalVariable::ExternalLinkage, - NULL, localname); + nullptr, localname); // LLVM passes sometimes strip metadata when moving load around // since the load at the new location satisfy the same condition as the original one. // Mark the global as constant to LLVM code using our own metadata @@ -426,7 +424,7 @@ static Constant *julia_pgv(jl_codectx_t &ctx, const char *cname, void *addr) return gv; } -static Constant *julia_pgv(jl_codectx_t &ctx, const char *prefix, jl_sym_t *name, jl_module_t *mod, void *addr) +static Constant *julia_pgv(jl_codegen_params_t ¶ms, Module *M, const char *prefix, jl_sym_t *name, jl_module_t *mod, void *addr) { // emit a GlobalVariable for a jl_value_t, using the prefix, name, and module to // to create a readable name of the form prefixModA.ModB.name# @@ -451,53 +449,49 @@ static Constant *julia_pgv(jl_codectx_t &ctx, const char *prefix, jl_sym_t *name finalname.resize(orig_end + prefix_name.size()); std::reverse_copy(prefix_name.begin(), prefix_name.end(), finalname.begin() + orig_end); std::reverse(finalname.begin(), finalname.end()); - return julia_pgv(ctx, finalname.c_str(), addr); + return julia_pgv(params, M, finalname.c_str(), addr); } static JuliaVariable *julia_const_gv(jl_value_t *val); -static Constant *literal_pointer_val_slot(jl_codectx_t &ctx, jl_value_t *p) +Constant *literal_pointer_val_slot(jl_codegen_params_t ¶ms, Module *M, jl_value_t *p) { // emit a pointer to a jl_value_t* which will allow it to be valid across reloading code // also, try to give it a nice name for gdb, for easy identification if (JuliaVariable *gv = julia_const_gv(p)) { // if this is a known special object, use the existing GlobalValue - return prepare_global_in(jl_Module, gv); + return prepare_global_in(M, gv); } if (jl_is_datatype(p)) { jl_datatype_t *addr = (jl_datatype_t*)p; if (addr->smalltag) { // some common builtin datatypes have a special pool for accessing them by smalltag id - Constant *tag = ConstantInt::get(getInt32Ty(ctx.builder.getContext()), addr->smalltag << 4); - Constant *smallp = ConstantExpr::getInBoundsGetElementPtr(getInt8Ty(ctx.builder.getContext()), prepare_global_in(jl_Module, jl_small_typeof_var), tag); - auto ty = ctx.types().T_ppjlvalue; - if (ty->getPointerAddressSpace() == smallp->getType()->getPointerAddressSpace()) - return ConstantExpr::getBitCast(smallp, ty); - else { - Constant *newsmallp = ConstantExpr::getAddrSpaceCast(smallp, ty); - return ConstantExpr::getBitCast(newsmallp, ty); - } + Constant *tag = ConstantInt::get(getInt32Ty(M->getContext()), addr->smalltag << 4); + Constant *smallp = ConstantExpr::getInBoundsGetElementPtr(getInt8Ty(M->getContext()), prepare_global_in(M, jl_small_typeof_var), tag); + if (smallp->getType()->getPointerAddressSpace() != 0) + smallp = ConstantExpr::getAddrSpaceCast(smallp, getPointerTy(M->getContext())); + return smallp; } // DataTypes are prefixed with a + - return julia_pgv(ctx, "+", addr->name->name, addr->name->module, p); + return julia_pgv(params, M, "+", addr->name->name, addr->name->module, p); } if (jl_is_method(p)) { jl_method_t *m = (jl_method_t*)p; // functions are prefixed with a - - return julia_pgv(ctx, "-", m->name, m->module, p); + return julia_pgv(params, M, "-", m->name, m->module, p); } if (jl_is_method_instance(p)) { jl_method_instance_t *linfo = (jl_method_instance_t*)p; // Type-inferred functions are also prefixed with a - if (jl_is_method(linfo->def.method)) - return julia_pgv(ctx, "-", linfo->def.method->name, linfo->def.method->module, p); + return julia_pgv(params, M, "-", linfo->def.method->name, linfo->def.method->module, p); } if (jl_is_symbol(p)) { jl_sym_t *addr = (jl_sym_t*)p; // Symbols are prefixed with jl_sym# - return julia_pgv(ctx, "jl_sym#", addr, NULL, p); + return julia_pgv(params, M, "jl_sym#", addr, NULL, p); } // something else gets just a generic name - return julia_pgv(ctx, "jl_global#", p); + return julia_pgv(params, M, "jl_global#", p); } static size_t dereferenceable_size(jl_value_t *jt) @@ -570,7 +564,7 @@ static Value *literal_pointer_val(jl_codectx_t &ctx, jl_value_t *p) { if (p == NULL) return Constant::getNullValue(ctx.types().T_pjlvalue); - Value *pgv = literal_pointer_val_slot(ctx, p); + Value *pgv = literal_pointer_val_slot(ctx.emission_context, jl_Module, p); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const); auto load = ai.decorateInst(maybe_mark_load_dereferenceable( ctx.builder.CreateAlignedLoad(ctx.types().T_pjlvalue, pgv, Align(sizeof(void*))), @@ -610,7 +604,7 @@ static Value *julia_binding_gv(jl_codectx_t &ctx, jl_binding_t *b) // emit a literal_pointer_val to a jl_binding_t // binding->value are prefixed with * jl_globalref_t *gr = b->globalref; - Value *pgv = gr ? julia_pgv(ctx, "*", gr->name, gr->mod, b) : julia_pgv(ctx, "*jl_bnd#", b); + Value *pgv = gr ? julia_pgv(ctx.emission_context, jl_Module, "*", gr->name, gr->mod, b) : julia_pgv(ctx.emission_context, jl_Module, "*jl_bnd#", b); jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_const); auto load = ai.decorateInst(ctx.builder.CreateAlignedLoad(ctx.types().T_pjlvalue, pgv, Align(sizeof(void*)))); setName(ctx.emission_context, load, pgv->getName()); @@ -1352,7 +1346,7 @@ static Value *emit_typeof(jl_codectx_t &ctx, const jl_cgval_t &p, bool maybenull ptr = get_pointer_to_constant(ctx.emission_context, ConstantInt::get(expr_type, jt->smalltag << 4), Align(sizeof(jl_value_t*)), StringRef("_j_smalltag_") + jl_symbol_name(jt->name->name), *jl_Module); } else { - ptr = ConstantExpr::getBitCast(literal_pointer_val_slot(ctx, (jl_value_t*)jt), datatype_or_p->getType()); + ptr = ConstantExpr::getBitCast(literal_pointer_val_slot(ctx.emission_context, jl_Module, (jl_value_t*)jt), datatype_or_p->getType()); } datatype_or_p = ctx.builder.CreateSelect(cmp, ptr, datatype_or_p); setName(ctx.emission_context, datatype_or_p, "typetag_ptr"); @@ -2284,7 +2278,7 @@ static jl_cgval_t typed_store(jl_codectx_t &ctx, const jl_cgval_t argv[3] = { cmp, lhs, rhs }; jl_cgval_t ret; if (modifyop) { - ret = emit_invoke(ctx, *modifyop, argv, 3, (jl_value_t*)jl_any_type, nullptr); + ret = emit_invoke(ctx, *modifyop, argv, 3, (jl_value_t*)jl_any_type); } else { if (trim_may_error(ctx.params->trim)) { @@ -4023,7 +4017,7 @@ static jl_cgval_t union_store(jl_codectx_t &ctx, emit_lockstate_value(ctx, needlock, false); const jl_cgval_t argv[3] = { cmp, oldval, rhs }; if (modifyop) { - rhs = emit_invoke(ctx, *modifyop, argv, 3, (jl_value_t*)jl_any_type, nullptr); + rhs = emit_invoke(ctx, *modifyop, argv, 3, (jl_value_t*)jl_any_type); } else { if (trim_may_error(ctx.params->trim)) { diff --git a/src/codegen.cpp b/src/codegen.cpp index e9e4275672c7e..7787b684fbd12 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -278,16 +278,16 @@ extern void _chkstk(void); // types struct jl_typecache_t { - Type *T_ptr; + PointerType *T_ptr; Type *T_size; Type *T_jlvalue; - Type *T_pjlvalue; - Type *T_prjlvalue; - Type *T_ppjlvalue; - Type *T_pprjlvalue; + PointerType *T_pjlvalue; + PointerType *T_prjlvalue; + PointerType *T_ppjlvalue; + PointerType *T_pprjlvalue; StructType *T_jlgenericmemory; StructType *T_jlarray; - Type *T_pjlarray; + PointerType *T_pjlarray; FunctionType *T_jlfunc; FunctionType *T_jlfuncparams; @@ -990,20 +990,12 @@ static const auto jlapplygeneric_func = new JuliaFunction<>{ static const auto jlinvoke_func = new JuliaFunction<>{ XSTR(jl_invoke), get_func2_sig, - [](LLVMContext &C) { return AttributeList::get(C, - AttributeSet(), - Attributes(C, {Attribute::NonNull}), - {AttributeSet(), - Attributes(C, {Attribute::ReadOnly, Attribute::NoCapture})}); }, + get_func_attrs, }; static const auto jlinvokeoc_func = new JuliaFunction<>{ XSTR(jl_invoke_oc), get_func2_sig, - [](LLVMContext &C) { return AttributeList::get(C, - AttributeSet(), - Attributes(C, {Attribute::NonNull}), - {AttributeSet(), - Attributes(C, {Attribute::ReadOnly, Attribute::NoCapture})}); }, + get_func_attrs, }; static const auto jlopaque_closure_call_func = new JuliaFunction<>{ XSTR(jl_f_opaque_closure_call), @@ -1396,6 +1388,14 @@ static const auto jlgetcfunctiontrampoline_func = new JuliaFunction<>{ Attributes(C, {Attribute::NonNull}), None); }, }; +static const auto jlgetabiconverter_func = new JuliaFunction{ + XSTR(jl_get_abi_converter), + [](LLVMContext &C, Type *T_size) { + Type *T_ptr = getPointerTy(C); + return FunctionType::get(T_ptr, + {T_ptr, T_ptr, T_ptr, T_ptr}, false); }, + nullptr, +}; static const auto diff_gc_total_bytes_func = new JuliaFunction<>{ XSTR(jl_gc_diff_total_bytes), [](LLVMContext &C) { return FunctionType::get(getInt64Ty(C), false); }, @@ -1462,7 +1462,6 @@ static const auto jlgetbuiltinfptr_func = new JuliaFunction<>{ nullptr, }; - // placeholder functions static const auto gcroot_flush_func = new JuliaFunction<>{ "julia.gcroot_flush", @@ -2095,7 +2094,7 @@ jl_aliasinfo_t jl_aliasinfo_t::fromTBAA(jl_codectx_t &ctx, MDNode *tbaa) { } static Type *julia_type_to_llvm(jl_codectx_t &ctx, jl_value_t *jt, bool *isboxed = NULL); -static jl_returninfo_t get_specsig_function(jl_codectx_t &ctx, Module *M, Value *fval, StringRef name, jl_value_t *sig, jl_value_t *jlrettype, bool is_opaque_closure, bool gcstack_arg, +static jl_returninfo_t get_specsig_function(jl_codegen_params_t &ctx, Module *M, Value *fval, StringRef name, jl_value_t *sig, jl_value_t *jlrettype, bool is_opaque_closure, ArrayRef ArgNames=None, unsigned nreq=0); static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaval = -1); static jl_cgval_t emit_checked_var(jl_codectx_t &ctx, Value *bp, jl_sym_t *name, jl_value_t *scope, bool isvol, MDNode *tbaa); @@ -2107,14 +2106,14 @@ static Value *get_tls_world_age(jl_codectx_t &ctx); static Value *get_scope_field(jl_codectx_t &ctx); static Value *get_tls_world_age_field(jl_codectx_t &ctx); static void CreateTrap(IRBuilder<> &irbuilder, bool create_new_block = true); -static CallInst *emit_jlcall(jl_codectx_t &ctx, FunctionCallee theFptr, Value *theF, +static CallInst *emit_jlcall(jl_codectx_t &ctx, Value *theFptr, Value *theF, ArrayRef args, size_t nargs, JuliaFunction<> *trampoline); static CallInst *emit_jlcall(jl_codectx_t &ctx, JuliaFunction<> *theFptr, Value *theF, ArrayRef args, size_t nargs, JuliaFunction<> *trampoline); static Value *emit_f_is(jl_codectx_t &ctx, const jl_cgval_t &arg1, const jl_cgval_t &arg2, Value *nullcheck1 = nullptr, Value *nullcheck2 = nullptr); static jl_cgval_t emit_new_struct(jl_codectx_t &ctx, jl_value_t *ty, size_t nargs, ArrayRef argv, bool is_promotable=false); -static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayRef argv, size_t nargs, jl_value_t *rt, Value *age_ok); +static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayRef argv, size_t nargs, jl_value_t *rt); static Value *literal_pointer_val(jl_codectx_t &ctx, jl_value_t *p); static unsigned julia_alignment(jl_value_t *jt); @@ -2914,7 +2913,7 @@ static jl_cgval_t convert_julia_type(jl_codectx_t &ctx, const jl_cgval_t &v, jl_ return jl_cgval_t(v, typ, new_tindex); } -std::unique_ptr jl_create_llvm_module(StringRef name, LLVMContext &context, const DataLayout &DL, const Triple &triple) +std::unique_ptr jl_create_llvm_module(StringRef name, LLVMContext &context, const DataLayout &DL, const Triple &triple) JL_NOTSAFEPOINT { ++ModulesCreated; auto m = std::make_unique(name, context); @@ -2941,14 +2940,16 @@ std::unique_ptr jl_create_llvm_module(StringRef name, LLVMContext &conte return m; } -static void jl_name_jlfunc_args(jl_codegen_params_t ¶ms, Function *F) { +static void jl_name_jlfunc_args(jl_codegen_params_t ¶ms, Function *F) JL_NOTSAFEPOINT +{ assert(F->arg_size() == 3); F->getArg(0)->setName("function::Core.Function"); F->getArg(1)->setName("args::Any[]"); F->getArg(2)->setName("nargs::UInt32"); } -static void jl_name_jlfuncparams_args(jl_codegen_params_t ¶ms, Function *F) { +static void jl_name_jlfuncparams_args(jl_codegen_params_t ¶ms, Function *F) JL_NOTSAFEPOINT +{ assert(F->arg_size() == 4); F->getArg(0)->setName("function::Core.Function"); F->getArg(1)->setName("args::Any[]"); @@ -2956,7 +2957,7 @@ static void jl_name_jlfuncparams_args(jl_codegen_params_t ¶ms, Function *F) F->getArg(3)->setName("sparams::Any"); } -void jl_init_function(Function *F, const Triple &TT) +void jl_init_function(Function *F, const Triple &TT) JL_NOTSAFEPOINT { // set any attributes that *must* be set on all functions AttrBuilder attr(F->getContext()); @@ -3020,6 +3021,7 @@ static bool uses_specsig(jl_value_t *sig, bool needsparams, jl_value_t *rettype, bool allSingleton = true; for (size_t i = 0; i < jl_nparams(sig); i++) { jl_value_t *sigt = jl_tparam(sig, i); + // TODO: sigt = unwrap_va(sigt) bool issing = jl_is_datatype(sigt) && jl_is_datatype_singleton((jl_datatype_t*)sigt); allSingleton &= issing; if (!deserves_argbox(sigt) && !issing) { @@ -5311,14 +5313,14 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } // Returns ctx.types().T_prjlvalue -static CallInst *emit_jlcall(jl_codectx_t &ctx, FunctionCallee theFptr, Value *theF, +static CallInst *emit_jlcall(jl_codectx_t &ctx, Value *theFptr, Value *theF, ArrayRef argv, size_t nargs, JuliaFunction<> *trampoline) { ++EmittedJLCalls; Function *TheTrampoline = prepare_call(trampoline); // emit arguments SmallVector theArgs; - theArgs.push_back(theFptr.getCallee()); + theArgs.push_back(theFptr); if (theF) theArgs.push_back(theF); for (size_t i = 0; i < nargs; i++) { @@ -5485,12 +5487,11 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_clos } static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_closure, jl_value_t *specTypes, jl_value_t *jlretty, llvm::Value *callee, StringRef specFunctionObject, jl_code_instance_t *fromexternal, - ArrayRef argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *nreturn_roots, jl_value_t *inferred_retty, Value *age_ok) + ArrayRef argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *nreturn_roots, jl_value_t *inferred_retty) { ++EmittedSpecfunCalls; // emit specialized call site - bool gcstack_arg = JL_FEAT_TEST(ctx, gcstack_arg); - jl_returninfo_t returninfo = get_specsig_function(ctx, jl_Module, callee, specFunctionObject, specTypes, jlretty, is_opaque_closure, gcstack_arg); + jl_returninfo_t returninfo = get_specsig_function(ctx.emission_context, jl_Module, callee, specFunctionObject, specTypes, jlretty, is_opaque_closure); *cc = returninfo.cc; *nreturn_roots = returninfo.return_roots; if (fromexternal) { @@ -5510,31 +5511,17 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_clos setName(ctx.emission_context, TheCallee, namep); returninfo.decl = FunctionCallee(returninfo.decl.getFunctionType(), TheCallee); } - if (age_ok) { - std::string funcName(specFunctionObject); - funcName += "_gfthunk"; - Function *gf_thunk = Function::Create(returninfo.decl.getFunctionType(), - GlobalVariable::InternalLinkage, funcName, jl_Module); - jl_init_function(gf_thunk, ctx.emission_context.TargetTriple); - gf_thunk->setAttributes(AttributeList::get(gf_thunk->getContext(), {returninfo.attrs, gf_thunk->getAttributes()})); - // build a specsig -> jl_apply_generic converter thunk - // this builds a method that calls jl_apply_generic (as a closure over a singleton function pointer), - // but which has the signature of a specsig - emit_specsig_to_fptr1(gf_thunk, returninfo.cc, returninfo.return_roots, specTypes, jlretty, is_opaque_closure, nargs, ctx.emission_context, - prepare_call(jlapplygeneric_func)); - returninfo.decl = FunctionCallee(returninfo.decl.getFunctionType(), ctx.builder.CreateSelect(age_ok, returninfo.decl.getCallee(), gf_thunk)); - } jl_cgval_t retval = emit_call_specfun_other(ctx, is_opaque_closure, specTypes, jlretty, returninfo, argv, nargs); // see if inference has a different / better type for the call than the lambda return update_julia_type(ctx, retval, inferred_retty); } static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, jl_method_instance_t *mi, jl_value_t *jlretty, StringRef specFunctionObject, jl_code_instance_t *fromexternal, - ArrayRef argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *return_roots, jl_value_t *inferred_retty, Value *age_ok) + ArrayRef argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *return_roots, jl_value_t *inferred_retty) { bool is_opaque_closure = jl_is_method(mi->def.value) && mi->def.method->is_for_opaque_closure; return emit_call_specfun_other(ctx, is_opaque_closure, mi->specTypes, jlretty, NULL, - specFunctionObject, fromexternal, argv, nargs, cc, return_roots, inferred_retty, age_ok); + specFunctionObject, fromexternal, argv, nargs, cc, return_roots, inferred_retty); } static jl_value_t *get_ci_abi(jl_code_instance_t *ci) @@ -5545,16 +5532,16 @@ static jl_value_t *get_ci_abi(jl_code_instance_t *ci) } static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, jl_code_instance_t *ci, StringRef specFunctionObject, jl_code_instance_t *fromexternal, - ArrayRef argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *return_roots, jl_value_t *inferred_retty, Value *age_ok) + ArrayRef argv, size_t nargs, jl_returninfo_t::CallingConv *cc, unsigned *return_roots, jl_value_t *inferred_retty) { jl_method_instance_t *mi = jl_get_ci_mi(ci); bool is_opaque_closure = jl_is_method(mi->def.value) && mi->def.method->is_for_opaque_closure; return emit_call_specfun_other(ctx, is_opaque_closure, get_ci_abi(ci), ci->rettype, NULL, - specFunctionObject, fromexternal, argv, nargs, cc, return_roots, inferred_retty, age_ok); + specFunctionObject, fromexternal, argv, nargs, cc, return_roots, inferred_retty); } static jl_cgval_t emit_call_specfun_boxed(jl_codectx_t &ctx, jl_value_t *jlretty, StringRef specFunctionObject, jl_code_instance_t *fromexternal, - ArrayRef argv, size_t nargs, jl_value_t *inferred_retty, Value *age_ok) + ArrayRef argv, size_t nargs, jl_value_t *inferred_retty) { Value *theFptr; if (fromexternal) { @@ -5577,9 +5564,7 @@ static jl_cgval_t emit_call_specfun_boxed(jl_codectx_t &ctx, jl_value_t *jlretty theFptr = jl_Module->getOrInsertFunction(specFunctionObject, ctx.types().T_jlfunc).getCallee(); addRetAttr(cast(theFptr), Attribute::NonNull); } - if (age_ok) - theFptr = ctx.builder.CreateSelect(age_ok, theFptr, prepare_call(jlapplygeneric_func)); - Value *ret = emit_jlcall(ctx, FunctionCallee(ctx.types().T_jlfunc, theFptr), nullptr, argv, nargs, julia_call); + Value *ret = emit_jlcall(ctx, theFptr, nullptr, argv, nargs, julia_call); return update_julia_type(ctx, mark_julia_type(ctx, ret, true, jlretty), inferred_retty); } @@ -5597,10 +5582,10 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, jl_expr_t *ex, jl_value_t *rt) if (argv[i].typ == jl_bottom_type) return jl_cgval_t(); } - return emit_invoke(ctx, lival, argv, nargs, rt, nullptr); + return emit_invoke(ctx, lival, argv, nargs, rt); } -static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayRef argv, size_t nargs, jl_value_t *rt, Value *age_ok) +static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayRef argv, size_t nargs, jl_value_t *rt) { ++EmittedInvokes; bool handled = false; @@ -5633,7 +5618,7 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayR unsigned return_roots = 0; jl_returninfo_t::CallingConv cc = jl_returninfo_t::CallingConv::Boxed; StringRef protoname = f->getName(); - result = emit_call_specfun_other(ctx, mi, ctx.rettype, protoname, nullptr, argv, nargs, &cc, &return_roots, rt, age_ok); + result = emit_call_specfun_other(ctx, mi, ctx.rettype, protoname, nullptr, argv, nargs, &cc, &return_roots, rt); } handled = true; } @@ -5699,9 +5684,9 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayR jl_returninfo_t::CallingConv cc = jl_returninfo_t::CallingConv::Boxed; unsigned return_roots = 0; if (specsig) - result = emit_call_specfun_other(ctx, codeinst, protoname, external ? codeinst : nullptr, argv, nargs, &cc, &return_roots, rt, age_ok); + result = emit_call_specfun_other(ctx, codeinst, protoname, external ? codeinst : nullptr, argv, nargs, &cc, &return_roots, rt); else - result = emit_call_specfun_boxed(ctx, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, rt, age_ok); + result = emit_call_specfun_boxed(ctx, codeinst->rettype, protoname, external ? codeinst : nullptr, argv, nargs, rt); if (need_to_emit) { Function *trampoline_decl = cast(jl_Module->getNamedValue(protoname)); ctx.call_targets[codeinst] = {cc, return_roots, trampoline_decl, nullptr, specsig}; @@ -5726,8 +5711,8 @@ static jl_cgval_t emit_invoke(jl_codectx_t &ctx, const jl_cgval_t &lival, ArrayR print_stacktrace(ctx, ctx.params->trim); } } - Value *r = age_ok ? emit_jlcall(ctx, jlapplygeneric_func, nullptr, argv, nargs, julia_call) : emit_jlcall(ctx, jlinvoke_func, boxed(ctx, lival), argv, nargs, julia_call2); - result = mark_julia_type(ctx, r, true, age_ok ? (jl_value_t*)jl_any_type : rt); + Value *r = emit_jlcall(ctx, jlinvoke_func, boxed(ctx, lival), argv, nargs, julia_call2); + result = mark_julia_type(ctx, r, true, rt); } if (result.typ == jl_bottom_type) { #ifndef JL_NDEBUG @@ -5818,9 +5803,10 @@ static jl_cgval_t emit_specsig_oc_call(jl_codectx_t &ctx, jl_value_t *oc_type, j jl_cgval_t &theArg = argv[0]; jl_cgval_t closure_specptr = emit_getfield_knownidx(ctx, theArg, 4, (jl_datatype_t*)oc_type, jl_memory_order_notatomic); Value *specptr = emit_unbox(ctx, ctx.types().T_size, closure_specptr, (jl_value_t*)jl_long_type); + specptr = emit_inttoptr(ctx, specptr, ctx.types().T_ptr); JL_GC_PUSH1(&sigtype); jl_cgval_t r = emit_call_specfun_other(ctx, true, sigtype, oc_rett, specptr, "", NULL, argv, nargs, - &cc, &return_roots, oc_rett, nullptr); + &cc, &return_roots, oc_rett); JL_GC_POP(); return r; } @@ -5898,14 +5884,14 @@ static jl_cgval_t emit_call(jl_codectx_t &ctx, jl_expr_t *ex, jl_value_t *rt, bo return mark_julia_type(ctx, ret, true, rt); } } - FunctionCallee fptr; + Value *fptr; JuliaFunction<> *cc; if (f.typ == (jl_value_t*)jl_intrinsic_type) { fptr = prepare_call(jlintrinsic_func); cc = julia_call3; } else { - fptr = FunctionCallee(get_func_sig(ctx.builder.getContext()), ctx.builder.CreateCall(prepare_call(jlgetbuiltinfptr_func), {emit_typeof(ctx, f)})); + fptr = ctx.builder.CreateCall(prepare_call(jlgetbuiltinfptr_func), {emit_typeof(ctx, f)}); cc = julia_call; } if (trim_may_error(ctx.params->trim)) { @@ -6723,8 +6709,7 @@ static std::pair get_oc_function(jl_codectx_t &ctx, jl_met bool is_opaque_closure = jl_is_method(mi->def.value) && mi->def.method->is_for_opaque_closure; assert(is_opaque_closure); if (specsig) { - bool gcstack_arg = JL_FEAT_TEST(ctx, gcstack_arg); - jl_returninfo_t returninfo = get_specsig_function(ctx, jl_Module, nullptr, protoname, mi->specTypes, rettype, is_opaque_closure, gcstack_arg); + jl_returninfo_t returninfo = get_specsig_function(ctx.emission_context, jl_Module, nullptr, protoname, mi->specTypes, rettype, is_opaque_closure); cc = returninfo.cc; return_roots = returninfo.return_roots; specF = cast(returninfo.decl.getCallee()); @@ -7192,7 +7177,7 @@ JL_GCC_IGNORE_STOP // --- generate function bodies --- // gc frame emission -static void allocate_gc_frame(jl_codectx_t &ctx, BasicBlock *b0, bool or_new=false) +static void allocate_gc_frame(jl_codectx_t &ctx, BasicBlock *b0, bool or_new=false) JL_NOTSAFEPOINT { // allocate a placeholder gc instruction // this will require the runtime, but it gets deleted later if unused @@ -7244,12 +7229,34 @@ static Value *get_scope_field(jl_codectx_t &ctx) return emit_ptrgep(ctx, ct, offsetof(jl_task_t, scope), "scope"); } +static std::string get_function_name(bool specsig, bool needsparams, const char *unadorned_name, const Triple &TargetTriple) +{ + std::string _funcName; + raw_string_ostream funcName(_funcName); + // try to avoid conflicts in the global symbol table + if (specsig) + funcName << "julia_"; // api 5 + else if (needsparams) + funcName << "japi3_"; + else + funcName << "japi1_"; + if (TargetTriple.isOSLinux()) { + if (unadorned_name[0] == '@') + unadorned_name++; + } + funcName << unadorned_name << "_" << jl_atomic_fetch_add_relaxed(&globalUniqueGeneratedNames, 1); + return funcName.str(); +} + +static void gen_invoke_wrapper(jl_method_instance_t *lam, jl_value_t *abi, jl_value_t *jlretty, jl_value_t *declrt, jl_returninfo_t &f, unsigned nargs, int retarg, bool is_opaque_closure, StringRef funcName, + Module *M, jl_codegen_params_t ¶ms); + Function *get_or_emit_fptr1(StringRef preal_decl, Module *M) { return cast(M->getOrInsertFunction(preal_decl, get_func_sig(M->getContext()), get_func_attrs(M->getContext())).getCallee()); } -Function *emit_tojlinvoke(jl_code_instance_t *codeinst, StringRef theFptrName, Module *M, jl_codegen_params_t ¶ms) JL_NOTSAFEPOINT +Function *emit_tojlinvoke(jl_code_instance_t *codeinst, Value *theFunc, Module *M, jl_codegen_params_t ¶ms) JL_NOTSAFEPOINT { ++EmittedToJLInvokes; jl_codectx_t ctx(M->getContext(), params, codeinst); @@ -7265,14 +7272,11 @@ Function *emit_tojlinvoke(jl_code_instance_t *codeinst, StringRef theFptrName, M jl_name_jlfunc_args(params, f); //f->setAlwaysInline(); ctx.f = f; // for jl_Module - BasicBlock *b0 = BasicBlock::Create(ctx.builder.getContext(), "top", f); + BasicBlock *b0 = BasicBlock::Create(M->getContext(), "top", f); ctx.builder.SetInsertPoint(b0); - Function *theFunc; Value *theFarg; - if (!theFptrName.empty()) { - theFunc = cast( - M->getOrInsertFunction(theFptrName, jlinvoke_func->_type(ctx.builder.getContext())).getCallee()); + if (theFunc) { theFarg = literal_pointer_val(ctx, (jl_value_t*)codeinst); } else { @@ -7283,12 +7287,20 @@ Function *emit_tojlinvoke(jl_code_instance_t *codeinst, StringRef theFptrName, M } theFarg = track_pjlvalue(ctx, theFarg); auto args = f->arg_begin(); - CallInst *r = ctx.builder.CreateCall(theFunc, { &*args, &*++args, &*++args, theFarg }); - r->setAttributes(theFunc->getAttributes()); + CallInst *r = ctx.builder.CreateCall(FunctionCallee(jlinvoke_func->_type(M->getContext()), theFunc), { &*args, &*++args, &*++args, theFarg }); + r->setAttributes(jlinvoke_func->_attrs(M->getContext())); ctx.builder.CreateRet(r); return f; } +Function *emit_tojlinvoke(jl_code_instance_t *codeinst, StringRef theFptrName, Module *M, jl_codegen_params_t ¶ms) JL_NOTSAFEPOINT +{ + Value *theFunc = nullptr; + if (!theFptrName.empty()) + theFunc = M->getOrInsertFunction(theFptrName, jlinvoke_func->_type(M->getContext()), jlinvoke_func->_attrs(M->getContext())).getCallee(); + return emit_tojlinvoke(codeinst, theFunc, M, params); +} + static jl_value_t *get_oc_type(jl_value_t *calltype, jl_value_t *rettype) JL_ALWAYS_LEAFTYPE { jl_value_t *argtype = jl_argtype_without_function((jl_value_t*)calltype); @@ -7299,12 +7311,16 @@ static jl_value_t *get_oc_type(jl_value_t *calltype, jl_value_t *rettype) JL_ALW return oc_type; } -void emit_specsig_to_fptr1( +static void emit_specsig_to_specsig( Function *gf_thunk, jl_returninfo_t::CallingConv cc, unsigned return_roots, jl_value_t *calltype, jl_value_t *rettype, bool is_for_opaque_closure, size_t nargs, jl_codegen_params_t ¶ms, - Function *target) + Value *target, + jl_value_t *targetsig, + jl_value_t *targetrt, + jl_returninfo_t *targetspec, + jl_value_t *rettype_const) { ++EmittedCFuncInvalidates; jl_codectx_t ctx(gf_thunk->getParent()->getContext(), params, 0, 0); @@ -7321,7 +7337,7 @@ void emit_specsig_to_fptr1( ++AI; if (return_roots) ++AI; - if (JL_FEAT_TEST(ctx,gcstack_arg)){ + if (JL_FEAT_TEST(ctx,gcstack_arg)) { ++AI; // gcstack_arg } for (size_t i = 0; i < nargs; i++) { @@ -7372,16 +7388,23 @@ void emit_specsig_to_fptr1( } } assert(AI == gf_thunk->arg_end()); - Value *gf_ret = emit_jlcall(ctx, target, nullptr, myargs, nargs, julia_call); - jl_cgval_t gf_retbox = mark_julia_type(ctx, gf_ret, true, jl_any_type); - if (cc != jl_returninfo_t::Boxed) { - emit_typecheck(ctx, gf_retbox, rettype, "cfunction"); - gf_retbox = update_julia_type(ctx, gf_retbox, rettype); + jl_cgval_t gf_retval; + if (target || targetspec) { + if (targetspec == nullptr) + gf_retval = mark_julia_type(ctx, emit_jlcall(ctx, target, nullptr, myargs, nargs, julia_call), true, targetrt); + else + gf_retval = emit_call_specfun_other(ctx, is_for_opaque_closure, targetsig, targetrt, *targetspec, myargs, nargs); + } + if (rettype_const) + gf_retval = mark_julia_const(ctx, rettype_const); + if (targetrt != rettype) { + emit_typecheck(ctx, gf_retval, rettype, "cfunction"); + gf_retval = update_julia_type(ctx, gf_retval, rettype); } switch (cc) { case jl_returninfo_t::Boxed: - ctx.builder.CreateRet(gf_ret); + ctx.builder.CreateRet(boxed(ctx, gf_retval)); break; case jl_returninfo_t::Register: { Type *gfrt = gf_thunk->getReturnType(); @@ -7389,7 +7412,7 @@ void emit_specsig_to_fptr1( ctx.builder.CreateRetVoid(); } else { - ctx.builder.CreateRet(ctx.builder.CreateAlignedLoad(gfrt, gf_ret, Align(julia_alignment(rettype)))); + ctx.builder.CreateRet(emit_unbox(ctx, gfrt, gf_retval, rettype)); } break; } @@ -7398,65 +7421,273 @@ void emit_specsig_to_fptr1( Align align(julia_alignment(rettype)); if (return_roots) { Value *roots = gf_thunk->arg_begin() + 1; // root1 has type [n x {}*]* - split_value_into(ctx, gf_retbox, align, sret, align, jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_stack), roots, jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe)); + split_value_into(ctx, gf_retval, align, sret, align, jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_stack), roots, jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe)); } else { - emit_unbox_store(ctx, gf_retbox, sret, ctx.tbaa().tbaa_stack, align); + emit_unbox_store(ctx, gf_retval, sret, ctx.tbaa().tbaa_stack, align); } ctx.builder.CreateRetVoid(); break; } case jl_returninfo_t::Union: { + Value *gf_ret = boxed(ctx, gf_retval); // TODO: this is not the most optimal way to emit this Type *retty = gf_thunk->getReturnType(); - Value *gf_retval = UndefValue::get(retty); - Value *tindex = compute_box_tindex(ctx, emit_typeof(ctx, gf_retbox, false, true), (jl_value_t*)jl_any_type, rettype); + Value *retval = UndefValue::get(retty); + Value *tindex = compute_box_tindex(ctx, emit_typeof(ctx, gf_retval, false, true), (jl_value_t*)jl_any_type, rettype); tindex = ctx.builder.CreateOr(tindex, ConstantInt::get(getInt8Ty(ctx.builder.getContext()), UNION_BOX_MARKER)); - gf_retval = ctx.builder.CreateInsertValue(gf_retval, gf_ret, 0); - gf_retval = ctx.builder.CreateInsertValue(gf_retval, tindex, 1); - ctx.builder.CreateRet(gf_retval); + retval = ctx.builder.CreateInsertValue(retval, gf_ret, 0); + retval = ctx.builder.CreateInsertValue(retval, tindex, 1); + ctx.builder.CreateRet(retval); break; } case jl_returninfo_t::Ghosts: { - Value *gf_retval = compute_tindex_unboxed(ctx, gf_retbox, rettype); - ctx.builder.CreateRet(gf_retval); + Value *retval = compute_tindex_unboxed(ctx, gf_retval, rettype); + ctx.builder.CreateRet(retval); break; } } } +void emit_specsig_to_fptr1( + Function *gf_thunk, jl_returninfo_t::CallingConv cc, unsigned return_roots, + jl_value_t *calltype, jl_value_t *rettype, bool is_for_opaque_closure, + size_t nargs, + jl_codegen_params_t ¶ms, + Function *target) +{ + emit_specsig_to_specsig(gf_thunk, cc, return_roots, calltype, rettype, is_for_opaque_closure, nargs, params, target, calltype, rettype, nullptr, nullptr); +} + +static void emit_fptr1_wrapper(Module *M, StringRef gf_thunk_name, Value *target, jl_value_t *rettype_const, jl_value_t *declrt, jl_value_t *jlrettype, jl_codegen_params_t ¶ms) +{ + Function *w = Function::Create(get_func_sig(M->getContext()), GlobalVariable::ExternalLinkage, gf_thunk_name, M); + jl_init_function(w, params.TargetTriple); + w->setAttributes(AttributeList::get(M->getContext(), {get_func_attrs(M->getContext()), w->getAttributes()})); + w->addFnAttr(Attribute::OptimizeNone); + w->addFnAttr(Attribute::NoInline); + + jl_codectx_t ctx(M->getContext(), params, 0, 0); + ctx.f = w; + ctx.rettype = declrt; + + BasicBlock *b0 = BasicBlock::Create(ctx.builder.getContext(), "top", w); + ctx.builder.SetInsertPoint(b0); + DebugLoc noDbg; + ctx.builder.SetCurrentDebugLocation(noDbg); + allocate_gc_frame(ctx, b0); + + jl_cgval_t gf_retval; + if (target) { + FunctionCallee theFunc(w->getFunctionType(), target); + auto args = w->arg_begin(); + CallInst *r = ctx.builder.CreateCall(theFunc, { &*args, &*++args, &*++args }); // cf emit_tojlinvoke + assert(++args == w->arg_end()); + r->setAttributes(w->getAttributes()); + gf_retval = mark_julia_type(ctx, r, true, jlrettype); + } + if (rettype_const) + gf_retval = mark_julia_const(ctx, rettype_const); + if (jlrettype != declrt) + emit_typecheck(ctx, gf_retval, declrt, "cfunction"); + ctx.builder.CreateRet(boxed(ctx, gf_retval)); +} + +static void emit_specsig_to_specsig( + Module *M, StringRef gf_thunk_name, + jl_value_t *calltype, jl_value_t *rettype, bool is_for_opaque_closure, + size_t nargs, + jl_codegen_params_t ¶ms, + Value *target, + jl_value_t *targetsig, + jl_value_t *targetrt, + jl_returninfo_t *targetspec, + jl_value_t *rettype_const) +{ + jl_returninfo_t returninfo = get_specsig_function(params, M, nullptr, gf_thunk_name, calltype, rettype, is_for_opaque_closure); + Function *gf_thunk = cast(returninfo.decl.getCallee()); + jl_init_function(gf_thunk, params.TargetTriple); + gf_thunk->setAttributes(AttributeList::get(gf_thunk->getContext(), {returninfo.attrs, gf_thunk->getAttributes()})); + emit_specsig_to_specsig(gf_thunk, returninfo.cc, returninfo.return_roots, calltype, rettype, is_for_opaque_closure, nargs, params, target, targetsig, targetrt, targetspec, rettype_const); +} + +std::string emit_abi_converter(Module *M, jl_codegen_params_t ¶ms, jl_value_t *declrt, jl_value_t *sigt, size_t nargs, bool specsig, jl_code_instance_t *codeinst, Value *target, bool target_specsig) +{ + // this builds a method that calls a method with the same arguments but a different specsig + // build a specsig -> specsig converter thunk + // build a specsig -> arg1 converter thunk + // build a args1 -> specsig converter thunk (gen_invoke_wrapper) + // build a args1 -> args1 converter thunk (to add typeassert on result) + bool needsparams = false; + bool is_opaque_closure = false; + jl_method_instance_t *mi = jl_get_ci_mi(codeinst); + std::string gf_thunk_name = get_function_name(specsig, needsparams, name_from_method_instance(mi), params.TargetTriple); + gf_thunk_name += "_gfthunk"; + if (target_specsig) { + jl_value_t *abi = get_ci_abi(codeinst); + jl_returninfo_t targetspec = get_specsig_function(params, M, target, "", abi, codeinst->rettype, is_opaque_closure); + if (specsig) + emit_specsig_to_specsig(M, gf_thunk_name, sigt, declrt, is_opaque_closure, nargs, params, + target, mi->specTypes, codeinst->rettype, &targetspec, nullptr); + else + gen_invoke_wrapper(mi, abi, codeinst->rettype, declrt, targetspec, nargs, -1, is_opaque_closure, gf_thunk_name, M, params); + } + else { + if (specsig) + emit_specsig_to_specsig(M, gf_thunk_name, sigt, declrt, is_opaque_closure, nargs, params, + target, mi->specTypes, codeinst->rettype, nullptr, nullptr); + else + emit_fptr1_wrapper(M, gf_thunk_name, target, nullptr, declrt, codeinst->rettype, params); + } + return gf_thunk_name; +} + +std::string emit_abi_dispatcher(Module *M, jl_codegen_params_t ¶ms, jl_value_t *declrt, jl_value_t *sigt, size_t nargs, bool specsig, jl_code_instance_t *codeinst, Value *invoke) +{ + // this builds a method that calls a method with the same arguments but a different specsig + // build a specsig -> args1 (apply_generic) or invoke (emit_tojlinvoke) call + // build a args1 -> args1 call (emit_fptr1_wrapper) + // build a args1 -> invoke call (emit_tojlinvoke) + bool is_opaque_closure = false; + Value *target; + if (!codeinst) + target = prepare_call_in(M, jlapplygeneric_func); + else + target = emit_tojlinvoke(codeinst, invoke, M, params); // TODO: inline this call? + std::string gf_thunk_name; + if (codeinst) + raw_string_ostream(gf_thunk_name) << "jfptr_" << name_from_method_instance(jl_get_ci_mi(codeinst)) << "_"; + else + raw_string_ostream(gf_thunk_name) << "j_"; + raw_string_ostream(gf_thunk_name) << jl_atomic_fetch_add_relaxed(&globalUniqueGeneratedNames, 1) << "_gfthunk"; + if (specsig) + emit_specsig_to_specsig(M, gf_thunk_name, sigt, declrt, is_opaque_closure, nargs, params, + target, sigt, codeinst ? codeinst->rettype : (jl_value_t*)jl_any_type, nullptr, nullptr); + else + emit_fptr1_wrapper(M, gf_thunk_name, target, nullptr, declrt, codeinst ? codeinst->rettype : (jl_value_t*)jl_any_type, params); + return gf_thunk_name; +} + +std::string emit_abi_constreturn(Module *M, jl_codegen_params_t ¶ms, jl_value_t *declrt, jl_value_t *sigt, size_t nargs, bool specsig, jl_value_t *rettype_const) +{ + bool is_opaque_closure = false; + std::string gf_thunk_name; + raw_string_ostream(gf_thunk_name) << "jconst_" << jl_atomic_fetch_add_relaxed(&globalUniqueGeneratedNames, 1); + if (specsig) { + emit_specsig_to_specsig(M, gf_thunk_name, sigt, declrt, is_opaque_closure, nargs, params, + nullptr, sigt, jl_typeof(rettype_const), nullptr, rettype_const); + } + else { + emit_fptr1_wrapper(M, gf_thunk_name, nullptr, rettype_const, declrt, jl_typeof(rettype_const), params); + } + return gf_thunk_name; +} + +std::string emit_abi_constreturn(Module *M, jl_codegen_params_t ¶ms, bool specsig, jl_code_instance_t *codeinst) +{ + jl_value_t *abi = get_ci_abi(codeinst); + return emit_abi_constreturn(M, params, codeinst->rettype, abi, specsig ? jl_nparams(abi) : 0, specsig, codeinst->rettype_const); +} + +// release jl_world_counter +// store theFptr +// release last_world_v +// +// acquire last_world_v +// read theFptr +// acquire jl_world_counter +// if (last_world_v != jl_world_counter) +// fptr = compute_new_fptr(&last_world_v) +// return fptr() +static jl_cgval_t emit_abi_call(jl_codectx_t &ctx, jl_value_t *declrt, jl_value_t *sigt, ArrayRef inputargs, size_t nargs, Value *world_age_field) +{ + jl_cgval_t retval; + if (sigt) { + jl_temporary_root(ctx, declrt); + jl_temporary_root(ctx, sigt); + assert(nargs == jl_nparams(sigt)); + bool needsparams = false; + bool is_opaque_closure = false; + bool specsig = uses_specsig(sigt, needsparams, declrt, ctx.params->prefer_specsig); + PointerType *T_ptr = ctx.types().T_ptr; + Type *T_size = ctx.types().T_size; + Constant *Vnull = ConstantPointerNull::get(T_ptr); + Module *M = jl_Module; + GlobalVariable *theFptr = new GlobalVariable(*M, T_ptr, false, + GlobalVariable::PrivateLinkage, + Vnull); + GlobalVariable *last_world_p = new GlobalVariable(*M, T_size, false, + GlobalVariable::PrivateLinkage, + ConstantInt::get(T_size, 0)); + ArrayType *T_cfuncdata = ArrayType::get(T_ptr, 6); + size_t flags = specsig; + GlobalVariable *cfuncdata = new GlobalVariable(*M, T_cfuncdata, false, + GlobalVariable::PrivateLinkage, + ConstantArray::get(T_cfuncdata, { + Vnull, + Vnull, + Vnull, + literal_pointer_val_slot(ctx.emission_context, M, declrt), + literal_pointer_val_slot(ctx.emission_context, M, sigt), + literal_static_pointer_val((void*)flags, T_ptr)})); + LoadInst *last_world_v = ctx.builder.CreateAlignedLoad(T_size, last_world_p, ctx.types().alignof_ptr); + last_world_v->setOrdering(AtomicOrdering::Acquire); + LoadInst *callee = ctx.builder.CreateAlignedLoad(T_ptr, theFptr, ctx.types().alignof_ptr); + callee->setOrdering(AtomicOrdering::Monotonic); + LoadInst *world_v = ctx.builder.CreateAlignedLoad(ctx.types().T_size, + prepare_global_in(M, jlgetworld_global), ctx.types().alignof_ptr); + world_v->setOrdering(AtomicOrdering::Acquire); + ctx.builder.CreateStore(world_v, world_age_field); + Value *age_not_ok = ctx.builder.CreateICmpNE(last_world_v, world_v); + Value *target = emit_guarded_test(ctx, age_not_ok, callee, [&] { + Function *getcaller = prepare_call(jlgetabiconverter_func); + CallInst *cw = ctx.builder.CreateCall(getcaller, { + get_current_task(ctx), + theFptr, + last_world_p, + cfuncdata}); + cw->setAttributes(getcaller->getAttributes()); + return cw; + }); + ctx.emission_context.cfuncs.push_back({declrt, sigt, nargs, specsig, theFptr, cfuncdata}); + if (specsig) { + // TODO: could we force this to guarantee passing a box for `f` here (since we + // know we had it here) and on the receiver end (emit_abi_converter / + // emit_abi_dispatcher), force it to know that it can simply use this pointer + // instead of re-boxing it if it needs to the boxed copy of it. This comes up + // very rarely since usually the ABI calls are concrete and match exactly and + // aren't closures, but sometimes there are cases like that because of + // `::Function` de-specialization heuristics, such as for the `Returns` callable + // given that it is `@nospecialize`. + jl_returninfo_t targetspec = get_specsig_function(ctx.emission_context, M, target, "", sigt, declrt, is_opaque_closure); + retval = emit_call_specfun_other(ctx, is_opaque_closure, sigt, declrt, targetspec, inputargs, nargs); + } + else { + retval = mark_julia_type(ctx, emit_jlcall(ctx, target, nullptr, inputargs, nargs, julia_call), true, declrt); + } + } + else { + // emit a dispatch + Value *ret = emit_jlcall(ctx, jlapplygeneric_func, NULL, inputargs, nargs, julia_call); + retval = mark_julia_type(ctx, ret, true, jl_any_type); + // inline a call to typeassert here + emit_typecheck(ctx, retval, declrt, "cfunction"); + retval = update_julia_type(ctx, retval, declrt); + } + return retval; +} + static Function *gen_cfun_wrapper( Module *into, jl_codegen_params_t ¶ms, const function_sig_t &sig, jl_value_t *ff, const char *aliasname, - jl_value_t *declrt, jl_method_instance_t *lam, + jl_value_t *declrt, jl_value_t *sigt, jl_unionall_t *unionall_env, jl_svec_t *sparam_vals, jl_array_t **closure_types) { ++GeneratedCFuncWrappers; // Generate a c-callable wrapper assert(into); size_t nargs = sig.nccallargs; - const char *name = "cfunction"; - size_t world = jl_atomic_load_acquire(&jl_world_counter); + const char *name = aliasname ? aliasname : "cfunction"; bool nest = (!ff || unionall_env); - jl_value_t *astrt = (jl_value_t*)jl_any_type; - if (aliasname) - name = aliasname; - else if (lam) - name = jl_symbol_name(lam->def.method->name); - - jl_code_instance_t *codeinst = NULL; - if (lam) { - // TODO: this isn't ideal to be unconditionally calling type inference from here - codeinst = jl_type_infer(lam, world, SOURCE_MODE_NOT_REQUIRED); - if (codeinst) - astrt = codeinst->rettype; - if (astrt != (jl_value_t*)jl_bottom_type && - jl_type_intersection(astrt, declrt) == jl_bottom_type) { - // Do not warn if the function never returns since it is - // occasionally required by the C API (typically error callbacks) - // even though we're likely to encounter memory errors in that case - jl_printf(JL_STDERR, "WARNING: cfunction: return type of %s does not match\n", name); - } - } std::string funcName; raw_string_ostream(funcName) << "jlcapi_" << name << "_" << jl_atomic_fetch_add_relaxed(&globalUniqueGeneratedNames, 1); @@ -7538,19 +7769,6 @@ static Function *gen_cfun_wrapper( jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe); ctx.world_age_at_entry = ai.decorateInst( ctx.builder.CreateAlignedLoad(ctx.types().T_size, world_age_field, ctx.types().alignof_ptr)); - Value *world_v = ctx.builder.CreateAlignedLoad(ctx.types().T_size, - prepare_global_in(jl_Module, jlgetworld_global), ctx.types().alignof_ptr); - cast(world_v)->setOrdering(AtomicOrdering::Acquire); - - Value *age_ok = nullptr; - if (codeinst) { - LoadInst *lam_max = ctx.builder.CreateAlignedLoad( - ctx.types().T_size, - emit_ptrgep(ctx, literal_pointer_val(ctx, (jl_value_t*)codeinst), offsetof(jl_code_instance_t, max_world)), - ctx.types().alignof_ptr); - age_ok = ctx.builder.CreateICmpUGE(lam_max, world_v); - } - ctx.builder.CreateStore(world_v, world_age_field); // first emit code to record the arguments Function::arg_iterator AI = cw->arg_begin(); @@ -7705,30 +7923,8 @@ static Function *gen_cfun_wrapper( assert(AI == cw->arg_end()); // Create the call - bool jlfunc_sret; - jl_cgval_t retval; - if (codeinst) { - retval = emit_invoke(ctx, mark_julia_const(ctx, (jl_value_t*)codeinst), inputargs, nargs + 1, astrt, age_ok); - jlfunc_sret = retval.V && isa(retval.V) && !retval.TIndex && retval.inline_roots.empty(); - if (jlfunc_sret && sig.sret) { - // fuse the two sret together - assert(retval.ispointer()); - AllocaInst *result = cast(retval.V); - retval.V = sretPtr; - result->replaceAllUsesWith(sretPtr); - result->eraseFromParent(); - } - } - else { - // emit a dispatch - jlfunc_sret = false; - Value *ret = emit_jlcall(ctx, jlapplygeneric_func, NULL, inputargs, nargs + 1, julia_call); - retval = mark_julia_type(ctx, ret, true, astrt); - } - - // inline a call to typeassert here, if required - emit_typecheck(ctx, retval, declrt, "cfunction"); - retval = update_julia_type(ctx, retval, declrt); + jl_cgval_t retval = emit_abi_call(ctx, declrt, sigt, inputargs, nargs + 1, world_age_field); + bool jlfunc_sret = retval.V && isa(retval.V) && !retval.TIndex && retval.inline_roots.empty(); // Prepare the return value Value *r; @@ -7738,7 +7934,12 @@ static Function *gen_cfun_wrapper( r = boxed(ctx, retval); } else if (sig.sret && jlfunc_sret) { - // nothing to do + // fuse the two sret together + assert(retval.ispointer()); + AllocaInst *result = cast(retval.V); + retval.V = sretPtr; + result->replaceAllUsesWith(sretPtr); + result->eraseFromParent(); r = NULL; } else if (!type_is_ghost(sig.lrt)) { @@ -7761,14 +7962,6 @@ static Function *gen_cfun_wrapper( ctx.builder.SetCurrentDebugLocation(noDbg); ctx.builder.ClearInsertionPoint(); - if (aliasname) { - auto alias = GlobalAlias::create(cw->getValueType(), cw->getType()->getAddressSpace(), - GlobalValue::ExternalLinkage, aliasname, cw, M); - if(ctx.emission_context.TargetTriple.isOSBinFormatCOFF()) { - alias->setDLLStorageClass(GlobalValue::DLLStorageClassTypes::DLLExportStorageClass); - } - } - if (nest) { funcName += "make"; Function *cw_make = Function::Create( @@ -7797,6 +7990,26 @@ static Function *gen_cfun_wrapper( return cw; } +static const char *derive_sigt_name(jl_value_t *jargty) +{ + jl_datatype_t *dt = (jl_datatype_t*)jl_argument_datatype(jargty); + if ((jl_value_t*)dt == jl_nothing) + return NULL; + jl_sym_t *name = dt->name->name; + // if we have a kwcall, use that as the name anyways + jl_methtable_t *mt = dt->name->mt; + if (mt == jl_type_type_mt || mt == jl_nonfunction_mt || mt == NULL) { + // our value for `name` from MethodTable is not good, try to come up with something better + if (jl_is_type_type((jl_value_t*)dt)) { + dt = (jl_datatype_t*)jl_argument_datatype(jl_tparam0(dt)); + if ((jl_value_t*)dt != jl_nothing) { + name = dt->name->name; + } + } + } + return jl_symbol_name(name); +} + // Get the LLVM Function* for the C-callable entry point for a certain function // and argument types. // here argt does not include the leading function type argument @@ -7896,13 +8109,11 @@ static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, con return jl_cgval_t(); } } - size_t world = jl_atomic_load_acquire(&jl_world_counter); - // try to look up this function for direct invoking - jl_method_instance_t *lam = sigt ? jl_get_specialization1((jl_tupletype_t*)sigt, world, 0) : NULL; + const char *name = derive_sigt_name(fexpr_rt.typ); Value *F = gen_cfun_wrapper( jl_Module, ctx.emission_context, - sig, fexpr_rt.constant, NULL, - declrt, lam, + sig, fexpr_rt.constant, name, + declrt, sigt, unionall_env, sparam_vals, &closure_types); bool outboxed; if (nest) { @@ -7967,6 +8178,7 @@ const char *jl_generate_ccallable(Module *llvmmod, void *sysimg_handle, jl_value { ++GeneratedCCallables; jl_datatype_t *ft = (jl_datatype_t*)jl_tparam0(sigt); + assert(jl_is_datatype(ft)); jl_value_t *ff = ft->instance; assert(ff); const char *name = jl_symbol_name(ft->name->mt->name); @@ -7991,7 +8203,6 @@ const char *jl_generate_ccallable(Module *llvmmod, void *sysimg_handle, jl_value function_sig_t sig("cfunction", lcrt, crt, toboxed, argtypes, NULL, false, CallingConv::C, false, ¶ms); if (sig.err_msg.empty()) { - size_t world = jl_atomic_load_acquire(&jl_world_counter); if (sysimg_handle) { // restore a ccallable from the system image void *addr; @@ -8004,9 +8215,13 @@ const char *jl_generate_ccallable(Module *llvmmod, void *sysimg_handle, jl_value } } else { - jl_method_instance_t *lam = jl_get_specialization1((jl_tupletype_t*)sigt, world, 0); //Safe b/c params holds context lock - gen_cfun_wrapper(llvmmod, params, sig, ff, name, declrt, lam, NULL, NULL, NULL); + Function *cw = gen_cfun_wrapper(llvmmod, params, sig, ff, name, declrt, sigt, NULL, NULL, NULL); + auto alias = GlobalAlias::create(cw->getValueType(), cw->getType()->getAddressSpace(), + GlobalValue::ExternalLinkage, name, cw, llvmmod); + if (params.TargetTriple.isOSBinFormatCOFF()) { + alias->setDLLStorageClass(GlobalValue::DLLStorageClassTypes::DLLExportStorageClass); + } } JL_GC_POP(); return name; @@ -8018,7 +8233,7 @@ const char *jl_generate_ccallable(Module *llvmmod, void *sysimg_handle, jl_value // generate a julia-callable function that calls f (AKA lam) // if is_opaque_closure, then generate the OC invoke, rather than a real invoke -static void gen_invoke_wrapper(jl_method_instance_t *lam, jl_value_t *abi, jl_value_t *jlretty, jl_returninfo_t &f, unsigned nargs, int retarg, bool is_opaque_closure, StringRef funcName, +static void gen_invoke_wrapper(jl_method_instance_t *lam, jl_value_t *abi, jl_value_t *jlretty, jl_value_t *declrt, jl_returninfo_t &f, unsigned nargs, int retarg, bool is_opaque_closure, StringRef funcName, Module *M, jl_codegen_params_t ¶ms) { ++GeneratedInvokeWrappers; @@ -8069,6 +8284,10 @@ static void gen_invoke_wrapper(jl_method_instance_t *lam, jl_value_t *abi, jl_va argv[i] = mark_julia_type(ctx, theArg, true, ty); } jl_cgval_t retval = emit_call_specfun_other(ctx, is_opaque_closure, abi, jlretty, f, argv, nargs); + if (declrt != jlretty) { + emit_typecheck(ctx, retval, declrt, "cfunction"); + retval = update_julia_type(ctx, retval, declrt); + } if (retarg != -1) { Value *theArg; if (retarg == 0) @@ -8085,20 +8304,22 @@ static void gen_invoke_wrapper(jl_method_instance_t *lam, jl_value_t *abi, jl_va ctx.builder.CreateRet(boxed(ctx, retval)); } -static jl_returninfo_t get_specsig_function(jl_codectx_t &ctx, Module *M, Value *fval, StringRef name, jl_value_t *sig, jl_value_t *jlrettype, bool is_opaque_closure, bool gcstack_arg, +static jl_returninfo_t get_specsig_function(jl_codegen_params_t ¶ms, Module *M, Value *fval, StringRef name, jl_value_t *sig, jl_value_t *jlrettype, bool is_opaque_closure, ArrayRef ArgNames, unsigned nreq) { + bool gcstack_arg = params.params->gcstack_arg; jl_returninfo_t props = {}; SmallVector fsig; SmallVector argnames; Type *rt = NULL; Type *srt = NULL; + Type *T_prjlvalue = PointerType::get(M->getContext(), AddressSpace::Tracked); if (jlrettype == (jl_value_t*)jl_bottom_type) { - rt = getVoidTy(ctx.builder.getContext()); + rt = getVoidTy(M->getContext()); props.cc = jl_returninfo_t::Register; } else if (jl_is_structtype(jlrettype) && jl_is_datatype_singleton((jl_datatype_t*)jlrettype)) { - rt = getVoidTy(ctx.builder.getContext()); + rt = getVoidTy(M->getContext()); props.cc = jl_returninfo_t::Register; } else if (jl_is_uniontype(jlrettype)) { @@ -8106,25 +8327,25 @@ static jl_returninfo_t get_specsig_function(jl_codectx_t &ctx, Module *M, Value union_alloca_type((jl_uniontype_t*)jlrettype, allunbox, props.union_bytes, props.union_align, props.union_minalign); if (props.union_bytes) { props.cc = jl_returninfo_t::Union; - Type *AT = ArrayType::get(getInt8Ty(ctx.builder.getContext()), props.union_bytes); + Type *AT = ArrayType::get(getInt8Ty(M->getContext()), props.union_bytes); fsig.push_back(AT->getPointerTo()); argnames.push_back("union_bytes_return"); - Type *pair[] = { ctx.types().T_prjlvalue, getInt8Ty(ctx.builder.getContext()) }; - rt = StructType::get(ctx.builder.getContext(), ArrayRef(pair)); + Type *pair[] = { T_prjlvalue, getInt8Ty(M->getContext()) }; + rt = StructType::get(M->getContext(), ArrayRef(pair)); } else if (allunbox) { props.cc = jl_returninfo_t::Ghosts; - rt = getInt8Ty(ctx.builder.getContext()); + rt = getInt8Ty(M->getContext()); } else { - rt = ctx.types().T_prjlvalue; + rt = T_prjlvalue; } } else if (!deserves_retbox(jlrettype)) { bool retboxed; - rt = julia_type_to_llvm(ctx, jlrettype, &retboxed); + rt = _julia_type_to_llvm(¶ms, M->getContext(), jlrettype, &retboxed); assert(!retboxed); - if (rt != getVoidTy(ctx.builder.getContext()) && deserves_sret(jlrettype, rt)) { + if (rt != getVoidTy(M->getContext()) && deserves_sret(jlrettype, rt)) { auto tracked = CountTrackedPointers(rt, true); assert(!tracked.derived); if (tracked.count && !tracked.all) { @@ -8139,53 +8360,53 @@ static jl_returninfo_t get_specsig_function(jl_codectx_t &ctx, Module *M, Value fsig.push_back(rt->getPointerTo(M->getDataLayout().getAllocaAddrSpace())); argnames.push_back("sret_return"); srt = rt; - rt = getVoidTy(ctx.builder.getContext()); + rt = getVoidTy(M->getContext()); } else { props.cc = jl_returninfo_t::Register; } } else { - rt = ctx.types().T_prjlvalue; + rt = T_prjlvalue; } SmallVector attrs; // function declaration attributes if (props.cc == jl_returninfo_t::SRet) { assert(srt); - AttrBuilder param(ctx.builder.getContext()); + AttrBuilder param(M->getContext()); param.addStructRetAttr(srt); param.addAttribute(Attribute::NoAlias); param.addAttribute(Attribute::NoCapture); param.addAttribute(Attribute::NoUndef); - attrs.push_back(AttributeSet::get(ctx.builder.getContext(), param)); + attrs.push_back(AttributeSet::get(M->getContext(), param)); assert(fsig.size() == 1); } if (props.cc == jl_returninfo_t::Union) { - AttrBuilder param(ctx.builder.getContext()); + AttrBuilder param(M->getContext()); param.addAttribute(Attribute::NoAlias); param.addAttribute(Attribute::NoCapture); param.addAttribute(Attribute::NoUndef); - attrs.push_back(AttributeSet::get(ctx.builder.getContext(), param)); + attrs.push_back(AttributeSet::get(M->getContext(), param)); assert(fsig.size() == 1); } if (props.return_roots) { - AttrBuilder param(ctx.builder.getContext()); + AttrBuilder param(M->getContext()); param.addAttribute(Attribute::NoAlias); param.addAttribute(Attribute::NoCapture); param.addAttribute(Attribute::NoUndef); - attrs.push_back(AttributeSet::get(ctx.builder.getContext(), param)); - fsig.push_back(ctx.types().T_ptr); + attrs.push_back(AttributeSet::get(M->getContext(), param)); + fsig.push_back(getPointerTy(M->getContext())); argnames.push_back("return_roots"); } - if (gcstack_arg){ - AttrBuilder param(ctx.builder.getContext()); - if (ctx.emission_context.use_swiftcc) + if (gcstack_arg) { + AttrBuilder param(M->getContext()); + if (params.use_swiftcc) param.addAttribute(Attribute::SwiftSelf); param.addAttribute(Attribute::NonNull); - attrs.push_back(AttributeSet::get(ctx.builder.getContext(), param)); - fsig.push_back(PointerType::get(JuliaType::get_ppjlvalue_ty(ctx.builder.getContext()), 0)); + attrs.push_back(AttributeSet::get(M->getContext(), param)); + fsig.push_back(PointerType::get(M->getContext(), 0)); argnames.push_back("pgcstack_arg"); } @@ -8198,16 +8419,16 @@ static jl_returninfo_t get_specsig_function(jl_codectx_t &ctx, Module *M, Value if (is_uniquerep_Type(jt)) continue; isboxed = deserves_argbox(jt); - et = isboxed ? ctx.types().T_prjlvalue : julia_type_to_llvm(ctx, jt); + et = isboxed ? T_prjlvalue : _julia_type_to_llvm(¶ms, M->getContext(), jt, nullptr); if (type_is_ghost(et)) continue; } - AttrBuilder param(ctx.builder.getContext()); + AttrBuilder param(M->getContext()); Type *ty = et; if (et == nullptr || et->isAggregateType()) { // aggregate types are passed by pointer param.addAttribute(Attribute::NoCapture); param.addAttribute(Attribute::ReadOnly); - ty = ctx.builder.getPtrTy(AddressSpace::Derived); + ty = PointerType::get(M->getContext(), AddressSpace::Derived); } else if (isboxed && jl_is_immutable_datatype(jt)) { param.addAttribute(Attribute::ReadOnly); @@ -8217,7 +8438,7 @@ static jl_returninfo_t get_specsig_function(jl_codectx_t &ctx, Module *M, Value Attribute::AttrKind attr = issigned ? Attribute::SExt : Attribute::ZExt; param.addAttribute(attr); } - attrs.push_back(AttributeSet::get(ctx.builder.getContext(), param)); + attrs.push_back(AttributeSet::get(M->getContext(), param)); fsig.push_back(ty); size_t argno = i < nreq ? i : nreq; std::string genname; @@ -8233,8 +8454,8 @@ static jl_returninfo_t get_specsig_function(jl_codectx_t &ctx, Module *M, Value if (et && et->isAggregateType()) { auto tracked = CountTrackedPointers(et); if (tracked.count && !tracked.all) { - attrs.push_back(AttributeSet::get(ctx.builder.getContext(), param)); - fsig.push_back(ctx.builder.getPtrTy(M->getDataLayout().getAllocaAddrSpace())); + attrs.push_back(AttributeSet::get(M->getContext(), param)); + fsig.push_back(PointerType::get(M->getContext(), M->getDataLayout().getAllocaAddrSpace())); if (!genname.empty()) argnames.push_back((Twine(".roots.") + genname).str()); } @@ -8244,25 +8465,26 @@ static jl_returninfo_t get_specsig_function(jl_codectx_t &ctx, Module *M, Value AttributeSet FnAttrs; AttributeSet RetAttrs; if (jlrettype == (jl_value_t*)jl_bottom_type) - FnAttrs = FnAttrs.addAttribute(ctx.builder.getContext(), Attribute::NoReturn); - else if (rt == ctx.types().T_prjlvalue) - RetAttrs = RetAttrs.addAttribute(ctx.builder.getContext(), Attribute::NonNull); - AttributeList attributes = AttributeList::get(ctx.builder.getContext(), FnAttrs, RetAttrs, attrs); + FnAttrs = FnAttrs.addAttribute(M->getContext(), Attribute::NoReturn); + else if (rt == T_prjlvalue) + RetAttrs = RetAttrs.addAttribute(M->getContext(), Attribute::NonNull); + AttributeList attributes = AttributeList::get(M->getContext(), FnAttrs, RetAttrs, attrs); FunctionType *ftype = FunctionType::get(rt, fsig, false); if (fval == NULL) { Function *f = M ? cast_or_null(M->getNamedValue(name)) : NULL; if (f == NULL) { f = Function::Create(ftype, GlobalVariable::ExternalLinkage, name, M); - jl_init_function(f, ctx.emission_context.TargetTriple); - if (ctx.emission_context.params->debug_info_level >= 2) { + jl_init_function(f, params.TargetTriple); + if (params.params->debug_info_level >= 2) { ios_t sigbuf; ios_mem(&sigbuf, 0); jl_static_show_func_sig((JL_STREAM*) &sigbuf, sig); - f->setAttributes(AttributeList::get(f->getContext(), {attributes.addFnAttribute(ctx.builder.getContext(),"julia.fsig", StringRef(sigbuf.buf, sigbuf.size)), f->getAttributes()})); + f->setAttributes(AttributeList::get(f->getContext(), {attributes.addFnAttribute(M->getContext(),"julia.fsig", StringRef(sigbuf.buf, sigbuf.size)), f->getAttributes()})); ios_close(&sigbuf); - } else + } else { f->setAttributes(AttributeList::get(f->getContext(), {attributes, f->getAttributes()})); + } } else { assert(f->getFunctionType() == ftype); @@ -8270,11 +8492,10 @@ static jl_returninfo_t get_specsig_function(jl_codectx_t &ctx, Module *M, Value fval = f; } else { - if (fval->getType()->isIntegerTy()) - fval = emit_inttoptr(ctx, fval, ftype->getPointerTo()); + assert(fval->getType()->isPointerTy()); } if (auto F = dyn_cast(fval)) { - if (gcstack_arg && ctx.emission_context.use_swiftcc) + if (gcstack_arg && params.use_swiftcc) F->setCallingConv(CallingConv::Swift); assert(F->arg_size() >= argnames.size()); for (size_t i = 0; i < argnames.size(); i++) { @@ -8321,25 +8542,6 @@ static jl_datatype_t *compute_va_type(jl_value_t *sig, size_t nreq) return (jl_datatype_t*)typ; } -static std::string get_function_name(bool specsig, bool needsparams, const char *unadorned_name, const Triple &TargetTriple) -{ - std::string _funcName; - raw_string_ostream funcName(_funcName); - // try to avoid conflicts in the global symbol table - if (specsig) - funcName << "julia_"; // api 5 - else if (needsparams) - funcName << "japi3_"; - else - funcName << "japi1_"; - if (TargetTriple.isOSLinux()) { - if (unadorned_name[0] == '@') - unadorned_name++; - } - funcName << unadorned_name << "_" << jl_atomic_fetch_add_relaxed(&globalUniqueGeneratedNames, 1); - return funcName.str(); -} - // Compile to LLVM IR, using a specialized signature if applicable. static jl_llvm_functions_t emit_function( @@ -8555,8 +8757,8 @@ static jl_llvm_functions_t ArgNames[i] = name; } } - returninfo = get_specsig_function(ctx, M, NULL, declarations.specFunctionObject, abi, - jlrettype, ctx.is_opaque_closure, JL_FEAT_TEST(ctx,gcstack_arg), + returninfo = get_specsig_function(params, M, NULL, declarations.specFunctionObject, abi, + jlrettype, ctx.is_opaque_closure, ArgNames, nreq); f = cast(returninfo.decl.getCallee()); has_sret = (returninfo.cc == jl_returninfo_t::SRet || returninfo.cc == jl_returninfo_t::Union); @@ -8590,7 +8792,7 @@ static jl_llvm_functions_t raw_string_ostream(wrapName) << "jfptr_" << ctx.name << "_" << jl_atomic_fetch_add_relaxed(&globalUniqueGeneratedNames, 1); declarations.functionObject = wrapName; size_t nparams = jl_nparams(abi); - gen_invoke_wrapper(lam, abi, jlrettype, returninfo, nparams, retarg, ctx.is_opaque_closure, declarations.functionObject, M, ctx.emission_context); + gen_invoke_wrapper(lam, abi, jlrettype, jlrettype, returninfo, nparams, retarg, ctx.is_opaque_closure, declarations.functionObject, M, ctx.emission_context); // TODO: add attributes: maybe_mark_argument_dereferenceable(Arg, argType) // TODO: add attributes: dereferenceable // TODO: (if needsparams) add attributes: dereferenceable, readonly, nocapture @@ -9958,6 +10160,39 @@ static jl_llvm_functions_t // --- entry point --- +jl_llvm_functions_t jl_emit_codedecls( + orc::ThreadSafeModule &M, + jl_code_instance_t *codeinst, + jl_codegen_params_t ¶ms) +{ + jl_llvm_functions_t decls = {}; + jl_method_instance_t *mi = jl_get_ci_mi(codeinst); + bool specsig, needsparams; + std::tie(specsig, needsparams) = uses_specsig(get_ci_abi(codeinst), mi, codeinst->rettype, params.params->prefer_specsig); + const char *name = name_from_method_instance(mi); + if (specsig) + raw_string_ostream(decls.functionObject) << "jfptr_" << name << "_" << jl_atomic_fetch_add_relaxed(&globalUniqueGeneratedNames, 1); + else if (needsparams) + decls.functionObject = "jl_fptr_sparam"; + else + decls.functionObject = "jl_fptr_args"; + raw_string_ostream(decls.specFunctionObject) << (specsig ? "j_" : "j1_") << name << "_" << jl_atomic_fetch_add_relaxed(&globalUniqueGeneratedNames, 1); + M.withModuleDo([&](Module &M) { + bool is_opaque_closure = jl_is_method(mi->def.value) && mi->def.method->is_for_opaque_closure; + if (specsig) { + get_specsig_function(params, &M, nullptr, decls.specFunctionObject, get_ci_abi(codeinst), codeinst->rettype, is_opaque_closure); + } + else { + Function *f = Function::Create(needsparams ? JuliaType::get_jlfuncparams_ty(M.getContext()) : JuliaType::get_jlfunc_ty(M.getContext()), + GlobalVariable::ExternalLinkage, + decls.specFunctionObject, M); + jl_init_function(f, params.TargetTriple); + f->setAttributes(AttributeList::get(M.getContext(), {get_func_attrs(M.getContext()), f->getAttributes()})); + } + }); + return decls; +} + jl_llvm_functions_t jl_emit_code( orc::ThreadSafeModule &m, jl_method_instance_t *li, @@ -10012,7 +10247,7 @@ static jl_llvm_functions_t jl_emit_oc_wrapper(orc::ThreadSafeModule &m, jl_codeg jl_codectx_t ctx(M->getContext(), params, 0, 0); ctx.name = M->getModuleIdentifier().data(); std::string funcName = get_function_name(true, false, ctx.name, ctx.emission_context.TargetTriple); - jl_returninfo_t returninfo = get_specsig_function(ctx, M, NULL, funcName, mi->specTypes, rettype, true, JL_FEAT_TEST(ctx,gcstack_arg)); + jl_returninfo_t returninfo = get_specsig_function(params, M, NULL, funcName, mi->specTypes, rettype, true); Function *gf_thunk = cast(returninfo.decl.getCallee()); jl_init_function(gf_thunk, ctx.emission_context.TargetTriple); size_t nrealargs = jl_nparams(mi->specTypes); @@ -10032,8 +10267,8 @@ jl_llvm_functions_t jl_emit_codeinst( { JL_TIMING(CODEGEN, CODEGEN_Codeinst); jl_timing_show_method_instance(jl_get_ci_mi(codeinst), JL_TIMING_DEFAULT_BLOCK); + jl_method_instance_t *mi = jl_get_ci_mi(codeinst); if (!src) { - jl_method_instance_t *mi = jl_get_ci_mi(codeinst); // Assert that this this is the generic method for opaque closure wrappers: // this signals to instead compile specptr such that it holds the specptr -> invoke wrapper // to satisfy the dispatching implementation requirements of jl_f_opaque_closure_call @@ -10044,7 +10279,7 @@ jl_llvm_functions_t jl_emit_codeinst( return jl_llvm_functions_t(); // user error } //assert(jl_egal((jl_value_t*)jl_atomic_load_relaxed(&codeinst->debuginfo), (jl_value_t*)src->debuginfo) && "trying to generate code for a codeinst for an incompatible src"); - jl_llvm_functions_t decls = jl_emit_code(m, jl_get_ci_mi(codeinst), src, get_ci_abi(codeinst), codeinst->rettype, params); + jl_llvm_functions_t decls = jl_emit_code(m, mi, src, get_ci_abi(codeinst), codeinst->rettype, params); return decls; } @@ -10152,6 +10387,7 @@ static void init_jit_functions(void) add_named_global(jlunlockvalue_func, &jl_unlock_value); add_named_global(jllockfield_func, &jl_lock_field); add_named_global(jlunlockfield_func, &jl_unlock_field); + add_named_global(jlgetabiconverter_func, &jl_get_abi_converter); #ifdef _OS_WINDOWS_ #if defined(_CPU_X86_64_) diff --git a/src/gf.c b/src/gf.c index 710dda208f0b2..82e1e43333eb4 100644 --- a/src/gf.c +++ b/src/gf.c @@ -3165,6 +3165,7 @@ jl_method_instance_t *jl_normalize_to_compilable_mi(jl_method_instance_t *mi JL_ JL_DLLEXPORT jl_method_instance_t *jl_method_match_to_mi(jl_method_match_t *match, size_t world, size_t min_valid, size_t max_valid, int mt_cache) { jl_method_t *m = match->method; + JL_GC_PROMISE_ROOTED(m); jl_svec_t *env = match->sparams; jl_tupletype_t *ti = match->spec_types; jl_method_instance_t *mi = NULL; @@ -3200,7 +3201,7 @@ JL_DLLEXPORT jl_method_instance_t *jl_method_match_to_mi(jl_method_match_t *matc } // compile-time method lookup -jl_method_instance_t *jl_get_specialization1(jl_tupletype_t *types JL_PROPAGATES_ROOT, size_t world, int mt_cache) +jl_method_instance_t *jl_get_specialization1(jl_tupletype_t *types, size_t world, int mt_cache) { if (jl_has_free_typevars((jl_value_t*)types)) return NULL; // don't poison the cache due to a malformed query diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index e4dc2459e8db6..4006397d08ea1 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -454,6 +454,7 @@ static Value *emit_unbox(jl_codectx_t &ctx, Type *to, const jl_cgval_t &x, jl_va Constant *c = x.constant ? julia_const_to_llvm(ctx, x.constant) : nullptr; if ((x.inline_roots.empty() && !x.ispointer()) || c != nullptr) { // already unboxed, but sometimes need conversion Value *unboxed = c ? c : x.V; + assert(unboxed); // clang-sa doesn't know that !x.ispointer() implies x.V does have a value return emit_unboxed_coercion(ctx, to, unboxed); } @@ -461,6 +462,7 @@ static Value *emit_unbox(jl_codectx_t &ctx, Type *to, const jl_cgval_t &x, jl_va Value *p = x.constant ? literal_pointer_val(ctx, x.constant) : x.V; if (jt == (jl_value_t*)jl_bool_type || to->isIntegerTy(1)) { + assert(p && x.inline_roots.empty()); // clang-sa doesn't know that x.ispointer() implied these are true jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, x.tbaa); Instruction *unbox_load = ai.decorateInst(ctx.builder.CreateLoad(getInt8Ty(ctx.builder.getContext()), p)); setName(ctx.emission_context, unbox_load, p->getName() + ".unbox"); @@ -486,6 +488,7 @@ static Value *emit_unbox(jl_codectx_t &ctx, Type *to, const jl_cgval_t &x, jl_va p = combined; ai = combined_ai; } + assert(p); // clang-sa doesn't know that x.ispointer() implied this is true Instruction *load = ctx.builder.CreateAlignedLoad(to, p, Align(alignment)); setName(ctx.emission_context, load, p->getName() + ".unbox"); return ai.decorateInst(load); diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 0acb7beaca9ab..80642bef95619 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -213,13 +213,84 @@ static void jl_optimize_roots(jl_codegen_params_t ¶ms, jl_method_instance_t JL_UNLOCK(&m->writelock); } -void jl_jit_globals(std::map &globals) JL_NOTSAFEPOINT +static void finish_params(Module *M, jl_codegen_params_t ¶ms, SmallVector &sharedmodules) JL_NOTSAFEPOINT { - for (auto &global : globals) { - jl_link_global(global.second, global.first); + if (params._shared_module) { + sharedmodules.push_back(orc::ThreadSafeModule(std::move(params._shared_module), params.tsctx)); + } + + // In imaging mode, we can't inline global variable initializers in order to preserve + // the fiction that we don't know what loads from the global will return. Thus, we + // need to emit a separate module for the globals before any functions are compiled, + // to ensure that the globals are defined when they are compiled. + if (jl_options.image_codegen) { + if (!params.global_targets.empty()) { + void **globalslots = new void*[params.global_targets.size()]; + void **slot = globalslots; + for (auto &global : params.global_targets) { + auto GV = global.second; + *slot = global.first; + jl_ExecutionEngine->addGlobalMapping(GV->getName(), (uintptr_t)slot); + slot++; + } +#ifdef __clang_analyzer__ + static void **leaker = globalslots; // for the purpose of the analyzer, we need to expressly leak this variable or it thinks we forgot to free it +#endif + } + } + else { + StringMap NewGlobals; + for (auto &global : params.global_targets) { + NewGlobals[global.second->getName()] = global.first; + } + for (auto &GV : M->globals()) { + auto InitValue = NewGlobals.find(GV.getName()); + if (InitValue != NewGlobals.end()) { + jl_link_global(&GV, InitValue->second); + } + } } } +extern "C" JL_DLLEXPORT_CODEGEN +void *jl_jit_abi_converter_impl(jl_task_t *ct, void *unspecialized, jl_value_t *declrt, jl_value_t *sigt, size_t nargs, int specsig, + jl_code_instance_t *codeinst, jl_callptr_t invoke, void *target, int target_specsig) +{ + if (codeinst == nullptr && unspecialized != nullptr) + return unspecialized; + orc::ThreadSafeModule result_m; + std::string gf_thunk_name; + { + jl_codegen_params_t params(std::make_unique(), jl_ExecutionEngine->getDataLayout(), jl_ExecutionEngine->getTargetTriple()); // Locks the context + params.getContext().setDiscardValueNames(true); + params.cache = true; + params.imaging_mode = 0; + result_m = jl_create_ts_module("gfthunk", params.tsctx, params.DL, params.TargetTriple); + Module *M = result_m.getModuleUnlocked(); + if (target) { + Value *llvmtarget = literal_static_pointer_val((void*)target, PointerType::get(M->getContext(), 0)); + gf_thunk_name = emit_abi_converter(M, params, declrt, sigt, nargs, specsig, codeinst, llvmtarget, target_specsig); + } + else if (invoke == jl_fptr_const_return_addr) { + gf_thunk_name = emit_abi_constreturn(M, params, declrt, sigt, nargs, specsig, codeinst->rettype_const); + } + else { + Value *llvminvoke = invoke ? literal_static_pointer_val((void*)invoke, PointerType::get(M->getContext(), 0)) : nullptr; + gf_thunk_name = emit_abi_dispatcher(M, params, declrt, sigt, nargs, specsig, codeinst, llvminvoke); + } + SmallVector sharedmodules; + finish_params(M, params, sharedmodules); + assert(sharedmodules.empty()); + } + int8_t gc_state = jl_gc_safe_enter(ct->ptls); + jl_ExecutionEngine->addModule(std::move(result_m)); + uintptr_t Addr = jl_ExecutionEngine->getFunctionAddress(gf_thunk_name); + jl_gc_safe_leave(ct->ptls, gc_state); + assert(Addr); + return (void*)Addr; +} + + // lock for places where only single threaded behavior is implemented, so we need GC support static jl_mutex_t jitlock; // locks for adding external code to the JIT atomically @@ -262,45 +333,6 @@ static DenseMap> incompl // as materialization may need to acquire TSC locks. -static void finish_params(Module *M, jl_codegen_params_t ¶ms) JL_NOTSAFEPOINT -{ - if (params._shared_module) { - sharedmodules.push_back(orc::ThreadSafeModule(std::move(params._shared_module), params.tsctx)); - } - - // In imaging mode, we can't inline global variable initializers in order to preserve - // the fiction that we don't know what loads from the global will return. Thus, we - // need to emit a separate module for the globals before any functions are compiled, - // to ensure that the globals are defined when they are compiled. - if (jl_options.image_codegen) { - if (!params.global_targets.empty()) { - void **globalslots = new void*[params.global_targets.size()]; - void **slot = globalslots; - for (auto &global : params.global_targets) { - auto GV = global.second; - *slot = global.first; - jl_ExecutionEngine->addGlobalMapping(GV->getName(), (uintptr_t)slot); - slot++; - } -#ifdef __clang_analyzer__ - static void **leaker = globalslots; // for the purpose of the analyzer, we need to expressly leak this variable or it thinks we forgot to free it -#endif - } - } - else { - StringMap NewGlobals; - for (auto &global : params.global_targets) { - NewGlobals[global.second->getName()] = global.first; - } - for (auto &GV : M->globals()) { - auto InitValue = NewGlobals.find(GV.getName()); - if (InitValue != NewGlobals.end()) { - jl_link_global(&GV, InitValue->second); - } - } - } -} - static int jl_analyze_workqueue(jl_code_instance_t *callee, jl_codegen_params_t ¶ms, bool forceall=false) JL_NOTSAFEPOINT_LEAVE JL_NOTSAFEPOINT_ENTER { jl_task_t *ct = jl_current_task; @@ -516,7 +548,7 @@ static void prepare_compile(jl_code_instance_t *codeinst) JL_NOTSAFEPOINT_LEAVE waiting = jl_analyze_workqueue(codeinst, params, true); // may safepoint assert(!waiting); (void)waiting; Module *M = emittedmodules[codeinst].getModuleUnlocked(); - finish_params(M, params); + finish_params(M, params, sharedmodules); incompletemodules.erase(it); } // and then indicate this should be compiled now @@ -548,7 +580,7 @@ static void complete_emit(jl_code_instance_t *edge) JL_NOTSAFEPOINT_LEAVE JL_NOT int waiting = jl_analyze_workqueue(callee, params); // may safepoint assert(!waiting); (void)waiting; Module *M = emittedmodules[callee].getModuleUnlocked(); - finish_params(M, params); + finish_params(M, params, sharedmodules); incompletemodules.erase(it); } } @@ -764,7 +796,7 @@ void jl_emit_codeinst_to_jit_impl( incompletemodules.try_emplace(codeinst, std::move(params), waiting); } else { - finish_params(result_m.getModuleUnlocked(), params); + finish_params(result_m.getModuleUnlocked(), params, sharedmodules); } emittedmodules[codeinst] = std::move(result_m); } @@ -832,7 +864,7 @@ int jl_compile_extern_c_impl(LLVMOrcThreadSafeModuleRef llvmmod, void *p, void * } jl_analyze_workqueue(nullptr, params, true); assert(params.workqueue.empty()); - finish_params(&M, params); + finish_params(&M, params, sharedmodules); } } pparams = nullptr; diff --git a/src/jitlayers.h b/src/jitlayers.h index 4637670ec588c..139137d0ca477 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -212,6 +212,16 @@ struct jl_codegen_call_target_t { bool specsig; }; +// reification of a call to jl_jit_abi_convert, so that it isn't necessary to parse the Modules to recover this info +struct cfunc_decl_t { + jl_value_t *declrt; + jl_value_t *sigt; + size_t nargs; + bool specsig; + llvm::GlobalVariable *theFptr; + llvm::GlobalVariable *cfuncdata; +}; + typedef SmallVector, 0> jl_workqueue_t; typedef std::list> CallFrames; @@ -227,6 +237,7 @@ struct jl_codegen_params_t { typedef StringMap SymMapGV; // outputs jl_workqueue_t workqueue; + SmallVector cfuncs; std::map global_targets; jl_array_t *temporary_roots = nullptr; std::map, GlobalVariable*> external_fns; @@ -288,6 +299,11 @@ jl_llvm_functions_t jl_emit_codeinst( jl_code_info_t *src, jl_codegen_params_t ¶ms); +jl_llvm_functions_t jl_emit_codedecls( + orc::ThreadSafeModule &M, + jl_code_instance_t *codeinst, + jl_codegen_params_t ¶ms); + enum CompilationPolicy { Default = 0, Extern = 1, @@ -296,6 +312,13 @@ enum CompilationPolicy { Function *jl_cfunction_object(jl_function_t *f, jl_value_t *rt, jl_tupletype_t *argt, jl_codegen_params_t ¶ms); +extern "C" JL_DLLEXPORT_CODEGEN +void *jl_jit_abi_convert(jl_task_t *ct, jl_value_t *declrt, jl_value_t *sigt, size_t nargs, bool specsig, _Atomic(void*) *fptr, _Atomic(size_t) *last_world, void *data); +std::string emit_abi_dispatcher(Module *M, jl_codegen_params_t ¶ms, jl_value_t *declrt, jl_value_t *sigt, size_t nargs, bool specsig, jl_code_instance_t *codeinst, Value *invoke); +std::string emit_abi_converter(Module *M, jl_codegen_params_t ¶ms, jl_value_t *declrt, jl_value_t *sigt, size_t nargs, bool specsig, jl_code_instance_t *codeinst, Value *target, bool target_specsig); +std::string emit_abi_constreturn(Module *M, jl_codegen_params_t ¶ms, jl_value_t *declrt, jl_value_t *sigt, size_t nargs, bool specsig, jl_value_t *rettype_const); +std::string emit_abi_constreturn(Module *M, jl_codegen_params_t ¶ms, bool specsig, jl_code_instance_t *codeinst); + Function *emit_tojlinvoke(jl_code_instance_t *codeinst, StringRef theFptrName, Module *M, jl_codegen_params_t ¶ms) JL_NOTSAFEPOINT; void emit_specsig_to_fptr1( Function *gf_thunk, jl_returninfo_t::CallingConv cc, unsigned return_roots, @@ -308,6 +331,8 @@ void jl_init_function(Function *F, const Triple &TT) JL_NOTSAFEPOINT; void add_named_global(StringRef name, void *addr) JL_NOTSAFEPOINT; +Constant *literal_pointer_val_slot(jl_codegen_params_t ¶ms, Module *M, jl_value_t *p); + static inline Constant *literal_static_pointer_val(const void *p, Type *T) JL_NOTSAFEPOINT { // this function will emit a static pointer into the generated code diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index 4d1ab94644e39..21b5afa74c5f4 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -547,6 +547,7 @@ YY(jl_getUnwindInfo) \ YY(jl_get_libllvm) \ YY(jl_register_passbuilder_callbacks) \ + YY(jl_jit_abi_converter) \ YY(JLJITGetLLVMOrcExecutionSession) \ YY(JLJITGetJuliaOJIT) \ YY(JLJITGetExternalJITDylib) \ diff --git a/src/julia_internal.h b/src/julia_internal.h index 9817c8cc8263b..41a650969ae01 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -1229,15 +1229,15 @@ _Atomic(jl_value_t*) *jl_table_peek_bp(jl_genericmemory_t *a, jl_value_t *key) J JL_DLLEXPORT jl_method_t *jl_new_method_uninit(jl_module_t*); JL_DLLEXPORT jl_methtable_t *jl_new_method_table(jl_sym_t *name, jl_module_t *module); -JL_DLLEXPORT jl_method_instance_t *jl_get_specialization1(jl_tupletype_t *types, size_t world, int mt_cache); -jl_method_instance_t *jl_get_specialized(jl_method_t *m, jl_value_t *types, jl_svec_t *sp); +JL_DLLEXPORT jl_method_instance_t *jl_get_specialization1(jl_tupletype_t *types JL_PROPAGATES_ROOT, size_t world, int mt_cache); +jl_method_instance_t *jl_get_specialized(jl_method_t *m, jl_value_t *types, jl_svec_t *sp) JL_PROPAGATES_ROOT; JL_DLLEXPORT jl_value_t *jl_rettype_inferred(jl_value_t *owner, jl_method_instance_t *li JL_PROPAGATES_ROOT, size_t min_world, size_t max_world); JL_DLLEXPORT jl_value_t *jl_rettype_inferred_native(jl_method_instance_t *mi, size_t min_world, size_t max_world) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_code_instance_t *jl_method_compiled(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t world) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_methtable_lookup(jl_methtable_t *mt JL_PROPAGATES_ROOT, jl_value_t *type, size_t world); JL_DLLEXPORT jl_method_instance_t *jl_specializations_get_linfo( jl_method_t *m JL_PROPAGATES_ROOT, jl_value_t *type, jl_svec_t *sparams); -jl_method_instance_t *jl_specializations_get_or_insert(jl_method_instance_t *mi_ins); +jl_method_instance_t *jl_specializations_get_or_insert(jl_method_instance_t *mi_ins JL_PROPAGATES_ROOT); JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, jl_value_t *invokesig, jl_code_instance_t *caller); JL_DLLEXPORT void jl_method_table_add_backedge(jl_methtable_t *mt, jl_value_t *typ, jl_code_instance_t *caller); JL_DLLEXPORT void jl_mi_cache_insert(jl_method_instance_t *mi JL_ROOTING_ARGUMENT, @@ -1557,6 +1557,9 @@ JL_DLLEXPORT jl_value_t *jl_get_cfunction_trampoline( jl_value_t *fobj, jl_datatype_t *result, htable_t *cache, jl_svec_t *fill, void *(*init_trampoline)(void *tramp, void **nval), jl_unionall_t *env, jl_value_t **vals); +JL_DLLEXPORT void *jl_get_abi_converter(jl_task_t *ct, _Atomic(void*) *fptr, _Atomic(size_t) *last_world, void *data); +JL_DLLIMPORT void *jl_jit_abi_converter(jl_task_t *ct, void *unspecialized, jl_value_t *declrt, jl_value_t *sigt, size_t nargs, int specsig, + jl_code_instance_t *codeinst, jl_callptr_t invoke, void *target, int target_specsig); // Special filenames used to refer to internal julia libraries diff --git a/src/runtime_ccall.cpp b/src/runtime_ccall.cpp index 2a6cb00961594..dd5ceb2c6ad90 100644 --- a/src/runtime_ccall.cpp +++ b/src/runtime_ccall.cpp @@ -326,6 +326,136 @@ jl_value_t *jl_get_cfunction_trampoline( } JL_GCC_IGNORE_STOP +struct cfuncdata_t { + jl_code_instance_t** plast_codeinst; + jl_code_instance_t* last_codeinst; + void *unspecialized; + jl_value_t *const *const declrt; + jl_value_t *const *const sigt; + size_t flags; +}; + +extern "C" JL_DLLEXPORT +void *jl_jit_abi_converter_fallback(jl_task_t *ct, void *unspecialized, jl_value_t *declrt, jl_value_t *sigt, size_t nargs, int specsig, + jl_code_instance_t *codeinst, jl_callptr_t invoke, void *target, int target_specsig) +{ + if (unspecialized) + return unspecialized; + jl_errorf("cfunction not available in this build of Julia"); +} + +static const inline char *name_from_method_instance(jl_method_instance_t *li) JL_NOTSAFEPOINT +{ + return jl_is_method(li->def.method) ? jl_symbol_name(li->def.method->name) : "top-level scope"; +} + +static jl_mutex_t cfun_lock; +// release jl_world_counter +// store theFptr +// release last_world_v +// +// acquire last_world_v +// read theFptr +// acquire jl_world_counter +extern "C" JL_DLLEXPORT +void *jl_get_abi_converter(jl_task_t *ct, _Atomic(void*) *fptr, _Atomic(size_t) *last_world, void *data) +{ + cfuncdata_t *cfuncdata = (cfuncdata_t*)data; + jl_value_t *sigt = *cfuncdata->sigt; + JL_GC_PROMISE_ROOTED(sigt); + jl_value_t *declrt = *cfuncdata->declrt; + JL_GC_PROMISE_ROOTED(declrt); + bool specsig = cfuncdata->flags & 1; + size_t nargs = jl_nparams(sigt); + jl_method_instance_t *mi; + jl_code_instance_t *codeinst; + size_t world; + // check first, while behind this lock, of the validity of the current contents of this cfunc thunk + JL_LOCK(&cfun_lock); + do { + size_t last_world_v = jl_atomic_load_relaxed(last_world); + void *f = jl_atomic_load_relaxed(fptr); + jl_code_instance_t *last_ci = cfuncdata->plast_codeinst ? *cfuncdata->plast_codeinst : nullptr; + world = jl_atomic_load_acquire(&jl_world_counter); + ct->world_age = world; + if (world == last_world_v) { + JL_UNLOCK(&cfun_lock); + return f; + } + mi = jl_get_specialization1((jl_tupletype_t*)sigt, world, 0); + if (f != nullptr) { + if (last_ci == nullptr) { + if (mi == nullptr) { + jl_atomic_store_release(last_world, world); + JL_UNLOCK(&cfun_lock); + return f; + } + } + else { + if (jl_get_ci_mi(last_ci) == mi && jl_atomic_load_relaxed(&last_ci->max_world) >= world) { // same dispatch and source + jl_atomic_store_release(last_world, world); + JL_UNLOCK(&cfun_lock); + return f; + } + } + } + JL_UNLOCK(&cfun_lock); + // next, try to figure out what the target should look like (outside of the lock since this is very slow) + codeinst = mi ? jl_type_infer(mi, world, SOURCE_MODE_ABI) : nullptr; + // relock for the remainder of the function + JL_LOCK(&cfun_lock); + } while (jl_atomic_load_acquire(&jl_world_counter) != world); // restart entirely, since jl_world_counter changed thus jl_get_specialization1 might have changed + // double-check if the values were set on another thread + size_t last_world_v = jl_atomic_load_relaxed(last_world); + void *f = jl_atomic_load_relaxed(fptr); + if (world == last_world_v) { + JL_UNLOCK(&cfun_lock); + return f; // another thread fixed this up while we were away + } + auto assign_fptr = [fptr, last_world, cfuncdata, world, codeinst](void *f) { + cfuncdata->plast_codeinst = &cfuncdata->last_codeinst; + cfuncdata->last_codeinst = codeinst; + jl_atomic_store_relaxed(fptr, f); + jl_atomic_store_release(last_world, world); + JL_UNLOCK(&cfun_lock); + return f; + }; + jl_callptr_t invoke = nullptr; + if (codeinst != NULL) { + jl_value_t *astrt = codeinst->rettype; + if (astrt != (jl_value_t*)jl_bottom_type && + jl_type_intersection(astrt, declrt) == jl_bottom_type) { + // Do not warn if the function never returns since it is + // occasionally required by the C API (typically error callbacks) + // even though we're likely to encounter memory errors in that case + jl_printf(JL_STDERR, "WARNING: cfunction: return type of %s does not match\n", name_from_method_instance(mi)); + } + uint8_t specsigflags; + jl_read_codeinst_invoke(codeinst, &specsigflags, &invoke, &f, 1); + if (invoke != nullptr) { + if (invoke == jl_fptr_const_return_addr) { + return assign_fptr(jl_jit_abi_converter(ct, cfuncdata->unspecialized, declrt, sigt, nargs, specsig, codeinst, invoke, nullptr, false)); + } + else if (invoke == jl_fptr_args_addr) { + assert(f); + if (!specsig && jl_subtype(astrt, declrt)) + return assign_fptr(f); + return assign_fptr(jl_jit_abi_converter(ct, cfuncdata->unspecialized, declrt, sigt, nargs, specsig, codeinst, invoke, f, false)); + } + else if (specsigflags & 0b1) { + assert(f); + if (specsig && jl_egal(mi->specTypes, sigt) && jl_egal(declrt, astrt)) + return assign_fptr(f); + return assign_fptr(jl_jit_abi_converter(ct, cfuncdata->unspecialized, declrt, sigt, nargs, specsig, codeinst, invoke, f, true)); + } + } + } + f = jl_jit_abi_converter(ct, cfuncdata->unspecialized, declrt, sigt, nargs, specsig, codeinst, invoke, nullptr, false); + if (codeinst == nullptr) + cfuncdata->unspecialized = f; + return assign_fptr(f); +} + void jl_init_runtime_ccall(void) { JL_MUTEX_INIT(&libmap_lock, "libmap_lock"); diff --git a/src/staticdata.c b/src/staticdata.c index cb1dc54d26d50..ec77c771bd880 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -1859,6 +1859,9 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED else if (invokeptr_id == -4) { fptr_id = JL_API_OC_CALL; } + else if (invokeptr_id == -5) { + abort(); + } else { assert(invokeptr_id > 0); ios_ensureroom(s->fptr_record, invokeptr_id * sizeof(void*)); From 888cf0350668a677ef27c87ab80a8562f3bc211e Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Thu, 6 Feb 2025 01:14:47 -0500 Subject: [PATCH 290/342] bpart: Fully switch to partitioned semantics (#57253) This is the final PR in the binding partitions series (modulo bugs and tweaks), i.e. it closes #54654 and thus closes #40399, which was the original design sketch. This thus activates the full designed semantics for binding partitions, in particular allowing safe replacement of const bindings. It in particular allows struct redefinitions. This thus closes timholy/Revise.jl#18 and also closes #38584. The biggest semantic change here is probably that this gets rid of the notion of "resolvedness" of a binding. Previously, a lot of the behavior of our implementation depended on when bindings were "resolved", which could happen at basically an arbitrary point (in the compiler, in REPL completion, in a different thread), making a lot of the semantics around bindings ill- or at least implementation-defined. There are several related issues in the bugtracker, so this closes #14055 closes #44604 closes #46354 closes #30277 It is also the last step to close #24569. It also supports bindings for undef->defined transitions and thus closes #53958 closes #54733 - however, this is not activated yet for performance reasons and may need some further optimization. Since resolvedness no longer exists, we need to replace it with some hopefully more well-defined semantics. I will describe the semantics below, but before I do I will make two notes: 1. There are a number of cases where these semantics will behave slightly differently than the old semantics absent some other task going around resolving random bindings. 2. The new behavior (except for the replacement stuff) was generally permissible under the old semantics if the bindings happened to be resolved at the right time. With all that said, there are essentially three "strengths" of bindings: 1. Implicit Bindings: Anything implicitly obtained from `using Mod`, "no binding", plus slightly more exotic corner cases around conflicts 2. Weakly declared bindings: Declared using `global sym` and nothing else 3. Strongly declared bindings: Declared using `global sym::T`, `const sym=val`, `import Mod: sym`, `using Mod: sym` or as an implicit strong global declaration in `sym=val`, where `sym` is known to be global (either by being at toplevle or as `global sym=val` inside a function). In general, you always allowed to syntactically replace a weaker binding by a stronger one (although the runtime permits arbitrary binding deletion now, this is just a syntactic constraint to catch errors). Second, any implicit binding can be replaced by other implicit bindings as the result of changing the `using`'ed module. And lastly, any constants may be replaced by any other constants (irrespective of type). We do not currently allow replacing globals, but may consider changing that in 1.13. This is mostly how things used to work, as well in the absence of any stray external binding resolutions. The most prominent difference is probably this one: ``` set_foo!() = global foo = 1 ``` In the above terminology, this now always declares a "strongly declared binding", whereas before it declared a "weakly declared binding" that would become strongly declared on first write to the global (unless of course somebody had created a different strongly declared global in the meantime). To see the difference, this is now disallowed: ``` julia> set_foo!() = global foo = 1 set_foo! (generic function with 1 method) julia> const foo = 1 ERROR: cannot declare Main.foo constant; it was already declared global Stacktrace: [1] top-level scope @ REPL[2]:1 ``` Before it would depend on the order of binding resolution (although it just crashes on current master for some reason - whoops, probably my fault). Another major change is the ambiguousness of imports. In: ``` module M1; export x; x=1; end module M2; export x; x=2; end using .M1, .M2 ``` the binding `Main.x` is now always ambiguous and will throw on access. Before which binding you get, would depend on resolution order. To choose one, use an explicit import (which was the behavior you would previously get if neither binding was resolved before both imports). --- Compiler/src/Compiler.jl | 2 +- Compiler/src/abstractinterpretation.jl | 32 +- Compiler/src/ssair/ir.jl | 2 +- Compiler/src/ssair/verify.jl | 1 - Compiler/src/validation.jl | 2 +- Compiler/test/effects.jl | 31 +- Compiler/test/inference.jl | 2 +- base/boot.jl | 2 +- base/client.jl | 3 +- base/deprecated.jl | 25 + base/invalidation.jl | 64 +- base/reflection.jl | 86 --- base/runtime_internals.jl | 118 ++- base/show.jl | 26 +- contrib/generate_precompile.jl | 7 +- doc/src/manual/variables-and-scoping.md | 53 +- doc/src/manual/variables.md | 10 +- src/builtins.c | 76 +- src/codegen.cpp | 15 +- src/gc-stock.c | 3 + src/interpreter.c | 9 +- src/jl_exported_funcs.inc | 4 +- src/jlapi.c | 40 + src/julia-syntax.scm | 60 +- src/julia.h | 77 +- src/julia_internal.h | 13 +- src/method.c | 45 +- src/module.c | 719 ++++++++++-------- src/staticdata.c | 124 ++- src/toplevel.c | 161 ++-- .../InteractiveUtils/src/InteractiveUtils.jl | 4 +- stdlib/REPL/src/REPL.jl | 1 - stdlib/REPL/src/REPLCompletions.jl | 3 +- stdlib/REPL/src/docview.jl | 10 +- stdlib/REPL/test/replcompletions.jl | 2 - stdlib/Test/src/Test.jl | 4 +- test/ambiguous.jl | 4 - test/atomics.jl | 18 +- test/core.jl | 120 ++- test/docs.jl | 2 +- test/errorshow.jl | 7 +- test/misc.jl | 4 +- test/precompile.jl | 494 ++++++------ test/rebinding.jl | 93 ++- test/reflection.jl | 4 - test/show.jl | 9 - test/staged.jl | 2 +- test/syntax.jl | 12 +- test/worlds.jl | 25 +- 49 files changed, 1557 insertions(+), 1073 deletions(-) diff --git a/Compiler/src/Compiler.jl b/Compiler/src/Compiler.jl index 0fc7bd6e328e7..ba6d1607ded55 100644 --- a/Compiler/src/Compiler.jl +++ b/Compiler/src/Compiler.jl @@ -49,7 +49,7 @@ using Core: ABIOverride, Builtin, CodeInstance, IntrinsicFunction, MethodInstanc using Base using Base: @_foldable_meta, @_gc_preserve_begin, @_gc_preserve_end, @nospecializeinfer, - BINDING_KIND_GLOBAL, BINDING_KIND_UNDEF_CONST, BINDING_KIND_BACKDATED_CONST, + BINDING_KIND_GLOBAL, BINDING_KIND_UNDEF_CONST, BINDING_KIND_BACKDATED_CONST, BINDING_KIND_DECLARED, Base, BitVector, Bottom, Callable, DataTypeFieldDesc, EffectsOverride, Filter, Generator, IteratorSize, JLOptions, NUM_EFFECTS_OVERRIDES, OneTo, Ordering, RefValue, SizeUnknown, _NAMEDTUPLE_NAME, diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index fe7cc1dbf5680..8a7e8aee715a6 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -3464,14 +3464,7 @@ world_range(ci::CodeInfo) = WorldRange(ci.min_world, ci.max_world) world_range(ci::CodeInstance) = WorldRange(ci.min_world, ci.max_world) world_range(compact::IncrementalCompact) = world_range(compact.ir) -function force_binding_resolution!(g::GlobalRef, world::UInt) - # Force resolution of the binding - # TODO: This will go away once we switch over to fully partitioned semantics - ccall(:jl_force_binding_resolution, Cvoid, (Any, Csize_t), g, world) - return nothing -end - -function abstract_eval_globalref_type(g::GlobalRef, src::Union{CodeInfo, IRCode, IncrementalCompact}, retry_after_resolve::Bool=true) +function abstract_eval_globalref_type(g::GlobalRef, src::Union{CodeInfo, IRCode, IncrementalCompact}) worlds = world_range(src) partition = lookup_binding_partition(min_world(worlds), g) partition.max_world < max_world(worlds) && return Any @@ -3480,25 +3473,18 @@ function abstract_eval_globalref_type(g::GlobalRef, src::Union{CodeInfo, IRCode, partition = lookup_binding_partition(min_world(worlds), imported_binding) partition.max_world < max_world(worlds) && return Any end - if is_some_guard(binding_kind(partition)) - if retry_after_resolve - # This method is surprisingly hot. For performance, don't ask the runtime to resolve - # the binding unless necessary - doing so triggers an additional lookup, which though - # not super expensive is hot enough to show up in benchmarks. - force_binding_resolution!(g, min_world(worlds)) - return abstract_eval_globalref_type(g, src, false) - end + kind = binding_kind(partition) + if is_some_guard(kind) # return Union{} return Any end - if is_some_const_binding(binding_kind(partition)) + if is_some_const_binding(kind) return Const(partition_restriction(partition)) end - return partition_restriction(partition) + return kind == BINDING_KIND_DECLARED ? Any : partition_restriction(partition) end function lookup_binding_partition!(interp::AbstractInterpreter, g::GlobalRef, sv::AbsIntState) - force_binding_resolution!(g, get_inference_world(interp)) partition = lookup_binding_partition(get_inference_world(interp), g) update_valid_age!(sv, WorldRange(partition.min_world, partition.max_world)) partition @@ -3541,7 +3527,11 @@ function abstract_eval_partition_load(interp::AbstractInterpreter, partition::Co return RTEffects(rt, Union{}, Effects(EFFECTS_TOTAL, inaccessiblememonly=is_mutation_free_argtype(rt) ? ALWAYS_TRUE : ALWAYS_FALSE)) end - rt = partition_restriction(partition) + if kind == BINDING_KIND_DECLARED + rt = Any + else + rt = partition_restriction(partition) + end return RTEffects(rt, UndefVarError, generic_getglobal_effects) end @@ -3580,7 +3570,7 @@ function global_assignment_binding_rt_exct(interp::AbstractInterpreter, partitio elseif is_some_const_binding(kind) return Pair{Any,Any}(Bottom, ErrorException) end - ty = partition_restriction(partition) + ty = kind == BINDING_KIND_DECLARED ? Any : partition_restriction(partition) wnewty = widenconst(newty) if !hasintersect(wnewty, ty) return Pair{Any,Any}(Bottom, TypeError) diff --git a/Compiler/src/ssair/ir.jl b/Compiler/src/ssair/ir.jl index f86ada2309ddc..e6c8f3a6d2c78 100644 --- a/Compiler/src/ssair/ir.jl +++ b/Compiler/src/ssair/ir.jl @@ -581,7 +581,7 @@ function is_relevant_expr(e::Expr) :foreigncall, :isdefined, :copyast, :throw_undef_if_not, :cfunction, :method, :pop_exception, - :leave, + :leave, :const, :globaldecl, :new_opaque_closure) end diff --git a/Compiler/src/ssair/verify.jl b/Compiler/src/ssair/verify.jl index 2d6d59cc4e22b..974690885a2e4 100644 --- a/Compiler/src/ssair/verify.jl +++ b/Compiler/src/ssair/verify.jl @@ -61,7 +61,6 @@ function check_op(ir::IRCode, domtree::DomTree, @nospecialize(op), use_bb::Int, raise_error() end elseif isa(op, GlobalRef) - force_binding_resolution!(op, min_world(ir.valid_worlds)) bpart = lookup_binding_partition(min_world(ir.valid_worlds), op) while is_some_imported(binding_kind(bpart)) && max_world(ir.valid_worlds) <= bpart.max_world imported_binding = partition_restriction(bpart)::Core.Binding diff --git a/Compiler/src/validation.jl b/Compiler/src/validation.jl index 6700aa8d4508f..9bde405a49956 100644 --- a/Compiler/src/validation.jl +++ b/Compiler/src/validation.jl @@ -22,7 +22,7 @@ const VALID_EXPR_HEADS = IdDict{Symbol,UnitRange{Int}}( :copyast => 1:1, :meta => 0:typemax(Int), :global => 1:1, - :globaldecl => 2:2, + :globaldecl => 1:2, :foreigncall => 5:typemax(Int), # name, RT, AT, nreq, (cconv, effects), args..., roots... :cfunction => 5:5, :isdefined => 1:2, diff --git a/Compiler/test/effects.jl b/Compiler/test/effects.jl index b8a841b6b74b7..082d954b4a9bc 100644 --- a/Compiler/test/effects.jl +++ b/Compiler/test/effects.jl @@ -378,32 +378,27 @@ let effects = Base.infer_effects(; optimize=false) do end # we should taint `nothrow` if the binding doesn't exist and isn't fixed yet, -# as the cached effects can be easily wrong otherwise -# since the inference currently doesn't track "world-age" of global variables -@eval global_assignment_undefinedyet() = $(GlobalRef(@__MODULE__, :UNDEFINEDYET)) = 42 setglobal!_nothrow_undefinedyet() = setglobal!(@__MODULE__, :UNDEFINEDYET, 42) -let effects = Base.infer_effects() do - global_assignment_undefinedyet() - end +let effects = Base.infer_effects(setglobal!_nothrow_undefinedyet) @test !Compiler.is_nothrow(effects) end -let effects = Base.infer_effects() do - setglobal!_nothrow_undefinedyet() - end - @test !Compiler.is_nothrow(effects) +@test_throws ErrorException setglobal!_nothrow_undefinedyet() +# This declares the binding as ::Any +@eval global_assignment_undefinedyet() = $(GlobalRef(@__MODULE__, :UNDEFINEDYET)) = 42 +let effects = Base.infer_effects(global_assignment_undefinedyet) + @test Compiler.is_nothrow(effects) end -global UNDEFINEDYET::String = "0" -let effects = Base.infer_effects() do - global_assignment_undefinedyet() - end +# Again with type mismatch +global UNDEFINEDYET2::String = "0" +setglobal!_nothrow_undefinedyet2() = setglobal!(@__MODULE__, :UNDEFINEDYET2, 42) +@eval global_assignment_undefinedyet2() = $(GlobalRef(@__MODULE__, :UNDEFINEDYET2)) = 42 +let effects = Base.infer_effects(global_assignment_undefinedyet2) @test !Compiler.is_nothrow(effects) end -let effects = Base.infer_effects() do - setglobal!_nothrow_undefinedyet() - end +let effects = Base.infer_effects(setglobal!_nothrow_undefinedyet2) @test !Compiler.is_nothrow(effects) end -@test_throws Union{ErrorException,TypeError} setglobal!_nothrow_undefinedyet() # TODO: what kind of error should this be? +@test_throws TypeError setglobal!_nothrow_undefinedyet2() # Nothrow for setfield! mutable struct SetfieldNothrow diff --git a/Compiler/test/inference.jl b/Compiler/test/inference.jl index d4ea990e7d148..563828ac77296 100644 --- a/Compiler/test/inference.jl +++ b/Compiler/test/inference.jl @@ -6160,7 +6160,7 @@ end === Int swapglobal!(@__MODULE__, :swapglobal!_xxx, x) end === Union{} -global swapglobal!_must_throw +eval(Expr(:const, :swapglobal!_must_throw)) @newinterp SwapGlobalInterp Compiler.InferenceParams(::SwapGlobalInterp) = Compiler.InferenceParams(; assume_bindings_static=true) function func_swapglobal!_must_throw(x) diff --git a/base/boot.jl b/base/boot.jl index e50d74659d399..26a405f92f884 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -229,7 +229,7 @@ export Expr, QuoteNode, LineNumberNode, GlobalRef, # object model functions fieldtype, getfield, setfield!, swapfield!, modifyfield!, replacefield!, setfieldonce!, - nfields, throw, tuple, ===, isdefined, eval, + nfields, throw, tuple, ===, isdefined, # access to globals getglobal, setglobal!, swapglobal!, modifyglobal!, replaceglobal!, setglobalonce!, isdefinedglobal, # ifelse, sizeof # not exported, to avoid conflicting with Base diff --git a/base/client.jl b/base/client.jl index 2527d382c695d..3449e2fbf2e62 100644 --- a/base/client.jl +++ b/base/client.jl @@ -267,9 +267,8 @@ function exec_options(opts) let Distributed = require(PkgId(UUID((0x8ba89e20_285c_5b6f, 0x9357_94700520ee1b)), "Distributed")) Core.eval(MainInclude, :(const Distributed = $Distributed)) Core.eval(Main, :(using Base.MainInclude.Distributed)) + invokelatest(Distributed.process_opts, opts) end - - invokelatest(Main.Distributed.process_opts, opts) end interactiveinput = (repl || is_interactive::Bool) && isa(stdin, TTY) diff --git a/base/deprecated.jl b/base/deprecated.jl index cffff05d954d1..f72698ad47008 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -531,4 +531,29 @@ end # BEGIN 1.12 deprecations +@deprecate isbindingresolved(m::Module, var::Symbol) true false + +""" + isbindingresolved(m::Module, s::Symbol) -> Bool + +Returns whether the binding of a symbol in a module is resolved. + +See also: [`isexported`](@ref), [`ispublic`](@ref), [`isdeprecated`](@ref) + +```jldoctest +julia> module Mod + foo() = 17 + end +Mod + +julia> Base.isbindingresolved(Mod, :foo) +true +``` + +!!! warning + This function is deprecated. The concept of binding "resolvedness" was removed in Julia 1.12. + The function now always returns `true`. +""" +isbindingresolved + # END 1.12 deprecations diff --git a/base/invalidation.jl b/base/invalidation.jl index 36b867ede2868..c0aed35aa90a0 100644 --- a/base/invalidation.jl +++ b/base/invalidation.jl @@ -113,32 +113,56 @@ function invalidate_method_for_globalref!(gr::GlobalRef, method::Method, invalid end end -function invalidate_code_for_globalref!(gr::GlobalRef, invalidated_bpart::Core.BindingPartition, new_max_world::UInt) - b = convert(Core.Binding, gr) - try - valid_in_valuepos = false - foreach_module_mtable(gr.mod, new_max_world) do mt::Core.MethodTable - for method in MethodList(mt) - invalidate_method_for_globalref!(gr, method, invalidated_bpart, new_max_world) +const BINDING_FLAG_EXPORTP = 0x2 + +function invalidate_code_for_globalref!(b::Core.Binding, invalidated_bpart::Core.BindingPartition, new_bpart::Union{Core.BindingPartition, Nothing}, new_max_world::UInt) + gr = b.globalref + if is_some_guard(binding_kind(invalidated_bpart)) + # TODO: We may want to invalidate for these anyway, since they have performance implications + return + end + foreach_module_mtable(gr.mod, new_max_world) do mt::Core.MethodTable + for method in MethodList(mt) + invalidate_method_for_globalref!(gr, method, invalidated_bpart, new_max_world) + end + return true + end + if isdefined(b, :backedges) + for edge in b.backedges + if isa(edge, CodeInstance) + ccall(:jl_invalidate_code_instance, Cvoid, (Any, UInt), edge, new_max_world) + elseif isa(edge, Core.Binding) + isdefined(edge, :partitions) || continue + latest_bpart = edge.partitions + latest_bpart.max_world == typemax(UInt) || continue + is_some_imported(binding_kind(latest_bpart)) || continue + partition_restriction(latest_bpart) === b || continue + invalidate_code_for_globalref!(edge, latest_bpart, nothing, new_max_world) + else + invalidate_method_for_globalref!(gr, edge::Method, invalidated_bpart, new_max_world) end - return true end - b = convert(Core.Binding, gr) - if isdefined(b, :backedges) - for edge in b.backedges - if isa(edge, CodeInstance) - ccall(:jl_invalidate_code_instance, Cvoid, (Any, UInt), edge, new_max_world) - else - invalidate_method_for_globalref!(gr, edge::Method, invalidated_bpart, new_max_world) - end + end + if (b.flags & BINDING_FLAG_EXPORTP) != 0 + # This binding was exported - we need to check all modules that `using` us to see if they + # have an implicit binding to us. + usings_backedges = ccall(:jl_get_module_usings_backedges, Any, (Any,), gr.mod) + if usings_backedges !== nothing + for user in usings_backedges::Vector{Any} + user_binding = ccall(:jl_get_module_binding_or_nothing, Any, (Any, Any), user, gr.name) + user_binding === nothing && continue + isdefined(user_binding, :partitions) || continue + latest_bpart = user_binding.partitions + latest_bpart.max_world == typemax(UInt) || continue + is_some_imported(binding_kind(latest_bpart)) || continue + partition_restriction(latest_bpart) === b || continue + invalidate_code_for_globalref!(convert(Core.Binding, user_binding), latest_bpart, nothing, new_max_world) end end - catch err - bt = catch_backtrace() - invokelatest(Base.println, "Internal Error during invalidation:") - invokelatest(Base.display_error, err, bt) end end +invalidate_code_for_globalref!(gr::GlobalRef, invalidated_bpart::Core.BindingPartition, new_bpart::Core.BindingPartition, new_max_world::UInt) = + invalidate_code_for_globalref!(convert(Core.Binding, gr), invalidated_bpart, new_bpart, new_max_world) gr_needs_backedge_in_module(gr::GlobalRef, mod::Module) = gr.mod !== mod diff --git a/base/reflection.jl b/base/reflection.jl index 78e701692a2a7..c98f6244cc89f 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -46,92 +46,6 @@ function code_lowered(@nospecialize(f), @nospecialize(t=Tuple); generated::Bool= return ret end -# high-level, more convenient method lookup functions - -function visit(f, mt::Core.MethodTable) - mt.defs !== nothing && visit(f, mt.defs) - nothing -end -function visit(f, mc::Core.TypeMapLevel) - function avisit(f, e::Memory{Any}) - for i in 2:2:length(e) - isassigned(e, i) || continue - ei = e[i] - if ei isa Memory{Any} - for j in 2:2:length(ei) - isassigned(ei, j) || continue - visit(f, ei[j]) - end - else - visit(f, ei) - end - end - end - if mc.targ !== nothing - avisit(f, mc.targ::Memory{Any}) - end - if mc.arg1 !== nothing - avisit(f, mc.arg1::Memory{Any}) - end - if mc.tname !== nothing - avisit(f, mc.tname::Memory{Any}) - end - if mc.name1 !== nothing - avisit(f, mc.name1::Memory{Any}) - end - mc.list !== nothing && visit(f, mc.list) - mc.any !== nothing && visit(f, mc.any) - nothing -end -function visit(f, d::Core.TypeMapEntry) - while d !== nothing - f(d.func) - d = d.next - end - nothing -end -struct MethodSpecializations - specializations::Union{Nothing, Core.MethodInstance, Core.SimpleVector} -end -""" - specializations(m::Method) → itr - -Return an iterator `itr` of all compiler-generated specializations of `m`. -""" -specializations(m::Method) = MethodSpecializations(isdefined(m, :specializations) ? m.specializations : nothing) -function iterate(specs::MethodSpecializations) - s = specs.specializations - s === nothing && return nothing - isa(s, Core.MethodInstance) && return (s, nothing) - return iterate(specs, 0) -end -iterate(specs::MethodSpecializations, ::Nothing) = nothing -function iterate(specs::MethodSpecializations, i::Int) - s = specs.specializations::Core.SimpleVector - n = length(s) - i >= n && return nothing - item = nothing - while i < n && item === nothing - item = s[i+=1] - end - item === nothing && return nothing - return (item, i) -end -length(specs::MethodSpecializations) = count(Returns(true), specs) - -function length(mt::Core.MethodTable) - n = 0 - visit(mt) do m - n += 1 - end - return n::Int -end -isempty(mt::Core.MethodTable) = (mt.defs === nothing) - -uncompressed_ir(m::Method) = isdefined(m, :source) ? _uncompressed_ir(m) : - isdefined(m, :generator) ? error("Method is @generated; try `code_lowered` instead.") : - error("Code for this Method is not available.") - # for backwards compat const uncompressed_ast = uncompressed_ir const _uncompressed_ast = _uncompressed_ir diff --git a/base/runtime_internals.jl b/base/runtime_internals.jl index b61e24c11f3f9..36961f58c5c3f 100644 --- a/base/runtime_internals.jl +++ b/base/runtime_internals.jl @@ -177,28 +177,6 @@ ispublic(m::Module, s::Symbol) = ccall(:jl_module_public_p, Cint, (Any, Any), m, # `Base.deprecate`, not the @deprecated macro: isdeprecated(m::Module, s::Symbol) = ccall(:jl_is_binding_deprecated, Cint, (Any, Any), m, s) != 0 -""" - isbindingresolved(m::Module, s::Symbol) -> Bool - -Returns whether the binding of a symbol in a module is resolved. - -See also: [`isexported`](@ref), [`ispublic`](@ref), [`isdeprecated`](@ref) - -```jldoctest -julia> module Mod - foo() = 17 - end -Mod - -julia> Base.isbindingresolved(Mod, :foo) -true - -julia> Base.isbindingresolved(Mod, :bar) -false -``` -""" -isbindingresolved(m::Module, var::Symbol) = ccall(:jl_binding_resolved_p, Cint, (Any, Any), m, var) != 0 - function binding_module(m::Module, s::Symbol) p = ccall(:jl_get_module_of_binding, Ptr{Cvoid}, (Any, Any), m, s) p == C_NULL && return m @@ -234,7 +212,7 @@ const BINDING_KIND_BACKDATED_CONST = 0xa is_defined_const_binding(kind::UInt8) = (kind == BINDING_KIND_CONST || kind == BINDING_KIND_CONST_IMPORT || kind == BINDING_KIND_BACKDATED_CONST) is_some_const_binding(kind::UInt8) = (is_defined_const_binding(kind) || kind == BINDING_KIND_UNDEF_CONST) is_some_imported(kind::UInt8) = (kind == BINDING_KIND_IMPLICIT || kind == BINDING_KIND_EXPLICIT || kind == BINDING_KIND_IMPORTED) -is_some_guard(kind::UInt8) = (kind == BINDING_KIND_GUARD || kind == BINDING_KIND_DECLARED || kind == BINDING_KIND_FAILED || kind == BINDING_KIND_UNDEF_CONST) +is_some_guard(kind::UInt8) = (kind == BINDING_KIND_GUARD || kind == BINDING_KIND_FAILED || kind == BINDING_KIND_UNDEF_CONST) function lookup_binding_partition(world::UInt, b::Core.Binding) ccall(:jl_get_binding_partition, Ref{Core.BindingPartition}, (Any, UInt), b, world) @@ -412,8 +390,13 @@ parentmodule(t::UnionAll) = parentmodule(unwrap_unionall(t)) """ isconst(m::Module, s::Symbol) -> Bool + isconst(g::GlobalRef) -Determine whether a global is declared `const` in a given module `m`. +Determine whether a global is `const` in a given module `m`, either +because it was declared constant or because it was imported from a +constant binding. Note that constant-ness is specific to a particular +world age, so the result of this function may not be assumed to hold +after a world age update. """ isconst(m::Module, s::Symbol) = ccall(:jl_is_const, Cint, (Any, Any), m, s) != 0 @@ -1584,3 +1567,90 @@ hasintersect(@nospecialize(a), @nospecialize(b)) = typeintersect(a, b) !== Botto ########### _topmod(m::Module) = ccall(:jl_base_relative_to, Any, (Any,), m)::Module + + +# high-level, more convenient method lookup functions + +function visit(f, mt::Core.MethodTable) + mt.defs !== nothing && visit(f, mt.defs) + nothing +end +function visit(f, mc::Core.TypeMapLevel) + function avisit(f, e::Memory{Any}) + for i in 2:2:length(e) + isassigned(e, i) || continue + ei = e[i] + if ei isa Memory{Any} + for j in 2:2:length(ei) + isassigned(ei, j) || continue + visit(f, ei[j]) + end + else + visit(f, ei) + end + end + end + if mc.targ !== nothing + avisit(f, mc.targ::Memory{Any}) + end + if mc.arg1 !== nothing + avisit(f, mc.arg1::Memory{Any}) + end + if mc.tname !== nothing + avisit(f, mc.tname::Memory{Any}) + end + if mc.name1 !== nothing + avisit(f, mc.name1::Memory{Any}) + end + mc.list !== nothing && visit(f, mc.list) + mc.any !== nothing && visit(f, mc.any) + nothing +end +function visit(f, d::Core.TypeMapEntry) + while d !== nothing + f(d.func) + d = d.next + end + nothing +end +struct MethodSpecializations + specializations::Union{Nothing, Core.MethodInstance, Core.SimpleVector} +end +""" + specializations(m::Method) → itr + +Return an iterator `itr` of all compiler-generated specializations of `m`. +""" +specializations(m::Method) = MethodSpecializations(isdefined(m, :specializations) ? m.specializations : nothing) +function iterate(specs::MethodSpecializations) + s = specs.specializations + s === nothing && return nothing + isa(s, Core.MethodInstance) && return (s, nothing) + return iterate(specs, 0) +end +iterate(specs::MethodSpecializations, ::Nothing) = nothing +function iterate(specs::MethodSpecializations, i::Int) + s = specs.specializations::Core.SimpleVector + n = length(s) + i >= n && return nothing + item = nothing + while i < n && item === nothing + item = s[i+=1] + end + item === nothing && return nothing + return (item, i) +end +length(specs::MethodSpecializations) = count(Returns(true), specs) + +function length(mt::Core.MethodTable) + n = 0 + visit(mt) do m + n += 1 + end + return n::Int +end +isempty(mt::Core.MethodTable) = (mt.defs === nothing) + +uncompressed_ir(m::Method) = isdefined(m, :source) ? _uncompressed_ir(m) : + isdefined(m, :generator) ? error("Method is @generated; try `code_lowered` instead.") : + error("Code for this Method is not available.") diff --git a/base/show.jl b/base/show.jl index 27f0596e32e82..c1d5cf9035773 100644 --- a/base/show.jl +++ b/base/show.jl @@ -1021,18 +1021,24 @@ end # If an object with this name exists in 'from', we need to check that it's the same binding # and that it's not deprecated. function isvisible(sym::Symbol, parent::Module, from::Module) - owner = ccall(:jl_binding_owner, Ptr{Cvoid}, (Any, Any), parent, sym) - from_owner = ccall(:jl_binding_owner, Ptr{Cvoid}, (Any, Any), from, sym) - return owner !== C_NULL && from_owner === owner && - !isdeprecated(parent, sym) && - isdefinedglobal(from, sym) # if we're going to return true, force binding resolution + isdeprecated(parent, sym) && return false + isdefinedglobal(from, sym) || return false + parent_binding = convert(Core.Binding, GlobalRef(parent, sym)) + from_binding = convert(Core.Binding, GlobalRef(from, sym)) + while true + from_binding === parent_binding && return true + partition = lookup_binding_partition(tls_world_age(), from_binding) + is_some_imported(binding_kind(partition)) || break + from_binding = partition_restriction(partition)::Core.Binding + end + return false end function is_global_function(tn::Core.TypeName, globname::Union{Symbol,Nothing}) if globname !== nothing globname_str = string(globname::Symbol) if ('#' ∉ globname_str && '@' ∉ globname_str && isdefined(tn, :module) && - isbindingresolved(tn.module, globname) && isdefinedglobal(tn.module, globname) && + isdefinedglobal(tn.module, globname) && isconcretetype(tn.wrapper) && isa(getglobal(tn.module, globname), tn.wrapper)) return true end @@ -3383,16 +3389,16 @@ function print_partition(io::IO, partition::Core.BindingPartition) elseif kind == BINDING_KIND_FAILED print(io, "ambiguous binding - guard entry") elseif kind == BINDING_KIND_DECLARED - print(io, "undefined, but declared using `global` - guard entry") + print(io, "weak global binding declared using `global` (implicit type Any)") elseif kind == BINDING_KIND_IMPLICIT print(io, "implicit `using` from ") - print(io, partition_restriction(partition)) + print(io, partition_restriction(partition).globalref) elseif kind == BINDING_KIND_EXPLICIT print(io, "explicit `using` from ") - print(io, partition_restriction(partition)) + print(io, partition_restriction(partition).globalref) elseif kind == BINDING_KIND_IMPORTED print(io, "explicit `import` from ") - print(io, partition_restriction(partition)) + print(io, partition_restriction(partition).globalref) else @assert kind == BINDING_KIND_GLOBAL print(io, "global variable with type ") diff --git a/contrib/generate_precompile.jl b/contrib/generate_precompile.jl index b075223d9c7e4..f12e94e22fca5 100644 --- a/contrib/generate_precompile.jl +++ b/contrib/generate_precompile.jl @@ -107,6 +107,9 @@ precompile(Base.CoreLogging.env_override_minlevel, (Symbol, Module)) precompile(Base.StackTraces.lookup, (Ptr{Nothing},)) precompile(Tuple{typeof(Base.run_module_init), Module, Int}) +# Presence tested in the tests +precompile(Tuple{typeof(Base.print), Base.IOStream, String}) + # precompilepkgs precompile(Tuple{typeof(Base.get), Type{Array{String, 1}}, Base.Dict{String, Any}, String}) precompile(Tuple{typeof(Base.get), Type{Base.Dict{String, Any}}, Base.Dict{String, Any}, String}) @@ -352,10 +355,10 @@ generate_precompile_statements() = try # Make sure `ansi_enablecursor` is printe PrecompileStagingArea = Module() for (_pkgid, _mod) in Base.loaded_modules if !(_pkgid.name in ("Main", "Core", "Base")) - eval(PrecompileStagingArea, :(const $(Symbol(_mod)) = $_mod)) + Core.eval(PrecompileStagingArea, :(const $(Symbol(_mod)) = $_mod)) end end - eval(PrecompileStagingArea, :(const Compiler = Base.Compiler)) + Core.eval(PrecompileStagingArea, :(const Compiler = Base.Compiler)) n_succeeded = 0 # Make statements unique diff --git a/doc/src/manual/variables-and-scoping.md b/doc/src/manual/variables-and-scoping.md index 99f7ba088311d..ab2d969dd9b0e 100644 --- a/doc/src/manual/variables-and-scoping.md +++ b/doc/src/manual/variables-and-scoping.md @@ -730,65 +730,28 @@ Note that `const` only affects the variable binding; the variable may be bound t object (such as an array), and that object may still be modified. Additionally when one tries to assign a value to a variable that is declared constant the following scenarios are possible: -* if a new value has a different type than the type of the constant then an error is thrown: +* Attempting to replace a constant without the const `keyword` is disallowed: ```jldoctest julia> const x = 1.0 1.0 julia> x = 1 -ERROR: invalid redefinition of constant x +ERROR: invalid assignment to constant x. This redefinition may be permitted using the `const` keyword. ``` -* if a new value has the same type as the constant then a warning is printed: +* All other defefinitions of constants are permitted, but may cause significant re-compilation: ```jldoctest julia> const y = 1.0 1.0 julia> const y = 2.0 -WARNING: redefinition of constant y. This may fail, cause incorrect answers, or produce other errors. 2.0 ``` -* if an assignment would not result in the change of variable value no message is given: -```jldoctest -julia> const z = 100 -100 - -julia> z = 100 -100 -``` -* if an assignment would change the mutable object to which the variable points (regardless of whether those two objects are deeply equal), a warning is printed: -```jldoctest -julia> const a = [1] -1-element Vector{Int64}: - 1 - -julia> const a = [1] -WARNING: redefinition of constant a. This may fail, cause incorrect answers, or produce other errors. -1-element Vector{Int64}: - 1 -``` -Note that although sometimes possible, changing the value of a `const` variable is strongly -discouraged, and is intended only for convenience during interactive use. Changing constants can -cause various problems or unexpected behaviors. For instance, if a method references a constant and -is already compiled before the constant is changed, then it might keep using the old value: - -```jldoctest -julia> const x = 1 -1 - -julia> f() = x -f (generic function with 1 method) - -julia> f() -1 - -julia> const x = 2 -WARNING: redefinition of constant x. This may fail, cause incorrect answers, or produce other errors. -2 - -julia> f() -1 -``` +!!! compat "Julia 1.12" + Prior to julia 1.12, redefinition of constants was poorly supported. It was restricted to + redefinition of constants of the same type and could lead to observably incorrect behavior + or crashes. Constant redefinition is highly discouraged in versions of julia prior to 1.12. + See the manual for prior julia versions for further information. ## [Typed Globals](@id man-typed-globals) diff --git a/doc/src/manual/variables.md b/doc/src/manual/variables.md index ad2c60a029032..4c3e98ca57281 100644 --- a/doc/src/manual/variables.md +++ b/doc/src/manual/variables.md @@ -79,10 +79,12 @@ julia> Base.length length (generic function with 79 methods) ``` -However, if you try to redefine a built-in constant or function already in use, Julia will give -you an error: +However, if you try to redefine a built-in constant or function that you +have explicitly imported, Julia will give you an error: ```jldoctest +julia> using Base: pi, sqrt + julia> pi π = 3.1415926535897... @@ -96,6 +98,10 @@ julia> sqrt = 4 ERROR: cannot assign a value to imported variable Base.sqrt from module Main ``` +!!! compat "Julia 1.12" + Note that in versions prior to Julia 1.12, these errors depended on *use* rather than definition of + the conflicting binding. + ## [Allowed Variable Names](@id man-allowed-variable-names) Variable names must begin with a letter (A-Z or a-z), underscore, or a subset of Unicode code diff --git a/src/builtins.c b/src/builtins.c index f67ef65d35356..f3d2dfad42819 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -2197,11 +2197,13 @@ static int references_name(jl_value_t *p, jl_typename_t *name, int affects_layou JL_CALLABLE(jl_f__typebody) { - JL_NARGS(_typebody!, 1, 2); - jl_datatype_t *dt = (jl_datatype_t*)jl_unwrap_unionall(args[0]); + JL_NARGS(_typebody!, 2, 3); + jl_value_t *prev = args[0]; + jl_value_t *tret = args[1]; + jl_datatype_t *dt = (jl_datatype_t*)jl_unwrap_unionall(args[1]); JL_TYPECHK(_typebody!, datatype, (jl_value_t*)dt); - if (nargs == 2) { - jl_value_t *ft = args[1]; + if (nargs == 3) { + jl_value_t *ft = args[2]; JL_TYPECHK(_typebody!, simplevector, ft); size_t nf = jl_svec_len(ft); for (size_t i = 0; i < nf; i++) { @@ -2212,30 +2214,53 @@ JL_CALLABLE(jl_f__typebody) (jl_value_t*)jl_type_type, elt); } } - if (dt->types != NULL) { - if (!equiv_field_types((jl_value_t*)dt->types, ft)) - jl_errorf("invalid redefinition of type %s", jl_symbol_name(dt->name->name)); - } - else { - dt->types = (jl_svec_t*)ft; - jl_gc_wb(dt, ft); - // If a supertype can reference the same type, then we may not be - // able to compute the layout of the object before needing to - // publish it, so we must assume it cannot be inlined, if that - // check passes, then we also still need to check the fields too. - if (!dt->name->mutabl && (nf == 0 || !references_name((jl_value_t*)dt->super, dt->name, 0, 1))) { - int mayinlinealloc = 1; - size_t i; - for (i = 0; i < nf; i++) { - jl_value_t *fld = jl_svecref(ft, i); - if (references_name(fld, dt->name, 1, 1)) { - mayinlinealloc = 0; - break; + // Optimization: To avoid lots of unnecessary churning, lowering contains an optimization + // that re-uses the typevars of an existing definition (if any exists) for compute the field + // types. If such a previous type exists, there are two possibilities: + // 1. The field types are identical, we don't need to do anything and can proceed with the + // old type as if it was the new one. + // 2. The field types are not identical, in which case we need to rename the typevars + // back to their equivalents in the new type before proceeding. + if (prev == jl_false) { + if (dt->types != NULL) + jl_errorf("Internal Error: Expected type fields to be unset"); + } else { + jl_datatype_t *prev_dt = (jl_datatype_t*)jl_unwrap_unionall(prev); + JL_TYPECHK(_typebody!, datatype, (jl_value_t*)prev_dt); + if (equiv_field_types((jl_value_t*)prev_dt->types, ft)) { + tret = prev; + goto have_type; + } else { + if (jl_svec_len(prev_dt->parameters) != jl_svec_len(dt->parameters)) + jl_errorf("Internal Error: Types should not have been considered equivalent"); + for (size_t i = 0; i < nf; i++) { + jl_value_t *elt = jl_svecref(ft, i); + for (int j = 0; j < jl_svec_len(prev_dt->parameters); ++j) { + // Only the last svecset matters for semantics, but we re-use the GC root + elt = jl_substitute_var(elt, (jl_tvar_t *)jl_svecref(prev_dt->parameters, j), jl_svecref(dt->parameters, j)); + jl_svecset(ft, i, elt); } } - dt->name->mayinlinealloc = mayinlinealloc; } } + dt->types = (jl_svec_t*)ft; + jl_gc_wb(dt, ft); + // If a supertype can reference the same type, then we may not be + // able to compute the layout of the object before needing to + // publish it, so we must assume it cannot be inlined, if that + // check passes, then we also still need to check the fields too. + if (!dt->name->mutabl && (nf == 0 || !references_name((jl_value_t*)dt->super, dt->name, 0, 1))) { + int mayinlinealloc = 1; + size_t i; + for (i = 0; i < nf; i++) { + jl_value_t *fld = jl_svecref(ft, i); + if (references_name(fld, dt->name, 1, 1)) { + mayinlinealloc = 0; + break; + } + } + dt->name->mayinlinealloc = mayinlinealloc; + } } JL_TRY { @@ -2248,7 +2273,8 @@ JL_CALLABLE(jl_f__typebody) if (jl_is_structtype(dt)) jl_compute_field_offsets(dt); - return jl_nothing; +have_type: + return tret; } // this is a heuristic for allowing "redefining" a type to something identical diff --git a/src/codegen.cpp b/src/codegen.cpp index 7787b684fbd12..5507bd7bad801 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -918,7 +918,7 @@ static const auto jldeclareglobal_func = new JuliaFunction<>{ auto T_pjlvalue = JuliaType::get_pjlvalue_ty(C); auto T_prjlvalue = JuliaType::get_prjlvalue_ty(C); return FunctionType::get(getVoidTy(C), - {T_pjlvalue, T_pjlvalue, T_prjlvalue}, false); }, + {T_pjlvalue, T_pjlvalue, T_prjlvalue, getInt32Ty(C)}, false); }, nullptr, }; static const auto jlgetbindingorerror_func = new JuliaFunction<>{ @@ -6943,16 +6943,21 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaidx_ } } else if (head == jl_globaldecl_sym) { - assert(nargs == 2); + assert(nargs <= 2 && nargs >= 1); jl_sym_t *sym = (jl_sym_t*)args[0]; jl_module_t *mod = ctx.module; if (jl_is_globalref(sym)) { mod = jl_globalref_mod(sym); sym = jl_globalref_name(sym); } - jl_cgval_t typ = emit_expr(ctx, args[1]); - ctx.builder.CreateCall(prepare_call(jldeclareglobal_func), - { literal_pointer_val(ctx, (jl_value_t*)mod), literal_pointer_val(ctx, (jl_value_t*)sym), boxed(ctx, typ) }); + if (nargs == 2) { + jl_cgval_t typ = emit_expr(ctx, args[1]); + ctx.builder.CreateCall(prepare_call(jldeclareglobal_func), + { literal_pointer_val(ctx, (jl_value_t*)mod), literal_pointer_val(ctx, (jl_value_t*)sym), boxed(ctx, typ), ConstantInt::get(getInt32Ty(ctx.builder.getContext()), 1) }); + } else { + ctx.builder.CreateCall(prepare_call(jldeclareglobal_func), + { literal_pointer_val(ctx, (jl_value_t*)mod), literal_pointer_val(ctx, (jl_value_t*)sym), ConstantPointerNull::get(cast(ctx.types().T_prjlvalue)), ConstantInt::get(getInt32Ty(ctx.builder.getContext()), 1) }); + } } else if (head == jl_new_sym) { bool is_promotable = false; diff --git a/src/gc-stock.c b/src/gc-stock.c index 8118b3c5629ae..72479d14e67a5 100644 --- a/src/gc-stock.c +++ b/src/gc-stock.c @@ -2144,6 +2144,9 @@ STATIC_INLINE void gc_mark_module_binding(jl_ptls_t ptls, jl_module_t *mb_parent gc_heap_snapshot_record_module_to_binding(mb_parent, bindings, bindingkeyset); gc_assert_parent_validity((jl_value_t *)mb_parent, (jl_value_t *)mb_parent->parent); gc_try_claim_and_push(mq, (jl_value_t *)mb_parent->parent, &nptr); + gc_assert_parent_validity((jl_value_t *)mb_parent, (jl_value_t *)mb_parent->usings_backedges); + gc_try_claim_and_push(mq, (jl_value_t *)mb_parent->usings_backedges, &nptr); + gc_heap_snapshot_record_binding_partition_edge((jl_value_t*)mb_parent, mb_parent->usings_backedges); size_t nusings = module_usings_length(mb_parent); if (nusings > 0) { // this is only necessary because bindings for "using" modules diff --git a/src/interpreter.c b/src/interpreter.c index 35c70a9ead2f1..513fe58f7b5cc 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -634,9 +634,12 @@ static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, size_t ip, s->locals[jl_source_nslots(s->src) + s->ip] = res; } else if (head == jl_globaldecl_sym) { - jl_value_t *val = eval_value(jl_exprarg(stmt, 1), s); - s->locals[jl_source_nslots(s->src) + s->ip] = val; // temporarily root - jl_declare_global(s->module, jl_exprarg(stmt, 0), val); + jl_value_t *val = NULL; + if (jl_expr_nargs(stmt) >= 2) { + val = eval_value(jl_exprarg(stmt, 1), s); + s->locals[jl_source_nslots(s->src) + s->ip] = val; // temporarily root + } + jl_declare_global(s->module, jl_exprarg(stmt, 0), val, 1); s->locals[jl_source_nslots(s->src) + s->ip] = jl_nothing; } else if (head == jl_const_sym) { diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index 21b5afa74c5f4..664e1270c7381 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -42,7 +42,6 @@ XX(jl_atomic_swap_bits) \ XX(jl_backtrace_from_here) \ XX(jl_base_relative_to) \ - XX(jl_binding_resolved_p) \ XX(jl_bitcast) \ XX(jl_boundp) \ XX(jl_bounds_error) \ @@ -72,6 +71,7 @@ XX(jl_call1) \ XX(jl_call2) \ XX(jl_call3) \ + XX(jl_call4) \ XX(jl_calloc) \ XX(jl_call_in_typeinf_world) \ XX(jl_capture_interp_frame) \ @@ -213,6 +213,8 @@ XX(jl_get_module_infer) \ XX(jl_get_module_of_binding) \ XX(jl_get_module_optlevel) \ + XX(jl_get_module_usings_backedges) \ + XX(jl_get_module_binding_or_nothing) \ XX(jl_get_next_task) \ XX(jl_get_nth_field) \ XX(jl_get_nth_field_checked) \ diff --git a/src/jlapi.c b/src/jlapi.c index b8fbda801f43b..e205a4a4dc723 100644 --- a/src/jlapi.c +++ b/src/jlapi.c @@ -437,6 +437,46 @@ JL_DLLEXPORT jl_value_t *jl_call3(jl_function_t *f, jl_value_t *a, return v; } +/** + * @brief Call a Julia function with three arguments. + * + * A specialized case of `jl_call` for simpler scenarios. + * + * @param f A pointer to `jl_function_t` representing the Julia function to call. + * @param a A pointer to `jl_value_t` representing the first argument. + * @param b A pointer to `jl_value_t` representing the second argument. + * @param c A pointer to `jl_value_t` representing the third argument. + * @param d A pointer to `jl_value_t` representing the fourth argument. + * @return A pointer to `jl_value_t` representing the result of the function call. + */ +JL_DLLEXPORT jl_value_t *jl_call4(jl_function_t *f, jl_value_t *a, + jl_value_t *b, jl_value_t *c, + jl_value_t *d) +{ + jl_value_t *v; + jl_task_t *ct = jl_current_task; + JL_TRY { + jl_value_t **argv; + JL_GC_PUSHARGS(argv, 5); + argv[0] = f; + argv[1] = a; + argv[2] = b; + argv[3] = c; + argv[4] = d; + size_t last_age = ct->world_age; + ct->world_age = jl_get_world_counter(); + v = jl_apply(argv, 5); + ct->world_age = last_age; + JL_GC_POP(); + _jl_exception_clear(ct); + } + JL_CATCH { + ct->ptls->previous_exception = jl_current_exception(ct); + v = NULL; + } + return v; +} + /** * @brief Get a field from a Julia object. * diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 97d76e7762a9e..726312a13d10f 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1002,7 +1002,9 @@ (default-inner-ctors name field-names field-types params bounds locs) defs)) (min-initialized (min (ctors-min-initialized defs) (length fields))) - (prev (make-ssavalue))) + (hasprev (make-ssavalue)) + (prev (make-ssavalue)) + (newdef (make-ssavalue))) (let ((dups (has-dups field-names))) (if dups (error (string "duplicate field name: \"" (car dups) "\" is not unique")))) (for-each (lambda (v) @@ -1023,22 +1025,21 @@ (call (core svec) ,@attrs) ,mut ,min-initialized)) (call (core _setsuper!) ,name ,super) - (if (call (core isdefinedglobal) (thismodule) (inert ,name) (false)) - (block - (= ,prev (globalref (thismodule) ,name)) - (if (call (core _equiv_typedef) ,prev ,name) - ;; if this is compatible with an old definition, use the existing type object - ;; and its parameters - (block (= ,name ,prev) - ,@(if (pair? params) - `((= (tuple ,@params) (|.| - ,(foldl (lambda (_ x) `(|.| ,x (quote body))) - prev - params) - (quote parameters)))) - '()))))) - (call (core _typebody!) ,name (call (core svec) ,@(insert-struct-shim field-types name))) - (const (globalref (thismodule) ,name) ,name) + (= ,hasprev (&& (call (core isdefinedglobal) (thismodule) (inert ,name) (false)) (call (core _equiv_typedef) (globalref (thismodule) ,name) ,name))) + (= ,prev (if ,hasprev (globalref (thismodule) ,name) (false))) + (if ,hasprev + ;; if this is compatible with an old definition, use the old parameters, but the + ;; new object. This will fail to capture recursive cases, but the call to typebody! + ;; below is permitted to choose either type definition to put into the binding table + (block ,@(if (pair? params) + `((= (tuple ,@params) (|.| + ,(foldl (lambda (_ x) `(|.| ,x (quote body))) + prev + params) + (quote parameters)))) + '()))) + (= ,newdef (call (core _typebody!) ,prev ,name (call (core svec) ,@(insert-struct-shim field-types name)))) + (const (globalref (thismodule) ,name) ,newdef) (latestworld) (null))) ;; "inner" constructors @@ -1084,7 +1085,7 @@ (toplevel-only abstract_type) (= ,name (call (core _abstracttype) (thismodule) (inert ,name) (call (core svec) ,@params))) (call (core _setsuper!) ,name ,super) - (call (core _typebody!) ,name) + (call (core _typebody!) (false) ,name) (if (&& (call (core isdefinedglobal) (thismodule) (inert ,name) (false)) (call (core _equiv_typedef) (globalref (thismodule) ,name) ,name)) (null) @@ -1105,7 +1106,7 @@ (toplevel-only primitive_type) (= ,name (call (core _primitivetype) (thismodule) (inert ,name) (call (core svec) ,@params) ,n)) (call (core _setsuper!) ,name ,super) - (call (core _typebody!) ,name) + (call (core _typebody!) (false) ,name) (if (&& (call (core isdefinedglobal) (thismodule) (inert ,name) (false)) (call (core _equiv_typedef) (globalref (thismodule) ,name) ,name)) (null) @@ -3525,7 +3526,7 @@ f(x) = yt(x) (false) ,(length fields))) (call (core _setsuper!) ,s ,super) (const (globalref (thismodule) ,name) ,s) - (call (core _typebody!) ,s (call (core svec) ,@types)) + (call (core _typebody!) (false) ,s (call (core svec) ,@types)) (return (null))))))))) (define (type-for-closure name fields super) @@ -3539,7 +3540,7 @@ f(x) = yt(x) (false) ,(length fields))) (call (core _setsuper!) ,s ,super) (const (globalref (thismodule) ,name) ,s) - (call (core _typebody!) ,s + (call (core _typebody!) (false) ,s (call (core svec) ,@(map (lambda (v) '(core Box)) fields))) (return (null))))))))) @@ -3641,8 +3642,8 @@ f(x) = yt(x) rhs1)) (ex `(= ,var ,rhs))) (if (eq? rhs1 rhs0) - `(block ,ex ,rhs0) - `(block (= ,rhs1 ,rhs0) + `(block (globaldecl ,var) ,ex ,rhs0) + `(block (globaldecl ,var) (= ,rhs1 ,rhs0) ,ex ,rhs1)))) @@ -4624,11 +4625,7 @@ f(x) = yt(x) tests)) (define (emit-assignment-or-setglobal lhs rhs) (if (globalref? lhs) - (begin - (emit `(global ,lhs)) - (if (null? (cadr lam)) - (emit `(latestworld))) - (emit `(call (top setglobal!) ,(cadr lhs) (inert ,(caddr lhs)) ,rhs))) + (emit `(call (top setglobal!) ,(cadr lhs) (inert ,(caddr lhs)) ,rhs)) (emit `(= ,lhs ,rhs)))) (define (emit-assignment lhs rhs) (if rhs @@ -4951,11 +4948,12 @@ f(x) = yt(x) (emit `(latestworld)))) ((globaldecl) (if value (error "misplaced \"global\" declaration")) - (if (atom? (caddr e)) (begin (emit e) (emit `(latestworld))) + (if (or (length= e 2) (atom? (caddr e))) (emit e) (let ((rr (make-ssavalue))) (emit `(= ,rr ,(caddr e))) - (emit `(globaldecl ,(cadr e) ,rr)) - (emit `(latestworld))))) + (emit `(globaldecl ,(cadr e) ,rr)))) + (if (null? (cadr lam)) + (emit `(latestworld)))) ((local-def) #f) ((local) #f) ((moved-local) diff --git a/src/julia.h b/src/julia.h index a80a69049ccb2..dd3bc713a517f 100644 --- a/src/julia.h +++ b/src/julia.h @@ -616,6 +616,52 @@ typedef struct _jl_weakref_t { } jl_weakref_t; // N.B: Needs to be synced with runtime_internals.jl +// We track essentially three levels of binding strength: +// +// 1. Implicit Bindings (Weakest) +// These binding kinds depend solely on the set of using'd packages and are not explicitly +// declared: +// +// BINDING_KIND_IMPLICIT +// BINDING_KIND_GUARD +// BINDING_KIND_FAILED +// +// 2. Weakly Declared Bindings (Weak) +// The binding was declared using `global`. It is treated as a mutable, `Any` type global +// for almost all purposes, except that it receives slightly worse optimizations, since it +// may be replaced. +// +// BINDING_KIND_DECLARED +// +// 3. Strong Declared Bindings (Weak) +// All other bindings are explicitly declared using a keyword or global assignment. +// These are considered strongest: +// +// BINDING_KIND_CONST +// BINDING_KIND_CONST_IMPORT +// BINDING_KIND_EXPLICIT +// BINDING_KIND_IMPORTED +// BINDING_KIND_GLOBAL +// BINDING_KIND_UNDEF_CONST +// +// The runtime supports syntactic invalidation (by raising the world age and changing the partition type +// in the new world age) from any partition kind to any other. +// +// However, not all transitions are allowed syntactically. We have the following rules for SYNTACTIC invalidation: +// 1. It is always syntactically permissable to replace a weaker binding by a stronger binding +// 2. Implicit bindings can be syntactically changed to other implicit bindings by changing the `using` set. +// 3. Finally, we syntactically permit replacing one BINDING_KIND_CONST(_IMPORT) by another of a different value. +// +// We may make this list more permissive in the future. +// +// Finally, BINDING_KIND_BACKDATED_CONST is a special case, and the only case where we may replace an +// existing partition by a different partition kind in the same world age. As such, it needs special +// support in inference. Any partition kind that may be replaced by a BINDING_KIND_BACKDATED_CONST +// must be inferred accordingly. BINDING_KIND_BACKDATED_CONST is intended as a temporary compatibility +// measure. The following kinds may be replaced by BINDING_KIND_BACKDATED_CONST: +// - BINDING_KIND_GUARD +// - BINDING_KIND_FAILED +// - BINDING_KIND_DECLARED enum jl_partition_kind { // Constant: This binding partition is a constant declared using `const _ = ...` // ->restriction holds the constant value @@ -623,7 +669,8 @@ enum jl_partition_kind { // Import Constant: This binding partition is a constant declared using `import A` // ->restriction holds the constant value BINDING_KIND_CONST_IMPORT = 0x1, - // Global: This binding partition is a global variable. + // Global: This binding partition is a global variable. It was declared either using + // `global x::T` to implicitly through a syntactic global assignment. // -> restriction holds the type restriction BINDING_KIND_GLOBAL = 0x2, // Implicit: The binding was implicitly imported from a `using`'d module. @@ -638,7 +685,9 @@ enum jl_partition_kind { // Failed: We attempted to import the binding, but the import was ambiguous // ->restriction is NULL. BINDING_KIND_FAILED = 0x6, - // Declared: The binding was declared using `global` or similar + // Declared: The binding was declared using `global` or similar. This acts in most ways like + // BINDING_KIND_GLOBAL with an `Any` restriction, except that it may be redefined to a stronger + // binding like `const` or an explicit import. // ->restriction is NULL. BINDING_KIND_DECLARED = 0x7, // Guard: The binding was looked at, but no global or import was resolved at the time @@ -651,6 +700,10 @@ enum jl_partition_kind { // Backated constant. A constant that was backdated for compatibility. In all other // ways equivalent to BINDING_KIND_CONST, but prints a warning on access BINDING_KIND_BACKDATED_CONST = 0xa, + + // This is not a real binding kind, but can be used to ask for a re-resolution + // of the implicit binding kind + BINDING_KIND_IMPLICIT_RECOMPUTE = 0xb }; #ifdef _P64 @@ -672,17 +725,7 @@ typedef struct __attribute__((aligned(8))) _jl_binding_partition_t { * * Currently: Low 3 bits hold ->kind on _P64 to avoid needing >8 byte atomics * - * This field is updated atomically with both kind and restriction. The following - * transitions are allowed and modeled by the system: - * - * GUARD -> any - * (DECLARED, FAILED) -> any non-GUARD - * IMPLICIT -> {EXPLICIT, IMPORTED} (->restriction unchanged only) - * - * In addition, we permit (with warning about undefined behavior) changing the restriction - * pointer for CONST(_IMPORT). - * - * All other kind or restriction transitions are disallowed. + * This field is updated atomically with both kind and restriction */ _Atomic(jl_ptr_kind_union_t) restriction; size_t min_world; @@ -717,6 +760,7 @@ typedef struct _jl_module_t { _Atomic(jl_genericmemory_t*) bindingkeyset; // index lookup by name into bindings jl_sym_t *file; int32_t line; + jl_value_t *usings_backedges; // hidden fields: arraylist_t usings; /* arraylist of struct jl_module_using */ // modules with all bindings potentially imported jl_uuid_t build_id; @@ -1996,6 +2040,9 @@ JL_DLLEXPORT void jl_set_module_infer(jl_module_t *self, int value); JL_DLLEXPORT int jl_get_module_infer(jl_module_t *m); JL_DLLEXPORT void jl_set_module_max_methods(jl_module_t *self, int value); JL_DLLEXPORT int jl_get_module_max_methods(jl_module_t *m); +JL_DLLEXPORT jl_value_t *jl_get_module_usings_backedges(jl_module_t *m); +JL_DLLEXPORT jl_value_t *jl_get_module_binding_or_nothing(jl_module_t *m, jl_sym_t *s); + // get binding for reading JL_DLLEXPORT jl_binding_t *jl_get_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var); JL_DLLEXPORT jl_binding_t *jl_get_binding_or_error(jl_module_t *m, jl_sym_t *var); @@ -2007,7 +2054,6 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var); JL_DLLEXPORT int jl_boundp(jl_module_t *m, jl_sym_t *var, int allow_import); JL_DLLEXPORT int jl_defines_or_exports_p(jl_module_t *m, jl_sym_t *var); -JL_DLLEXPORT int jl_binding_resolved_p(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT int jl_globalref_is_const(jl_globalref_t *gr); JL_DLLEXPORT jl_value_t *jl_get_globalref_value(jl_globalref_t *gr); @@ -2253,6 +2299,9 @@ JL_DLLEXPORT jl_value_t *jl_call1(jl_function_t *f JL_MAYBE_UNROOTED, jl_value_t JL_DLLEXPORT jl_value_t *jl_call2(jl_function_t *f JL_MAYBE_UNROOTED, jl_value_t *a JL_MAYBE_UNROOTED, jl_value_t *b JL_MAYBE_UNROOTED); JL_DLLEXPORT jl_value_t *jl_call3(jl_function_t *f JL_MAYBE_UNROOTED, jl_value_t *a JL_MAYBE_UNROOTED, jl_value_t *b JL_MAYBE_UNROOTED, jl_value_t *c JL_MAYBE_UNROOTED); +JL_DLLEXPORT jl_value_t *jl_call4(jl_function_t *f JL_MAYBE_UNROOTED, jl_value_t *a JL_MAYBE_UNROOTED, + jl_value_t *b JL_MAYBE_UNROOTED, jl_value_t *c JL_MAYBE_UNROOTED, + jl_value_t *d JL_MAYBE_UNROOTED); // async signal handling ------------------------------------------------------ diff --git a/src/julia_internal.h b/src/julia_internal.h index 41a650969ae01..5fe6cad0d096c 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -843,12 +843,19 @@ int jl_type_equality_is_identity(jl_value_t *t1, jl_value_t *t2) JL_NOTSAFEPOINT JL_DLLEXPORT void jl_eval_const_decl(jl_module_t *m, jl_value_t *arg, jl_value_t *val); void jl_binding_set_type(jl_binding_t *b, jl_module_t *mod, jl_sym_t *sym, jl_value_t *ty); void jl_eval_global_expr(jl_module_t *m, jl_expr_t *ex, int set_type); -JL_DLLEXPORT void jl_declare_global(jl_module_t *m, jl_value_t *arg, jl_value_t *set_type); +JL_DLLEXPORT void jl_declare_global(jl_module_t *m, jl_value_t *arg, jl_value_t *set_type, int strong); JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val3(jl_binding_t *b JL_ROOTING_ARGUMENT, jl_module_t *mod, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT JL_MAYBE_UNROOTED, enum jl_partition_kind, size_t new_world) JL_GLOBALLY_ROOTED; JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *m, jl_value_t *e, int fast, int expanded, const char **toplevel_filename, int *toplevel_lineno); STATIC_INLINE struct _jl_module_using *module_usings_getidx(jl_module_t *m JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT; STATIC_INLINE jl_module_t *module_usings_getmod(jl_module_t *m JL_PROPAGATES_ROOT, size_t i) JL_NOTSAFEPOINT; +void jl_add_usings_backedge(jl_module_t *from, jl_module_t *to); +typedef struct _modstack_t { + jl_binding_t *b; + struct _modstack_t *prev; +} modstack_t; +void jl_check_new_binding_implicit( + jl_binding_partition_t *new_bpart JL_MAYBE_UNROOTED, jl_binding_t *b, modstack_t *st, size_t world); #ifndef __clang_gcanalyzer__ // The analyzer doesn't like looking through the arraylist, so just model the @@ -905,6 +912,8 @@ void jl_compute_field_offsets(jl_datatype_t *st); void jl_module_run_initializer(jl_module_t *m); JL_DLLEXPORT jl_binding_t *jl_get_module_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, int alloc); JL_DLLEXPORT void jl_binding_deprecation_warning(jl_module_t *m, jl_sym_t *sym, jl_binding_t *b); +JL_DLLEXPORT jl_binding_partition_t *jl_replace_binding_locked(jl_binding_t *b JL_PROPAGATES_ROOT, + jl_binding_partition_t *old_bpart, jl_value_t *restriction_val, enum jl_partition_kind kind, size_t new_world) JL_GLOBALLY_ROOTED; extern jl_array_t *jl_module_init_order JL_GLOBALLY_ROOTED; extern htable_t jl_current_modules JL_GLOBALLY_ROOTED; extern JL_DLLEXPORT jl_module_t *jl_precompile_toplevel_module JL_GLOBALLY_ROOTED; @@ -991,7 +1000,7 @@ STATIC_INLINE int jl_bkind_is_defined_constant(enum jl_partition_kind kind) JL_N } STATIC_INLINE int jl_bkind_is_some_guard(enum jl_partition_kind kind) JL_NOTSAFEPOINT { - return kind == BINDING_KIND_FAILED || kind == BINDING_KIND_GUARD || kind == BINDING_KIND_DECLARED; + return kind == BINDING_KIND_FAILED || kind == BINDING_KIND_GUARD; } JL_DLLEXPORT jl_binding_partition_t *jl_get_binding_partition(jl_binding_t *b JL_PROPAGATES_ROOT, size_t world) JL_GLOBALLY_ROOTED; diff --git a/src/method.c b/src/method.c index 8a14eb00182b1..1b38a16649d8a 100644 --- a/src/method.c +++ b/src/method.c @@ -62,6 +62,11 @@ static jl_value_t *resolve_definition_effects(jl_value_t *expr, jl_module_t *mod jl_eval_global_expr(module, e, 1); return jl_nothing; } + if (e->head == jl_globaldecl_sym && binding_effects) { + assert(jl_expr_nargs(e) == 1); + jl_declare_global(module, jl_exprarg(e, 0), NULL, 1); + return jl_nothing; + } // These exprs are not fully linearized if (e->head == jl_assign_sym) { jl_exprargset(e, 1, resolve_definition_effects(jl_exprarg(e, 1), module, sparam_vals, binding_edge, binding_effects, eager_resolve)); @@ -180,26 +185,24 @@ static jl_value_t *resolve_definition_effects(jl_value_t *expr, jl_module_t *mod jl_value_t *fe = jl_exprarg(e, 0); jl_module_t *fe_mod = jl_globalref_mod(fe); jl_sym_t *fe_sym = jl_globalref_name(fe); - if (jl_binding_resolved_p(fe_mod, fe_sym)) { - // look at some known called functions - jl_binding_t *b = jl_get_binding(fe_mod, fe_sym); - if (jl_get_binding_value_if_const(b) == jl_builtin_tuple) { - size_t j; - for (j = 1; j < nargs; j++) { - if (!jl_is_quotenode(jl_exprarg(e, j))) - break; + // look at some known called functions + jl_binding_t *b = jl_get_binding(fe_mod, fe_sym); + if (jl_get_binding_value_if_const(b) == jl_builtin_tuple) { + size_t j; + for (j = 1; j < nargs; j++) { + if (!jl_is_quotenode(jl_exprarg(e, j))) + break; + } + if (j == nargs) { + jl_value_t *val = NULL; + JL_TRY { + val = jl_interpret_toplevel_expr_in(module, (jl_value_t*)e, NULL, sparam_vals); } - if (j == nargs) { - jl_value_t *val = NULL; - JL_TRY { - val = jl_interpret_toplevel_expr_in(module, (jl_value_t*)e, NULL, sparam_vals); - } - JL_CATCH { - val = NULL; // To make the analyzer happy see #define JL_TRY - } - if (val) - return val; + JL_CATCH { + val = NULL; // To make the analyzer happy see #define JL_TRY } + if (val) + return val; } } } @@ -1052,9 +1055,11 @@ JL_DLLEXPORT jl_value_t *jl_declare_const_gf(jl_binding_t *b, jl_module_t *mod, JL_LOCK(&world_counter_lock); size_t new_world = jl_atomic_load_relaxed(&jl_world_counter) + 1; jl_binding_partition_t *bpart = jl_get_binding_partition(b, new_world); - jl_ptr_kind_union_t pku = jl_walk_binding_inplace(&b, &bpart, new_world); + jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); jl_value_t *gf = NULL; - if (!jl_bkind_is_some_guard(decode_restriction_kind(pku))) { + enum jl_partition_kind kind = decode_restriction_kind(pku); + if (!jl_bkind_is_some_guard(kind) && kind != BINDING_KIND_DECLARED && kind != BINDING_KIND_IMPLICIT) { + pku = jl_walk_binding_inplace(&b, &bpart, new_world); if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) { gf = decode_restriction_value(pku); JL_GC_PROMISE_ROOTED(gf); diff --git a/src/module.c b/src/module.c index b2a4018519fca..1b6b37e49949e 100644 --- a/src/module.c +++ b/src/module.c @@ -29,7 +29,130 @@ static jl_binding_partition_t *new_binding_partition(void) return bpart; } -jl_binding_partition_t *jl_get_binding_partition(jl_binding_t *b, size_t world) { + +static jl_binding_partition_t *jl_get_binding_partition2(jl_binding_t *b, size_t world, modstack_t *st); + +static int eq_bindings(jl_binding_partition_t *owner, jl_binding_t *alias, size_t world) +{ + jl_binding_t *ownerb = NULL; + jl_binding_partition_t *alias_bpart = jl_get_binding_partition(alias, world); + if (owner == alias_bpart) + return 1; + jl_ptr_kind_union_t owner_pku = jl_walk_binding_inplace(&ownerb, &owner, world); + jl_ptr_kind_union_t alias_pku = jl_walk_binding_inplace(&alias, &alias_bpart, world); + if (jl_bkind_is_some_constant(decode_restriction_kind(owner_pku)) && + jl_bkind_is_some_constant(decode_restriction_kind(alias_pku)) && + decode_restriction_value(owner_pku) && + decode_restriction_value(alias_pku) == decode_restriction_value(owner_pku)) + return 1; + return owner == alias_bpart; +} + +// find a binding from a module's `usings` list +void jl_check_new_binding_implicit( + jl_binding_partition_t *new_bpart JL_MAYBE_UNROOTED, jl_binding_t *b, modstack_t *st, size_t world) +{ + modstack_t top = { b, st }; + modstack_t *tmp = st; + for (; tmp != NULL; tmp = tmp->prev) { + if (tmp->b == b) { + jl_atomic_store_relaxed(&new_bpart->restriction, encode_restriction(NULL, BINDING_KIND_FAILED /* BINDING_KIND_CYCLE */)); + return; + } + } + + JL_GC_PUSH1(&new_bpart); + jl_module_t *m = b->globalref->mod; + jl_sym_t *var = b->globalref->name; + + jl_binding_t *deprecated_impb = NULL; + jl_binding_t *impb = NULL; + + size_t min_world = new_bpart->min_world; + size_t max_world = jl_atomic_load_relaxed(&new_bpart->max_world); + + JL_LOCK(&m->lock); + int i = (int)module_usings_length(m) - 1; + JL_UNLOCK(&m->lock); + enum jl_partition_kind guard_kind = BINDING_KIND_GUARD; + for (; i >= 0; --i) { + JL_LOCK(&m->lock); + struct _jl_module_using data = *module_usings_getidx(m, i); + JL_UNLOCK(&m->lock); + if (data.min_world > world) { + if (max_world > data.min_world) + max_world = data.min_world - 1; + continue; + } + if (data.max_world < world) { + if (min_world < data.max_world) + min_world = data.max_world + 1; + continue; + } + jl_module_t *imp = data.mod; + JL_GC_PROMISE_ROOTED(imp); + jl_binding_t *tempb = jl_get_module_binding(imp, var, 0); + if (tempb != NULL && tempb->exportp) { + if (data.min_world > min_world) + min_world = data.min_world; + if (data.max_world < min_world) + max_world = data.max_world; + + jl_binding_partition_t *tempbpart = jl_get_binding_partition2(tempb, world, &top); + JL_GC_PROMISE_ROOTED(tempbpart); + + size_t tempbmax_world = jl_atomic_load_relaxed(&tempbpart->max_world); + if (tempbpart->min_world > min_world) + min_world = tempbpart->min_world; + if (tempbmax_world < max_world) + max_world = tempbmax_world; + + if (impb) { + if (tempb->deprecated) + continue; + if (eq_bindings(tempbpart, impb, world)) + continue; + // Binding is ambiguous + // TODO: Even for eq bindings, this may need to further constrain the world age. + deprecated_impb = impb = NULL; + guard_kind = BINDING_KIND_FAILED; + break; + } + else if (tempb->deprecated) { + if (deprecated_impb) { + if (!eq_bindings(tempbpart, deprecated_impb, world)) { + guard_kind = BINDING_KIND_FAILED; + deprecated_impb = NULL; + } + } + else if (guard_kind == BINDING_KIND_GUARD) { + deprecated_impb = tempb; + } + } + else { + impb = tempb; + } + } + } + + if (deprecated_impb && !impb) + impb = deprecated_impb; + + assert(min_world <= max_world); + new_bpart->min_world = min_world; + jl_atomic_store_relaxed(&new_bpart->max_world, max_world); + if (impb) { + jl_atomic_store_relaxed(&new_bpart->restriction, encode_restriction((jl_value_t*)impb, BINDING_KIND_IMPLICIT)); + // TODO: World age constraints? + } else { + jl_atomic_store_relaxed(&new_bpart->restriction, encode_restriction(NULL, guard_kind)); + } + JL_GC_POP(); + return; +} + +STATIC_INLINE jl_binding_partition_t *jl_get_binding_partition_(jl_binding_t *b JL_PROPAGATES_ROOT, size_t world, modstack_t *st) JL_GLOBALLY_ROOTED +{ if (!b) return NULL; assert(jl_is_binding(b)); @@ -53,6 +176,8 @@ jl_binding_partition_t *jl_get_binding_partition(jl_binding_t *b, size_t world) jl_gc_wb_fresh(new_bpart, bpart); new_bpart->min_world = bpart ? jl_atomic_load_relaxed(&bpart->max_world) + 1 : 0; jl_atomic_store_relaxed(&new_bpart->max_world, max_world); + JL_GC_PROMISE_ROOTED(new_bpart); // TODO: Analyzer doesn't understand MAYBE_UNROOTED properly + jl_check_new_binding_implicit(new_bpart, b, st, world); if (jl_atomic_cmpswap(insert, &bpart, new_bpart)) { jl_gc_wb(parent, new_bpart); return new_bpart; @@ -60,6 +185,15 @@ jl_binding_partition_t *jl_get_binding_partition(jl_binding_t *b, size_t world) } } +jl_binding_partition_t *jl_get_binding_partition(jl_binding_t *b, size_t world) { + // Duplicate the code for the entry frame for branch prediction + return jl_get_binding_partition_(b, world, NULL); +} + +jl_binding_partition_t *jl_get_binding_partition2(jl_binding_t *b JL_PROPAGATES_ROOT, size_t world, modstack_t *st) JL_GLOBALLY_ROOTED { + return jl_get_binding_partition_(b, world, st); +} + jl_binding_partition_t *jl_get_binding_partition_all(jl_binding_t *b, size_t min_world, size_t max_world) { if (!b) return NULL; @@ -89,6 +223,7 @@ JL_DLLEXPORT jl_module_t *jl_new_module_(jl_sym_t *name, jl_module_t *parent, ui m->build_id.lo++; // build id 0 is invalid m->build_id.hi = ~(uint64_t)0; jl_atomic_store_relaxed(&m->counter, 1); + m->usings_backedges = jl_nothing; m->nospecialize = 0; m->optlevel = -1; m->compile = -1; @@ -255,7 +390,7 @@ extern jl_mutex_t jl_modules_mutex; extern void check_safe_newbinding(jl_module_t *m, jl_sym_t *var) { if (jl_current_task->ptls->in_pure_callback) - jl_errorf("new globals cannot be created in a generated function"); + jl_errorf("new strong globals cannot be created in a generated function. Declare them outside using `global x::Any`."); if (jl_options.incremental && jl_generating_output()) { JL_LOCK(&jl_modules_mutex); int open = ptrhash_has(&jl_current_modules, (void*)m); @@ -285,20 +420,14 @@ JL_DLLEXPORT void jl_check_binding_currently_writable(jl_binding_t *b, jl_module { jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); -retry: - if (decode_restriction_kind(pku) != BINDING_KIND_GLOBAL && !jl_bkind_is_some_constant(decode_restriction_kind(pku))) { - if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) { - if (decode_restriction_kind(pku) != BINDING_KIND_DECLARED) { - jl_errorf("Global %s.%s does not exist and cannot be assigned.\n" - "Note: Julia 1.9 and 1.10 inadvertently omitted this error check (#56933).\n" - "Hint: Declare it using `global %s` inside `%s` before attempting assignment.", - jl_symbol_name(m->name), jl_symbol_name(s), - jl_symbol_name(s), jl_symbol_name(m->name)); - } - jl_ptr_kind_union_t new_pku = encode_restriction((jl_value_t*)jl_any_type, BINDING_KIND_GLOBAL); - if (!jl_atomic_cmpswap(&bpart->restriction, &pku, new_pku)) - goto retry; - jl_gc_wb_knownold(bpart, jl_any_type); + enum jl_partition_kind kind = decode_restriction_kind(pku); + if (kind != BINDING_KIND_GLOBAL && kind != BINDING_KIND_DECLARED && !jl_bkind_is_some_constant(kind)) { + if (jl_bkind_is_some_guard(kind)) { + jl_errorf("Global %s.%s does not exist and cannot be assigned.\n" + "Note: Julia 1.9 and 1.10 inadvertently omitted this error check (#56933).\n" + "Hint: Declare it using `global %s` inside `%s` before attempting assignment.", + jl_symbol_name(m->name), jl_symbol_name(s), + jl_symbol_name(s), jl_symbol_name(m->name)); } else { jl_module_t *from = jl_binding_dbgmodule(b, m, s); if (from == m) @@ -321,10 +450,10 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, // return module of binding JL_DLLEXPORT jl_module_t *jl_get_module_of_binding(jl_module_t *m, jl_sym_t *var) { - jl_binding_t *b = jl_get_binding(m, var); - if (b == NULL) - return NULL; - return b->globalref->mod; // TODO: deprecate this? + jl_binding_t *b = jl_get_module_binding(m, var, 1); + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); + return b ? b->globalref->mod : m; } static NOINLINE void print_backdate_admonition(jl_binding_t *b) JL_NOTSAFEPOINT @@ -358,6 +487,7 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value(jl_binding_t *b) check_backdated_binding(b, kind); return decode_restriction_value(pku); } + assert(!jl_bkind_is_some_import(kind)); return jl_atomic_load_relaxed(&b->value); } @@ -372,6 +502,7 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_seqcst(jl_binding_t *b) check_backdated_binding(b, kind); return decode_restriction_value(pku); } + assert(!jl_bkind_is_some_import(kind)); return jl_atomic_load(&b->value); } @@ -444,19 +575,14 @@ JL_DLLEXPORT jl_value_t *jl_bpart_get_restriction_value(jl_binding_partition_t * return v; } -typedef struct _modstack_t { - jl_module_t *m; - jl_sym_t *var; - struct _modstack_t *prev; -} modstack_t; -static jl_binding_t *jl_resolve_owner(jl_binding_t *b/*optional*/, jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, modstack_t *st, size_t world); - JL_DLLEXPORT jl_value_t *jl_reresolve_binding_value_seqcst(jl_binding_t *b) { + /* jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); if (jl_bkind_is_some_guard(decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)))) { jl_resolve_owner(b, b->globalref->mod, b->globalref->name, NULL, jl_current_task->world_age); } + */ return jl_get_binding_value_seqcst(b); } @@ -467,91 +593,48 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_ jl_binding_t *b = jl_get_module_binding(m, var, 1); jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - if (decode_restriction_kind(pku) != BINDING_KIND_GLOBAL && !jl_bkind_is_some_constant(decode_restriction_kind(pku))) { - if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) { - if (decode_restriction_kind(pku) != BINDING_KIND_DECLARED) { - check_safe_newbinding(m, var); - } + enum jl_partition_kind kind = decode_restriction_kind(pku); + if (kind == BINDING_KIND_GLOBAL || kind == BINDING_KIND_DECLARED || jl_bkind_is_some_constant(decode_restriction_kind(pku))) + return b; + if (jl_bkind_is_some_guard(kind)) { + check_safe_newbinding(m, var); + return b; + } + jl_binding_t *ownerb = b; + pku = jl_walk_binding_inplace(&ownerb, &bpart, jl_current_task->world_age); + jl_value_t *f = NULL; + if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) + f = decode_restriction_value(pku); + if (f == NULL) { + if (kind == BINDING_KIND_IMPLICIT) { + check_safe_newbinding(m, var); return b; } - jl_value_t *f = jl_get_binding_value_if_const(b); - if (f == NULL) { - jl_module_t *from = jl_binding_dbgmodule(b, m, var); - // we must have implicitly imported this with using, so call jl_binding_dbgmodule to try to get the name of the module we got this from - jl_errorf("invalid method definition in %s: exported function %s.%s does not exist", - jl_symbol_name(m->name), jl_symbol_name(from->name), jl_symbol_name(var)); + jl_module_t *from = jl_binding_dbgmodule(b, m, var); + // we must have implicitly imported this with using, so call jl_binding_dbgmodule to try to get the name of the module we got this from + jl_errorf("invalid method definition in %s: exported function %s.%s does not exist", + jl_symbol_name(m->name), from ? jl_symbol_name(from->name) : "", jl_symbol_name(var)); + } + int istype = f && jl_is_type(f); + if (!istype) { + if (kind == BINDING_KIND_IMPLICIT) { + check_safe_newbinding(m, var); + return b; } - // TODO: we might want to require explicitly importing types to add constructors - // or we might want to drop this error entirely - if (decode_restriction_kind(pku) != BINDING_KIND_IMPORTED && !(f && jl_is_type(f) && strcmp(jl_symbol_name(var), "=>") != 0)) { + else if (kind != BINDING_KIND_IMPORTED) { + // TODO: we might want to require explicitly importing types to add constructors + // or we might want to drop this error entirely jl_module_t *from = jl_binding_dbgmodule(b, m, var); jl_errorf("invalid method definition in %s: function %s.%s must be explicitly imported to be extended", - jl_symbol_name(m->name), jl_symbol_name(from->name), jl_symbol_name(var)); + jl_symbol_name(m->name), from ? jl_symbol_name(from->name) : "", jl_symbol_name(var)); } - return b; } - return b; -} - -static int eq_bindings(jl_binding_partition_t *owner, jl_binding_t *alias, size_t world) -{ - jl_ptr_kind_union_t owner_pku = jl_atomic_load_relaxed(&owner->restriction); - assert(decode_restriction_kind(owner_pku) == BINDING_KIND_GLOBAL || decode_restriction_kind(owner_pku) == BINDING_KIND_DECLARED || - jl_bkind_is_some_constant(decode_restriction_kind(owner_pku))); - jl_binding_partition_t *alias_bpart = jl_get_binding_partition(alias, world); - if (owner == alias_bpart) - return 1; - jl_ptr_kind_union_t alias_pku = jl_walk_binding_inplace(&alias, &alias_bpart, world); - if (jl_bkind_is_some_constant(decode_restriction_kind(owner_pku)) && - jl_bkind_is_some_constant(decode_restriction_kind(alias_pku)) && - decode_restriction_value(owner_pku) && - decode_restriction_value(alias_pku) == decode_restriction_value(owner_pku)) - return 1; - return owner == alias_bpart; -} - -// find a binding from a module's `usings` list -static jl_binding_t *using_resolve_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, jl_module_t **from, modstack_t *st, int warn, size_t world) -{ - jl_binding_t *b = NULL; - jl_binding_partition_t *bpart = NULL; - jl_module_t *owner = NULL; - JL_LOCK(&m->lock); - int i = (int)module_usings_length(m) - 1; - JL_UNLOCK(&m->lock); - for (; i >= 0; --i) { - JL_LOCK(&m->lock); - jl_module_t *imp = module_usings_getmod(m, i); - JL_UNLOCK(&m->lock); - jl_binding_t *tempb = jl_get_module_binding(imp, var, 0); - if (tempb != NULL && tempb->exportp) { - tempb = jl_resolve_owner(NULL, imp, var, st, world); // find the owner for tempb - if (tempb == NULL) - // couldn't resolve; try next using (see issue #6105) - continue; - jl_binding_partition_t *tempbpart = jl_get_binding_partition(tempb, world); - jl_ptr_kind_union_t tempb_pku = jl_atomic_load_relaxed(&tempbpart->restriction); - assert(jl_bkind_is_some_guard(decode_restriction_kind(tempb_pku)) || decode_restriction_kind(tempb_pku) == BINDING_KIND_GLOBAL || decode_restriction_kind(tempb_pku) == BINDING_KIND_DECLARED || jl_bkind_is_some_constant(decode_restriction_kind(tempb_pku))); - (void)tempb_pku; - if (bpart != NULL && !tempb->deprecated && !b->deprecated && !eq_bindings(tempbpart, b, world)) { - if (warn) { - // set usingfailed=1 to avoid repeating this warning - // the owner will still be NULL, so it can be later imported or defined - tempb = jl_get_module_binding(m, var, 1); - tempbpart = jl_get_binding_partition(tempb, world); - jl_atomic_store_release(&tempbpart->restriction, encode_restriction(NULL, BINDING_KIND_FAILED)); - } - return NULL; - } - if (owner == NULL || !tempb->deprecated) { - owner = imp; - b = tempb; - bpart = tempbpart; - } - } + else if (strcmp(jl_symbol_name(var), "=>") == 0 && (kind == BINDING_KIND_IMPLICIT || kind == BINDING_KIND_EXPLICIT)) { + jl_module_t *from = jl_binding_dbgmodule(b, m, var); + jl_errorf("invalid method definition in %s: function %s.%s must be explicitly imported to be extended", + jl_symbol_name(m->name), from ? jl_symbol_name(from->name) : "", jl_symbol_name(var)); } - *from = owner; - return b; + return ownerb; } // for error message printing: look up the module that exported a binding to m as var @@ -559,100 +642,15 @@ static jl_binding_t *using_resolve_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl static jl_module_t *jl_binding_dbgmodule(jl_binding_t *b, jl_module_t *m, jl_sym_t *var) { jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - if (decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)) != BINDING_KIND_GLOBAL) { - // for implicitly imported globals, try to re-resolve it to find the module we got it from most directly - jl_module_t *from = NULL; - jl_binding_t *b2 = using_resolve_binding(m, var, &from, NULL, 0, jl_current_task->world_age); - if (b2) { - jl_binding_partition_t *b2part = jl_get_binding_partition(b2, jl_current_task->world_age); - if (eq_bindings(b2part, b, jl_current_task->world_age)) - return from; - // if we did not find it (or accidentally found a different one), ignore this - } + jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); + if (jl_bkind_is_some_import(decode_restriction_kind(pku))) { + return ((jl_binding_t*)decode_restriction_value(pku))->globalref->mod; } return m; } static void jl_binding_dep_message(jl_module_t *m, jl_sym_t *name, jl_binding_t *b); -// get binding for reading. might return NULL for unbound. -static jl_binding_t *jl_resolve_owner(jl_binding_t *b/*optional*/, jl_module_t *m, jl_sym_t *var, modstack_t *st, size_t world) -{ - if (b == NULL) - b = jl_get_module_binding(m, var, 1); - jl_binding_partition_t *bpart = jl_get_binding_partition(b, world); - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); -retry: - if (decode_restriction_kind(pku) == BINDING_KIND_FAILED) - return NULL; - if (decode_restriction_kind(pku) == BINDING_KIND_DECLARED) { - return b; - } - if (decode_restriction_kind(pku) == BINDING_KIND_GUARD) { - jl_binding_t *b2 = NULL; - modstack_t top = { m, var, st }; - modstack_t *tmp = st; - for (; tmp != NULL; tmp = tmp->prev) { - if (tmp->m == m && tmp->var == var) { - // import cycle without finding actual location - return NULL; - } - } - jl_module_t *from = NULL; // for error message printing - b2 = using_resolve_binding(m, var, &from, &top, 1, world); - if (b2 == NULL) - return NULL; - assert(from); - JL_GC_PROMISE_ROOTED(from); // gc-analysis does not understand output parameters - JL_GC_PROMISE_ROOTED(b2); - if (b2->deprecated) { - if (jl_get_binding_value(b2) == jl_nothing) { - // silently skip importing deprecated values assigned to nothing (to allow later mutation) - return NULL; - } - } - // do a full import to prevent the result of this lookup from - // changing, for example if this var is assigned to later. - if (!jl_atomic_cmpswap(&bpart->restriction, &pku, encode_restriction((jl_value_t*)b2, BINDING_KIND_IMPLICIT))) - goto retry; - jl_gc_wb(bpart, b2); - if (b2->deprecated) { - b->deprecated = 1; // we will warn about this below, but we might want to warn at the use sites too - if (m != jl_main_module && m != jl_base_module && - jl_options.depwarn != JL_OPTIONS_DEPWARN_OFF) { - /* with #22763, external packages wanting to replace - deprecated Base bindings should simply export the new - binding */ - jl_printf(JL_STDERR, - "WARNING: using deprecated binding %s.%s in %s.\n", - jl_symbol_name(from->name), jl_symbol_name(var), - jl_symbol_name(m->name)); - jl_binding_dep_message(from, var, b2); - } - } - return b2; - } - jl_walk_binding_inplace(&b, &bpart, world); - return b; -} - -// get the current likely owner of binding when accessing m.var, without resolving the binding (it may change later) -JL_DLLEXPORT jl_binding_t *jl_binding_owner(jl_module_t *m, jl_sym_t *var) -{ - jl_binding_t *b = jl_get_module_binding(m, var, 1); - jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - jl_module_t *from = m; - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - if (decode_restriction_kind(pku) == BINDING_KIND_GUARD) { - b = using_resolve_binding(m, var, &from, NULL, 0, jl_current_task->world_age); - bpart = jl_get_binding_partition(b, jl_current_task->world_age); - } - pku = jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); - if (decode_restriction_kind(pku) != BINDING_KIND_GLOBAL && !jl_bkind_is_some_constant(decode_restriction_kind(pku))) - return NULL; - return b; -} - // get type of binding m.var, without resolving the binding JL_DLLEXPORT jl_value_t *jl_get_binding_type(jl_module_t *m, jl_sym_t *var) { @@ -675,7 +673,7 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_type(jl_module_t *m, jl_sym_t *var) JL_DLLEXPORT jl_binding_t *jl_get_binding(jl_module_t *m, jl_sym_t *var) { - return jl_resolve_owner(NULL, m, var, NULL, jl_current_task->world_age); + return jl_get_module_binding(m, var, 1); } JL_DLLEXPORT jl_binding_t *jl_get_binding_or_error(jl_module_t *m, jl_sym_t *var) @@ -762,81 +760,82 @@ static void jl_binding_dep_message(jl_module_t *m, jl_sym_t *name, jl_binding_t static void module_import_(jl_module_t *to, jl_module_t *from, jl_sym_t *asname, jl_sym_t *s, int explici) { jl_binding_t *b = jl_get_binding(from, s); - if (b == NULL) { + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); + (void)pku; + if (b->deprecated) { + if (jl_get_binding_value(b) == jl_nothing) { + // silently skip importing deprecated values assigned to nothing (to allow later mutation) + return; + } + else if (to != jl_main_module && to != jl_base_module && + jl_options.depwarn != JL_OPTIONS_DEPWARN_OFF) { + /* with #22763, external packages wanting to replace + deprecated Base bindings should simply export the new + binding */ + jl_printf(JL_STDERR, + "WARNING: importing deprecated binding %s.%s into %s%s%s.\n", + jl_symbol_name(from->name), jl_symbol_name(s), + jl_symbol_name(to->name), + asname == s ? "" : " as ", + asname == s ? "" : jl_symbol_name(asname)); + jl_binding_dep_message(from, s, b); + } + } + + jl_binding_t *ownerb = b; + jl_binding_partition_t *ownerbpart = bpart; + jl_ptr_kind_union_t owner_pku = jl_walk_binding_inplace(&ownerb, &ownerbpart, jl_current_task->world_age); + + if (jl_bkind_is_some_guard(decode_restriction_kind(owner_pku))) { jl_printf(JL_STDERR, - "WARNING: could not import %s.%s into %s\n", + "WARNING: Imported binding %s.%s was undeclared at import time during import to %s.\n", jl_symbol_name(from->name), jl_symbol_name(s), jl_symbol_name(to->name)); } + + jl_binding_t *bto = jl_get_module_binding(to, asname, 1); + if (bto == b) { + // importing a binding on top of itself. harmless. + return; + } + JL_LOCK(&world_counter_lock); + size_t new_world = jl_atomic_load_acquire(&jl_world_counter)+1; + jl_binding_partition_t *btopart = jl_get_binding_partition(bto, new_world); + jl_ptr_kind_union_t bto_pku = jl_atomic_load_relaxed(&btopart->restriction); + if (decode_restriction_kind(bto_pku) == BINDING_KIND_GUARD || + decode_restriction_kind(bto_pku) == BINDING_KIND_IMPLICIT || + decode_restriction_kind(bto_pku) == BINDING_KIND_FAILED) { + + jl_binding_partition_t *new_bpart = jl_replace_binding_locked(bto, btopart, (jl_value_t*)b, (explici != 0) ? BINDING_KIND_IMPORTED : BINDING_KIND_EXPLICIT, new_world); + if (jl_atomic_load_relaxed(&new_bpart->max_world) == ~(size_t)0) + jl_add_binding_backedge(b, (jl_value_t*)bto); + jl_atomic_store_release(&jl_world_counter, new_world); + } else { - jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - assert(decode_restriction_kind(pku) == BINDING_KIND_GLOBAL || decode_restriction_kind(pku) == BINDING_KIND_DECLARED || jl_bkind_is_some_constant(decode_restriction_kind(pku))); - (void)pku; - if (b->deprecated) { - if (jl_get_binding_value(b) == jl_nothing) { - // silently skip importing deprecated values assigned to nothing (to allow later mutation) - return; - } - else if (to != jl_main_module && to != jl_base_module && - jl_options.depwarn != JL_OPTIONS_DEPWARN_OFF) { - /* with #22763, external packages wanting to replace - deprecated Base bindings should simply export the new - binding */ - jl_printf(JL_STDERR, - "WARNING: importing deprecated binding %s.%s into %s%s%s.\n", - jl_symbol_name(from->name), jl_symbol_name(s), - jl_symbol_name(to->name), - asname == s ? "" : " as ", - asname == s ? "" : jl_symbol_name(asname)); - jl_binding_dep_message(from, s, b); + if (eq_bindings(bpart, bto, new_world)) { + // already imported - potentially upgrade _EXPLICIT to _IMPORTED + if (decode_restriction_kind(bto_pku) == BINDING_KIND_EXPLICIT && explici != 0) { + jl_replace_binding_locked(bto, btopart, (jl_value_t*)b, BINDING_KIND_IMPORTED, new_world); + jl_atomic_store_release(&jl_world_counter, new_world); } } - - jl_binding_t *bto = jl_get_module_binding(to, asname, 1); - if (bto == b) { - // importing a binding on top of itself. harmless. - return; - } - jl_binding_partition_t *btopart = jl_get_binding_partition(bto, jl_current_task->world_age); - jl_ptr_kind_union_t bto_pku = jl_atomic_load_relaxed(&btopart->restriction); -retry: - if (decode_restriction_kind(bto_pku) == BINDING_KIND_GUARD || - decode_restriction_kind(bto_pku) == BINDING_KIND_IMPLICIT || - decode_restriction_kind(bto_pku) == BINDING_KIND_FAILED) { - - jl_ptr_kind_union_t new_pku = encode_restriction((jl_value_t*)b, (explici != 0) ? BINDING_KIND_IMPORTED : BINDING_KIND_EXPLICIT); - if (!jl_atomic_cmpswap(&btopart->restriction, &bto_pku, new_pku)) - goto retry; - jl_gc_wb(btopart, b); - bto->deprecated |= b->deprecated; // we already warned about this above, but we might want to warn at the use sites too + else if (jl_bkind_is_some_import(decode_restriction_kind(bto_pku))) { + // already imported from somewhere else + jl_printf(JL_STDERR, + "WARNING: ignoring conflicting import of %s.%s into %s\n", + jl_symbol_name(from->name), jl_symbol_name(s), + jl_symbol_name(to->name)); } else { - if (eq_bindings(bpart, bto, jl_current_task->world_age)) { - // already imported - potentially upgrade to _IMPORTED or _EXPLICIT - if (jl_bkind_is_some_import(decode_restriction_kind(bto_pku))) { - jl_ptr_kind_union_t new_pku = encode_restriction(decode_restriction_value(bto_pku), (explici != 0) ? BINDING_KIND_IMPORTED : BINDING_KIND_EXPLICIT); - if (!jl_atomic_cmpswap(&btopart->restriction, &bto_pku, new_pku)) - goto retry; - // No wb, because the value is unchanged - } - } - else if (jl_bkind_is_some_import(decode_restriction_kind(bto_pku))) { - // already imported from somewhere else - jl_printf(JL_STDERR, - "WARNING: ignoring conflicting import of %s.%s into %s\n", - jl_symbol_name(from->name), jl_symbol_name(s), - jl_symbol_name(to->name)); - } - else { - // conflict with name owned by destination module - jl_printf(JL_STDERR, - "WARNING: import of %s.%s into %s conflicts with an existing identifier; ignored.\n", - jl_symbol_name(from->name), jl_symbol_name(s), - jl_symbol_name(to->name)); - } + // conflict with name owned by destination module + jl_printf(JL_STDERR, + "WARNING: import of %s.%s into %s conflicts with an existing identifier; ignored.\n", + jl_symbol_name(from->name), jl_symbol_name(s), + jl_symbol_name(to->name)); } } + JL_UNLOCK(&world_counter_lock); } JL_DLLEXPORT void jl_module_import(jl_module_t *to, jl_module_t *from, jl_sym_t *s) @@ -859,57 +858,85 @@ JL_DLLEXPORT void jl_module_use_as(jl_module_t *to, jl_module_t *from, jl_sym_t module_import_(to, from, asname, s, 0); } +void jl_add_usings_backedge(jl_module_t *from, jl_module_t *to) +{ + JL_LOCK(&from->lock); + if (from->usings_backedges == jl_nothing) { + from->usings_backedges = (jl_value_t*)jl_alloc_vec_any(0); + jl_gc_wb(from, from->usings_backedges); + } + jl_array_ptr_1d_push((jl_array_t*)from->usings_backedges, (jl_value_t*)to); + JL_UNLOCK(&from->lock); +} + JL_DLLEXPORT void jl_module_using(jl_module_t *to, jl_module_t *from) { if (to == from) return; + JL_LOCK(&world_counter_lock); JL_LOCK(&to->lock); for (size_t i = 0; i < module_usings_length(to); i++) { if (from == module_usings_getmod(to, i)) { JL_UNLOCK(&to->lock); + JL_UNLOCK(&world_counter_lock); return; } } + + size_t new_world = jl_atomic_load_acquire(&jl_world_counter)+1; struct _jl_module_using new_item = { .mod = from, - .min_world = 0, - .max_world = (size_t)-1 + .min_world = new_world, + .max_world = ~(size_t)0 }; arraylist_grow(&to->usings, sizeof(struct _jl_module_using)/sizeof(void*)); memcpy(&to->usings.items[to->usings.len-3], &new_item, sizeof(struct _jl_module_using)); jl_gc_wb(to, from); + JL_UNLOCK(&to->lock); - // print a warning if something visible via this "using" conflicts with - // an existing identifier. note that an identifier added later may still - // silently override a "using" name. see issue #2054. + // Go through all exported bindings. If we have a binding for this in the + // importing module and it is some import or guard, we need to recompute + // it. jl_svec_t *table = jl_atomic_load_relaxed(&from->bindings); for (size_t i = 0; i < jl_svec_len(table); i++) { jl_binding_t *b = (jl_binding_t*)jl_svecref(table, i); if ((void*)b == jl_nothing) break; - jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - if (b->exportp && (decode_restriction_kind(pku) == BINDING_KIND_GLOBAL || decode_restriction_kind(pku) == BINDING_KIND_IMPORTED)) { + if (b->exportp) { jl_sym_t *var = b->globalref->name; jl_binding_t *tob = jl_get_module_binding(to, var, 0); if (tob) { - jl_binding_partition_t *tobpart = jl_get_binding_partition(tob, jl_current_task->world_age); - jl_ptr_kind_union_t tobpku = jl_walk_binding_inplace(&tob, &tobpart, jl_current_task->world_age); - if (tob && decode_restriction_kind(tobpku) != BINDING_KIND_GUARD && - // don't warn for conflicts with the module name itself. - // see issue #4715 - var != to->name && - !eq_bindings(tobpart, b, jl_current_task->world_age)) { - jl_printf(JL_STDERR, - "WARNING: using %s.%s in module %s conflicts with an existing identifier.\n", - jl_symbol_name(from->name), jl_symbol_name(var), - jl_symbol_name(to->name)); + jl_binding_partition_t *tobpart = jl_get_binding_partition(tob, new_world); + jl_ptr_kind_union_t tobpku = jl_atomic_load_relaxed(&tobpart->restriction); + enum jl_partition_kind kind = decode_restriction_kind(tobpku); + if (kind == BINDING_KIND_IMPLICIT || jl_bkind_is_some_guard(kind)) { + jl_replace_binding_locked(tob, tobpart, NULL, BINDING_KIND_IMPLICIT_RECOMPUTE, new_world); } } } table = jl_atomic_load_relaxed(&from->bindings); } + + jl_add_usings_backedge(from, to); + + jl_atomic_store_release(&jl_world_counter, new_world); + JL_UNLOCK(&world_counter_lock); +} + +JL_DLLEXPORT jl_value_t *jl_get_module_usings_backedges(jl_module_t *m) +{ + // We assume the caller holds the world_counter_lock, which is the only place we set this + // TODO: We may want to make this more precise with the module lock + return m->usings_backedges; +} + +JL_DLLEXPORT jl_value_t *jl_get_module_binding_or_nothing(jl_module_t *m, jl_sym_t *s) +{ + jl_binding_t *b = jl_get_module_binding(m, s, 0); + if (!b) + return jl_nothing; + return (jl_value_t*)b; } JL_DLLEXPORT void jl_module_public(jl_module_t *from, jl_sym_t *s, int exported) @@ -941,9 +968,6 @@ JL_DLLEXPORT int jl_boundp(jl_module_t *m, jl_sym_t *var, int allow_import) // u if (!bpart || jl_bkind_is_some_import(decode_restriction_kind(pku))) return 0; } else { - if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) { - jl_resolve_owner(b, b->globalref->mod, b->globalref->name, NULL, jl_current_task->world_age); - } pku = jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); } if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) @@ -974,16 +998,6 @@ JL_DLLEXPORT int jl_module_public_p(jl_module_t *m, jl_sym_t *var) return b && b->publicp; } -JL_DLLEXPORT int jl_binding_resolved_p(jl_module_t *m, jl_sym_t *var) -{ - jl_binding_t *b = jl_get_module_binding(m, var, 0); - jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - if (!bpart) - return 0; - enum jl_partition_kind kind = decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)); - return kind == BINDING_KIND_DECLARED || !jl_bkind_is_some_guard(kind); -} - uint_t bindingkey_hash(size_t idx, jl_value_t *data) { jl_binding_t *b = (jl_binding_t*)jl_svecref(data, idx); // This must always happen inside the lock @@ -1052,7 +1066,8 @@ JL_DLLEXPORT jl_binding_t *jl_get_module_binding(jl_module_t *m, jl_sym_t *var, JL_DLLEXPORT jl_value_t *jl_get_globalref_value(jl_globalref_t *gr) { jl_binding_t *b = gr->binding; - b = jl_resolve_owner(b, gr->mod, gr->name, NULL, jl_current_task->world_age); + if (!b) + b = jl_get_module_binding(gr->mod, gr->name, 1); // ignores b->deprecated return b == NULL ? NULL : jl_get_binding_value(b); } @@ -1079,23 +1094,27 @@ JL_DLLEXPORT void jl_set_const(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var // this function is mostly only used during initialization, so the data races here are not too important to us jl_binding_t *bp = jl_get_module_binding(m, var, 1); jl_binding_partition_t *bpart = jl_get_binding_partition(bp, jl_current_task->world_age); - assert(jl_bkind_is_some_guard(decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)))); + bpart->min_world = 0; + jl_atomic_store_release(&bpart->max_world, ~(size_t)0); jl_atomic_store_release(&bpart->restriction, encode_restriction(val, BINDING_KIND_CONST)); jl_gc_wb(bpart, val); } -void jl_invalidate_binding_refs(jl_globalref_t *ref, jl_binding_partition_t *invalidated_bpart, size_t new_world) +void jl_invalidate_binding_refs(jl_globalref_t *ref, jl_binding_partition_t *invalidated_bpart, jl_binding_partition_t *new_bpart, size_t new_world) { static jl_value_t *invalidate_code_for_globalref = NULL; if (invalidate_code_for_globalref == NULL && jl_base_module != NULL) invalidate_code_for_globalref = jl_get_global(jl_base_module, jl_symbol("invalidate_code_for_globalref!")); if (!invalidate_code_for_globalref) jl_error("Binding invalidation is not permitted during bootstrap."); - if (jl_generating_output()) - jl_error("Binding invalidation is not permitted during image generation."); - jl_value_t *boxed_world = jl_box_ulong(new_world); - JL_GC_PUSH1(&boxed_world); - jl_call3((jl_function_t*)invalidate_code_for_globalref, (jl_value_t*)ref, (jl_value_t*)invalidated_bpart, boxed_world); + jl_value_t **fargs; + JL_GC_PUSHARGS(fargs, 5); + fargs[0] = (jl_function_t*)invalidate_code_for_globalref; + fargs[1] = (jl_value_t*)ref; + fargs[2] = (jl_value_t*)invalidated_bpart; + fargs[3] = (jl_value_t*)new_bpart; + fargs[4] = jl_box_ulong(new_world); + jl_apply(fargs, 5); JL_GC_POP(); } @@ -1131,50 +1150,90 @@ JL_DLLEXPORT void jl_maybe_add_binding_backedge(jl_globalref_t *gr, jl_module_t jl_add_binding_backedge(b, edge); } -JL_DLLEXPORT void jl_disable_binding(jl_globalref_t *gr) +JL_DLLEXPORT jl_binding_partition_t *jl_replace_binding_locked(jl_binding_t *b, + jl_binding_partition_t *old_bpart, jl_value_t *restriction_val, enum jl_partition_kind kind, size_t new_world) { - jl_binding_t *b = gr->binding; - b = jl_resolve_owner(b, gr->mod, gr->name, NULL, jl_current_task->world_age); - jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + assert(jl_atomic_load_relaxed(&b->partitions) == old_bpart); + jl_atomic_store_release(&old_bpart->max_world, new_world-1); + jl_binding_partition_t *new_bpart = new_binding_partition(); + new_bpart->min_world = new_world; + if (kind == BINDING_KIND_IMPLICIT_RECOMPUTE) { + assert(!restriction_val); + jl_check_new_binding_implicit(new_bpart, b, NULL, new_world); + } + else + jl_atomic_store_relaxed(&new_bpart->restriction, encode_restriction(restriction_val, kind)); + jl_atomic_store_relaxed(&new_bpart->next, old_bpart); + jl_gc_wb(new_bpart, old_bpart); - if (decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)) == BINDING_KIND_GUARD) { - // Already guard - return; + jl_atomic_store_release(&b->partitions, new_bpart); + jl_gc_wb(b, new_bpart); + + + if (jl_typeinf_world != 1) { + jl_task_t *ct = jl_current_task; + size_t last_world = ct->world_age; + ct->world_age = jl_typeinf_world; + jl_invalidate_binding_refs(b->globalref, old_bpart, new_bpart, new_world-1); + ct->world_age = last_world; } + return new_bpart; +} + +JL_DLLEXPORT jl_binding_partition_t *jl_replace_binding(jl_binding_t *b, + jl_binding_partition_t *old_bpart, jl_value_t *restriction_val, enum jl_partition_kind kind) { + JL_LOCK(&world_counter_lock); - jl_task_t *ct = jl_current_task; - size_t last_world = ct->world_age; - size_t new_max_world = jl_atomic_load_acquire(&jl_world_counter); - jl_atomic_store_release(&bpart->max_world, new_max_world); - ct->world_age = jl_typeinf_world; - jl_invalidate_binding_refs(gr, bpart, new_max_world); - ct->world_age = last_world; - jl_atomic_store_release(&jl_world_counter, new_max_world + 1); + + if (jl_atomic_load_relaxed(&b->partitions) != old_bpart) { + JL_UNLOCK(&world_counter_lock); + return NULL; + } + + size_t new_world = jl_atomic_load_acquire(&jl_world_counter)+1; + jl_binding_partition_t *bpart = jl_replace_binding_locked(b, old_bpart, restriction_val, kind, new_world); + if (bpart && bpart->min_world == new_world) + jl_atomic_store_release(&jl_world_counter, new_world); + JL_UNLOCK(&world_counter_lock); + return bpart; } JL_DLLEXPORT int jl_globalref_is_const(jl_globalref_t *gr) { jl_binding_t *b = gr->binding; - b = jl_resolve_owner(b, gr->mod, gr->name, NULL, jl_current_task->world_age); + if (!b) + b = jl_get_module_binding(gr->mod, gr->name, 1); jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); if (!bpart) return 0; return jl_bkind_is_some_constant(decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction))); } -JL_DLLEXPORT void jl_force_binding_resolution(jl_globalref_t *gr, size_t world) +JL_DLLEXPORT void jl_disable_binding(jl_globalref_t *gr) { jl_binding_t *b = gr->binding; - jl_resolve_owner(b, gr->mod, gr->name, NULL, world); + if (!b) + b = jl_get_module_binding(gr->mod, gr->name, 1); + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + + if (decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)) == BINDING_KIND_GUARD) { + // Already guard + return; + } + + for (;;) + if (jl_replace_binding(b, bpart, NULL, BINDING_KIND_GUARD)) + break; } JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var) { jl_binding_t *b = jl_get_binding(m, var); jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - return b && jl_bkind_is_some_constant(decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction))); + jl_ptr_kind_union_t pku = jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); + return b && jl_bkind_is_some_constant(decode_restriction_kind(pku)); } // set the deprecated flag for a binding: @@ -1188,12 +1247,9 @@ JL_DLLEXPORT void jl_deprecate_binding(jl_module_t *m, jl_sym_t *var, int flag) JL_DLLEXPORT int jl_is_binding_deprecated(jl_module_t *m, jl_sym_t *var) { - if (jl_binding_resolved_p(m, var)) { - // XXX: this only considers if the original is deprecated, not this precise binding - jl_binding_t *b = jl_get_binding(m, var); - return b && b->deprecated; - } - return 0; + // XXX: this only considers if the original is deprecated, not this precise binding + jl_binding_t *b = jl_get_binding(m, var); + return b && b->deprecated; } void jl_binding_deprecation_warning(jl_module_t *m, jl_sym_t *s, jl_binding_t *b) @@ -1229,22 +1285,19 @@ jl_value_t *jl_check_binding_assign_value(jl_binding_t *b JL_PROPAGATES_ROOT, jl JL_GC_PUSH1(&rhs); // callee-rooted jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - assert(!jl_bkind_is_some_guard(decode_restriction_kind(pku)) && !jl_bkind_is_some_import(decode_restriction_kind(pku))); - if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) { + enum jl_partition_kind kind = decode_restriction_kind(pku); + if (jl_bkind_is_some_constant(kind)) { jl_value_t *old = decode_restriction_value(pku); JL_GC_PROMISE_ROOTED(old); if (jl_egal(rhs, old)) { JL_GC_POP(); return NULL; } - if (jl_typeof(rhs) == jl_typeof(old)) - jl_errorf("invalid redefinition of constant %s.%s. This redefinition may be permitted using the `const` keyword.", - jl_symbol_name(mod->name), jl_symbol_name(var)); - else - jl_errorf("invalid redefinition of constant %s.%s.", - jl_symbol_name(mod->name), jl_symbol_name(var)); + jl_errorf("invalid assignment to constant %s.%s. This redefinition may be permitted using the `const` keyword.", + jl_symbol_name(mod->name), jl_symbol_name(var)); } - jl_value_t *old_ty = decode_restriction_value(pku); + assert(kind == BINDING_KIND_DECLARED || kind == BINDING_KIND_GLOBAL); + jl_value_t *old_ty = kind == BINDING_KIND_DECLARED ? (jl_value_t*)jl_any_type : decode_restriction_value(pku); JL_GC_PROMISE_ROOTED(old_ty); if (old_ty != (jl_value_t*)jl_any_type && jl_typeof(rhs) != old_ty) { if (!jl_isa(rhs, old_ty)) @@ -1285,7 +1338,7 @@ JL_DLLEXPORT jl_value_t *jl_checked_modify(jl_binding_t *b, jl_module_t *mod, jl jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); assert(!jl_bkind_is_some_guard(decode_restriction_kind(pku)) && !jl_bkind_is_some_import(decode_restriction_kind(pku))); if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) - jl_errorf("invalid redefinition of constant %s.%s", + jl_errorf("invalid assignment to constant %s.%s", jl_symbol_name(mod->name), jl_symbol_name(var)); jl_value_t *ty = decode_restriction_value(pku); JL_GC_PROMISE_ROOTED(ty); @@ -1422,7 +1475,7 @@ JL_DLLEXPORT void jl_clear_implicit_imports(jl_module_t *m) break; jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); if (decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)) == BINDING_KIND_IMPLICIT) { - jl_atomic_store_relaxed(&bpart->restriction, encode_restriction(NULL, BINDING_KIND_GUARD)); + jl_atomic_store_relaxed(&b->partitions, NULL); } } JL_UNLOCK(&m->lock); diff --git a/src/staticdata.c b/src/staticdata.c index ec77c771bd880..9eb2922380c63 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -827,6 +827,8 @@ static void jl_queue_module_for_serialization(jl_serializer_state *s, jl_module_ for (size_t i = 0; i < module_usings_length(m); i++) { jl_queue_for_serialization(s, module_usings_getmod(m, i)); } + + jl_queue_for_serialization(s, m->usings_backedges); } // Anything that requires uniquing or fixing during deserialization needs to be "toplevel" @@ -1299,10 +1301,14 @@ static void jl_write_module(jl_serializer_state *s, uintptr_t item, jl_module_t newm->file = NULL; arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_module_t, file))); arraylist_push(&s->relocs_list, (void*)backref_id(s, m->file, s->link_ids_relocs)); + newm->usings_backedges = NULL; + arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_module_t, usings_backedges))); + arraylist_push(&s->relocs_list, (void*)backref_id(s, m->usings_backedges, s->link_ids_relocs)); // write out the usings list memset(&newm->usings._space, 0, sizeof(newm->usings._space)); if (m->usings.items == &m->usings._space[0]) { + newm->usings.items = &newm->usings._space[0]; // Push these relocations here, to keep them in order. This pairs with the `newm->usings.items = ` below. arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_module_t, usings.items))); arraylist_push(&s->relocs_list, (void*)(((uintptr_t)DataRef << RELOC_TAG_OFFSET) + item)); @@ -1314,9 +1320,9 @@ static void jl_write_module(jl_serializer_state *s, uintptr_t item, jl_module_t newm_data->min_world = data->min_world; newm_data->max_world = data->max_world; if (s->incremental) { - if (data->max_world != (size_t)-1) + if (data->max_world != ~(size_t)0) newm_data->max_world = 0; - newm_data->min_world = 0; + newm_data->min_world = jl_require_world; } arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_module_t, usings._space[3*i]))); arraylist_push(&s->relocs_list, (void*)backref_id(s, data->mod, s->link_ids_relocs)); @@ -1331,8 +1337,14 @@ static void jl_write_module(jl_serializer_state *s, uintptr_t item, jl_module_t for (i = 0; i < module_usings_length(m); i++) { struct _jl_module_using *data = module_usings_getidx(m, i); write_pointerfield(s, (jl_value_t*)data->mod); - write_uint(s->s, data->min_world); - write_uint(s->s, data->max_world); + if (s->incremental) { + // TODO: Drop dead ones entirely? + write_uint(s->s, jl_require_world); + write_uint(s->s, data->max_world == ~(size_t)0 ? ~(size_t)0 : 1); + } else { + write_uint(s->s, data->min_world); + write_uint(s->s, data->max_world); + } static_assert(sizeof(struct _jl_module_using) == 3*sizeof(void*), "_jl_module_using mismatch"); tot += sizeof(struct _jl_module_using); } @@ -3492,6 +3504,73 @@ extern void export_jl_small_typeof(void); // into the native code of the image. See https://github.com/JuliaLang/julia/pull/52123#issuecomment-1959965395. int IMAGE_NATIVE_CODE_TAINTED = 0; +// TODO: This should possibly be in Julia +static void jl_validate_binding_partition(jl_binding_t *b, jl_binding_partition_t *bpart, size_t mod_idx) +{ + + if (jl_atomic_load_relaxed(&bpart->max_world) != ~(size_t)0) + return; + jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); + enum jl_partition_kind kind = decode_restriction_kind(pku); + if (!jl_bkind_is_some_import(kind)) + return; + jl_binding_t *imported_binding = (jl_binding_t*)decode_restriction_value(pku); + jl_binding_partition_t *latest_imported_bpart = jl_atomic_load_relaxed(&imported_binding->partitions); + if (!latest_imported_bpart) + return; + if (kind == BINDING_KIND_IMPLICIT || kind == BINDING_KIND_FAILED) { + jl_check_new_binding_implicit(bpart, b, NULL, jl_atomic_load_relaxed(&jl_world_counter)); + if (bpart->min_world > jl_require_world) + goto invalidated; + } + if (latest_imported_bpart->min_world <= bpart->min_world) { + // Imported binding is still valid + if ((kind == BINDING_KIND_EXPLICIT || kind == BINDING_KIND_IMPORTED) && + external_blob_index((jl_value_t*)imported_binding) != mod_idx) { + jl_add_binding_backedge(imported_binding, (jl_value_t*)b); + } + return; + } + else { + // Binding partition was invalidated + assert(bpart->min_world == jl_require_world); + bpart->min_world = latest_imported_bpart->min_world; + } +invalidated: + // We need to go through and re-validate any bindings in the same image that + // may have imported us. + if (b->backedges) { + for (size_t i = 0; i < jl_array_len(b->backedges); i++) { + jl_value_t *edge = jl_array_ptr_ref(b->backedges, i); + if (!jl_is_binding(edge)) + continue; + jl_binding_t *bedge = (jl_binding_t*)edge; + if (!jl_atomic_load_relaxed(&bedge->partitions)) + continue; + jl_validate_binding_partition(bedge, jl_atomic_load_relaxed(&bedge->partitions), mod_idx); + } + } + if (b->exportp) { + jl_module_t *mod = b->globalref->mod; + jl_sym_t *name = b->globalref->name; + JL_LOCK(&mod->lock); + if (mod->usings_backedges) { + for (size_t i = 0; i < jl_array_len(mod->usings_backedges); i++) { + jl_module_t *edge = (jl_module_t*)jl_array_ptr_ref(mod->usings_backedges, i); + jl_binding_t *importee = jl_get_module_binding(edge, name, 0); + if (!importee) + continue; + if (!jl_atomic_load_relaxed(&importee->partitions)) + continue; + JL_UNLOCK(&mod->lock); + jl_validate_binding_partition(importee, jl_atomic_load_relaxed(&importee->partitions), mod_idx); + JL_LOCK(&mod->lock); + } + } + JL_UNLOCK(&mod->lock); + } +} + static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl_array_t *depmods, uint64_t checksum, /* outputs */ jl_array_t **restored, jl_array_t **init_order, jl_array_t **extext_methods, jl_array_t **internal_methods, @@ -3926,6 +4005,16 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl memcpy(newitems, mod->usings.items, mod->usings.len * sizeof(void*)); mod->usings.items = newitems; } + size_t mod_idx = external_blob_index((jl_value_t*)mod); + if (s.incremental) { + // Rebuild cross-image usings backedges + for (size_t i = 0; i < module_usings_length(mod); ++i) { + struct _jl_module_using *data = module_usings_getidx(mod, i); + if (external_blob_index((jl_value_t*)data->mod) != mod_idx) { + jl_add_usings_backedge(data->mod, mod); + } + } + } // Move the binding bits back to their correct place #ifdef _P64 jl_svec_t *table = jl_atomic_load_relaxed(&mod->bindings); @@ -3935,18 +4024,41 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl continue; jl_binding_partition_t *bpart = jl_atomic_load_relaxed(&b->partitions); while (bpart) { - jl_atomic_store_relaxed(&bpart->restriction, - encode_restriction((jl_value_t*)jl_atomic_load_relaxed(&bpart->restriction), bpart->reserved)); + jl_ptr_kind_union_t pku = encode_restriction( + (jl_value_t*)jl_atomic_load_relaxed(&bpart->restriction), + (enum jl_partition_kind)bpart->reserved); + jl_atomic_store_relaxed(&bpart->restriction, pku); bpart->reserved = 0; bpart = jl_atomic_load_relaxed(&bpart->next); } } + #endif } else { abort(); } } + if (s.incremental) { + // This needs to be done in a second pass after the binding partitions + // have the proper ABI again. + for (size_t i = 0; i < s.fixup_objs.len; i++) { + uintptr_t item = (uintptr_t)s.fixup_objs.items[i]; + jl_value_t *obj = (jl_value_t*)(image_base + item); + if (jl_is_module(obj)) { + jl_module_t *mod = (jl_module_t*)obj; + size_t mod_idx = external_blob_index((jl_value_t*)mod); + jl_svec_t *table = jl_atomic_load_relaxed(&mod->bindings); + for (size_t i = 0; i < jl_svec_len(table); i++) { + jl_binding_t *b = (jl_binding_t*)jl_svecref(table, i); + if ((jl_value_t*)b == jl_nothing) + continue; + jl_binding_partition_t *bpart = jl_atomic_load_relaxed(&b->partitions); + jl_validate_binding_partition(b, bpart, mod_idx); + } + } + } + } arraylist_free(&s.fixup_types); arraylist_free(&s.fixup_objs); diff --git a/src/toplevel.c b/src/toplevel.c index cdd390b9b49ed..321ef8c79dac0 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -303,7 +303,7 @@ static jl_value_t *jl_eval_dot_expr(jl_module_t *m, jl_value_t *x, jl_value_t *f } extern void check_safe_newbinding(jl_module_t *m, jl_sym_t *var); -void jl_declare_global(jl_module_t *m, jl_value_t *arg, jl_value_t *set_type) { +void jl_declare_global(jl_module_t *m, jl_value_t *arg, jl_value_t *set_type, int strong) { // create uninitialized mutable binding for "global x" decl sometimes or probably jl_module_t *gm; jl_sym_t *gs; @@ -321,42 +321,58 @@ void jl_declare_global(jl_module_t *m, jl_value_t *arg, jl_value_t *set_type) { size_t new_world = jl_atomic_load_relaxed(&jl_world_counter) + 1; jl_binding_t *b = jl_get_module_binding(gm, gs, 1); jl_binding_partition_t *bpart = NULL; - jl_ptr_kind_union_t new_pku = encode_restriction(set_type, set_type == NULL ? BINDING_KIND_DECLARED : BINDING_KIND_GLOBAL); + if (!strong && set_type) + jl_error("Weak global definitions cannot have types"); + enum jl_partition_kind new_kind = strong ? BINDING_KIND_GLOBAL : BINDING_KIND_DECLARED; + jl_value_t *global_type = set_type; + if (strong && !global_type) + global_type = (jl_value_t*)jl_any_type; while (1) { bpart = jl_get_binding_partition(b, new_world); jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - if (decode_restriction_kind(pku) != BINDING_KIND_GLOBAL) { - if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) { - if (decode_restriction_kind(pku) == BINDING_KIND_DECLARED && !set_type) - goto done; + enum jl_partition_kind kind = decode_restriction_kind(pku); + if (kind != BINDING_KIND_GLOBAL) { + if (jl_bkind_is_some_guard(kind) || kind == BINDING_KIND_DECLARED || kind == BINDING_KIND_IMPLICIT) { + if (decode_restriction_kind(pku) == new_kind) { + if (!set_type) + goto done; + goto check_type; + } check_safe_newbinding(gm, gs); - if (jl_atomic_cmpswap(&bpart->restriction, &pku, new_pku)) { - break; + if (bpart->min_world == new_world) { + if (jl_atomic_cmpswap(&bpart->restriction, &pku, encode_restriction(global_type, new_kind))) { + break; + } + if (set_type) + jl_gc_wb(bpart, set_type); + continue; + } else { + jl_replace_binding_locked(b, bpart, global_type, new_kind, new_world); } - continue; + break; } else if (set_type) { if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) { - jl_errorf("cannot set type for imported constant %s.%s.", + jl_errorf("cannot set type for constant %s.%s.", jl_symbol_name(gm->name), jl_symbol_name(gs)); } else { - jl_errorf("cannot set type for imported global %s.%s.", + jl_errorf("cannot set type for imported binding %s.%s.", jl_symbol_name(gm->name), jl_symbol_name(gs)); } } } - if (!set_type) - goto done; - jl_value_t *old_ty = decode_restriction_value(pku); - JL_GC_PROMISE_ROOTED(old_ty); - if (!jl_types_equal(set_type, old_ty)) { - jl_errorf("cannot set type for global %s.%s. It already has a value or is already set to a different type.", - jl_symbol_name(gm->name), jl_symbol_name(gs)); + if (set_type) + { +check_type: ; + jl_value_t *old_ty = decode_restriction_value(pku); + JL_GC_PROMISE_ROOTED(old_ty); + if (!jl_types_equal(set_type, old_ty)) { + jl_errorf("cannot set type for global %s.%s. It already has a value or is already set to a different type.", + jl_symbol_name(gm->name), jl_symbol_name(gs)); + } + } goto done; } - if (set_type) - jl_gc_wb(bpart, set_type); - bpart->min_world = new_world; jl_atomic_store_release(&jl_world_counter, new_world); done: JL_UNLOCK(&world_counter_lock); @@ -367,7 +383,7 @@ void jl_eval_global_expr(jl_module_t *m, jl_expr_t *ex, int set_type) size_t i, l = jl_array_nrows(ex->args); for (i = 0; i < l; i++) { jl_value_t *arg = jl_exprarg(ex, i); - jl_declare_global(m, arg, NULL); + jl_declare_global(m, arg, NULL, 0); } } @@ -431,10 +447,8 @@ static void expr_attributes(jl_value_t *v, jl_array_t *body, int *has_ccall, int if (jl_is_globalref(f)) { jl_module_t *mod = jl_globalref_mod(f); jl_sym_t *name = jl_globalref_name(f); - if (jl_binding_resolved_p(mod, name)) { - jl_binding_t *b = jl_get_binding(mod, name); - called = jl_get_binding_value_if_const(b); - } + jl_binding_t *b = jl_get_binding(mod, name); + called = jl_get_binding_value_if_const(b); } else if (jl_is_quotenode(f)) { called = jl_quotenode_value(f); @@ -666,7 +680,8 @@ static void import_module(jl_module_t *JL_NONNULL m, jl_module_t *import, jl_sym jl_binding_t *b = jl_get_module_binding(m, name, 1); jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - if (decode_restriction_kind(pku) != BINDING_KIND_GUARD && decode_restriction_kind(pku) != BINDING_KIND_FAILED) { + enum jl_partition_kind kind = decode_restriction_kind(pku); + if (kind != BINDING_KIND_GUARD && kind != BINDING_KIND_FAILED && kind != BINDING_KIND_DECLARED && kind != BINDING_KIND_IMPLICIT) { // Unlike regular constant declaration, we allow this as long as we eventually end up at a constant. pku = jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); if (decode_restriction_kind(pku) == BINDING_KIND_CONST || decode_restriction_kind(pku) == BINDING_KIND_BACKDATED_CONST || decode_restriction_kind(pku) == BINDING_KIND_CONST_IMPORT) { @@ -747,72 +762,72 @@ JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val3( if (!b) { b = jl_get_module_binding(mod, var, 1); } + jl_binding_partition_t *new_bpart = NULL; jl_binding_partition_t *bpart = jl_get_binding_partition(b, new_world); jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - int did_warn = 0; - while (1) { + while (!new_bpart) { enum jl_partition_kind kind = decode_restriction_kind(pku); if (jl_bkind_is_some_constant(kind)) { if (!val) { + new_bpart = bpart; break; } jl_value_t *old = decode_restriction_value(pku); JL_GC_PROMISE_ROOTED(old); - if (jl_egal(val, old)) + if (jl_egal(val, old)) { + new_bpart = bpart; break; - if (!did_warn) { - if (jl_typeof(val) != jl_typeof(old) || jl_is_type(val) || jl_is_module(val)) - jl_errorf("invalid redefinition of constant %s.%s", - jl_symbol_name(mod->name), - jl_symbol_name(var)); - else - jl_safe_printf("WARNING: redefinition of constant %s.%s. This may fail, cause incorrect answers, or produce other errors.\n", - jl_symbol_name(mod->name), - jl_symbol_name(var)); - did_warn = 1; - } - if (new_world > bpart->min_world) { - // TODO: Invoke invalidation logic here - jl_atomic_store_relaxed(&bpart->max_world, new_world - 1); - bpart = jl_get_binding_partition(b, new_world); - pku = jl_atomic_load_relaxed(&bpart->restriction); - } - } else if (!jl_bkind_is_some_guard(decode_restriction_kind(pku))) { - if (jl_bkind_is_some_import(decode_restriction_kind(pku))) { - jl_errorf("cannot declare %s.%s constant; it was already declared as an import", - jl_symbol_name(mod->name), jl_symbol_name(var)); - } else { - jl_errorf("cannot declare %s.%s constant; it was already declared global", - jl_symbol_name(mod->name), jl_symbol_name(var)); } + } else if (jl_bkind_is_some_import(kind) && kind != BINDING_KIND_IMPLICIT) { + jl_errorf("cannot declare %s.%s constant; it was already declared as an import", + jl_symbol_name(mod->name), jl_symbol_name(var)); + } else if (kind == BINDING_KIND_GLOBAL) { + jl_errorf("cannot declare %s.%s constant; it was already declared global", + jl_symbol_name(mod->name), jl_symbol_name(var)); } - if (!jl_atomic_cmpswap(&bpart->restriction, &pku, encode_restriction(val, constant_kind))) { - continue; + if (bpart->min_world == new_world) { + if (!jl_atomic_cmpswap(&bpart->restriction, &pku, encode_restriction(val, constant_kind))) { + continue; + } + jl_gc_wb(bpart, val); + new_bpart = bpart; + } else { + new_bpart = jl_replace_binding_locked(b, bpart, val, constant_kind, new_world); } - jl_gc_wb(bpart, val); - size_t prev_min_world = bpart->min_world; - bpart->min_world = new_world; - int need_backdate = 0; - if (new_world && val) { - if (prev_min_world == 0) { - need_backdate = 1; - } else if (kind == BINDING_KIND_DECLARED) { - jl_binding_partition_t *prev_bpart = jl_get_binding_partition(b, prev_min_world-1); + int need_backdate = new_world && val; + if (need_backdate) { + // We will backdate as long as this partition was never explicitly + // declared const, global, or imported. + jl_binding_partition_t *prev_bpart = bpart; + for (;;) { jl_ptr_kind_union_t prev_pku = jl_atomic_load_relaxed(&prev_bpart->restriction); - if (prev_bpart->min_world == 0 && decode_restriction_kind(prev_pku) == BINDING_KIND_GUARD) { - // Just keep it simple and use one backdated const entry for both previous guard partition - // ranges. - jl_atomic_store_relaxed(&prev_bpart->max_world, new_world-1); - need_backdate = 1; + enum jl_partition_kind prev_kind = decode_restriction_kind(prev_pku); + if (jl_bkind_is_some_constant(prev_kind) || prev_kind == BINDING_KIND_GLOBAL || + (jl_bkind_is_some_import(prev_kind))) { + need_backdate = 0; + break; } + if (prev_bpart->min_world == 0) + break; + prev_bpart = jl_get_binding_partition(b, prev_bpart->min_world - 1); } } + // If backdate is required, rewrite all previous binding partitions to + // backdated const if (need_backdate) { - jl_declare_constant_val3(b, mod, var, val, BINDING_KIND_BACKDATED_CONST, 0); + // We will backdate as long as this partition was never explicitly + // declared const, global, or *explicitly* imported. + jl_binding_partition_t *prev_bpart = bpart; + for (;;) { + jl_atomic_store_relaxed(&prev_bpart->restriction, encode_restriction(val, BINDING_KIND_BACKDATED_CONST)); + if (prev_bpart->min_world == 0) + break; + prev_bpart = jl_get_binding_partition(b, prev_bpart->min_world - 1); + } } } JL_GC_POP(); - return bpart; + return new_bpart; } JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val2( @@ -1035,7 +1050,7 @@ JL_DLLEXPORT jl_value_t *jl_toplevel_eval_flex(jl_module_t *JL_NONNULL m, jl_val size_t i, l = jl_array_nrows(ex->args); for (i = 0; i < l; i++) { jl_value_t *arg = jl_exprarg(ex, i); - jl_declare_global(m, arg, NULL); + jl_declare_global(m, arg, NULL, 0); } JL_GC_POP(); return jl_nothing; diff --git a/stdlib/InteractiveUtils/src/InteractiveUtils.jl b/stdlib/InteractiveUtils/src/InteractiveUtils.jl index 4a320282610cd..6b75a228b2761 100644 --- a/stdlib/InteractiveUtils/src/InteractiveUtils.jl +++ b/stdlib/InteractiveUtils/src/InteractiveUtils.jl @@ -17,7 +17,7 @@ export apropos, edit, less, code_warntype, code_llvm, code_native, methodswith, import Base.Docs.apropos using Base: unwrap_unionall, rewrap_unionall, isdeprecated, Bottom, summarysize, - signature_type, format_bytes, isbindingresolved + signature_type, format_bytes using Base.Libc using Markdown @@ -264,7 +264,7 @@ function _subtypes_in!(mods::Array, x::Type) m = pop!(mods) xt = xt::DataType for s in names(m, all = true) - if isbindingresolved(m, s) && !isdeprecated(m, s) && isdefined(m, s) + if !isdeprecated(m, s) && isdefined(m, s) t = getfield(m, s) dt = isa(t, UnionAll) ? unwrap_unionall(t) : t if isa(dt, DataType) diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index cc4f4f00cf8f6..561e4bcd4feb2 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -72,7 +72,6 @@ function UndefVarError_hint(io::IO, ex::UndefVarError) end function _UndefVarError_warnfor(io::IO, m::Module, var::Symbol) - Base.isbindingresolved(m, var) || return false (Base.isexported(m, var) || Base.ispublic(m, var)) || return false active_mod = Base.active_module() print(io, "\nHint: ") diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index eadc2672dd29b..e70eb8dd97927 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -240,8 +240,7 @@ function complete_symbol!(suggestions::Vector{Completion}, return suggestions end -completes_module(mod::Module, x::Symbol) = - Base.isbindingresolved(mod, x) && isdefined(mod, x) && isa(getglobal(mod, x), Module) +completes_module(mod::Module, x::Symbol) = isdefined(mod, x) && isa(getglobal(mod, x), Module) function add_field_completions!(suggestions::Vector{Completion}, name::String, @nospecialize(t)) if isa(t, Union) diff --git a/stdlib/REPL/src/docview.jl b/stdlib/REPL/src/docview.jl index 313994505b3ee..6a73a9631a49a 100644 --- a/stdlib/REPL/src/docview.jl +++ b/stdlib/REPL/src/docview.jl @@ -312,10 +312,11 @@ function summarize(binding::Binding, sig) else println(io, "No documentation found.\n") quot = any(isspace, sprint(print, binding)) ? "'" : "" - if Base.isbindingresolved(binding.mod, binding.var) - println(io, "Binding ", quot, "`", binding, "`", quot, " exists, but has not been assigned a value.") - else + bpart = Base.lookup_binding_partition(Base.tls_world_age(), convert(Core.Binding, GlobalRef(binding.mod, binding.var))) + if Base.binding_kind(bpart) === Base.BINDING_KIND_GUARD println(io, "Binding ", quot, "`", binding, "`", quot, " does not exist.") + else + println(io, "Binding ", quot, "`", binding, "`", quot, " exists, but has not been assigned a value.") end end md = Markdown.parse(seekstart(io)) @@ -567,8 +568,7 @@ function repl(io::IO, s::Symbol; brief::Bool=true, mod::Module=Main, internal_ac quote repl_latex($io, $str) repl_search($io, $str, $mod) - $(if !isdefined(mod, s) && !Base.isbindingresolved(mod, s) && !haskey(keywords, s) && !Base.isoperator(s) - # n.b. we call isdefined for the side-effect of resolving the binding, if possible + $(if !isdefined(mod, s) && !haskey(keywords, s) && !Base.isoperator(s) :(repl_corrections($io, $str, $mod)) end) $(_repl(s, brief, mod, internal_accesses)) diff --git a/stdlib/REPL/test/replcompletions.jl b/stdlib/REPL/test/replcompletions.jl index 77d056b63655d..59e994f88945b 100644 --- a/stdlib/REPL/test/replcompletions.jl +++ b/stdlib/REPL/test/replcompletions.jl @@ -214,8 +214,6 @@ end let s = "using REP" c, r = test_complete_32377(s) @test count(isequal("REPL"), c) == 1 - # issue #30234 - @test !Base.isbindingresolved(M32377, :tanh) # check what happens if REPL is already imported M32377.eval(:(using REPL)) c, r = test_complete_32377(s) diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index 88fd055f7bd58..e8d670b3d7d00 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -2158,7 +2158,7 @@ function detect_ambiguities(mods::Module...; while !isempty(work) mod = pop!(work) for n in names(mod, all = true) - (!Base.isbindingresolved(mod, n) || Base.isdeprecated(mod, n)) && continue + Base.isdeprecated(mod, n) && continue if !isdefined(mod, n) if is_in_mods(mod, recursive, mods) if allowed_undefineds === nothing || GlobalRef(mod, n) ∉ allowed_undefineds @@ -2229,7 +2229,7 @@ function detect_unbound_args(mods...; while !isempty(work) mod = pop!(work) for n in names(mod, all = true) - (!Base.isbindingresolved(mod, n) || Base.isdeprecated(mod, n)) && continue + Base.isdeprecated(mod, n) && continue if !isdefined(mod, n) if is_in_mods(mod, recursive, mods) if allowed_undefineds === nothing || GlobalRef(mod, n) ∉ allowed_undefineds diff --git a/test/ambiguous.jl b/test/ambiguous.jl index 5f859e773f5d2..0f29817e74dd5 100644 --- a/test/ambiguous.jl +++ b/test/ambiguous.jl @@ -171,12 +171,8 @@ module UnboundAmbig55868 using .B export C, D end -@test !Base.isbindingresolved(UnboundAmbig55868, :C) -@test !Base.isbindingresolved(UnboundAmbig55868, :D) @test isempty(detect_unbound_args(UnboundAmbig55868)) @test isempty(detect_ambiguities(UnboundAmbig55868)) -@test !Base.isbindingresolved(UnboundAmbig55868, :C) -@test !Base.isbindingresolved(UnboundAmbig55868, :D) # Test that Core and Base are free of ambiguities # not using isempty so this prints more information when it fails diff --git a/test/atomics.jl b/test/atomics.jl index adfe4c87138cd..7e9f29c23ca10 100644 --- a/test/atomics.jl +++ b/test/atomics.jl @@ -23,22 +23,32 @@ mutable struct Refxy{T} end modname = String(nameof(@__MODULE__)) -@test_throws ErrorException("invalid redefinition of constant $modname.ARefxy") @eval mutable struct ARefxy{T} +const orig_Refxy = Refxy +const orig_ARefxy = ARefxy +mutable struct ARefxy{T} @atomic x::T @atomic y::T end -@test_throws ErrorException("invalid redefinition of constant $modname.ARefxy") @eval mutable struct ARefxy{T} +@test orig_ARefxy !== ARefxy +const ARefxy = orig_ARefxy +mutable struct ARefxy{T} x::T y::T end -@test_throws ErrorException("invalid redefinition of constant $modname.ARefxy") @eval mutable struct ARefxy{T} +@test orig_ARefxy !== ARefxy +const ARefxy = orig_ARefxy +mutable struct ARefxy{T} x::T @atomic y::T end -@test_throws ErrorException("invalid redefinition of constant $modname.Refxy") @eval mutable struct Refxy{T} +@test orig_ARefxy !== ARefxy +const ARefxy = orig_ARefxy +mutable struct Refxy{T} x::T @atomic y::T end +@test orig_Refxy !== Refxy +const Refxy = orig_Refxy copy(r::Union{Refxy,ARefxy}) = typeof(r)(r.x, r.y) function add(x::T, y)::T where {T}; x + y; end diff --git a/test/core.jl b/test/core.jl index 5e2677f0f075f..ee47eba0d2c7d 100644 --- a/test/core.jl +++ b/test/core.jl @@ -63,20 +63,7 @@ mutable struct ABCDconst c const d::Union{Int,Nothing} end -@test_throws(ErrorException("invalid redefinition of constant $(nameof(curmod)).ABCDconst"), - mutable struct ABCDconst - const a - const b::Int - c - d::Union{Int,Nothing} - end) -@test_throws(ErrorException("invalid redefinition of constant $(nameof(curmod)).ABCDconst"), - mutable struct ABCDconst - a - b::Int - c - d::Union{Int,Nothing} - end) + let abcd = ABCDconst(1, 2, 3, 4) @test (1, 2, 3, 4) === (abcd.a, abcd.b, abcd.c, abcd.d) @test_throws(ErrorException("setfield!: const field .a of type ABCDconst cannot be changed"), @@ -113,6 +100,21 @@ let abcd = ABCDconst(1, 2, 3, 4) abcd.d = nothing) @test (1, 2, "not constant", 4) === (abcd.a, abcd.b, abcd.c, abcd.d) end +const orig_ABCDconst = ABCDconst +mutable struct ABCDconst + const a + const b::Int + c + d::Union{Int,Nothing} +end +@test ABCDconst !== orig_ABCDconst +mutable struct ABCDconst + a + b::Int + c + d::Union{Int,Nothing} +end +@test ABCDconst !== orig_ABCDconst # Issue #52686 struct A52686{T} end struct B52686{T, S} @@ -1210,15 +1212,11 @@ let A = [1] @test x == 1 end -# Make sure that `Module` is not resolved to `Core.Module` during sysimg generation -# so that users can define their own binding named `Module` in Main. -@test success(`$(Base.julia_cmd()) -e '@assert !Base.isbindingresolved(Main, :Module)'`) - # Module() constructor @test names(Module(:anonymous), all = true, imported = true) == [:anonymous] @test names(Module(:anonymous, false), all = true, imported = true) == [:anonymous] -@test Module(:anonymous, false, true).Core == Core -@test_throws UndefVarError Module(:anonymous, false, false).Core +@test invokelatest(getfield, Module(:anonymous, false, true), :Core) == Core +@test_throws UndefVarError invokelatest(getfield, Module(:anonymous, false, false), :Core) # exception from __init__() let didthrow = @@ -3885,11 +3883,13 @@ end struct NInitializedTestType a end +const orig_NInitializedTestType = NInitializedTestType -@test_throws ErrorException @eval struct NInitializedTestType +struct NInitializedTestType a NInitializedTestType() = new() end +@test orig_NInitializedTestType !== NInitializedTestType # issue #12394 mutable struct Empty12394 end @@ -5578,76 +5578,94 @@ struct A16424 x y end +const orig_A16424 = A16424 struct A16424 # allowed x y end +@test A16424 === orig_A16424 -@test_throws ErrorException @eval struct A16424 +struct A16424 x z end +@test A16424 !== orig_A16424 +const A16424 = orig_A16424 -@test_throws ErrorException @eval struct A16424 +struct A16424 x y::Real end +@test A16424 !== orig_A16424 +const A16424 = orig_A16424 struct B16424{T} a end +const orig_B16424 = B16424 struct B16424{T} a end +@test B16424 === orig_B16424 -@test_throws ErrorException @eval struct B16424{S} +struct B16424{S} a end +@test B16424 !== orig_B16424 struct C16424{T,S} x::T y::S end +const orig_C16424 = C16424 struct C16424{T,S} x::T y::S end +@test C16424 === orig_C16424 -@test_throws ErrorException @eval struct C16424{T,S} +struct C16424{T,S} x::S y::T end +@test C16424 !== orig_C16424 struct D16424{T<:Real,S<:T} x::Vector{S} y::Vector{T} end +const orig_D16424 = D16424 struct D16424{T<:Real,S<:T} x::Vector{S} y::Vector{T} end +@test D16424 === orig_D16424 -@test_throws ErrorException struct D16424{T<:Real,S<:Real} +struct D16424{T<:Real,S<:Real} x::Vector{S} y::Vector{T} end +@test D16424 !== orig_D16424 # issue #20999, allow more type redefinitions struct T20999 x::Array{T} where T<:Real end +const orig_T20999 = T20999 struct T20999 x::Array{T} where T<:Real end +@test T20999 === orig_T20999 -@test_throws ErrorException struct T20999 +struct T20999 x::Array{T} where T<:Integer end +@test T20999 !== orig_T20999 # issue #54757, type redefinitions with recursive reference in supertype struct T54757{A>:Int,N} <: AbstractArray{Tuple{X,Tuple{Vararg},Union{T54757{Union{X,Integer}},T54757{A,N}},Vararg{Y,N}} where {X,Y<:T54757}, N} @@ -5655,20 +5673,40 @@ struct T54757{A>:Int,N} <: AbstractArray{Tuple{X,Tuple{Vararg},Union{T54757{Unio y::Union{A,T54757{A,N}} z::T54757{A} end +const orig_T54757 = T54757 struct T54757{A>:Int,N} <: AbstractArray{Tuple{X,Tuple{Vararg},Union{T54757{Union{X,Integer}},T54757{A,N}},Vararg{Y,N}} where {X,Y<:T54757}, N} x::A y::Union{A,T54757{A,N}} z::T54757{A} end +# The type is identical - either answer is semantically allowed here +# However, knowing that the type is identical would require reasoning about the purity of the +# field definitions exprs, which we do not do. Thus, simply check that this doesn't error and +# then reset to the original for the next test. +const T54757 = orig_T54757 -@test_throws ErrorException struct T54757{A>:Int,N} <: AbstractArray{Tuple{X,Tuple{Vararg},Union{T54757{Union{X,Integer}},T54757{A}},Vararg{Y,N}} where {X,Y<:T54757}, N} +struct T54757{A>:Int,N} <: AbstractArray{Tuple{X,Tuple{Vararg},Union{T54757{Union{X,Integer}},T54757{A}},Vararg{Y,N}} where {X,Y<:T54757}, N} x::A y::Union{A,T54757{A,N}} z::T54757{A} end +@test orig_T54757 !== T54757 +# Type redefinition with multiple tvars and reference in the field types +struct DictLike{K, V} <: AbstractDict{K, V} + self::DictLike{K, V} +end +const orig_DictLike = DictLike + +struct DictLike{K, V} <: AbstractDict{K, V} + self::DictLike{K, V} +end +# It is semantically allowable to re-use the old type, but we need to +# make sure in either case that the field type matches the definition +@test fieldtype(DictLike, 1) === DictLike +# initialization of Vector{Core.TypeofBottom} let a = Vector{Core.TypeofBottom}(undef, 2) @test a[1] == Union{} @test a == [Union{}, Union{}] @@ -7676,29 +7714,35 @@ struct S36104{K,V} # check that redefining it works S36104{K,V}() where {K,V} = new() S36104{K,V}(x::S36104) where {K,V} = new(x) end -# with a gensymmed unionall -struct Symmetric{T,S<:AbstractMatrix{<:T}} <: AbstractMatrix{T} + +# with a gensymmed unionall (#39778) +struct Symmetric39778{T,S<:AbstractMatrix{<:T}} <: AbstractMatrix{T} data::S uplo::Char end -struct Symmetric{T,S<:AbstractMatrix{<:T}} <: AbstractMatrix{T} +const orig_Symmetric39778 = Symmetric39778 +struct Symmetric39778{T,S<:AbstractMatrix{<:T}} <: AbstractMatrix{T} data::S uplo::Char end -@test_throws ErrorException begin - struct Symmetric{T,S<:AbstractMatrix{T}} <: AbstractMatrix{T} - data::S - uplo::Char - end -end +@test Symmetric39778 === orig_Symmetric39778 +struct Symmetric39778{T,S<:AbstractMatrix{T}} <: AbstractMatrix{T} + data::S + uplo::Char end +@test Symmetric39778 !== orig_Symmetric39778 + +end # module M36104 + @test fieldtypes(M36104.T36104) == (Vector{M36104.T36104},) @test_throws ErrorException("expected") @eval(struct X36104; x::error("expected"); end) @test !@isdefined(X36104) struct X36104; x::Int; end @test fieldtypes(X36104) == (Int,) primitive type P36104 8 end -@test_throws ErrorException("invalid redefinition of constant $(nameof(curmod)).P36104") @eval(primitive type P36104 16 end) +const orig_P36104 = P36104 +primitive type P36104 16 end +@test P36104 !== orig_P36104 # Malformed invoke f_bad_invoke(x::Int) = invoke(x, (Any,), x) diff --git a/test/docs.jl b/test/docs.jl index 0fff85e90cb59..4404e4454849a 100644 --- a/test/docs.jl +++ b/test/docs.jl @@ -119,7 +119,7 @@ end # issue #38819 module NoDocStrings end -@test meta(NoDocStrings) === getfield(NoDocStrings, Base.Docs.META) +@test meta(NoDocStrings) === invokelatest(getfield, NoDocStrings, Base.Docs.META) # General tests for docstrings. diff --git a/test/errorshow.jl b/test/errorshow.jl index f83bbe31b7cc4..8f7482ce3235e 100644 --- a/test/errorshow.jl +++ b/test/errorshow.jl @@ -216,13 +216,14 @@ Base.show_method_candidates(buf, try bad_vararg_decl("hello", 3) catch e e end) macro except_str(expr, err_type) source_info = __source__ + errmsg = "expected failure, but no exception thrown for $expr" return quote let err = nothing try $(esc(expr)) catch err end - err === nothing && error("expected failure, but no exception thrown") + err === nothing && error($errmsg) @testset let expr=$(repr(expr)) $(Expr(:macrocall, Symbol("@test"), source_info, :(typeof(err) === $(esc(err_type))))) end @@ -255,6 +256,7 @@ end macro except_stackframe(expr, err_type) source_info = __source__ + errmsg = "expected failure, but no exception thrown for $expr" return quote let err = nothing local st @@ -263,7 +265,7 @@ macro except_stackframe(expr, err_type) catch err st = stacktrace(catch_backtrace()) end - err === nothing && error("expected failure, but no exception thrown") + err === nothing && error($errmsg) @testset let expr=$(repr(expr)) $(Expr(:macrocall, Symbol("@test"), source_info, :(typeof(err) === $(esc(err_type))))) end @@ -297,6 +299,7 @@ err_str = @except_str 1 + 2 MethodError err_str = @except_str Float64[](1) MethodError @test !occursin("import Base.Array", err_str) +global Array Array() = 1 err_str = @except_str Array([1]) MethodError @test occursin("import Base.Array", err_str) diff --git a/test/misc.jl b/test/misc.jl index 070952db89032..fef573e9fc747 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -1218,8 +1218,8 @@ end @test readlines(`$(Base.julia_cmd()) --startup-file=no -e 'foreach(println, names(Main))'`) == ["Base","Core","Main"] # issue #26310 -@test_warn "could not import" Core.eval(@__MODULE__, :(import .notdefined_26310__)) -@test_warn "could not import" Core.eval(Main, :(import ........notdefined_26310__)) +@test_warn "undeclared at import time" Core.eval(@__MODULE__, :(import .notdefined_26310__)) +@test_warn "undeclared at import time" Core.eval(Main, :(import ........notdefined_26310__)) @test_nowarn Core.eval(Main, :(import .Main)) @test_nowarn Core.eval(Main, :(import ....Main)) diff --git a/test/precompile.jl b/test/precompile.jl index 194f88719642e..e6c987326e44c 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -657,7 +657,7 @@ precompile_test_harness(false) do dir @test Base.stale_cachefile(relFooBar_file, joinpath(cachedir, "FooBar.ji")) isa Tsc @eval using FooBar - fb_uuid = Base.module_build_id(FooBar) + fb_uuid = invokelatest(()->Base.module_build_id(FooBar)) sleep(2); touch(FooBar_file) insert!(DEPOT_PATH, 1, dir2) @test Base.stale_cachefile(FooBar_file, joinpath(cachedir, "FooBar.ji")) isa Tsc @@ -667,9 +667,11 @@ precompile_test_harness(false) do dir @test isfile(joinpath(cachedir2, "FooBar1.ji")) @test Base.stale_cachefile(FooBar_file, joinpath(cachedir, "FooBar.ji")) isa Tsc @test Base.stale_cachefile(FooBar1_file, joinpath(cachedir2, "FooBar1.ji")) isa Tsc - @test fb_uuid == Base.module_build_id(FooBar) - fb_uuid1 = Base.module_build_id(FooBar1) - @test fb_uuid != fb_uuid1 + invokelatest() do + @test fb_uuid == Base.module_build_id(FooBar) + fb_uuid1 = Base.module_build_id(FooBar1) + @test fb_uuid != fb_uuid1 + end # test checksum open(joinpath(cachedir2, "FooBar1.ji"), "a") do f @@ -778,45 +780,48 @@ precompile_test_harness("code caching") do dir Base.compilecache(pkgid) @test Base.isprecompiled(pkgid) @eval using $Cache_module - M = getfield(@__MODULE__, Cache_module) - # Test that this cache file "owns" all the roots + M = invokelatest(getfield, @__MODULE__, Cache_module) Mid = rootid(M) - for name in (:f, :fpush, :callboth) - func = getfield(M, name) - m = only(collect(methods(func))) - @test all(i -> root_provenance(m, i) == Mid, 1:length(m.roots)) - end - # Check that we can cache external CodeInstances: - # length(::Vector) has an inferred specialization for `Vector{X}` - msize = which(length, (Vector{<:Any},)) - hasspec = false - for mi in Base.specializations(msize) - if mi.specTypes == Tuple{typeof(length),Vector{Cacheb8321416e8a3e2f1.X}} - if (isdefined(mi, :cache) && isa(mi.cache, Core.CodeInstance) && - mi.cache.max_world == typemax(UInt) && mi.cache.inferred !== nothing) - hasspec = true - break + invokelatest() do + # Test that this cache file "owns" all the roots + for name in (:f, :fpush, :callboth) + func = getfield(M, name) + m = only(collect(methods(func))) + @test all(i -> root_provenance(m, i) == Mid, 1:length(m.roots)) + end + # Check that we can cache external CodeInstances: + # length(::Vector) has an inferred specialization for `Vector{X}` + msize = which(length, (Vector{<:Any},)) + hasspec = false + for mi in Base.specializations(msize) + if mi.specTypes == Tuple{typeof(length),Vector{Cacheb8321416e8a3e2f1.X}} + if (isdefined(mi, :cache) && isa(mi.cache, Core.CodeInstance) && + mi.cache.max_world == typemax(UInt) && mi.cache.inferred !== nothing) + hasspec = true + break + end end end + @test hasspec + + # Check that internal methods and their roots are accounted appropriately + minternal = which(M.getelsize, (Vector,)) + mi = minternal.specializations::Core.MethodInstance + @test mi.specTypes == Tuple{typeof(M.getelsize),Vector{Int32}} + ci = mi.cache + @test (codeunits(ci.inferred::String)[end]) === 0x01 + @test ci.inferred !== nothing + # ...and that we can add "untracked" roots & non-relocatable CodeInstances to them too + Base.invokelatest() do + M.getelsize(M.X2[]) + end + mispecs = minternal.specializations::Core.SimpleVector + @test mispecs[1] === mi + mi = mispecs[2]::Core.MethodInstance + mi.specTypes == Tuple{typeof(M.getelsize),Vector{M.X2}} + ci = mi.cache + @test (codeunits(ci.inferred::String)[end]) == 0x00 end - @test hasspec - # Check that internal methods and their roots are accounted appropriately - minternal = which(M.getelsize, (Vector,)) - mi = minternal.specializations::Core.MethodInstance - @test mi.specTypes == Tuple{typeof(M.getelsize),Vector{Int32}} - ci = mi.cache - @test (codeunits(ci.inferred::String)[end]) === 0x01 - @test ci.inferred !== nothing - # ...and that we can add "untracked" roots & non-relocatable CodeInstances to them too - Base.invokelatest() do - M.getelsize(M.X2[]) - end - mispecs = minternal.specializations::Core.SimpleVector - @test mispecs[1] === mi - mi = mispecs[2]::Core.MethodInstance - mi.specTypes == Tuple{typeof(M.getelsize),Vector{M.X2}} - ci = mi.cache - @test (codeunits(ci.inferred::String)[end]) == 0x00 # PkgA loads PkgB, and both add roots to the same `push!` method (both before and after loading B) Cache_module2 = :Cachea1544c83560f0c99 write(joinpath(dir, "$Cache_module2.jl"), @@ -835,24 +840,26 @@ precompile_test_harness("code caching") do dir """) Base.compilecache(Base.PkgId(string(Cache_module2))) @eval using $Cache_module2 - M2 = getfield(@__MODULE__, Cache_module2) - M2id = rootid(M2) - dest = [] - Base.invokelatest() do # use invokelatest to see the results of loading the compile - M2.f(dest) - M.fpush(dest) - M2.g(dest) - @test dest == [M2.Y(), M.X(), M2.Z()] - @test M2.callf() == [M2.Y()] - @test M2.callg() == [M2.Z()] - @test M.fpush(M.X[]) == [M.X()] + invokelatest() do + M2 = getfield(@__MODULE__, Cache_module2) + M2id = rootid(M2) + dest = [] + Base.invokelatest() do # use invokelatest to see the results of loading the compile + M2.f(dest) + M.fpush(dest) + M2.g(dest) + @test dest == [M2.Y(), M.X(), M2.Z()] + @test M2.callf() == [M2.Y()] + @test M2.callg() == [M2.Z()] + @test M.fpush(M.X[]) == [M.X()] + end + mT = which(push!, (Vector{T} where T, Any)) + groups = group_roots(mT) + @test Memory{M2.Y} ∈ groups[M2id] + @test Memory{M2.Z} ∈ groups[M2id] + @test Memory{M.X} ∈ groups[Mid] + @test Memory{M.X} ∉ groups[M2id] end - mT = which(push!, (Vector{T} where T, Any)) - groups = group_roots(mT) - @test Memory{M2.Y} ∈ groups[M2id] - @test Memory{M2.Z} ∈ groups[M2id] - @test Memory{M.X} ∈ groups[Mid] - @test Memory{M.X} ∉ groups[M2id] # backedges of external MethodInstances # Root gets used by RootA and RootB, and both consumers end up inferring the same MethodInstance from Root # Do both callers get listed as backedges? @@ -895,31 +902,33 @@ precompile_test_harness("code caching") do dir Base.compilecache(Base.PkgId(string(RootB))) @eval using $RootA @eval using $RootB - MA = getfield(@__MODULE__, RootA) - MB = getfield(@__MODULE__, RootB) - M = getfield(MA, RootModule) - m = which(M.f, (Any,)) - for mi in Base.specializations(m) - mi === nothing && continue - mi = mi::Core.MethodInstance - if mi.specTypes.parameters[2] === Int8 - # external callers - mods = Module[] - for be in mi.backedges - push!(mods, ((be.def::Core.MethodInstance).def::Method).module) # XXX - end - @test MA ∈ mods - @test MB ∈ mods - @test length(mods) == 2 - elseif mi.specTypes.parameters[2] === Int16 - # internal callers - meths = Method[] - for be in mi.backedges - push!(meths, (be.def::Method).def) # XXX + invokelatest() do + MA = getfield(@__MODULE__, RootA) + MB = getfield(@__MODULE__, RootB) + M = getfield(MA, RootModule) + m = which(M.f, (Any,)) + for mi in Base.specializations(m) + mi === nothing && continue + mi = mi::Core.MethodInstance + if mi.specTypes.parameters[2] === Int8 + # external callers + mods = Module[] + for be in mi.backedges + push!(mods, ((be.def::Core.MethodInstance).def::Method).module) # XXX + end + @test MA ∈ mods + @test MB ∈ mods + @test length(mods) == 2 + elseif mi.specTypes.parameters[2] === Int16 + # internal callers + meths = Method[] + for be in mi.backedges + push!(meths, (be.def::Method).def) # XXX + end + @test which(M.g1, ()) ∈ meths + @test which(M.g2, ()) ∈ meths + @test length(meths) == 2 end - @test which(M.g1, ()) ∈ meths - @test which(M.g2, ()) ∈ meths - @test length(meths) == 2 end end @@ -1005,65 +1014,67 @@ precompile_test_harness("code caching") do dir Base.compilecache(Base.PkgId(string(pkg))) end @eval using $StaleA - MA = getfield(@__MODULE__, StaleA) + MA = invokelatest(getfield, @__MODULE__, StaleA) Base.eval(MA, :(nbits(::UInt8) = 8)) @eval using $StaleC invalidations = Base.StaticData.debug_method_invalidation(true) @eval using $StaleB Base.StaticData.debug_method_invalidation(false) - MB = getfield(@__MODULE__, StaleB) - MC = getfield(@__MODULE__, StaleC) - world = Base.get_world_counter() - m = only(methods(MA.use_stale)) - mi = m.specializations::Core.MethodInstance - @test hasvalid(mi, world) # it was re-inferred by StaleC - m = only(methods(MA.build_stale)) - mis = filter(!isnothing, collect(m.specializations::Core.SimpleVector)) - @test length(mis) == 2 - for mi in mis - mi = mi::Core.MethodInstance - if mi.specTypes.parameters[2] == Int - @test mi.cache.max_world < world - else - # The variant for String got "healed" by recompilation in StaleC - @test mi.specTypes.parameters[2] == String - @test mi.cache.max_world == typemax(UInt) + invokelatest() do + MB = getfield(@__MODULE__, StaleB) + MC = getfield(@__MODULE__, StaleC) + world = Base.get_world_counter() + m = only(methods(MA.use_stale)) + mi = m.specializations::Core.MethodInstance + @test hasvalid(mi, world) # it was re-inferred by StaleC + m = only(methods(MA.build_stale)) + mis = filter(!isnothing, collect(m.specializations::Core.SimpleVector)) + @test length(mis) == 2 + for mi in mis + mi = mi::Core.MethodInstance + if mi.specTypes.parameters[2] == Int + @test mi.cache.max_world < world + else + # The variant for String got "healed" by recompilation in StaleC + @test mi.specTypes.parameters[2] == String + @test mi.cache.max_world == typemax(UInt) + end + end + m = only(methods(MB.useA)) + mi = m.specializations::Core.MethodInstance + @test !hasvalid(mi, world) # invalidated by the stale(x::String) method in StaleC + m = only(methods(MC.call_buildstale)) + mi = m.specializations::Core.MethodInstance + @test hasvalid(mi, world) # was compiled with the new method + + # Reporting test (ensure SnoopCompile works) + @test all(i -> isassigned(invalidations, i), eachindex(invalidations)) + m = only(methods(MB.call_nbits)) + for mi in Base.specializations(m) + hv = hasvalid(mi, world) + @test mi.specTypes.parameters[end] === Integer ? !hv : hv end - end - m = only(methods(MB.useA)) - mi = m.specializations::Core.MethodInstance - @test !hasvalid(mi, world) # invalidated by the stale(x::String) method in StaleC - m = only(methods(MC.call_buildstale)) - mi = m.specializations::Core.MethodInstance - @test hasvalid(mi, world) # was compiled with the new method - - # Reporting test (ensure SnoopCompile works) - @test all(i -> isassigned(invalidations, i), eachindex(invalidations)) - m = only(methods(MB.call_nbits)) - for mi in Base.specializations(m) - hv = hasvalid(mi, world) - @test mi.specTypes.parameters[end] === Integer ? !hv : hv - end - idxs = findall(==("verify_methods"), invalidations) - idxsbits = filter(idxs) do i - mi = invalidations[i-1] - mi.def.def === m + idxs = findall(==("verify_methods"), invalidations) + idxsbits = filter(idxs) do i + mi = invalidations[i-1] + mi.def.def === m + end + idx = only(idxsbits) + tagbad = invalidations[idx+1] + @test isa(tagbad, Core.CodeInstance) + j = findfirst(==(tagbad), invalidations) + @test invalidations[j-1] == "insert_backedges_callee" + @test isa(invalidations[j-2], Type) + @test isa(invalidations[j+1], Vector{Any}) # [nbits(::UInt8)] + m = only(methods(MB.useA2)) + mi = only(Base.specializations(m)) + @test !hasvalid(mi, world) + @test any(x -> x isa Core.CodeInstance && x.def === mi, invalidations) + + m = only(methods(MB.map_nbits)) + @test !hasvalid(m.specializations::Core.MethodInstance, world+1) # insert_backedges invalidations also trigger their backedges end - idx = only(idxsbits) - tagbad = invalidations[idx+1] - @test isa(tagbad, Core.CodeInstance) - j = findfirst(==(tagbad), invalidations) - @test invalidations[j-1] == "insert_backedges_callee" - @test isa(invalidations[j-2], Type) - @test isa(invalidations[j+1], Vector{Any}) # [nbits(::UInt8)] - m = only(methods(MB.useA2)) - mi = only(Base.specializations(m)) - @test !hasvalid(mi, world) - @test any(x -> x isa Core.CodeInstance && x.def === mi, invalidations) - - m = only(methods(MB.map_nbits)) - @test !hasvalid(m.specializations::Core.MethodInstance, world+1) # insert_backedges invalidations also trigger their backedges end precompile_test_harness("invoke") do dir @@ -1181,88 +1192,90 @@ precompile_test_harness("invoke") do dir """) Base.compilecache(Base.PkgId(string(CallerModule))) @eval using $InvokeModule: $InvokeModule - MI = getfield(@__MODULE__, InvokeModule) + MI = invokelatest(getfield, @__MODULE__, InvokeModule) @eval $MI.getlast(a::UnitRange) = a.stop @eval using $CallerModule - M = getfield(@__MODULE__, CallerModule) + invokelatest() do + M = getfield(@__MODULE__, CallerModule) + + get_method_for_type(func, @nospecialize(T)) = which(func, (T,)) # return the method func(::T) + function nvalid(mi::Core.MethodInstance) + isdefined(mi, :cache) || return 0 + ci = mi.cache + n = Int(ci.max_world == typemax(UInt)) + while isdefined(ci, :next) + ci = ci.next + n += ci.max_world == typemax(UInt) + end + return n + end - get_method_for_type(func, @nospecialize(T)) = which(func, (T,)) # return the method func(::T) - function nvalid(mi::Core.MethodInstance) - isdefined(mi, :cache) || return 0 - ci = mi.cache - n = Int(ci.max_world == typemax(UInt)) - while isdefined(ci, :next) - ci = ci.next - n += ci.max_world == typemax(UInt) + for func in (M.f, M.g, M.internal, M.fnc, M.gnc, M.internalnc) + m = get_method_for_type(func, Real) + mi = m.specializations::Core.MethodInstance + @test length(mi.backedges) == 2 || length(mi.backedges) == 4 # internalnc might have a constprop edge + @test mi.backedges[1] === Tuple{typeof(func), Real} + @test isa(mi.backedges[2], Core.CodeInstance) + if length(mi.backedges) == 4 + @test mi.backedges[3] === Tuple{typeof(func), Real} + @test isa(mi.backedges[4], Core.CodeInstance) + @test mi.backedges[2] !== mi.backedges[4] + @test mi.backedges[2].def === mi.backedges[4].def + end + @test mi.cache.max_world == typemax(mi.cache.max_world) + end + for func in (M.q, M.qnc) + m = get_method_for_type(func, Integer) + mi = m.specializations::Core.MethodInstance + @test length(mi.backedges) == 2 + @test mi.backedges[1] === Tuple{typeof(func), Integer} + @test isa(mi.backedges[2], Core.CodeInstance) + @test mi.cache.max_world == typemax(mi.cache.max_world) end - return n - end - for func in (M.f, M.g, M.internal, M.fnc, M.gnc, M.internalnc) - m = get_method_for_type(func, Real) - mi = m.specializations::Core.MethodInstance - @test length(mi.backedges) == 2 || length(mi.backedges) == 4 # internalnc might have a constprop edge - @test mi.backedges[1] === Tuple{typeof(func), Real} - @test isa(mi.backedges[2], Core.CodeInstance) - if length(mi.backedges) == 4 - @test mi.backedges[3] === Tuple{typeof(func), Real} - @test isa(mi.backedges[4], Core.CodeInstance) - @test mi.backedges[2] !== mi.backedges[4] - @test mi.backedges[2].def === mi.backedges[4].def - end - @test mi.cache.max_world == typemax(mi.cache.max_world) - end - for func in (M.q, M.qnc) - m = get_method_for_type(func, Integer) + m = get_method_for_type(M.h, Real) + @test nvalid(m.specializations::Core.MethodInstance) == 0 + m = get_method_for_type(M.hnc, Real) + @test nvalid(m.specializations::Core.MethodInstance) == 0 + m = only(methods(M.callq)) + @test nvalid(m.specializations::Core.MethodInstance) == 0 + m = only(methods(M.callqnc)) + @test nvalid(m.specializations::Core.MethodInstance) == 1 + m = only(methods(M.callqi)) + @test (m.specializations::Core.MethodInstance).specTypes == Tuple{typeof(M.callqi), Int} + m = only(methods(M.callqnci)) + @test (m.specializations::Core.MethodInstance).specTypes == Tuple{typeof(M.callqnci), Int} + + m = only(methods(M.g44320)) + @test (m.specializations::Core.MethodInstance).cache.max_world == typemax(UInt) + + m = only(methods(M.g57115)) mi = m.specializations::Core.MethodInstance - @test length(mi.backedges) == 2 - @test mi.backedges[1] === Tuple{typeof(func), Integer} - @test isa(mi.backedges[2], Core.CodeInstance) - @test mi.cache.max_world == typemax(mi.cache.max_world) - end - m = get_method_for_type(M.h, Real) - @test nvalid(m.specializations::Core.MethodInstance) == 0 - m = get_method_for_type(M.hnc, Real) - @test nvalid(m.specializations::Core.MethodInstance) == 0 - m = only(methods(M.callq)) - @test nvalid(m.specializations::Core.MethodInstance) == 0 - m = only(methods(M.callqnc)) - @test nvalid(m.specializations::Core.MethodInstance) == 1 - m = only(methods(M.callqi)) - @test (m.specializations::Core.MethodInstance).specTypes == Tuple{typeof(M.callqi), Int} - m = only(methods(M.callqnci)) - @test (m.specializations::Core.MethodInstance).specTypes == Tuple{typeof(M.callqnci), Int} - - m = only(methods(M.g44320)) - @test (m.specializations::Core.MethodInstance).cache.max_world == typemax(UInt) - - m = only(methods(M.g57115)) - mi = m.specializations::Core.MethodInstance - - f_m = get_method_for_type(M.f57115, Any) - f_mi = f_m.specializations::Core.MethodInstance - - # Make sure that f57115(::Any) has a 'call' backedge to 'g57115' - has_f_call_backedge = false - i = 1 - while i ≤ length(f_mi.backedges) - if f_mi.backedges[i] isa DataType - # invoke edge - skip - i += 2 - else - caller = f_mi.backedges[i]::Core.CodeInstance - if caller.def === mi - has_f_call_backedge = true - break + f_m = get_method_for_type(M.f57115, Any) + f_mi = f_m.specializations::Core.MethodInstance + + # Make sure that f57115(::Any) has a 'call' backedge to 'g57115' + has_f_call_backedge = false + i = 1 + while i ≤ length(f_mi.backedges) + if f_mi.backedges[i] isa DataType + # invoke edge - skip + i += 2 + else + caller = f_mi.backedges[i]::Core.CodeInstance + if caller.def === mi + has_f_call_backedge = true + break + end + i += 1 end - i += 1 end - end - @test has_f_call_backedge + @test has_f_call_backedge - m = which(MI.getlast, (Any,)) - @test (m.specializations::Core.MethodInstance).cache.max_world == typemax(UInt) + m = which(MI.getlast, (Any,)) + @test (m.specializations::Core.MethodInstance).cache.max_world == typemax(UInt) + end # Precompile specific methods for arbitrary arg types invokeme(x) = 1 @@ -1359,7 +1372,6 @@ precompile_test_harness("package_callbacks") do dir """) Base.compilecache(Base.PkgId("$(Test2_module)")) - @test !Base.isbindingresolved(Main, Test2_module) Base.require(Main, Test2_module) @test take!(loaded_modules) == Test1_module @test take!(loaded_modules) == Test2_module @@ -1454,13 +1466,15 @@ end end try @eval using $ModuleB - uuid = Base.module_build_id(Base.root_module(Main, ModuleB)) - for wid in test_workers - @test Distributed.remotecall_eval(Main, wid, quote - Base.module_build_id(Base.root_module(Main, $(QuoteNode(ModuleB)))) - end) == uuid - if wid != myid() # avoid world-age errors on the local proc - @test remotecall_fetch(g, wid) == wid + invokelatest() do + uuid = Base.module_build_id(Base.root_module(Main, ModuleB)) + for wid in test_workers + @test Distributed.remotecall_eval(Main, wid, quote + Base.module_build_id(Base.root_module(Main, $(QuoteNode(ModuleB)))) + end) == uuid + if wid != myid() # avoid world-age errors on the local proc + @test remotecall_fetch(g, wid) == wid + end end end finally @@ -1612,7 +1626,9 @@ precompile_test_harness("Issue #29936") do load_path end """) @eval using Foo29936 - @test [("Plan", Foo29936.m), ("Plan", Foo29936.h),] isa Vector{Tuple{String,Val}} + invokelatest() do + @test [("Plan", Foo29936.m), ("Plan", Foo29936.h),] isa Vector{Tuple{String,Val}} + end end precompile_test_harness("Issue #25971") do load_path @@ -1795,8 +1811,10 @@ precompile_test_harness("Recursive types") do load_path """) Base.compilecache(Base.PkgId("RecursiveTypeDef")) (@eval (using RecursiveTypeDef)) - a = Base.invokelatest(RecursiveTypeDef.A{Float64,2,String}, (3, 3)) - @test isa(a, AbstractArray) + invokelatest() do + a = Base.invokelatest(RecursiveTypeDef.A{Float64,2,String}, (3, 3)) + @test isa(a, AbstractArray) + end end @testset "issue 46778" begin @@ -1820,7 +1838,9 @@ precompile_test_harness("Module tparams") do load_path """) Base.compilecache(Base.PkgId("ModuleTparams")) (@eval (using ModuleTparams)) - @test ModuleTparams.the_struct === Base.invokelatest(ModuleTparams.ParamStruct{ModuleTparams.TheTParam}) + invokelatest() do + @test ModuleTparams.the_struct === Base.invokelatest(ModuleTparams.ParamStruct{ModuleTparams.TheTParam}) + end end precompile_test_harness("PkgCacheInspector") do load_path @@ -1894,7 +1914,9 @@ precompile_test_harness("DynamicExpressions") do load_path """) Base.compilecache(Base.PkgId("Float16MWE")) @eval using Float16MWE - @test @invokelatest(Float16MWE.doconvert(Float16MWE.Node{Float16}, -1.2)) === Float16(-1.2) + invokelatest() do + @test Float16MWE.doconvert(Float16MWE.Node{Float16}, -1.2) === Float16(-1.2) + end end precompile_test_harness("BadInvalidations") do load_path @@ -1909,7 +1931,9 @@ precompile_test_harness("BadInvalidations") do load_path Base.compilecache(Base.PkgId("BadInvalidations")) @eval Base a_method_to_overwrite_in_test() = inferencebarrier(2) @eval using BadInvalidations - @test Base.invokelatest(BadInvalidations.getval) === 2 + invokelatest() do + @test BadInvalidations.getval() === 2 + end end # https://github.com/JuliaLang/julia/issues/48074 @@ -1945,7 +1969,7 @@ precompile_test_harness("Issue #48391") do load_path """) ji, ofile = Base.compilecache(Base.PkgId("I48391")) @eval using I48391 - x = Base.invokelatest(I48391.SurrealFinite) + x = invokelatest(()->I48391.SurrealFinite()) @test Base.invokelatest(isless, x, x) === "good" @test_throws ErrorException isless(x, x) end @@ -1985,13 +2009,17 @@ precompile_test_harness("Issue #50538") do load_path """) ji, ofile = Base.compilecache(Base.PkgId("I50538")) @eval using I50538 - @test I50538.newglobal.msg == "Creating a new global in closed module `Base` (`newglobal`) breaks incremental compilation because the side effects will not be permanent." - @test I50538.newtype.msg == "Evaluation into the closed module `Base` breaks incremental compilation because the side effects will not be permanent. This is likely due to some other module mutating `Base` with `eval` during precompilation - don't do this." - @test_throws(ErrorException("cannot set type for global I50538.undefglobal. It already has a value or is already set to a different type."), - Core.eval(I50538, :(global undefglobal::Int))) - Core.eval(I50538, :(global undefglobal::Any)) - @test Core.get_binding_type(I50538, :undefglobal) === Any - @test !isdefined(I50538, :undefglobal) + invokelatest() do + @test I50538.newglobal.msg == "Creating a new global in closed module `Base` (`newglobal`) breaks incremental compilation because the side effects will not be permanent." + @test I50538.newtype.msg == "Evaluation into the closed module `Base` breaks incremental compilation because the side effects will not be permanent. This is likely due to some other module mutating `Base` with `eval` during precompilation - don't do this." + @test_throws(ErrorException("cannot set type for global I50538.undefglobal. It already has a value or is already set to a different type."), + Core.eval(I50538, :(global undefglobal::Int))) + Core.eval(I50538, :(global undefglobal::Any)) + invokelatest() do + @test Core.get_binding_type(I50538, :undefglobal) === Any + @test !isdefined(I50538, :undefglobal) + end + end end precompile_test_harness("Test flags") do load_path @@ -2040,14 +2068,15 @@ precompile_test_harness("No backedge precompile") do load_path write(joinpath(load_path, "NoBackEdges.jl"), """ module NoBackEdges - using Core.Intrinsics: add_int - f(a::Int, b::Int) = add_int(a, b) + @eval f(a::Int, b::Int) = \$(Core.Intrinsics.add_int)(a, b) precompile(f, (Int, Int)) end """) ji, ofile = Base.compilecache(Base.PkgId("NoBackEdges")) @eval using NoBackEdges - @test first(methods(NoBackEdges.f)).specializations.cache.max_world === typemax(UInt) + invokelatest() do + @test first(methods(NoBackEdges.f)).specializations.cache.max_world === typemax(UInt) + end end # Test precompilation of generated functions that return opaque closures @@ -2078,7 +2107,7 @@ precompile_test_harness("Generated Opaque") do load_path """) Base.compilecache(Base.PkgId("GeneratedOpaque")) @eval using GeneratedOpaque - let oc = invokelatest(GeneratedOpaque.oc_re_generated_no_partial) + let oc = invokelatest(()->GeneratedOpaque.oc_re_generated_no_partial()) @test oc.source.specializations.cache.max_world === typemax(UInt) @test oc() === 1 end @@ -2143,9 +2172,10 @@ precompile_test_harness("Binding Unique") do load_path @eval using UniqueBinding1 @eval using UniqueBinding2 - - @test UniqueBinding2.thebinding === ccall(:jl_get_module_binding, Ref{Core.Binding}, (Any, Any, Cint), UniqueBinding1, :x, true) - @test UniqueBinding2.thebinding2 === ccall(:jl_get_module_binding, Ref{Core.Binding}, (Any, Any, Cint), UniqueBinding2, :thebinding, true) + invokelatest() do + @test UniqueBinding2.thebinding === ccall(:jl_get_module_binding, Ref{Core.Binding}, (Any, Any, Cint), UniqueBinding1, :x, true) + @test UniqueBinding2.thebinding2 === ccall(:jl_get_module_binding, Ref{Core.Binding}, (Any, Any, Cint), UniqueBinding2, :thebinding, true) + end end precompile_test_harness("Detecting importing outside of a package module") do load_path diff --git a/test/rebinding.jl b/test/rebinding.jl index aee866facaf02..23feb8ded0e56 100644 --- a/test/rebinding.jl +++ b/test/rebinding.jl @@ -62,6 +62,26 @@ module Rebinding @test f_generated_return_delete_me() == 4 Base.delete_binding(@__MODULE__, :delete_me) @test_throws UndefVarError f_generated_return_delete_me() + + module DeleteMeModule + export delete_me_implicit + const delete_me_explicit = 5 + const delete_me_implicit = 6 + end + + # + via import + using .DeleteMeModule: delete_me_explicit + f_return_delete_me_explicit() = delete_me_explicit + @test f_return_delete_me_explicit() == 5 + Base.delete_binding(DeleteMeModule, :delete_me_explicit) + @test_throws UndefVarError f_return_delete_me_explicit() + + # + via using + using .DeleteMeModule + f_return_delete_me_implicit() = delete_me_implicit + @test f_return_delete_me_implicit() == 6 + Base.delete_binding(DeleteMeModule, :delete_me_implicit) + @test_throws UndefVarError f_return_delete_me_implicit() end module RebindingPrecompile @@ -77,6 +97,9 @@ module RebindingPrecompile const delete_me_2 = 2 const delete_me_3 = 3 const delete_me_4 = 4 + export delete_me_5 + const delete_me_5 = 5 + const delete_me_6 = 6 end """) Base.compilecache(Base.PkgId("LotsOfBindingsToDelete")) @@ -88,16 +111,22 @@ module RebindingPrecompile @eval f_use_bindings2() = \$(GlobalRef(LotsOfBindingsToDelete, :delete_me_2)) f_use_bindings3() = LotsOfBindingsToDelete.delete_me_3 f_use_bindings4() = LotsOfBindingsToDelete.delete_me_4 + f_use_bindings5() = delete_me_5 + import LotsOfBindingsToDelete: delete_me_6 + f_use_bindings6() = delete_me_6 # Code Instances for each of these - @assert (f_use_bindings1(), f_use_bindings2(), f_use_bindings3(), f_use_bindings4()) == - (1, 2, 3, 4) + @assert (f_use_bindings1(), f_use_bindings2(), f_use_bindings3(), + f_use_bindings4(), f_use_bindings5(), f_use_bindings6()) == + (1, 2, 3, 4, 5, 6) end """) Base.compilecache(Base.PkgId("UseTheBindings")) @eval using LotsOfBindingsToDelete - # Delete some bindings before loading the dependent package - Base.delete_binding(LotsOfBindingsToDelete, :delete_me_1) - Base.delete_binding(LotsOfBindingsToDelete, :delete_me_3) + invokelatest() do + # Delete some bindings before loading the dependent package + Base.delete_binding(LotsOfBindingsToDelete, :delete_me_1) + Base.delete_binding(LotsOfBindingsToDelete, :delete_me_3) + end # Load the dependent package @eval using UseTheBindings invokelatest() do @@ -105,13 +134,67 @@ module RebindingPrecompile @test UseTheBindings.f_use_bindings2() == 2 @test_throws UndefVarError UseTheBindings.f_use_bindings3() @test UseTheBindings.f_use_bindings4() == 4 + @test UseTheBindings.f_use_bindings5() == 5 + @test UseTheBindings.f_use_bindings6() == 6 # Delete remaining bindings Base.delete_binding(LotsOfBindingsToDelete, :delete_me_2) Base.delete_binding(LotsOfBindingsToDelete, :delete_me_4) + Base.delete_binding(LotsOfBindingsToDelete, :delete_me_5) + Base.delete_binding(LotsOfBindingsToDelete, :delete_me_6) invokelatest() do @test_throws UndefVarError UseTheBindings.f_use_bindings2() @test_throws UndefVarError UseTheBindings.f_use_bindings4() + @test_throws UndefVarError UseTheBindings.f_use_bindings5() + @test_throws UndefVarError UseTheBindings.f_use_bindings6() + end + end + end + + precompile_test_harness("export change") do load_path + write(joinpath(load_path, "Export1.jl"), + """ + module Export1 + export import_me1 + const import_me1 = 11 + export import_me2 + const import_me2 = 12 + end + """) + write(joinpath(load_path, "Export2.jl"), + """ + module Export2 + end + """) + write(joinpath(load_path, "ImportTest.jl"), + """ + module ImportTest + using Export1, Export2 + f_use_binding1() = import_me1 + f_use_binding2() = import_me2 + @assert f_use_binding1() == 11 + @assert f_use_binding2() == 12 + end + """) + @eval using Export1 + @eval using Export2 + # Change the import resolution for ImportTest + invokelatest() do + Core.eval(Export2, :(export import_me1)) + Core.eval(Export2, :(const import_me1 = 21)) + end + @eval using ImportTest + invokelatest() do + @test_throws UndefVarError ImportTest.f_use_binding1() + @test ImportTest.f_use_binding2() == 12 + end + invokelatest() do + Core.eval(Export2, :(export import_me2)) + Core.eval(Export2, :(const import_me2 = 22)) + end + invokelatest() do + # Currently broken + # @test_throws UndefVarError ImportTest.f_use_binding2() end end diff --git a/test/reflection.jl b/test/reflection.jl index 9aa8fe512cd7c..57c32d19de629 100644 --- a/test/reflection.jl +++ b/test/reflection.jl @@ -969,10 +969,6 @@ f20872(::Val, ::Val) = false @test_throws ErrorException which(f20872, Tuple{Any,Val{N}} where N) @test which(Tuple{typeof(f20872), Val{1}, Val{2}}).sig == Tuple{typeof(f20872), Val, Val} -module M29962 end -# make sure checking if a binding is deprecated does not resolve it -@test !Base.isdeprecated(M29962, :sin) && !Base.isbindingresolved(M29962, :sin) - # @locals using Base: @locals let diff --git a/test/show.jl b/test/show.jl index 3057fcc3026e0..f68e5beaf3b3f 100644 --- a/test/show.jl +++ b/test/show.jl @@ -1903,15 +1903,6 @@ end b = IOBuffer() show(IOContext(b, :module => @__MODULE__), TypeA) @test String(take!(b)) == "TypeA" - - # issue #26354; make sure testing for symbol visibility doesn't cause - # spurious binding resolutions - show(IOContext(b, :module => TestShowType), Base.Pair) - @test !Base.isbindingresolved(TestShowType, :Pair) - @test String(take!(b)) == "Core.Pair" - show(IOContext(b, :module => TestShowType), Base.Complex) - @test Base.isbindingresolved(TestShowType, :Complex) - @test String(take!(b)) == "Complex" end @testset "typeinfo" begin diff --git a/test/staged.jl b/test/staged.jl index f3dbdcd73d811..6811bc05a9b68 100644 --- a/test/staged.jl +++ b/test/staged.jl @@ -312,7 +312,7 @@ end :(global x33243 = 2) end @test_throws ErrorException f33243() -global x33243 +global x33243::Any @test f33243() === 2 @test x33243 === 2 diff --git a/test/syntax.jl b/test/syntax.jl index f29dd4978d309..61672a6786762 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -2652,10 +2652,10 @@ using ..Mod end @test Mod3.f(10) == 21 @test !isdefined(Mod3, :func) -@test_throws ErrorException("invalid method definition in Mod3: function Mod3.f must be explicitly imported to be extended") Core.eval(Mod3, :(f(x::Int) = x)) +@test_throws ErrorException("invalid method definition in Mod3: function Mod.f must be explicitly imported to be extended") Core.eval(Mod3, :(f(x::Int) = x)) @test !isdefined(Mod3, :always_undef) # resolve this binding now in Mod3 -@test_throws ErrorException("invalid method definition in Mod3: exported function Mod.always_undef does not exist") Core.eval(Mod3, :(always_undef(x::Int) = x)) -@test_throws ErrorException("cannot declare Mod3.always_undef constant; it was already declared as an import") Core.eval(Mod3, :(const always_undef = 3)) +@test Core.eval(Mod3, :(always_undef(x::Int) = x)) == invokelatest(getglobal, Mod3, :always_undef) +@test Core.eval(Mod3, :(const always_undef = 3)) == invokelatest(getglobal, Mod3, :always_undef) @test_throws ErrorException("cannot declare Mod3.f constant; it was already declared as an import") Core.eval(Mod3, :(const f = 3)) @test_throws ErrorException("cannot declare Mod.maybe_undef constant; it was already declared global") Core.eval(Mod, :(const maybe_undef = 3)) @@ -4046,3 +4046,9 @@ function fs56711() return f end @test !@isdefined(x_should_not_be_defined) + +# Test that importing twice is allowed without warning +@test_nowarn @eval baremodule ImportTwice + import ..Base + using .Base: zero, zero +end diff --git a/test/worlds.jl b/test/worlds.jl index 48fb6593d3a37..f4558327c744b 100644 --- a/test/worlds.jl +++ b/test/worlds.jl @@ -107,7 +107,7 @@ end g265() = [f265(x) for x in 1:3.] wc265 = get_world_counter() wc265_41332a = Task(tls_world_age) -@test tls_world_age() == wc265 + 2 +@test tls_world_age() == wc265 + 1 (function () global wc265_41332b = Task(tls_world_age) @eval f265(::Any) = 1.0 @@ -115,15 +115,15 @@ wc265_41332a = Task(tls_world_age) global wc265_41332d = Task(tls_world_age) nothing end)() -@test wc265 + 10 == get_world_counter() == tls_world_age() +@test wc265 + 12 == get_world_counter() == tls_world_age() schedule(wc265_41332a) schedule(wc265_41332b) schedule(wc265_41332c) schedule(wc265_41332d) @test wc265 + 1 == fetch(wc265_41332a) -@test wc265 + 8 == fetch(wc265_41332b) -@test wc265 + 10 == fetch(wc265_41332c) -@test wc265 + 8 == fetch(wc265_41332d) +@test wc265 + 10 == fetch(wc265_41332b) +@test wc265 + 12 == fetch(wc265_41332c) +@test wc265 + 10 == fetch(wc265_41332d) chnls, tasks = Base.channeled_tasks(2, wfunc) t265 = tasks[1] @@ -509,3 +509,18 @@ struct FooBackdated FooBackdated() = new(FooBackdated[]) end @test Base.invoke_in_world(before_backdate_age, isdefined, @__MODULE__, :FooBackdated) + +# Test that ambiguous binding intersect the using'd binding's world ranges +module AmbigWorldTest + using Test + module M1; export x; end + module M2; export x; end + using .M1, .M2 + Core.eval(M1, :(x=1)) + Core.eval(M2, :(x=2)) + @test_throws UndefVarError x + @test convert(Core.Binding, GlobalRef(@__MODULE__, :x)).partitions.min_world == max( + convert(Core.Binding, GlobalRef(M1, :x)).partitions.min_world, + convert(Core.Binding, GlobalRef(M2, :x)).partitions.min_world + ) +end From f0446c624b2af960c597e22a39131ced9cfce6fb Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Thu, 6 Feb 2025 13:03:27 +0100 Subject: [PATCH 291/342] fix "Right arrow autocompletes at line end" implementation (#57273) Fixes https://github.com/JuliaLang/julia/issues/56864. Ref https://github.com/JuliaLang/julia/blob/99fd5d9a92190e826bc462d5739e7be948a3bf44/stdlib/REPL/src/LineEdit.jl#L504 --------- Co-authored-by: Ian Butterworth --- stdlib/REPL/src/LineEdit.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/REPL/src/LineEdit.jl b/stdlib/REPL/src/LineEdit.jl index 1075aa648b926..288a9cb1ea91f 100644 --- a/stdlib/REPL/src/LineEdit.jl +++ b/stdlib/REPL/src/LineEdit.jl @@ -835,7 +835,7 @@ function edit_move_right(m::MIState) # Replace word by completion prev_pos = position(s) push_undo(s) - edit_splice!(s, (prev_pos - sizeof(partial)) => prev_pos, completions[1]) + edit_splice!(s, (prev_pos - sizeof(partial)) => prev_pos, completions[1].completion) refresh_line(state(s)) return true else @@ -2260,7 +2260,7 @@ function complete_line(s::SearchState, repeats, mod::Module; hint::Bool=false) if length(completions) == 1 prev_pos = position(s) push_undo(s) - edit_splice!(s, (prev_pos - sizeof(partial)) => prev_pos, completions[1]) + edit_splice!(s, (prev_pos - sizeof(partial)) => prev_pos, completions[1].completion) return true end return false From 6f992ab0fc513998f53ab5d585752d4e50e5ed11 Mon Sep 17 00:00:00 2001 From: Eduardo Souza Date: Fri, 7 Feb 2025 01:14:19 +1100 Subject: [PATCH 292/342] Refactoring code in `mk_symbol` to remove stock specific code (#57214) This PR lifts up some code that uses specific information about the stock GC (`GC_OLD_MARKED` in the header bits). MMTk sets the log bits for immortal objects in a side table, but this requires that they are allocated with `jl_gc_permobj` instead of `jl_gc_perm_alloc`, since the latter allocates a memory slot and not necessarily an object. --- src/datatype.c | 16 ++++++++-------- src/gc-interface.h | 5 ++++- src/gc-mmtk.c | 6 ++++-- src/gc-stock.c | 12 +++++++----- src/jltypes.c | 6 +++--- src/runtime_ccall.cpp | 2 +- src/simplevector.c | 2 +- src/staticdata.c | 2 +- src/symbol.c | 10 +++++----- src/task.c | 2 +- 10 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/datatype.c b/src/datatype.c index fd25cca503676..240b1ace2295f 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -336,7 +336,7 @@ STATIC_INLINE void jl_maybe_allocate_singleton_instance(jl_datatype_t *st) JL_NO if (st->instance) return; if (jl_is_datatype_make_singleton(st)) { - st->instance = jl_gc_permobj(0, st); + st->instance = jl_gc_permobj(0, st, 0); } } @@ -575,7 +575,7 @@ void jl_get_genericmemory_layout(jl_datatype_t *st) if (jl_is_addrspacecore(addrspace) && jl_unbox_uint8(addrspace) == 0) { if (kind == (jl_value_t*)jl_not_atomic_sym || kind == (jl_value_t*)jl_atomic_sym) { - jl_genericmemory_t *zeroinst = (jl_genericmemory_t*)jl_gc_permobj(LLT_ALIGN(sizeof(jl_genericmemory_t), JL_SMALL_BYTE_ALIGNMENT) + (elsz ? elsz : isunion), st); + jl_genericmemory_t *zeroinst = (jl_genericmemory_t*)jl_gc_permobj(LLT_ALIGN(sizeof(jl_genericmemory_t), JL_SMALL_BYTE_ALIGNMENT) + (elsz ? elsz : isunion), st, 0); zeroinst->length = 0; zeroinst->ptr = (char*)zeroinst + JL_SMALL_BYTE_ALIGNMENT; memset(zeroinst->ptr, 0, elsz ? elsz : isunion); @@ -1385,13 +1385,13 @@ JL_DLLEXPORT int jl_atomic_storeonce_bits(jl_datatype_t *dt, char *dst, const jl return success; } -#define PERMBOXN_FUNC(nb) \ +#define PERMBOXN_FUNC(nb) \ jl_value_t *jl_permbox##nb(jl_datatype_t *t, uintptr_t tag, uint##nb##_t x) \ - { /* n.b. t must be a concrete isbits datatype of the right size */ \ - jl_value_t *v = jl_gc_permobj(LLT_ALIGN(nb, sizeof(void*)), t); \ - if (tag) jl_set_typetagof(v, tag, GC_OLD_MARKED); \ - *(uint##nb##_t*)jl_data_ptr(v) = x; \ - return v; \ + { /* n.b. t must be a concrete isbits datatype of the right size */ \ + jl_value_t *v = jl_gc_permobj(LLT_ALIGN(nb, sizeof(void*)), t, 0); \ + if (tag) jl_set_typetagof(v, tag, GC_OLD_MARKED); \ + *(uint##nb##_t*)jl_data_ptr(v) = x; \ + return v; \ } PERMBOXN_FUNC(8) PERMBOXN_FUNC(16) diff --git a/src/gc-interface.h b/src/gc-interface.h index 826e91355b17a..618077b127803 100644 --- a/src/gc-interface.h +++ b/src/gc-interface.h @@ -201,12 +201,15 @@ JL_DLLEXPORT void *jl_gc_perm_alloc(size_t sz, int zero, unsigned align, // object header must be included in the object size. This object is allocated in an // immortal region that is never swept. The second parameter specifies the type of the // object being allocated and will be used to set the object header. +// If the value passed as alignment is 0, then the result will be aligned according to the object +// size: if sz is 0 it will be aligned to pointer size, to 2x pointer size if sz < 2*sizeof(void*), +// or to 16 otherwise. // // !!! warning: Because permanently allocated objects are not swept, the GC will not // necessarily mark any objects that would have ordinarily been rooted by // the allocated object. All objects stored in fields of this object // must be either permanently allocated or have other roots. -struct _jl_value_t *jl_gc_permobj(size_t sz, void *ty) JL_NOTSAFEPOINT; +struct _jl_value_t *jl_gc_permobj(size_t sz, void *ty, unsigned align) JL_NOTSAFEPOINT; // This function notifies the GC about memory addresses that are set when loading the boot image. // The GC may use that information to, for instance, determine that such objects should // be treated as marked and belonged to the old generation in nursery collections. diff --git a/src/gc-mmtk.c b/src/gc-mmtk.c index 2f261a2e8e2fd..a6650dd7cb68c 100644 --- a/src/gc-mmtk.c +++ b/src/gc-mmtk.c @@ -1028,11 +1028,13 @@ void *jl_gc_perm_alloc(size_t sz, int zero, unsigned align, unsigned offset) return jl_gc_perm_alloc_nolock(sz, zero, align, offset); } -jl_value_t *jl_gc_permobj(size_t sz, void *ty) JL_NOTSAFEPOINT +jl_value_t *jl_gc_permobj(size_t sz, void *ty, unsigned align) JL_NOTSAFEPOINT { const size_t allocsz = sz + sizeof(jl_taggedvalue_t); - unsigned align = (sz == 0 ? sizeof(void*) : (allocsz <= sizeof(void*) * 2 ? + if (align == 0) { + align = ((sz == 0) ? sizeof(void*) : (allocsz <= sizeof(void*) * 2 ? sizeof(void*) * 2 : 16)); + } jl_taggedvalue_t *o = (jl_taggedvalue_t*)jl_gc_perm_alloc(allocsz, 0, align, sizeof(void*) % align); diff --git a/src/gc-stock.c b/src/gc-stock.c index 72479d14e67a5..d0f0baf4f4715 100644 --- a/src/gc-stock.c +++ b/src/gc-stock.c @@ -3931,16 +3931,18 @@ void *jl_gc_perm_alloc(size_t sz, int zero, unsigned align, unsigned offset) return p; } -jl_value_t *jl_gc_permobj(size_t sz, void *ty) JL_NOTSAFEPOINT +jl_value_t *jl_gc_permobj(size_t sz, void *ty, unsigned align) JL_NOTSAFEPOINT { const size_t allocsz = sz + sizeof(jl_taggedvalue_t); - unsigned align = (sz == 0 ? sizeof(void*) : (allocsz <= sizeof(void*) * 2 ? + if (align == 0) { + align = ((sz == 0) ? sizeof(void*) : (allocsz <= sizeof(void*) * 2 ? sizeof(void*) * 2 : 16)); + } jl_taggedvalue_t *o = (jl_taggedvalue_t*)jl_gc_perm_alloc(allocsz, 0, align, sizeof(void*) % align); - uintptr_t tag = (uintptr_t)ty; - o->header = tag | GC_OLD_MARKED; - return jl_valueof(o); + jl_value_t* v = jl_valueof(o); + jl_set_typeof(v, (void*)(((uintptr_t)(ty) | GC_OLD_MARKED))); + return v; } JL_DLLEXPORT int jl_gc_enable_conservative_gc_support(void) diff --git a/src/jltypes.c b/src/jltypes.c index b94922ce9cf54..dc7422460c0cf 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2956,7 +2956,7 @@ void jl_init_types(void) JL_GC_DISABLED XX(simplevector); jl_methtable_type = jl_new_uninitialized_datatype(); - jl_emptysvec = (jl_svec_t*)jl_gc_permobj(sizeof(void*), jl_simplevector_type); + jl_emptysvec = (jl_svec_t*)jl_gc_permobj(sizeof(void*), jl_simplevector_type, 0); jl_set_typetagof(jl_emptysvec, jl_simplevector_tag, GC_OLD_MARKED); jl_svec_set_len_unsafe(jl_emptysvec, 0); @@ -3088,7 +3088,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_typeofbottom_type = jl_new_datatype(jl_symbol("TypeofBottom"), core, type_type, jl_emptysvec, jl_emptysvec, jl_emptysvec, jl_emptysvec, 0, 0, 0); XX(typeofbottom); - jl_bottom_type = jl_gc_permobj(0, jl_typeofbottom_type); + jl_bottom_type = jl_gc_permobj(0, jl_typeofbottom_type, 0); jl_set_typetagof(jl_bottom_type, jl_typeofbottom_tag, GC_OLD_MARKED); jl_typeofbottom_type->instance = jl_bottom_type; @@ -3138,7 +3138,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_typeofbottom_type->super = jl_wrap_Type(jl_bottom_type); jl_typeofbottom_type->super->layout = jl_typeofbottom_type->layout; // the only abstract type with a layout jl_emptytuple_type = (jl_datatype_t*)jl_apply_tuple_type(jl_emptysvec, 0); - jl_emptytuple = jl_gc_permobj(0, jl_emptytuple_type); + jl_emptytuple = jl_gc_permobj(0, jl_emptytuple_type, 0); jl_emptytuple_type->instance = jl_emptytuple; // non-primitive definitions follow diff --git a/src/runtime_ccall.cpp b/src/runtime_ccall.cpp index dd5ceb2c6ad90..9b7374d95af50 100644 --- a/src/runtime_ccall.cpp +++ b/src/runtime_ccall.cpp @@ -295,7 +295,7 @@ jl_value_t *jl_get_cfunction_trampoline( permanent = true; } if (permanent) { - result = jl_gc_permobj(sizeof(jl_taggedvalue_t) + jl_datatype_size(result_type), result_type); + result = jl_gc_permobj(sizeof(jl_taggedvalue_t) + jl_datatype_size(result_type), result_type, 0); memset(result, 0, jl_datatype_size(result_type)); } else { diff --git a/src/simplevector.c b/src/simplevector.c index 5f1fd744abd0c..d87d3a046cf82 100644 --- a/src/simplevector.c +++ b/src/simplevector.c @@ -22,7 +22,7 @@ JL_DLLEXPORT jl_svec_t *(ijl_svec)(size_t n, ...) jl_svec_t *(jl_perm_symsvec)(size_t n, ...) { if (n == 0) return jl_emptysvec; - jl_svec_t *jv = (jl_svec_t*)jl_gc_permobj((n + 1) * sizeof(void*), jl_simplevector_type); + jl_svec_t *jv = (jl_svec_t*)jl_gc_permobj((n + 1) * sizeof(void*), jl_simplevector_type, 0); jl_set_typetagof(jv, jl_simplevector_tag, jl_astaggedvalue(jv)->bits.gc); jl_svec_set_len_unsafe(jv, n); va_list args; diff --git a/src/staticdata.c b/src/staticdata.c index 9eb2922380c63..bf4dba555e735 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -3832,7 +3832,7 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl // and we overwrite the name field (field 0) now so preserve it too if (dt->instance) { if (dt->instance == jl_nothing) - dt->instance = jl_gc_permobj(0, newdt); + dt->instance = jl_gc_permobj(0, newdt, 0); newdt->instance = dt->instance; } static_assert(offsetof(jl_datatype_t, name) == 0, ""); diff --git a/src/symbol.c b/src/symbol.c index ef2c11e0842e8..34b9073240cf3 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -29,16 +29,16 @@ static uintptr_t hash_symbol(const char *str, size_t len) JL_NOTSAFEPOINT static size_t symbol_nbytes(size_t len) JL_NOTSAFEPOINT { - return (sizeof(jl_taggedvalue_t) + sizeof(jl_sym_t) + len + 1 + 7) & -8; + return ((sizeof(jl_sym_t) + len + 1 + 7) & -8); } static jl_sym_t *mk_symbol(const char *str, size_t len) JL_NOTSAFEPOINT { - jl_sym_t *sym; size_t nb = symbol_nbytes(len); - jl_taggedvalue_t *tag = (jl_taggedvalue_t*)jl_gc_perm_alloc(nb, 0, sizeof(void*), 0); - sym = (jl_sym_t*)jl_valueof(tag); - // set to old marked so that we won't look at it in the GC or write barrier. + // jl_sym_t is an object and needs to be allocated with jl_gc_permobj + // but its type is set below with jl_set_typetagof since + // jl_symbol_type might not have been initialized + jl_sym_t *sym = (jl_sym_t*)jl_gc_permobj(nb, NULL, sizeof(void*)); jl_set_typetagof(sym, jl_symbol_tag, GC_OLD_MARKED); jl_atomic_store_relaxed(&sym->left, NULL); jl_atomic_store_relaxed(&sym->right, NULL); diff --git a/src/task.c b/src/task.c index 37e7f0e1f5440..068689d534a03 100644 --- a/src/task.c +++ b/src/task.c @@ -1535,7 +1535,7 @@ jl_task_t *jl_init_root_task(jl_ptls_t ptls, void *stack_lo, void *stack_hi) jl_set_pgcstack(&bootstrap_task.value.gcstack); bootstrap_task.value.ptls = ptls; if (jl_nothing == NULL) // make a placeholder - jl_nothing = jl_gc_permobj(0, jl_nothing_type); + jl_nothing = jl_gc_permobj(0, jl_nothing_type, 0); jl_task_t *ct = (jl_task_t*)jl_gc_alloc(ptls, sizeof(jl_task_t), jl_task_type); jl_set_typetagof(ct, jl_task_tag, 0); memset(ct, 0, sizeof(jl_task_t)); From 7621dc541a2f7b63441ffa797163e3ee01094368 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Thu, 6 Feb 2025 16:21:58 +0100 Subject: [PATCH 293/342] move NEWS to HISTORY (#57256) --- HISTORY.md | 276 +++++++++++++++++++++++++++++++++++++++++++++++++++++ NEWS.md | 226 ------------------------------------------- 2 files changed, 276 insertions(+), 226 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index c3ca212453d07..0351c875ed404 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,279 @@ +Julia v1.12 Release Notes +======================== + +New language features +--------------------- + +* New option `--trim` creates smaller binaries by removing code that was not proven to be reachable from + entry points. Entry points can be marked using `Base.Experimental.entrypoint` ([#55047]). +* 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`, + which modifies `v[3]` atomically with monotonic ordering semantics ([#54707]). + The supported syntax allows + * atomic fetch (`x = @atomic v[3]`), + * atomic set (`@atomic v[3] = 4`), + * atomic modify (`@atomic v[3] += 2`), + * atomic set once (`@atomiconce v[3] = 2`), + * atomic swap (`x = @atomicswap v[3] = 2`), and + * atomic replace (`x = @atomicreplace v[3] 2=>5`). +* New option `--task-metrics=yes` to enable the collection of per-task timing information, + which can also be enabled/disabled at runtime with `Base.Experimental.task_metrics(::Bool)` ([#56320]). + The available metrics are: + * actual running time for the task (`Base.Experimental.task_running_time_ns`), and + * wall-time for the task (`Base.Experimental.task_wall_time_ns`). +* Support for Unicode 16 ([#56925]). +* `Threads.@spawn` now takes a `:samepool` argument to specify the same threadpool as the caller. + `Threads.@spawn :samepool foo()` which is shorthand for `Threads.@spawn Threads.threadpool() foo()` ([#57109]). + +Language changes +---------------- + +* Julia now defaults to 1 "interactive" thread, in addition to the 1 default "worker" thread. i.e. `-t1,1`. + This means in default configuration the main task and repl (when in interactive mode), which both run on + thread 1, now run within the `interactive` threadpool. The libuv IO loop also runs on thread 1, + helping efficient utilization of the worker threadpool used by `Threads.@spawn`. Pass `0` to disable the + interactive thread i.e. `-t1,0` or `JULIA_NUM_THREADS=1,0`, or `-tauto,0` etc. The zero is explicitly + required to disable it, `-t2` will set the equivalent of `-t2,1` ([#57087]). +* When a method is replaced with an exactly equivalent one, the old method is not deleted. Instead, the + new method takes priority and becomes more specific than the old method. Thus if the new method is deleted + later, the old method will resume operating. This can be useful in mocking frameworks (as in SparseArrays, + Pluto, and Mocking, among others), as they do not need to explicitly restore the old method. + At this time, inference and compilation must be repeated in this situation, but we may eventually be + able to re-use the old results ([#53415]). +* Macro expansion will no longer eagerly recurse into `Expr(:toplevel)` expressions returned from macros. + Instead, macro expansion of `:toplevel` expressions will be delayed until evaluation time. This allows a + later expression within a given `:toplevel` expression to make use of macros defined earlier in the same + `:toplevel` expression ([#53515]). +* Trivial infinite loops (like `while true; end`) are no longer undefined behavior. Infinite loops that + do things (e.g. have side effects or sleep) were never and are still not undefined behavior ([#52999]). +* It is now an error to mark a binding as both `public` and `export`ed ([#53664]). +* Errors during `getfield` now raise a new `FieldError` exception type instead of the generic + `ErrorException` ([#54504]). + +Compiler/Runtime improvements +----------------------------- + +* Generated LLVM IR now uses pointer types instead of passing pointers as integers. + This affects `llvmcall`: Inline LLVM IR should be updated to use `i8*` or `ptr` instead of + `i32` or `i64`, and remove unneeded `ptrtoint`/`inttoptr` conversions. For compatibility, + IR with integer pointers is still supported, but generates a deprecation warning ([#53687]). + +Command-line option changes +--------------------------- + +* The `-m/--module` flag can be passed to run the `main` function inside a package with a set of arguments. + This `main` function should be declared using `@main` to indicate that it is an entry point ([#52103]). +* Enabling or disabling color text in Julia can now be controlled with the + [`NO_COLOR`](https://no-color.org/) or [`FORCE_COLOR`](https://force-color.org/) environment + variables. These variables are also honored by Julia's build system ([#53742], [#56346]). +* `--project=@temp` starts Julia with a temporary environment ([#51149]). +* New `--trace-compile-timing` option to report how long each method reported by `--trace-compile` took + to compile, in ms ([#54662]). +* `--trace-compile` now prints recompiled methods in yellow or with a trailing comment if color is not + supported ([#55763]). +* New `--trace-dispatch` option to report methods that are dynamically dispatched ([#55848]). + +Multi-threading changes +----------------------- + +* New types are defined to handle the pattern of code that must run once per process, called + a `OncePerProcess{T}` type, which allows defining a function that should be run exactly once + the first time it is called, and then always return the same result value of type `T` + every subsequent time afterwards. There are also `OncePerThread{T}` and `OncePerTask{T}` types for + similar usage with threads or tasks ([#55793]). + +Build system changes +-------------------- + +* There are new `Makefile`s to build Julia and LLVM using the Binary Optimization and Layout Tool (BOLT). + See `contrib/bolt` and `contrib/pgo-lto-bolt` ([#54107]). + +New library functions +--------------------- + +* `logrange(start, stop; length)` makes a range of constant ratio, instead of constant step ([#39071]). +* The new `isfull(c::Channel)` function can be used to check if `put!(c, some_value)` will block ([#53159]). +* `waitany(tasks; throw=false)` and `waitall(tasks; failfast=false, throw=false)` which wait for multiple tasks + at once ([#53341]). +* `uuid7()` creates an RFC 9652 compliant UUID with version 7 ([#54834]). +* `insertdims(array; dims)` inserts singleton dimensions into an array --- the inverse operation of + `dropdims` ([#45793]). +* A new `Fix` type generalizes `Fix1/Fix2` for fixing a single argument ([#54653]). +* `Sys.detectwsl()` tests whether Julia is running inside WSL at runtime ([#57069]). + +New library features +-------------------- + +* `escape_string` takes additional keyword arguments `ascii=true` (to escape all non-ASCII characters) and + `fullhex=true` (to require full 4/8-digit hex numbers for u/U escapes, e.g. for C compatibility) ([#55099]). +* `tempname` can now take a suffix string to allow the file name to include a suffix and include that suffix in + the uniquing checking ([#53474]). +* `RegexMatch` objects can now be used to construct `NamedTuple`s and `Dict`s ([#50988]). +* `Lockable` is now exported ([#54595]). +* `Base.require_one_based_indexing` and `Base.has_offset_axes` are now public ([#56196]). +* New `ltruncate`, `rtruncate` and `ctruncate` functions for truncating strings to text width, accounting for + char widths ([#55351]). +* `isless` (and thus `cmp`, sorting, etc.) is now supported for zero-dimensional `AbstractArray`s ([#55772]). +* `invoke` now supports passing a `Method` instead of a type signature ([#56692]). +* `invoke` now supports passing a `CodeInstance` instead of a type, which can enable certain compiler plugin + workflows ([#56660]). +* `Timer(f, ...)` will now match the stickiness of the parent task when creating timer tasks, which can be + overridden by the new `spawn` keyword argument. This avoids the issue where sticky tasks (i.e. `@async`) + make their parent sticky ([#56745]). +* `Timer` now has readable `timeout` and `interval` properties, and a more descriptive `show` method ([#57081]). +* `sort` now supports `NTuple`s ([#54494]). +* `map!(f, A)` now stores the results in `A`, like `map!(f, A, A)` or `A .= f.(A)` ([#40632]). + +Standard library changes +------------------------ + +* `gcdx(0, 0)` now returns `(0, 0, 0)` instead of `(0, 1, 0)` ([#40989]). +* `fd` returns a `RawFD` instead of an `Int` ([#55080]). + +#### JuliaSyntaxHighlighting + +* A new standard library for applying syntax highlighting to Julia code, this uses `JuliaSyntax` and + `StyledStrings` to implement a `highlight` function that creates an `AnnotatedString` with syntax highlighting + applied ([#51810]). + +#### LinearAlgebra + +* `rank` can now take a `QRPivoted` matrix to allow rank estimation via QR factorization ([#54283]). +* Added keyword argument `alg` to `eigen`, `eigen!`, `eigvals` and `eigvals!` for self-adjoint matrix types + (i.e., the type union `RealHermSymComplexHerm`) that allows one to switch between different eigendecomposition + algorithms ([#49355]). +* Added a generic version of the (unblocked) pivoted Cholesky decomposition (callable via + `cholesky[!](A, RowMaximum())`) ([#54619]). +* The number of default BLAS threads now respects process affinity, instead of using the total number of logical + threads available on the system ([#55574]). +* A new function `zeroslike` is added that generates the zero elements for matrix-valued banded matrices. + Custom array types may specialize this function to return an appropriate result ([#55252]). +* The matrix multiplication `A * B` calls `matprod_dest(A, B, T::Type)` to generate the destination. + This function is now public ([#55537]). +* The function `haszero(T::Type)` is used to check if a type `T` has a unique zero element defined as `zero(T)`. + This is now public ([#56223]). +* A new function `diagview` is added that returns a view into a specific band of an `AbstractMatrix` ([#56175]). + +#### Profile + +* `Profile.take_heap_snapshot` takes a new keyword argument, `redact_data::Bool`, which is `true` by default. + When set, the contents of Julia objects are not emitted in the heap snapshot. This currently only applies to + strings ([#55326]). +* `Profile.print()` now colors Base/Core/Package modules similarly to how they are in stacktraces. + Also paths, even if truncated, are now clickable in terminals that support URI links + to take you to the specified `JULIA_EDITOR` for the given file & line number ([#55335]). + +#### REPL + +* Using the new `usings=true` feature of the `names()` function, REPL completions can now + complete names visible via `using` ([#54610]). +* REPL completions can now complete input lines like `[import|using] Mod: xxx|` e.g. + complete `using Base.Experimental: @op` to `using Base.Experimental: @opaque` ([#54719]). +* The REPL will now warn if it detects a name is being accessed via a module which does not define it (nor has + a submodule which defines it), and for which the name is not public in that module. For example, `map` is + defined in Base, and executing `LinearAlgebra.map` in the REPL will now issue a warning the first time it + occurs ([#54872]). +* When the result of a REPL input is printed, the output is now truncated to 20 KiB. + This does not affect manual calls to `show`, `print`, etc. ([#53959]). +* Backslash completions now print the respective glyph or emoji next to each matching backslash shortcode ([#54800]). + +#### Test + +* A failing `DefaultTestSet` now prints to screen the random number generator (RNG) of the failed test, to help + reproducing a stochastic failure which only depends on the state of the RNG. + It is also possible seed a test set by passing the `rng` keyword argument to `@testset`: + ```julia + using Test, Random + @testset rng=Xoshiro(0x2e026445595ed28e, 0x07bb81ac4c54926d, 0x83d7d70843e8bad6, 0xdbef927d150af80b, 0xdbf91ddf2534f850) begin + @test rand() == 0.559472630416976 + end + ``` + +#### InteractiveUtils + +* New macros `@trace_compile` and `@trace_dispatch` for running an expression with + `--trace-compile=stderr --trace-compile-timing` and `--trace-dispatch=stderr` respectively enabled ([#55915]). + +External dependencies +--------------------- + +* The terminal info database, `terminfo`, is now vendored by default, providing a better + REPL user experience when `terminfo` is not available on the system. Julia can be built + without vendoring the database using the Makefile option `WITH_TERMINFO=0` ([#55411]). + +Tooling Improvements +-------------------- + +* A wall-time profiler is now available for users who need a sampling profiler that captures tasks regardless + of their scheduling or running state. This type of profiler enables profiling of I/O-heavy tasks and helps + detect areas of heavy contention in the system ([#55889]). + + +[#39071]: https://github.com/JuliaLang/julia/issues/39071 +[#40632]: https://github.com/JuliaLang/julia/issues/40632 +[#40989]: https://github.com/JuliaLang/julia/issues/40989 +[#45793]: https://github.com/JuliaLang/julia/issues/45793 +[#49355]: https://github.com/JuliaLang/julia/issues/49355 +[#50988]: https://github.com/JuliaLang/julia/issues/50988 +[#51149]: https://github.com/JuliaLang/julia/issues/51149 +[#51810]: https://github.com/JuliaLang/julia/issues/51810 +[#52103]: https://github.com/JuliaLang/julia/issues/52103 +[#52999]: https://github.com/JuliaLang/julia/issues/52999 +[#53159]: https://github.com/JuliaLang/julia/issues/53159 +[#53341]: https://github.com/JuliaLang/julia/issues/53341 +[#53415]: https://github.com/JuliaLang/julia/issues/53415 +[#53474]: https://github.com/JuliaLang/julia/issues/53474 +[#53515]: https://github.com/JuliaLang/julia/issues/53515 +[#53664]: https://github.com/JuliaLang/julia/issues/53664 +[#53687]: https://github.com/JuliaLang/julia/issues/53687 +[#53742]: https://github.com/JuliaLang/julia/issues/53742 +[#53959]: https://github.com/JuliaLang/julia/issues/53959 +[#54107]: https://github.com/JuliaLang/julia/issues/54107 +[#54283]: https://github.com/JuliaLang/julia/issues/54283 +[#54494]: https://github.com/JuliaLang/julia/issues/54494 +[#54504]: https://github.com/JuliaLang/julia/issues/54504 +[#54595]: https://github.com/JuliaLang/julia/issues/54595 +[#54609]: https://github.com/JuliaLang/julia/issues/54609 +[#54610]: https://github.com/JuliaLang/julia/issues/54610 +[#54619]: https://github.com/JuliaLang/julia/issues/54619 +[#54653]: https://github.com/JuliaLang/julia/issues/54653 +[#54662]: https://github.com/JuliaLang/julia/issues/54662 +[#54707]: https://github.com/JuliaLang/julia/issues/54707 +[#54719]: https://github.com/JuliaLang/julia/issues/54719 +[#54800]: https://github.com/JuliaLang/julia/issues/54800 +[#54834]: https://github.com/JuliaLang/julia/issues/54834 +[#54872]: https://github.com/JuliaLang/julia/issues/54872 +[#55047]: https://github.com/JuliaLang/julia/issues/55047 +[#55080]: https://github.com/JuliaLang/julia/issues/55080 +[#55099]: https://github.com/JuliaLang/julia/issues/55099 +[#55252]: https://github.com/JuliaLang/julia/issues/55252 +[#55326]: https://github.com/JuliaLang/julia/issues/55326 +[#55335]: https://github.com/JuliaLang/julia/issues/55335 +[#55351]: https://github.com/JuliaLang/julia/issues/55351 +[#55411]: https://github.com/JuliaLang/julia/issues/55411 +[#55537]: https://github.com/JuliaLang/julia/issues/55537 +[#55574]: https://github.com/JuliaLang/julia/issues/55574 +[#55763]: https://github.com/JuliaLang/julia/issues/55763 +[#55772]: https://github.com/JuliaLang/julia/issues/55772 +[#55793]: https://github.com/JuliaLang/julia/issues/55793 +[#55848]: https://github.com/JuliaLang/julia/issues/55848 +[#55889]: https://github.com/JuliaLang/julia/issues/55889 +[#55915]: https://github.com/JuliaLang/julia/issues/55915 +[#56175]: https://github.com/JuliaLang/julia/issues/56175 +[#56196]: https://github.com/JuliaLang/julia/issues/56196 +[#56223]: https://github.com/JuliaLang/julia/issues/56223 +[#56320]: https://github.com/JuliaLang/julia/issues/56320 +[#56346]: https://github.com/JuliaLang/julia/issues/56346 +[#56660]: https://github.com/JuliaLang/julia/issues/56660 +[#56692]: https://github.com/JuliaLang/julia/issues/56692 +[#56745]: https://github.com/JuliaLang/julia/issues/56745 +[#56925]: https://github.com/JuliaLang/julia/issues/56925 +[#57069]: https://github.com/JuliaLang/julia/issues/57069 +[#57081]: https://github.com/JuliaLang/julia/issues/57081 +[#57087]: https://github.com/JuliaLang/julia/issues/57087 +[#57109]: https://github.com/JuliaLang/julia/issues/57109 + Julia v1.11 Release Notes ======================== diff --git a/NEWS.md b/NEWS.md index 403d832ee6f68..fb3e524bf2cf7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,272 +4,46 @@ Julia v1.12 Release Notes New language features --------------------- -* New option `--trim` creates smaller binaries by removing code that was not proven to be reachable from - entry points. Entry points can be marked using `Base.Experimental.entrypoint` ([#55047]). -* 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`, - which modifies `v[3]` atomically with monotonic ordering semantics ([#54707]). - The supported syntax allows - * atomic fetch (`x = @atomic v[3]`), - * atomic set (`@atomic v[3] = 4`), - * atomic modify (`@atomic v[3] += 2`), - * atomic set once (`@atomiconce v[3] = 2`), - * atomic swap (`x = @atomicswap v[3] = 2`), and - * atomic replace (`x = @atomicreplace v[3] 2=>5`). -* New option `--task-metrics=yes` to enable the collection of per-task timing information, - which can also be enabled/disabled at runtime with `Base.Experimental.task_metrics(::Bool)` ([#56320]). - The available metrics are: - * actual running time for the task (`Base.Experimental.task_running_time_ns`), and - * wall-time for the task (`Base.Experimental.task_wall_time_ns`). -* Support for Unicode 16 ([#56925]). -* `Threads.@spawn` now takes a `:samepool` argument to specify the same threadpool as the caller. - `Threads.@spawn :samepool foo()` which is shorthand for `Threads.@spawn Threads.threadpool() foo()` ([#57109]). - Language changes ---------------- -* Julia now defaults to 1 "interactive" thread, in addition to the 1 default "worker" thread. i.e. `-t1,1`. - This means in default configuration the main task and repl (when in interactive mode), which both run on - thread 1, now run within the `interactive` threadpool. The libuv IO loop also runs on thread 1, - helping efficient utilization of the worker threadpool used by `Threads.@spawn`. Pass `0` to disable the - interactive thread i.e. `-t1,0` or `JULIA_NUM_THREADS=1,0`, or `-tauto,0` etc. The zero is explicitly - required to disable it, `-t2` will set the equivalent of `-t2,1` ([#57087]). -* When a method is replaced with an exactly equivalent one, the old method is not deleted. Instead, the - new method takes priority and becomes more specific than the old method. Thus if the new method is deleted - later, the old method will resume operating. This can be useful in mocking frameworks (as in SparseArrays, - Pluto, and Mocking, among others), as they do not need to explicitly restore the old method. - At this time, inference and compilation must be repeated in this situation, but we may eventually be - able to re-use the old results ([#53415]). -* Macro expansion will no longer eagerly recurse into `Expr(:toplevel)` expressions returned from macros. - Instead, macro expansion of `:toplevel` expressions will be delayed until evaluation time. This allows a - later expression within a given `:toplevel` expression to make use of macros defined earlier in the same - `:toplevel` expression ([#53515]). -* Trivial infinite loops (like `while true; end`) are no longer undefined behavior. Infinite loops that - do things (e.g. have side effects or sleep) were never and are still not undefined behavior ([#52999]). -* It is now an error to mark a binding as both `public` and `export`ed ([#53664]). -* Errors during `getfield` now raise a new `FieldError` exception type instead of the generic - `ErrorException` ([#54504]). - Compiler/Runtime improvements ----------------------------- -* Generated LLVM IR now uses pointer types instead of passing pointers as integers. - This affects `llvmcall`: Inline LLVM IR should be updated to use `i8*` or `ptr` instead of - `i32` or `i64`, and remove unneeded `ptrtoint`/`inttoptr` conversions. For compatibility, - IR with integer pointers is still supported, but generates a deprecation warning ([#53687]). - Command-line option changes --------------------------- -* The `-m/--module` flag can be passed to run the `main` function inside a package with a set of arguments. - This `main` function should be declared using `@main` to indicate that it is an entry point ([#52103]). -* Enabling or disabling color text in Julia can now be controlled with the - [`NO_COLOR`](https://no-color.org/) or [`FORCE_COLOR`](https://force-color.org/) environment - variables. These variables are also honored by Julia's build system ([#53742], [#56346]). -* `--project=@temp` starts Julia with a temporary environment ([#51149]). -* New `--trace-compile-timing` option to report how long each method reported by `--trace-compile` took - to compile, in ms ([#54662]). -* `--trace-compile` now prints recompiled methods in yellow or with a trailing comment if color is not - supported ([#55763]). -* New `--trace-dispatch` option to report methods that are dynamically dispatched ([#55848]). - Multi-threading changes ----------------------- -* New types are defined to handle the pattern of code that must run once per process, called - a `OncePerProcess{T}` type, which allows defining a function that should be run exactly once - the first time it is called, and then always return the same result value of type `T` - every subsequent time afterwards. There are also `OncePerThread{T}` and `OncePerTask{T}` types for - similar usage with threads or tasks ([#55793]). - Build system changes -------------------- -* There are new `Makefile`s to build Julia and LLVM using the Binary Optimization and Layout Tool (BOLT). - See `contrib/bolt` and `contrib/pgo-lto-bolt` ([#54107]). - New library functions --------------------- -* `logrange(start, stop; length)` makes a range of constant ratio, instead of constant step ([#39071]). -* The new `isfull(c::Channel)` function can be used to check if `put!(c, some_value)` will block ([#53159]). -* `waitany(tasks; throw=false)` and `waitall(tasks; failfast=false, throw=false)` which wait for multiple tasks - at once ([#53341]). -* `uuid7()` creates an RFC 9652 compliant UUID with version 7 ([#54834]). -* `insertdims(array; dims)` inserts singleton dimensions into an array --- the inverse operation of - `dropdims` ([#45793]). -* A new `Fix` type generalizes `Fix1/Fix2` for fixing a single argument ([#54653]). -* `Sys.detectwsl()` tests whether Julia is running inside WSL at runtime ([#57069]). - New library features -------------------- -* `escape_string` takes additional keyword arguments `ascii=true` (to escape all non-ASCII characters) and - `fullhex=true` (to require full 4/8-digit hex numbers for u/U escapes, e.g. for C compatibility) ([#55099]). -* `tempname` can now take a suffix string to allow the file name to include a suffix and include that suffix in - the uniquing checking ([#53474]). -* `RegexMatch` objects can now be used to construct `NamedTuple`s and `Dict`s ([#50988]). -* `Lockable` is now exported ([#54595]). -* `Base.require_one_based_indexing` and `Base.has_offset_axes` are now public ([#56196]). -* New `ltruncate`, `rtruncate` and `ctruncate` functions for truncating strings to text width, accounting for - char widths ([#55351]). -* `isless` (and thus `cmp`, sorting, etc.) is now supported for zero-dimensional `AbstractArray`s ([#55772]). -* `invoke` now supports passing a `Method` instead of a type signature ([#56692]). -* `invoke` now supports passing a `CodeInstance` instead of a type, which can enable certain compiler plugin - workflows ([#56660]). -* `Timer(f, ...)` will now match the stickiness of the parent task when creating timer tasks, which can be - overridden by the new `spawn` keyword argument. This avoids the issue where sticky tasks (i.e. `@async`) - make their parent sticky ([#56745]). -* `Timer` now has readable `timeout` and `interval` properties, and a more descriptive `show` method ([#57081]). -* `sort` now supports `NTuple`s ([#54494]). -* `map!(f, A)` now stores the results in `A`, like `map!(f, A, A)` or `A .= f.(A)` ([#40632]). - Standard library changes ------------------------ -* `gcdx(0, 0)` now returns `(0, 0, 0)` instead of `(0, 1, 0)` ([#40989]). -* `fd` returns a `RawFD` instead of an `Int` ([#55080]). - #### JuliaSyntaxHighlighting -* A new standard library for applying syntax highlighting to Julia code, this uses `JuliaSyntax` and - `StyledStrings` to implement a `highlight` function that creates an `AnnotatedString` with syntax highlighting - applied ([#51810]). - #### LinearAlgebra -* `rank` can now take a `QRPivoted` matrix to allow rank estimation via QR factorization ([#54283]). -* Added keyword argument `alg` to `eigen`, `eigen!`, `eigvals` and `eigvals!` for self-adjoint matrix types - (i.e., the type union `RealHermSymComplexHerm`) that allows one to switch between different eigendecomposition - algorithms ([#49355]). -* Added a generic version of the (unblocked) pivoted Cholesky decomposition (callable via - `cholesky[!](A, RowMaximum())`) ([#54619]). -* The number of default BLAS threads now respects process affinity, instead of using the total number of logical - threads available on the system ([#55574]). -* A new function `zeroslike` is added that generates the zero elements for matrix-valued banded matrices. - Custom array types may specialize this function to return an appropriate result ([#55252]). -* The matrix multiplication `A * B` calls `matprod_dest(A, B, T::Type)` to generate the destination. - This function is now public ([#55537]). -* The function `haszero(T::Type)` is used to check if a type `T` has a unique zero element defined as `zero(T)`. - This is now public ([#56223]). -* A new function `diagview` is added that returns a view into a specific band of an `AbstractMatrix` ([#56175]). - #### Profile -* `Profile.take_heap_snapshot` takes a new keyword argument, `redact_data::Bool`, which is `true` by default. - When set, the contents of Julia objects are not emitted in the heap snapshot. This currently only applies to - strings ([#55326]). -* `Profile.print()` now colors Base/Core/Package modules similarly to how they are in stacktraces. - Also paths, even if truncated, are now clickable in terminals that support URI links - to take you to the specified `JULIA_EDITOR` for the given file & line number ([#55335]). - #### REPL -* Using the new `usings=true` feature of the `names()` function, REPL completions can now - complete names visible via `using` ([#54610]). -* REPL completions can now complete input lines like `[import|using] Mod: xxx|` e.g. - complete `using Base.Experimental: @op` to `using Base.Experimental: @opaque` ([#54719]). -* The REPL will now warn if it detects a name is being accessed via a module which does not define it (nor has - a submodule which defines it), and for which the name is not public in that module. For example, `map` is - defined in Base, and executing `LinearAlgebra.map` in the REPL will now issue a warning the first time it - occurs ([#54872]). -* When the result of a REPL input is printed, the output is now truncated to 20 KiB. - This does not affect manual calls to `show`, `print`, etc. ([#53959]). -* Backslash completions now print the respective glyph or emoji next to each matching backslash shortcode ([#54800]). - #### Test -* A failing `DefaultTestSet` now prints to screen the random number generator (RNG) of the failed test, to help - reproducing a stochastic failure which only depends on the state of the RNG. - It is also possible seed a test set by passing the `rng` keyword argument to `@testset`: - ```julia - using Test, Random - @testset rng=Xoshiro(0x2e026445595ed28e, 0x07bb81ac4c54926d, 0x83d7d70843e8bad6, 0xdbef927d150af80b, 0xdbf91ddf2534f850) begin - @test rand() == 0.559472630416976 - end - ``` - #### InteractiveUtils -* New macros `@trace_compile` and `@trace_dispatch` for running an expression with - `--trace-compile=stderr --trace-compile-timing` and `--trace-dispatch=stderr` respectively enabled ([#55915]). - External dependencies --------------------- -* The terminal info database, `terminfo`, is now vendored by default, providing a better - REPL user experience when `terminfo` is not available on the system. Julia can be built - without vendoring the database using the Makefile option `WITH_TERMINFO=0` ([#55411]). - Tooling Improvements -------------------- -* A wall-time profiler is now available for users who need a sampling profiler that captures tasks regardless - of their scheduling or running state. This type of profiler enables profiling of I/O-heavy tasks and helps - detect areas of heavy contention in the system ([#55889]). - -[#39071]: https://github.com/JuliaLang/julia/issues/39071 -[#40632]: https://github.com/JuliaLang/julia/issues/40632 -[#40989]: https://github.com/JuliaLang/julia/issues/40989 -[#45793]: https://github.com/JuliaLang/julia/issues/45793 -[#49355]: https://github.com/JuliaLang/julia/issues/49355 -[#50988]: https://github.com/JuliaLang/julia/issues/50988 -[#51149]: https://github.com/JuliaLang/julia/issues/51149 -[#51810]: https://github.com/JuliaLang/julia/issues/51810 -[#52103]: https://github.com/JuliaLang/julia/issues/52103 -[#52999]: https://github.com/JuliaLang/julia/issues/52999 -[#53159]: https://github.com/JuliaLang/julia/issues/53159 -[#53341]: https://github.com/JuliaLang/julia/issues/53341 -[#53415]: https://github.com/JuliaLang/julia/issues/53415 -[#53474]: https://github.com/JuliaLang/julia/issues/53474 -[#53515]: https://github.com/JuliaLang/julia/issues/53515 -[#53664]: https://github.com/JuliaLang/julia/issues/53664 -[#53687]: https://github.com/JuliaLang/julia/issues/53687 -[#53742]: https://github.com/JuliaLang/julia/issues/53742 -[#53959]: https://github.com/JuliaLang/julia/issues/53959 -[#54107]: https://github.com/JuliaLang/julia/issues/54107 -[#54283]: https://github.com/JuliaLang/julia/issues/54283 -[#54494]: https://github.com/JuliaLang/julia/issues/54494 -[#54504]: https://github.com/JuliaLang/julia/issues/54504 -[#54595]: https://github.com/JuliaLang/julia/issues/54595 -[#54609]: https://github.com/JuliaLang/julia/issues/54609 -[#54610]: https://github.com/JuliaLang/julia/issues/54610 -[#54619]: https://github.com/JuliaLang/julia/issues/54619 -[#54653]: https://github.com/JuliaLang/julia/issues/54653 -[#54662]: https://github.com/JuliaLang/julia/issues/54662 -[#54707]: https://github.com/JuliaLang/julia/issues/54707 -[#54719]: https://github.com/JuliaLang/julia/issues/54719 -[#54800]: https://github.com/JuliaLang/julia/issues/54800 -[#54834]: https://github.com/JuliaLang/julia/issues/54834 -[#54872]: https://github.com/JuliaLang/julia/issues/54872 -[#55047]: https://github.com/JuliaLang/julia/issues/55047 -[#55080]: https://github.com/JuliaLang/julia/issues/55080 -[#55099]: https://github.com/JuliaLang/julia/issues/55099 -[#55252]: https://github.com/JuliaLang/julia/issues/55252 -[#55326]: https://github.com/JuliaLang/julia/issues/55326 -[#55335]: https://github.com/JuliaLang/julia/issues/55335 -[#55351]: https://github.com/JuliaLang/julia/issues/55351 -[#55411]: https://github.com/JuliaLang/julia/issues/55411 -[#55537]: https://github.com/JuliaLang/julia/issues/55537 -[#55574]: https://github.com/JuliaLang/julia/issues/55574 -[#55763]: https://github.com/JuliaLang/julia/issues/55763 -[#55772]: https://github.com/JuliaLang/julia/issues/55772 -[#55793]: https://github.com/JuliaLang/julia/issues/55793 -[#55848]: https://github.com/JuliaLang/julia/issues/55848 -[#55889]: https://github.com/JuliaLang/julia/issues/55889 -[#55915]: https://github.com/JuliaLang/julia/issues/55915 -[#56175]: https://github.com/JuliaLang/julia/issues/56175 -[#56196]: https://github.com/JuliaLang/julia/issues/56196 -[#56223]: https://github.com/JuliaLang/julia/issues/56223 -[#56320]: https://github.com/JuliaLang/julia/issues/56320 -[#56346]: https://github.com/JuliaLang/julia/issues/56346 -[#56660]: https://github.com/JuliaLang/julia/issues/56660 -[#56692]: https://github.com/JuliaLang/julia/issues/56692 -[#56745]: https://github.com/JuliaLang/julia/issues/56745 -[#56925]: https://github.com/JuliaLang/julia/issues/56925 -[#57069]: https://github.com/JuliaLang/julia/issues/57069 -[#57081]: https://github.com/JuliaLang/julia/issues/57081 -[#57087]: https://github.com/JuliaLang/julia/issues/57087 -[#57109]: https://github.com/JuliaLang/julia/issues/57109 From 97c920dc4e12f7c6c65e681adb3f21d6f7abebdf Mon Sep 17 00:00:00 2001 From: Chengyu Han Date: Thu, 6 Feb 2025 23:57:55 +0800 Subject: [PATCH 294/342] dep: Update JuliaSyntax (#57280) - Update `JuliaSyntax.jl` to v1.0.1 - Revert workaround changes, use original test case `n37134` Fix #57223 --- deps/JuliaSyntax.version | 2 +- .../md5 | 1 - .../sha512 | 1 - .../md5 | 1 + .../sha512 | 1 + test/syntax.jl | 4 +--- 6 files changed, 4 insertions(+), 6 deletions(-) delete mode 100644 deps/checksums/JuliaSyntax-2e965a159dd9f87d216d2d50ecbd2ed4f9af2c5a.tar.gz/md5 delete mode 100644 deps/checksums/JuliaSyntax-2e965a159dd9f87d216d2d50ecbd2ed4f9af2c5a.tar.gz/sha512 create mode 100644 deps/checksums/JuliaSyntax-86bc4331eaa08e08bf2af1ba7b50bbbf4af70cdb.tar.gz/md5 create mode 100644 deps/checksums/JuliaSyntax-86bc4331eaa08e08bf2af1ba7b50bbbf4af70cdb.tar.gz/sha512 diff --git a/deps/JuliaSyntax.version b/deps/JuliaSyntax.version index a7d31b7c16403..70dac3231f626 100644 --- a/deps/JuliaSyntax.version +++ b/deps/JuliaSyntax.version @@ -1,4 +1,4 @@ JULIASYNTAX_BRANCH = main -JULIASYNTAX_SHA1 = 2e965a159dd9f87d216d2d50ecbd2ed4f9af2c5a +JULIASYNTAX_SHA1 = 86bc4331eaa08e08bf2af1ba7b50bbbf4af70cdb 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-2e965a159dd9f87d216d2d50ecbd2ed4f9af2c5a.tar.gz/md5 b/deps/checksums/JuliaSyntax-2e965a159dd9f87d216d2d50ecbd2ed4f9af2c5a.tar.gz/md5 deleted file mode 100644 index 96f356f3faaec..0000000000000 --- a/deps/checksums/JuliaSyntax-2e965a159dd9f87d216d2d50ecbd2ed4f9af2c5a.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -40d7bcc6e5741d50a457ace2ca8b2c0c diff --git a/deps/checksums/JuliaSyntax-2e965a159dd9f87d216d2d50ecbd2ed4f9af2c5a.tar.gz/sha512 b/deps/checksums/JuliaSyntax-2e965a159dd9f87d216d2d50ecbd2ed4f9af2c5a.tar.gz/sha512 deleted file mode 100644 index fd7770cdeaa75..0000000000000 --- a/deps/checksums/JuliaSyntax-2e965a159dd9f87d216d2d50ecbd2ed4f9af2c5a.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -b9429b90a28460ef0272cd42a5c221629c6d60221ed088ae3e591cc3d8dbdec32788074397419e58b611bda7df32c7379ec7fafeead7056ed9665591474cec5d diff --git a/deps/checksums/JuliaSyntax-86bc4331eaa08e08bf2af1ba7b50bbbf4af70cdb.tar.gz/md5 b/deps/checksums/JuliaSyntax-86bc4331eaa08e08bf2af1ba7b50bbbf4af70cdb.tar.gz/md5 new file mode 100644 index 0000000000000..c5d3c249ca1e0 --- /dev/null +++ b/deps/checksums/JuliaSyntax-86bc4331eaa08e08bf2af1ba7b50bbbf4af70cdb.tar.gz/md5 @@ -0,0 +1 @@ +a514fe65096a489bd4d3c06b675573c7 diff --git a/deps/checksums/JuliaSyntax-86bc4331eaa08e08bf2af1ba7b50bbbf4af70cdb.tar.gz/sha512 b/deps/checksums/JuliaSyntax-86bc4331eaa08e08bf2af1ba7b50bbbf4af70cdb.tar.gz/sha512 new file mode 100644 index 0000000000000..bdb48e7ef87eb --- /dev/null +++ b/deps/checksums/JuliaSyntax-86bc4331eaa08e08bf2af1ba7b50bbbf4af70cdb.tar.gz/sha512 @@ -0,0 +1 @@ +95d45a27e427f2553da4d4e821edaee6896121977ce6572212c4234013c6f85bc69fc78d237b4dae5d4ed3451f3ba9e1a7172668025ef7bf8aad024293aa2865 diff --git a/test/syntax.jl b/test/syntax.jl index 61672a6786762..c9a5d5dd52a41 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -2454,9 +2454,7 @@ end @test_throws MethodError @m37134()(1.0) == 62 macro n37134() - quote - ((x...,)) -> (x) - end |> esc + :($(esc(Expr(:tuple, Expr(:..., :x))))->$(esc(:x))) end @test @n37134()(2,1) === (2,1) From 34aceb528d26c2a3529d1afe5aed3bc039fdb181 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Thu, 6 Feb 2025 14:31:05 -0500 Subject: [PATCH 295/342] staticdata: Close data race after backedge insertion (#57229) Addresses review comment in https://github.com/JuliaLang/julia/pull/57212#discussion_r1937694448. The key is that the hand-off of responsibility for verification between the loading code and the ordinary backedge mechanism happens under the world counter lock to ensure synchronization. --- base/staticdata.jl | 28 ++++++++++++++++------------ src/staticdata.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/base/staticdata.jl b/base/staticdata.jl index a4a40b9af0a7c..7283a93dd8b3b 100644 --- a/base/staticdata.jl +++ b/base/staticdata.jl @@ -37,9 +37,16 @@ end function _insert_backedges(edges::Vector{Any}, stack::Vector{CodeInstance}, visiting::IdDict{CodeInstance,Int}, mwis::IdSet{Method}, external::Bool=false) for i = 1:length(edges) codeinst = edges[i]::CodeInstance - verify_method_graph(codeinst, stack, visiting, mwis) + validation_world = get_world_counter() + verify_method_graph(codeinst, stack, visiting, mwis, validation_world) + # After validation, under the world_counter_lock, set max_world to typemax(UInt) for all dependencies + # (recursively). From that point onward the ordinary backedge mechanism is responsible for maintaining + # validity. + @ccall jl_promote_ci_to_current(codeinst::Any, validation_world::UInt)::Cvoid minvalid = codeinst.min_world maxvalid = codeinst.max_world + # Finally, if this CI is still valid in some world age and and belongs to an external method(specialization), + # poke it that mi's cache if maxvalid ≥ minvalid && external caller = get_ci_mi(codeinst) @assert isdefined(codeinst, :inferred) # See #53586, #53109 @@ -55,9 +62,9 @@ function _insert_backedges(edges::Vector{Any}, stack::Vector{CodeInstance}, visi end end -function verify_method_graph(codeinst::CodeInstance, stack::Vector{CodeInstance}, visiting::IdDict{CodeInstance,Int}, mwis::IdSet{Method}) +function verify_method_graph(codeinst::CodeInstance, stack::Vector{CodeInstance}, visiting::IdDict{CodeInstance,Int}, mwis::IdSet{Method}, validation_world::UInt) @assert isempty(stack); @assert isempty(visiting); - child_cycle, minworld, maxworld = verify_method(codeinst, stack, visiting, mwis) + child_cycle, minworld, maxworld = verify_method(codeinst, stack, visiting, mwis, validation_world) @assert child_cycle == 0 @assert isempty(stack); @assert isempty(visiting); nothing @@ -67,15 +74,14 @@ end # - Visit the entire call graph, starting from edges[idx] to determine if that method is valid # - Implements Tarjan's SCC (strongly connected components) algorithm, simplified to remove the count variable # and slightly modified with an early termination option once the computation reaches its minimum -function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visiting::IdDict{CodeInstance,Int}, mwis::IdSet{Method}) +function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visiting::IdDict{CodeInstance,Int}, mwis::IdSet{Method}, validation_world::UInt) world = codeinst.min_world let max_valid2 = codeinst.max_world if max_valid2 ≠ WORLD_AGE_REVALIDATION_SENTINEL return 0, world, max_valid2 end end - current_world = get_world_counter() - local minworld::UInt, maxworld::UInt = 1, current_world + local minworld::UInt, maxworld::UInt = 1, validation_world def = get_ci_mi(codeinst).def @assert def isa Method if haskey(visiting, codeinst) @@ -177,7 +183,7 @@ function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visi end callee = edge local min_valid2::UInt, max_valid2::UInt - child_cycle, min_valid2, max_valid2 = verify_method(callee, stack, visiting, mwis) + child_cycle, min_valid2, max_valid2 = verify_method(callee, stack, visiting, mwis, validation_world) if minworld < min_valid2 minworld = min_valid2 end @@ -209,16 +215,14 @@ function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visi if maxworld ≠ 0 @atomic :monotonic child.min_world = minworld end - if maxworld == current_world + @atomic :monotonic child.max_world = maxworld + if maxworld == validation_world && validation_world == get_world_counter() Base.Compiler.store_backedges(child, child.edges) - @atomic :monotonic child.max_world = typemax(UInt) - else - @atomic :monotonic child.max_world = maxworld end @assert visiting[child] == length(stack) + 1 delete!(visiting, child) invalidations = _jl_debug_method_invalidation[] - if invalidations !== nothing && maxworld < current_world + if invalidations !== nothing && maxworld < validation_world push!(invalidations, child, "verify_methods", cause) end end diff --git a/src/staticdata.c b/src/staticdata.c index bf4dba555e735..4ea93fc58a9e0 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -4380,6 +4380,34 @@ JL_DLLEXPORT jl_value_t *jl_restore_package_image_from_file(const char *fname, j return mod; } +JL_DLLEXPORT void _jl_promote_ci_to_current(jl_code_instance_t *ci, size_t validated_world) JL_NOTSAFEPOINT +{ + if (jl_atomic_load_relaxed(&ci->max_world) != validated_world) + return; + jl_atomic_store_relaxed(&ci->max_world, ~(size_t)0); + jl_svec_t *edges = jl_atomic_load_relaxed(&ci->edges); + for (size_t i = 0; i < jl_svec_len(edges); i++) { + jl_value_t *edge = jl_svecref(edges, i); + if (!jl_is_code_instance(edge)) + continue; + _jl_promote_ci_to_current(ci, validated_world); + } +} + +JL_DLLEXPORT void jl_promote_ci_to_current(jl_code_instance_t *ci, size_t validated_world) +{ + size_t current_world = jl_atomic_load_relaxed(&jl_world_counter); + // No need to acquire the lock if we've been invalidated anyway + if (current_world > validated_world) + return; + JL_LOCK(&world_counter_lock); + current_world = jl_atomic_load_relaxed(&jl_world_counter); + if (current_world == validated_world) { + _jl_promote_ci_to_current(ci, validated_world); + } + JL_UNLOCK(&world_counter_lock); +} + #ifdef __cplusplus } #endif From b65f0040dd367f2da76f6ed4b01924a368fe50b8 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 7 Feb 2025 00:08:34 -0500 Subject: [PATCH 296/342] Allow macrocall as function sig (#55040) @KristofferC requested that `function @main(args) end` should work. This is currently a parse error. This PR makes it work as expected by allowing macrocall as a valid signature in function (needs to exapand to a call expr). Note that this is only the flisp changes. If this PR is accepted, an equivalent change would need to be made in JuliaSyntax. --- HISTORY.md | 1 + base/client.jl | 15 ++++++++------- src/julia-parser.scm | 6 +++--- test/syntax.jl | 31 +++++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 10 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 0351c875ed404..dfb96241bef13 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -50,6 +50,7 @@ Language changes * It is now an error to mark a binding as both `public` and `export`ed ([#53664]). * Errors during `getfield` now raise a new `FieldError` exception type instead of the generic `ErrorException` ([#54504]). +* Macros in function-signature-position no longer require parentheses. E.g. `function @main(args) ... end` is now permitted, whereas `function (@main)(args) ... end` was required in prior Julia versions. Compiler/Runtime improvements ----------------------------- diff --git a/base/client.jl b/base/client.jl index 3449e2fbf2e62..df0cf9043996e 100644 --- a/base/client.jl +++ b/base/client.jl @@ -605,7 +605,7 @@ The `@main` macro may be used standalone or as part of the function definition, case, parentheses are required. In particular, the following are equivalent: ``` -function (@main)(args) +function @main(args) println("Hello World") end ``` @@ -624,7 +624,7 @@ imported into `Main`, it will be treated as an entrypoint in `Main`: ``` module MyApp export main - (@main)(args) = println("Hello World") + @main(args) = println("Hello World") end using .MyApp # `julia` Will execute MyApp.main at the conclusion of script execution @@ -634,7 +634,7 @@ Note that in particular, the semantics do not attach to the method or the name: ``` module MyApp - (@main)(args) = println("Hello World") + @main(args) = println("Hello World") end const main = MyApp.main # `julia` Will *NOT* execute MyApp.main unless there is a separate `@main` annotation in `Main` @@ -644,9 +644,6 @@ const main = MyApp.main This macro is new in Julia 1.11. At present, the precise semantics of `@main` are still subject to change. """ macro main(args...) - if !isempty(args) - error("`@main` is expected to be used as `(@main)` without macro arguments.") - end if isdefined(__module__, :main) if Base.binding_module(__module__, :main) !== __module__ error("Symbol `main` is already a resolved import in module $(__module__). `@main` must be used in the defining module.") @@ -657,5 +654,9 @@ macro main(args...) global main global var"#__main_is_entrypoint__#"::Bool = true end) - esc(:main) + if !isempty(args) + Expr(:call, esc(:main), map(esc, args)...) + else + esc(:main) + end end diff --git a/src/julia-parser.scm b/src/julia-parser.scm index 891a26bb0ea49..4415dc8686065 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -1329,13 +1329,13 @@ (define (valid-func-sig? paren sig) (and (pair? sig) - (or (eq? (car sig) 'call) - (eq? (car sig) 'tuple) + (or (memq (car sig) '(call tuple)) + (and (not paren) (eq? (car sig) 'macrocall)) (and paren (eq? (car sig) 'block)) (and paren (eq? (car sig) '...)) (and (eq? (car sig) '|::|) (pair? (cadr sig)) - (eq? (car (cadr sig)) 'call)) + (memq (car (cadr sig)) '(call macrocall))) (and (eq? (car sig) 'where) (valid-func-sig? paren (cadr sig)))))) diff --git a/test/syntax.jl b/test/syntax.jl index c9a5d5dd52a41..b409dba5335f1 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -4050,3 +4050,34 @@ end import ..Base using .Base: zero, zero end + +# PR# 55040 - Macrocall as function sig +@test :(function @f()() end) == :(function (@f)() end) + +function callme end +macro callmemacro(args...) + Expr(:call, esc(:callme), map(esc, args)...) +end +function @callmemacro(a::Int) + return 1 +end +@callmemacro(b::Float64) = 2 +function @callmemacro(a::T, b::T) where T <: Int + return 3 +end +function @callmemacro(a::Int, b::Int, c::Int)::Float64 + return 4 +end +function @callmemacro(d::String) + (a, b, c) + # ^ Should not be accidentally parsed as an argument list + return 4 +end + +@test callme(1) === 1 +@test callme(2.0) === 2 +@test callme(3, 3) === 3 +@test callme(4, 4, 4) === 4.0 + +# Ambiguous 1-arg anymous vs macrosig +@test_parseerror "function (@foo(a)) end" From e553fc8c6f794118a5dfcb0506fe3a0a0cd34ee4 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 7 Feb 2025 02:38:24 -0500 Subject: [PATCH 297/342] Add missing latestworld after parameterized type alias (#57299) Fixes #57267 --- src/julia-syntax.scm | 1 + test/syntax.jl | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 726312a13d10f..035d2a84e729d 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1480,6 +1480,7 @@ `(block (= ,rr (where ,type-ex ,@params)) (,(if allow-local 'assign-const-if-global 'const) ,name ,rr) + (latestworld-if-toplevel) ,rr))) (expand-forms `(const (= ,name ,type-ex))))) diff --git a/test/syntax.jl b/test/syntax.jl index b409dba5335f1..5f49f13fca641 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -4081,3 +4081,10 @@ end # Ambiguous 1-arg anymous vs macrosig @test_parseerror "function (@foo(a)) end" + +# #57267 - Missing `latestworld` after typealias +abstract type A57267{S, T} end +@test_nowarn @eval begin + B57267{S} = A57267{S, 1} + const C57267 = B57267 +end From 778e07906923fdf4966000983135901e11540109 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 7 Feb 2025 15:09:29 -0500 Subject: [PATCH 298/342] Add explicit imports for types and fix bugs (#57302) I was playing with strengthening the semantics around #57290. However, the particular change I was trying turned out too breaking (I may try a weaker version of it). Still, there were a number of good changes found in two categories: 1. We should explicitly import types when defining constructors. This has been allowed for a long time, but we may want to consider removing it, especially given the new binding semantics which make it more confusing as in #57290. 2. There were a couple of places where I don't think it was intended for generic functions in question not to extend Base. --- Compiler/src/Compiler.jl | 2 +- base/Base_compiler.jl | 1 + base/bool.jl | 2 ++ base/char.jl | 2 ++ base/coreir.jl | 2 +- base/deprecated.jl | 1 + base/filesystem.jl | 6 +++--- base/float.jl | 3 +++ base/gmp.jl | 2 ++ base/hamt.jl | 10 +++++----- base/mpfr.jl | 5 ++++- base/multidimensional.jl | 4 +++- base/namedtuple.jl | 2 ++ base/refpointer.jl | 2 ++ base/strings/basic.jl | 2 ++ base/tuple.jl | 2 ++ 16 files changed, 36 insertions(+), 12 deletions(-) diff --git a/Compiler/src/Compiler.jl b/Compiler/src/Compiler.jl index ba6d1607ded55..2c68729ee1dc2 100644 --- a/Compiler/src/Compiler.jl +++ b/Compiler/src/Compiler.jl @@ -72,7 +72,7 @@ using Base.Order import Base: ==, _topmod, append!, convert, copy, copy!, findall, first, get, get!, getindex, haskey, in, isempty, isready, iterate, iterate, last, length, max_world, - min_world, popfirst!, push!, resize!, setindex!, size + min_world, popfirst!, push!, resize!, setindex!, size, intersect const getproperty = Core.getfield const setproperty! = Core.setfield! diff --git a/base/Base_compiler.jl b/base/Base_compiler.jl index 4ec6bae171d8f..20aa1f5a793ef 100644 --- a/base/Base_compiler.jl +++ b/base/Base_compiler.jl @@ -224,6 +224,7 @@ function cld end function fld end # Lazy strings +import Core: String include("strings/lazy.jl") # array structures diff --git a/base/bool.jl b/base/bool.jl index 3a5c36b09ae2c..3658318d158e5 100644 --- a/base/bool.jl +++ b/base/bool.jl @@ -1,5 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +import Core: Bool + # promote Bool to any other numeric type promote_rule(::Type{Bool}, ::Type{T}) where {T<:Number} = T diff --git a/base/char.jl b/base/char.jl index 2e8410f6903e2..c089262ebf779 100644 --- a/base/char.jl +++ b/base/char.jl @@ -1,5 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +import Core: AbstractChar, Char + """ The `AbstractChar` type is the supertype of all character implementations in Julia. A character represents a Unicode code point, and can be converted diff --git a/base/coreir.jl b/base/coreir.jl index 5199dfd35f028..59422afb44add 100644 --- a/base/coreir.jl +++ b/base/coreir.jl @@ -49,5 +49,5 @@ while processing a call, then `Conditional` everywhere else. """ Core.InterConditional -InterConditional(var::SlotNumber, @nospecialize(thentype), @nospecialize(elsetype)) = +Core.InterConditional(var::SlotNumber, @nospecialize(thentype), @nospecialize(elsetype)) = InterConditional(slot_id(var), thentype, elsetype) diff --git a/base/deprecated.jl b/base/deprecated.jl index f72698ad47008..eeb7c0e60638e 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -353,6 +353,7 @@ end @deprecate one(i::CartesianIndex) oneunit(i) @deprecate one(I::Type{CartesianIndex{N}}) where {N} oneunit(I) +import .MPFR: BigFloat @deprecate BigFloat(x, prec::Int) BigFloat(x; precision=prec) @deprecate BigFloat(x, prec::Int, rounding::RoundingMode) BigFloat(x, rounding; precision=prec) @deprecate BigFloat(x::Real, prec::Int) BigFloat(x; precision=prec) diff --git a/base/filesystem.jl b/base/filesystem.jl index bc1f4942877e8..87b3552c80a2f 100644 --- a/base/filesystem.jl +++ b/base/filesystem.jl @@ -137,11 +137,11 @@ export File, S_IROTH, S_IWOTH, S_IXOTH, S_IRWXO import .Base: - IOError, _UVError, _sizeof_uv_fs, check_open, close, eof, eventloop, fd, isopen, - bytesavailable, position, read, read!, readavailable, seek, seekend, show, + IOError, _UVError, _sizeof_uv_fs, check_open, close, closewrite, eof, eventloop, fd, isopen, + bytesavailable, position, read, read!, readbytes!, readavailable, seek, seekend, show, skip, stat, unsafe_read, unsafe_write, write, transcode, uv_error, setup_stdio, rawhandle, OS_HANDLE, INVALID_OS_HANDLE, windowserror, filesize, - isexecutable, isreadable, iswritable, MutableDenseArrayType + isexecutable, isreadable, iswritable, MutableDenseArrayType, truncate import .Base.RefValue diff --git a/base/float.jl b/base/float.jl index faded5cd5978c..54e232a01b8cb 100644 --- a/base/float.jl +++ b/base/float.jl @@ -2,6 +2,9 @@ const IEEEFloat = Union{Float16, Float32, Float64} +import Core: Float16, Float32, Float64, AbstractFloat +import Core: Int8, Int16, Int32, Int64, Int128, UInt8, UInt16, UInt32, UInt64, UInt128 + ## floating point traits ## """ diff --git a/base/gmp.jl b/base/gmp.jl index 4d2b4b66ac41b..97488551f60f6 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -13,6 +13,8 @@ import .Base: *, +, -, /, <, <<, >>, >>>, <=, ==, >, >=, ^, (~), (&), (|), xor, sign, hastypemax, isodd, iseven, digits!, hash, hash_integer, top_set_bit, clamp, unsafe_takestring +import Core: Signed, Float16, Float32, Float64 + if Clong == Int32 const ClongMax = Union{Int8, Int16, Int32} const CulongMax = Union{UInt8, UInt16, UInt32} diff --git a/base/hamt.jl b/base/hamt.jl index e3e4b4bd03ba9..c77c592b17e58 100644 --- a/base/hamt.jl +++ b/base/hamt.jl @@ -239,11 +239,11 @@ or grows the HAMT by inserting a new trie instead. end end -length(::Leaf) = 1 -length(trie::HAMT) = sum((length(trie.data[i]) for i in eachindex(trie.data)), init=0) +Base.length(::Leaf) = 1 +Base.length(trie::HAMT) = sum((length(trie.data[i]) for i in eachindex(trie.data)), init=0) -isempty(::Leaf) = false -function isempty(trie::HAMT) +Base.isempty(::Leaf) = false +function Base.isempty(trie::HAMT) if islevel_empty(trie) return true end @@ -251,7 +251,7 @@ function isempty(trie::HAMT) end # DFS -function iterate(trie::HAMT, state=nothing) +function Base.iterate(trie::HAMT, state=nothing) if state === nothing state = (;parent=nothing, trie, i=1) end diff --git a/base/mpfr.jl b/base/mpfr.jl index 1e39f52b9d1a3..e8380577190aa 100644 --- a/base/mpfr.jl +++ b/base/mpfr.jl @@ -20,12 +20,15 @@ import sinpi, cospi, sincospi, tanpi, sind, cosd, tand, asind, acosd, atand, uinttype, exponent_max, exponent_min, ieee754_representation, significand_mask +import .Core: AbstractFloat +import .Base: Rational, Float16, Float32, Float64, Bool + using .Base.Libc import ..Rounding: Rounding, rounding_raw, setrounding_raw, rounds_to_nearest, rounds_away_from_zero, tie_breaker_is_to_even, correct_rounding_requires_increment -import ..GMP: ClongMax, CulongMax, CdoubleMax, Limb, libgmp +import ..GMP: ClongMax, CulongMax, CdoubleMax, Limb, libgmp, BigInt import ..FastMath.sincos_fast diff --git a/base/multidimensional.jl b/base/multidimensional.jl index ba08f0679590b..40fff7243cd55 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -4,10 +4,12 @@ module IteratorsMD import .Base: eltype, length, size, first, last, in, getindex, setindex!, min, max, zero, oneunit, isless, eachindex, - convert, show, iterate, promote_rule, to_indices, copy + convert, show, iterate, promote_rule, to_indices, copy, + isassigned import .Base: +, -, *, (:) import .Base: simd_outer_range, simd_inner_length, simd_index, setindex + import Core: Tuple using .Base: to_index, fill_to_length, tail, safe_tail using .Base: IndexLinear, IndexCartesian, AbstractCartesianIndex, ReshapedArray, ReshapedArrayLF, OneTo, Fix1 diff --git a/base/namedtuple.jl b/base/namedtuple.jl index 991c4d35da52f..f71b13852b953 100644 --- a/base/namedtuple.jl +++ b/base/namedtuple.jl @@ -1,5 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +import Core: NamedTuple + """ NamedTuple diff --git a/base/refpointer.jl b/base/refpointer.jl index 5027462eeb6b6..c5968934aa748 100644 --- a/base/refpointer.jl +++ b/base/refpointer.jl @@ -1,5 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +import Core: Ref + """ Ref{T} diff --git a/base/strings/basic.jl b/base/strings/basic.jl index bf11199143c1e..3f26aed736b8d 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -1,5 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +import Core: Symbol + """ The `AbstractString` type is the supertype of all string implementations in Julia. Strings are encodings of sequences of [Unicode](https://unicode.org/) diff --git a/base/tuple.jl b/base/tuple.jl index ee3174d783531..2ff8a1185a007 100644 --- a/base/tuple.jl +++ b/base/tuple.jl @@ -1,5 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +import Core: Tuple + # Document NTuple here where we have everything needed for the doc system """ NTuple{N, T} From 72f8a106c357de6819e07352e88e49148c8c9546 Mon Sep 17 00:00:00 2001 From: Eduardo Souza Date: Sat, 8 Feb 2025 12:28:49 +1100 Subject: [PATCH 299/342] Updating binding version to fix MMTk CI (#57298) Updating mmtk-julia version to include https://github.com/mmtk/mmtk-julia/pull/228 and fix the MMTk CI. I've also changed the allocation profiler tests to skip all tests instead of just a few since I've seen some spurious errors - they should all be related though, we need to make sure the profiler accounts for fastpath allocation (see https://github.com/JuliaLang/julia/issues/57103) This should fix https://github.com/JuliaLang/julia/issues/57306. --- Makefile | 18 ++++++++++++++++++ deps/checksums/mmtk_julia | 4 ++++ deps/mmtk_julia.mk | 19 +++++++++++++++++++ deps/mmtk_julia.version | 6 +++--- stdlib/Profile/test/allocs.jl | 19 ++++++++----------- 5 files changed, 52 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index b193b3849c6aa..0f1e8c45edf40 100644 --- a/Makefile +++ b/Makefile @@ -282,8 +282,26 @@ endif endif ifneq (${MMTK_PLAN},None) +# Make sure we use the right version of $MMTK_PLAN, $MMTK_MOVING and $MMTK_BUILD +# if we use the BinaryBuilder version of mmtk-julia +ifeq ($(USE_BINARYBUILDER_MMTK_JULIA),1) +ifeq (${MMTK_PLAN},Immix) +LIB_PATH_PLAN = immix +else ifeq (${MMTK_PLAN},StickyImmix) +LIB_PATH_PLAN = sticky +endif + +ifeq ($(MMTK_MOVING), 0) +LIB_PATH_MOVING := non_moving +else +LIB_PATH_MOVING := moving +endif + +JL_PRIVATE_LIBS-0 += $(LIB_PATH_PLAN)/$(LIB_PATH_MOVING)/$(MMTK_BUILD)/libmmtk_julia +else JL_PRIVATE_LIBS-0 += libmmtk_julia endif +endif # Note that we disable MSYS2's path munging here, as otherwise # it replaces our `:`-separated list as a `;`-separated one. diff --git a/deps/checksums/mmtk_julia b/deps/checksums/mmtk_julia index 098937aea1991..4ccc7b407cb60 100644 --- a/deps/checksums/mmtk_julia +++ b/deps/checksums/mmtk_julia @@ -8,3 +8,7 @@ mmtk_julia-c9e046baf3a0d52fe75d6c8b28f6afd69b045d95.tar.gz/md5/73a8fbea71edce30a mmtk_julia-c9e046baf3a0d52fe75d6c8b28f6afd69b045d95.tar.gz/sha512/374848b7696b565dea66daa208830581f92c1fcb0138e7a7ab88564402e94bc79c54b6ed370ec68473e31e2bd411bf82c97793796c31d39aafbbfffea9c05588 mmtk_julia.v0.30.4+0.x86_64-linux-gnu.tar.gz/md5/8cdeb14fd69945f64308be49f6912f9c mmtk_julia.v0.30.4+0.x86_64-linux-gnu.tar.gz/sha512/3692502f65dec8c0971b56b9bf8178641892b390d520cbcd69880d75b7500e6341534d87882246e68998f590f824ec54c18f4b8fb4aa09b8f313de065c48450e +mmtk_julia-10ad6638b69b31a97a844f2f4e651e5ccea4e298.tar.gz/md5/59ed2c0e0b48673988a40527907f13ae +mmtk_julia-10ad6638b69b31a97a844f2f4e651e5ccea4e298.tar.gz/sha512/d0988c37e82b8d481753f4ce83f38ba11276af3dafa8f65ee2c51122fce0dab056a65b3029cb255732226cc28d1a02e607bdaac91a02c0fd6a9fcfae834fee8c +mmtk_julia.v0.30.5+1.x86_64-linux-gnu.tar.gz/md5/4d12d64754bb5c61e86e97e88bcf7912 +mmtk_julia.v0.30.5+1.x86_64-linux-gnu.tar.gz/sha512/0d619f00fd644338ca1ca2582b20e41db702dff8e0c338c093b2759b54379ba26ae7e0181c64931a45ebd5c3995540e535c248df9b986e73b18b65a39c5d78d2 diff --git a/deps/mmtk_julia.mk b/deps/mmtk_julia.mk index 424113fd4164c..1dc59749a00b5 100644 --- a/deps/mmtk_julia.mk +++ b/deps/mmtk_julia.mk @@ -75,6 +75,25 @@ endif # MMTK_JULIA_DIR else # We are building using the BinaryBuilder version of the binding +# This will download all the versions of the binding that are available in the BinaryBuilder $(eval $(call bb-install,mmtk_julia,MMTK_JULIA,false)) +# Make sure we use the right version of $MMTK_PLAN, $MMTK_MOVING and $MMTK_BUILD +ifeq (${MMTK_PLAN},Immix) +LIB_PATH_PLAN = immix +else ifeq (${MMTK_PLAN},StickyImmix) +LIB_PATH_PLAN = sticky +endif + +ifeq ($(MMTK_MOVING), 0) +LIB_PATH_MOVING := non_moving +else +LIB_PATH_MOVING := moving +endif + +version-check-mmtk_julia: $(BUILDROOT)/usr/lib/libmmtk_julia.so + +$(BUILDROOT)/usr/lib/libmmtk_julia.so: get-mmtk_julia + @ln -sf $(BUILDROOT)/usr/lib/$(LIB_PATH_PLAN)/$(LIB_PATH_MOVING)/$(MMTK_BUILD)/libmmtk_julia.so $@ + endif # USE_BINARYBUILDER_MMTK_JULIA diff --git a/deps/mmtk_julia.version b/deps/mmtk_julia.version index 684197bbe3e4e..530b6d9ed81e1 100644 --- a/deps/mmtk_julia.version +++ b/deps/mmtk_julia.version @@ -1,6 +1,6 @@ MMTK_JULIA_BRANCH = master -MMTK_JULIA_SHA1 = c9e046baf3a0d52fe75d6c8b28f6afd69b045d95 +MMTK_JULIA_SHA1 = 10ad6638b69b31a97a844f2f4e651e5ccea4e298 MMTK_JULIA_GIT_URL := https://github.com/mmtk/mmtk-julia.git -MMTK_JULIA_TAR_URL = https://github.com/mmtk/mmtk-julia/archive/refs/tags/v0.30.4.tar.gz -MMTK_JULIA_JLL_VER := 0.30.4+0 +MMTK_JULIA_TAR_URL = https://github.com/mmtk/mmtk-julia/archive/refs/tags/v0.30.5.tar.gz +MMTK_JULIA_JLL_VER := 0.30.5+1 MMTK_JULIA_JLL_NAME := mmtk_julia diff --git a/stdlib/Profile/test/allocs.jl b/stdlib/Profile/test/allocs.jl index 5607783c782f9..8f6539e0baed6 100644 --- a/stdlib/Profile/test/allocs.jl +++ b/stdlib/Profile/test/allocs.jl @@ -8,6 +8,11 @@ let iobuf = IOBuffer() end end +# Issue #57103: This test does not work with MMTk because of fastpath +# allocation which never calls the allocation profiler. +# TODO: We should port these observability tools (e.g. allocation +# profiler and heap snapshot) to MMTk +@static if Base.USING_STOCK_GC @testset "alloc profiler doesn't segfault" begin res = Allocs.@profile sample_rate=1.0 begin # test the allocations during compilation @@ -73,14 +78,8 @@ end @test length(first_alloc.stacktrace) > 0 @test length(string(first_alloc.type)) > 0 - # Issue #57103: This test does not work with MMTk because of fastpath - # allocation which never calls the allocation profiler. - # TODO: We should port these observability tools (e.g. allocation - # profiler and heap snapshot) to MMTk - @static if Base.USING_STOCK_GC - @testset for type in (Task, Vector{Float64},) - @test length(filter(a->a.type <: type, profile.allocs)) >= NUM_TASKS - end + @testset for type in (Task, Vector{Float64},) + @test length(filter(a->a.type <: type, profile.allocs)) >= NUM_TASKS end # TODO: it would be nice to assert that these tasks @@ -149,8 +148,6 @@ end @test length([a for a in prof.allocs if a.type == String]) >= 1 end -# FIXME: Issue #57103 disabling test for MMTk. -@static if Base.USING_STOCK_GC @testset "alloc profiler catches allocs from codegen" begin @eval begin struct MyType x::Int; y::Int end @@ -170,7 +167,6 @@ end @test length(prof.allocs) >= 1 @test length([a for a in prof.allocs if a.type == MyType]) >= 1 end -end @testset "alloc profiler catches allocs from buffer resize" begin f(a) = for _ in 1:100; push!(a, 1); end @@ -187,3 +183,4 @@ end @test length([a for a in prof.allocs if a.type === Allocs.BufferType]) == 1 @test length([a for a in prof.allocs if a.type === Memory{Int}]) >= 2 end +end From baf8124d9d004c6c255134ce6206875d1df92618 Mon Sep 17 00:00:00 2001 From: Sam Schweigel <33556084+xal-0@users.noreply.github.com> Date: Fri, 7 Feb 2025 18:02:46 -0800 Subject: [PATCH 300/342] Always add the frame-pointer=all attribute (#57209) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At some point LLVM on MacOS started doing frame pointer optimization by default. We should ask for a frame pointer on every function, on all platforms. Prior to this change, on `1.11.3+0.aarch64.apple.darwin14`: ``` julia> @code_native ((x,y) -> Core.Intrinsics.add_float(x,y))(1.0,2.0) .section __TEXT,__text,regular,pure_instructions .build_version macos, 15, 0 .globl "_julia_#1_678" ; -- Begin function julia_#1_678 .p2align 2 "_julia_#1_678": ; @"julia_#1_678" ; Function Signature: var"#1"(Float64, Float64) ; ┌ @ REPL[1]:1 within `#1` ; %bb.0: ; %top ; │ @ REPL[1] within `#1` ;DEBUG_VALUE: #1:x <- $d0 ;DEBUG_VALUE: #1:x <- $d0 ;DEBUG_VALUE: #1:y <- $d1 ;DEBUG_VALUE: #1:y <- $d1 ; │ @ REPL[1]:1 within `#1` fadd d0, d0, d1 ret ; └ ; -- End function .section __DATA,__const .p2align 3, 0x0 ; @"+Core.Float64#680" "l_+Core.Float64#680": .quad "l_+Core.Float64#680.jit" .set "l_+Core.Float64#680.jit", 5490712608 .subsections_via_symbols ``` Prior to this change, on `1.11.3+0.aarch64.linux.gnu`: ``` julia> @code_native ((x,y) -> Core.Intrinsics.add_float(x,y))(1.0,2.0) .text .file "#1" .globl "julia_#1_656" // -- Begin function julia_#1_656 .p2align 2 .type "julia_#1_656",@function "julia_#1_656": // @"julia_#1_656" ; Function Signature: var"#1"(Float64, Float64) ; ┌ @ REPL[1]:1 within `#1` // %bb.0: // %top ; │ @ REPL[1] within `#1` //DEBUG_VALUE: #1:x <- $d0 //DEBUG_VALUE: #1:x <- $d0 //DEBUG_VALUE: #1:y <- $d1 //DEBUG_VALUE: #1:y <- $d1 stp x29, x30, [sp, #-16]! // 16-byte Folded Spill mov x29, sp ; │ @ REPL[1]:1 within `#1` fadd d0, d0, d1 ldp x29, x30, [sp], #16 // 16-byte Folded Reload ret .Lfunc_end0: .size "julia_#1_656", .Lfunc_end0-"julia_#1_656" ; └ // -- End function .type ".L+Core.Float64#658",@object // @"+Core.Float64#658" .section .rodata,"a",@progbits .p2align 3, 0x0 ".L+Core.Float64#658": .xword ".L+Core.Float64#658.jit" .size ".L+Core.Float64#658", 8 .set ".L+Core.Float64#658.jit", 278205186835760 .size ".L+Core.Float64#658.jit", 8 .section ".note.GNU-stack","",@progbits ``` --- src/codegen.cpp | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 5507bd7bad801..16cedabed107a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -83,20 +83,6 @@ using namespace llvm; -static bool jl_fpo_disabled(const Triple &TT) { -#ifdef JL_DISABLE_FPO - return true; -#endif -#ifdef _COMPILER_MSAN_ENABLED_ - // MSAN doesn't support FPO - return true; -#endif - if (TT.isOSLinux() || TT.isOSWindows() || TT.isOSFreeBSD() || TT.isOSOpenBSD()) { - return true; - } - return false; -} - static bool jl_floattemp_var_needed(const Triple &TT) { #ifdef JL_NEED_FLOATTEMP_VAR return true; @@ -2970,8 +2956,7 @@ void jl_init_function(Function *F, const Triple &TT) JL_NOTSAFEPOINT if (TT.isOSWindows() && TT.getArch() == Triple::x86_64) { attr.addUWTableAttr(llvm::UWTableKind::Default); // force NeedsWinEH } - if (jl_fpo_disabled(TT)) - attr.addAttribute("frame-pointer", "all"); + attr.addAttribute("frame-pointer", "all"); if (!TT.isOSWindows()) { #if !defined(_COMPILER_ASAN_ENABLED_) // ASAN won't like us accessing undefined memory causing spurious issues, From 4ebb50b6a0445b6ecdd74374c3999da5b3f33b9d Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Sat, 8 Feb 2025 13:14:56 +0900 Subject: [PATCH 301/342] improve concurrency safety for `Compiler.finish!` (#57248) Similar to JuliaLang/julia#57229, this commit ensures that `Compiler.finish!` properly synchronizes the operations to set `max_world` for cached `CodeInstance`s by holding the world counter lock. Previously, `Compiler.finish!` relied on a narrow timing window to avoid race conditions, which was not a robust approach in a concurrent execution environment. This change ensures that `Compiler.finish!` holds the appropriate lock (via `jl_promote_ci_to_current`). --- Compiler/src/typeinfer.jl | 29 ++++++++++++++++++++--------- src/staticdata.c | 16 ++++++++++++++++ 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index f1da2e8a75a67..427f485f9118b 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -92,7 +92,7 @@ If set to `true`, record per-method-instance timings within type inference in th __set_measure_typeinf(onoff::Bool) = __measure_typeinf__[] = onoff const __measure_typeinf__ = RefValue{Bool}(false) -function finish!(interp::AbstractInterpreter, caller::InferenceState) +function finish!(interp::AbstractInterpreter, caller::InferenceState, validation_world::UInt) result = caller.result opt = result.src if opt isa OptimizationState @@ -108,12 +108,7 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState) ci = result.ci # if we aren't cached, we don't need this edge # but our caller might, so let's just make it anyways - if last(result.valid_worlds) >= get_world_counter() - # TODO: this should probably come after all store_backedges (after optimizations) for the entire graph in finish_cycle - # since we should be requiring that all edges first get their backedges set, as a batch - result.valid_worlds = WorldRange(first(result.valid_worlds), typemax(UInt)) - end - if last(result.valid_worlds) == typemax(UInt) + if last(result.valid_worlds) >= validation_world # if we can record all of the backedges in the global reverse-cache, # we can now widen our applicability in the global cache too store_backedges(ci, edges) @@ -202,7 +197,14 @@ function finish_nocycle(::AbstractInterpreter, frame::InferenceState) if opt isa OptimizationState # implies `may_optimize(caller.interp) === true` optimize(frame.interp, opt, frame.result) end - finish!(frame.interp, frame) + validation_world = get_world_counter() + finish!(frame.interp, frame, validation_world) + if isdefined(frame.result, :ci) + # After validation, under the world_counter_lock, set max_world to typemax(UInt) for all dependencies + # (recursively). From that point onward the ordinary backedge mechanism is responsible for maintaining + # validity. + ccall(:jl_promote_ci_to_current, Cvoid, (Any, UInt), frame.result.ci, validation_world) + end if frame.cycleid != 0 frames = frame.callstack::Vector{AbsIntState} @assert frames[end] === frame @@ -236,10 +238,19 @@ function finish_cycle(::AbstractInterpreter, frames::Vector{AbsIntState}, cyclei optimize(caller.interp, opt, caller.result) end end + validation_world = get_world_counter() + cis = CodeInstance[] for frameid = cycleid:length(frames) caller = frames[frameid]::InferenceState - finish!(caller.interp, caller) + finish!(caller.interp, caller, validation_world) + if isdefined(caller.result, :ci) + push!(cis, caller.result.ci) + end end + # After validation, under the world_counter_lock, set max_world to typemax(UInt) for all dependencies + # (recursively). From that point onward the ordinary backedge mechanism is responsible for maintaining + # validity. + ccall(:jl_promote_cis_to_current, Cvoid, (Ptr{CodeInstance}, Csize_t, UInt), cis, length(cis), validation_world) resize!(frames, cycleid - 1) return nothing end diff --git a/src/staticdata.c b/src/staticdata.c index 4ea93fc58a9e0..36ebaa1c1b247 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -4408,6 +4408,22 @@ JL_DLLEXPORT void jl_promote_ci_to_current(jl_code_instance_t *ci, size_t valida JL_UNLOCK(&world_counter_lock); } +JL_DLLEXPORT void jl_promote_cis_to_current(jl_code_instance_t **cis, size_t n, size_t validated_world) +{ + size_t current_world = jl_atomic_load_relaxed(&jl_world_counter); + // No need to acquire the lock if we've been invalidated anyway + if (current_world > validated_world) + return; + JL_LOCK(&world_counter_lock); + current_world = jl_atomic_load_relaxed(&jl_world_counter); + if (current_world == validated_world) { + for (size_t i = 0; i < n; i++) { + _jl_promote_ci_to_current(cis[i], validated_world); + } + } + JL_UNLOCK(&world_counter_lock); +} + #ifdef __cplusplus } #endif From b682f496bc3fa81f8ee488b50245275f24f5e7db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Belmant?= Date: Sat, 8 Feb 2025 05:15:25 +0100 Subject: [PATCH 302/342] Inference: propagate struct initialization info on `setfield!` (#57222) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a variable has a field set with `setfield!(var, field, value)`, inference now assumes that this specific field is defined and may for example constant-propagate `isdefined(var, field)` as `true`. `PartialStruct`, the lattice element used to encode this information, still has a few limitations in terms of what it may represent (it cannot represent mutable structs with non-contiguously defined fields yet), further work on extending it would increase the impact of this change. Consider the following function: ```julia julia> function f() a = A(1) setfield!(a, :y, 2) invokelatest(identity, a) isdefined(a, :y) && return 1.0 a end f (generic function with 1 method) ``` Here is before on `master`: ```julia julia> @code_typed f() CodeInfo( 1 ─ %1 = %new(Main.A, 1)::A │ builtin Main.setfield!(%1, :y, 2)::Int64 │ dynamic builtin (Core._call_latest)(identity, %1)::Any │ %4 = builtin Main.isdefined(%1, :y)::Bool └── goto #3 if not %4 2 ─ return 1.0 3 ─ return %1 ) => Union{Float64, A} ``` And after this PR: ```julia julia> @code_typed f() CodeInfo( 1 ─ %1 = %new(Main.A, 1)::A │ builtin Main.setfield!(%1, :y, 2)::Int64 │ dynamic builtin (Core._call_latest)(identity, %1)::Any └── return 1.0 ) => Float64 ``` --------- Co-authored-by: Cédric Belmant --- Compiler/src/abstractinterpretation.jl | 20 ++++++++++++++++---- Compiler/test/irpasses.jl | 11 +++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index 8a7e8aee715a6..c9d42197d6405 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -2665,12 +2665,24 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f), end pushfirst!(argtypes, ft) refinements = nothing - if sv isa InferenceState && f === typeassert - # perform very limited back-propagation of invariants after this type assertion - if rt !== Bottom && isa(fargs, Vector{Any}) + if sv isa InferenceState + if f === typeassert + # perform very limited back-propagation of invariants after this type assertion + if rt !== Bottom && isa(fargs, Vector{Any}) + farg2 = ssa_def_slot(fargs[2], sv) + if farg2 isa SlotNumber + refinements = SlotRefinement(farg2, rt) + end + end + elseif f === setfield! && length(argtypes) == 4 && isa(argtypes[3], Const) + # from there on we know that the struct field will never be undefined, + # so we try to encode that information with a `PartialStruct` farg2 = ssa_def_slot(fargs[2], sv) if farg2 isa SlotNumber - refinements = SlotRefinement(farg2, rt) + refined = form_partially_defined_struct(argtypes[2], argtypes[3]) + if refined !== nothing + refinements = SlotRefinement(farg2, refined) + end end end end diff --git a/Compiler/test/irpasses.jl b/Compiler/test/irpasses.jl index 0d0b0e4daf83e..445ad10307807 100644 --- a/Compiler/test/irpasses.jl +++ b/Compiler/test/irpasses.jl @@ -2042,3 +2042,14 @@ let src = code_typed1(()) do end @test count(iscall((src, setfield!)), src.code) == 1 end + +# optimize `isdefined` away in the presence of a dominating `setfield!` +let src = code_typed1(()) do + a = Ref{Any}() + setfield!(a, :x, 2) + invokelatest(identity, a) + isdefined(a, :x) && return 1.0 + a[] + end + @test count(iscall((src, isdefined)), src.code) == 0 +end From 132057c378af992f768e5b2a9b69543c0017c0d9 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Sat, 8 Feb 2025 10:29:25 -0500 Subject: [PATCH 303/342] Profile.print: de-focus sleeping frames as gray (#57312) --- stdlib/Profile/src/Profile.jl | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/stdlib/Profile/src/Profile.jl b/stdlib/Profile/src/Profile.jl index f59b49d8a4a36..2e4092fb22c24 100644 --- a/stdlib/Profile/src/Profile.jl +++ b/stdlib/Profile/src/Profile.jl @@ -980,13 +980,14 @@ mutable struct StackFrameTree{T} # where T <: Union{UInt64, StackFrame} flat_count::Int # number of times this frame was in the flattened representation (unlike count, this'll sum to 100% of parent) max_recur::Int # maximum number of times this frame was the *top* of the recursion in the stack count_recur::Int # sum of the number of times this frame was the *top* of the recursion in a stack (divide by count to get an average) + sleeping::Bool # whether this frame was in a sleeping state down::Dict{T, StackFrameTree{T}} # construction workers: recur::Int builder_key::Vector{UInt64} builder_value::Vector{StackFrameTree{T}} up::StackFrameTree{T} - StackFrameTree{T}() where {T} = new(UNKNOWN, 0, 0, 0, 0, 0, Dict{T, StackFrameTree{T}}(), 0, UInt64[], StackFrameTree{T}[]) + StackFrameTree{T}() where {T} = new(UNKNOWN, 0, 0, 0, 0, 0, true, Dict{T, StackFrameTree{T}}(), 0, UInt64[], StackFrameTree{T}[]) end @@ -1027,6 +1028,10 @@ function tree_format(frames::Vector{<:StackFrameTree}, level::Int, cols::Int, ma base = string(base, "+", nextra, " ") end strcount = rpad(string(frame.count), ndigcounts, " ") + if frame.sleeping + stroverhead = styled"{gray:$(stroverhead)}" + strcount = styled"{gray:$(strcount)}" + end if li != UNKNOWN if li.line == li.pointer strs[i] = string(stroverhead, "╎", base, strcount, " ", @@ -1039,6 +1044,7 @@ function tree_format(frames::Vector{<:StackFrameTree}, level::Int, cols::Int, ma else fname = string(li.func) end + frame.sleeping && (fname = styled"{gray:$(fname)}") path, pkgname, filename = short_path(li.file, filenamemap) if showpointer fname = string( @@ -1082,15 +1088,15 @@ function tree!(root::StackFrameTree{T}, all::Vector{UInt64}, lidict::Union{LineI skip = false nsleeping = 0 is_task_profile = false + is_sleeping = true for i in startframe:-1:1 (startframe - 1) >= i >= (startframe - (nmeta + 1)) && continue # skip metadata (it's read ahead below) and extra block end NULL IP ip = all[i] if is_block_end(all, i) # read metadata thread_sleeping_state = all[i - META_OFFSET_SLEEPSTATE] - 1 # subtract 1 as state is incremented to avoid being equal to 0 - if thread_sleeping_state == 2 - is_task_profile = true - end + is_sleeping = thread_sleeping_state == 1 + is_task_profile = thread_sleeping_state == 2 # cpu_cycle_clock = all[i - META_OFFSET_CPUCYCLECLOCK] taskid = all[i - META_OFFSET_TASKID] threadid = all[i - META_OFFSET_THREADID] @@ -1145,6 +1151,7 @@ function tree!(root::StackFrameTree{T}, all::Vector{UInt64}, lidict::Union{LineI parent = build[j] parent.recur += 1 parent.count_recur += 1 + parent.sleeping &= is_sleeping found = true break end @@ -1164,6 +1171,7 @@ function tree!(root::StackFrameTree{T}, all::Vector{UInt64}, lidict::Union{LineI while this !== parent && (recur === :off || this.recur == 0) this.count += 1 this.recur = 1 + this.sleeping &= is_sleeping this = this.up end end @@ -1185,6 +1193,7 @@ function tree!(root::StackFrameTree{T}, all::Vector{UInt64}, lidict::Union{LineI this.up = parent this.count += 1 this.recur = 1 + this.sleeping &= is_sleeping end parent = this end From dbd528025166f92bf0041471b2ddea3027e106e6 Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Sat, 8 Feb 2025 14:46:24 -0400 Subject: [PATCH 304/342] Make `OncePerX` subtype `Function` (#57289) --- base/lock.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/base/lock.jl b/base/lock.jl index 59e554c01c24a..17a08888bf711 100644 --- a/base/lock.jl +++ b/base/lock.jl @@ -693,7 +693,7 @@ julia> procstate === fetch(@async global_state()) true ``` """ -mutable struct OncePerProcess{T, F} +mutable struct OncePerProcess{T, F} <: Function value::Union{Nothing,T} @atomic state::UInt8 # 0=initial, 1=hasrun, 2=error @atomic allow_compile_time::Bool @@ -801,7 +801,7 @@ julia> threadvec === thread_state[Threads.threadid()] true ``` """ -mutable struct OncePerThread{T, F} +mutable struct OncePerThread{T, F} <: Function @atomic xs::AtomicMemory{T} # values @atomic ss::AtomicMemory{UInt8} # states: 0=initial, 1=hasrun, 2=error, 3==concurrent const initializer::F @@ -926,7 +926,7 @@ Making lazy task value...done. false ``` """ -mutable struct OncePerTask{T, F} +mutable struct OncePerTask{T, F} <: Function const initializer::F OncePerTask{T}(initializer::F) where {T, F} = new{T,F}(initializer) From 79e98e3b89da5e57f829ccde21b576be9fc8ea1b Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Sat, 8 Feb 2025 21:36:34 -0300 Subject: [PATCH 305/342] Make ptls allocations at least 128 byte aligned (#57310) Fixes https://github.com/JuliaLang/julia/issues/54560#issuecomment-2439710448 --- src/threading.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/threading.c b/src/threading.c index a51916cdcd8d8..690c5fafb5792 100644 --- a/src/threading.c +++ b/src/threading.c @@ -336,7 +336,17 @@ jl_ptls_t jl_init_threadtls(int16_t tid) #endif if (jl_get_pgcstack() != NULL) abort(); - jl_ptls_t ptls = (jl_ptls_t)calloc(1, sizeof(jl_tls_states_t)); + jl_ptls_t ptls; +#if defined(_OS_WINDOWS_) + ptls = _aligned_malloc(sizeof(jl_tls_states_t), alignof(jl_tls_states_t)); + if (ptls == NULL) + abort(); +#else + if (posix_memalign((void**)&ptls, alignof(jl_tls_states_t), sizeof(jl_tls_states_t))) + abort(); +#endif + memset(ptls, 0, sizeof(jl_tls_states_t)); + #ifndef _OS_WINDOWS_ pthread_setspecific(jl_task_exit_key, (void*)ptls); #endif From c269329aeccc4e226363c514da517a72e6fcdbeb Mon Sep 17 00:00:00 2001 From: Valentin Churavy Date: Sun, 9 Feb 2025 22:53:33 +0100 Subject: [PATCH 306/342] Remove mentioned of unused LLVM patch (#57323) --- deps/patches/llvm7-symver-jlprefix.patch | 18 ------------------ doc/src/devdocs/build/build.md | 1 - 2 files changed, 19 deletions(-) delete mode 100644 deps/patches/llvm7-symver-jlprefix.patch diff --git a/deps/patches/llvm7-symver-jlprefix.patch b/deps/patches/llvm7-symver-jlprefix.patch deleted file mode 100644 index bdfb8e523668b..0000000000000 --- a/deps/patches/llvm7-symver-jlprefix.patch +++ /dev/null @@ -1,18 +0,0 @@ -From f23277bb91a4925ba8763337137a3123a7600557 Mon Sep 17 00:00:00 2001 -From: Valentin Churavy -Date: Tue, 16 Jan 2018 17:29:05 -0500 -Subject: [PATCH] add JL prefix to all LLVM version suffixes - ---- - tools/llvm-shlib/simple_version_script.map.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tools/llvm-shlib/simple_version_script.map.in b/tools/llvm-shlib/simple_version_script.map.in -index e9515fe7862..af082581627 100644 ---- a/tools/llvm-shlib/simple_version_script.map.in -+++ b/tools/llvm-shlib/simple_version_script.map.in -@@ -1 +1 @@ --LLVM_@LLVM_VERSION_MAJOR@ { global: *; }; -+JL_LLVM_@LLVM_VERSION_MAJOR@.@LLVM_VERSION_MINOR@ { global: *; }; --- -2.15.1 diff --git a/doc/src/devdocs/build/build.md b/doc/src/devdocs/build/build.md index 5fe038959edf0..97bf4e41398f7 100644 --- a/doc/src/devdocs/build/build.md +++ b/doc/src/devdocs/build/build.md @@ -250,7 +250,6 @@ For packaging Julia with LLVM, we recommend either: - bundling a Julia-only LLVM library inside the Julia package, or - adding the patches to the LLVM package of the distribution. * A complete list of patches is available in on [Github](https://github.com/JuliaLang/llvm-project) see the `julia-release/18.x` branch. - * The only Julia-specific patch is the lib renaming (`llvm7-symver-jlprefix.patch`), which should _not_ be applied to a system LLVM. * The remaining patches are all upstream bug fixes, and have been contributed into upstream LLVM. Using an unpatched or different version of LLVM will result in errors and/or poor performance. From 8c62f42947ee01fb17d1baf8c5e953fb3516b31f Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Mon, 10 Feb 2025 08:31:20 -0500 Subject: [PATCH 307/342] Add a warning for auto-import of types (#57311) This adds a warning for the auto-import of types cases (#25744) that we have long considered a bit of a bug, but didn't want to change because it is too breaking. The reason to do it now is that the binding rework has made this case more problematic (see #57290). To summarize, the question is what happens when the compiler sees `f(x) = ...` and `f` is currently and implicitly imported binding. There are two options: 1. We add a method to the generic function referred to by `f`, or 2. We create a new generic function `f` in the current module. Historically, case 1 has the additional complication that this error'd unless `f` is a type. It is my impression that a lot of existing code did not have a particularly good understanding of the resolved-ness dependence of this behavior. However, because case 1 errors for generic functions, it appears that existing code generally expects case 2. On the other hand, for types, there is existing code in both directions (#57290 is an example of case 2; see #57302 for examples of case 1). That said, case 1 is more common (because types tend to be resolved because they're used in signatures at toplevel). Thus, to retain compatibility, the current behavior on master (where resolvedness is no longer available) is that we always choose case 2 for functions and case 1 for types. This inconsistency is unfortunate, but I tried resolving this in either way (making all situations case 1 or all case 2) and the result was too breaking. Nevertheless, it is problematic that there is existing code that expects case 2 beavior for types and we should help users to know what the correct way to fix it is. The proposed resolution is thus: 1. Retain case 1 behavior for types 2. Make it a warning to use, encouraging people to explicitly import, since we generally consider the #25744 case a bug. Example: ``` julia> module Foo String(i::Int) = i end WARNING: Type Core.String was auto-`import`ed in `Foo`. NOTE: This behavior is deprecated and may change in future Julia versions. NOTE: This behavior may have differed in Julia versions prior to 1.12 depending on binding resolution. Hint: To retain the current behavior, add an explicit `import Core: String` in Foo. Hint: To create a new generic function of the same name use `function String end`. Main.Foo ``` --- src/codegen.cpp | 25 ++++------------------ src/interpreter.c | 3 +-- src/julia.h | 11 ++++++++-- src/julia_internal.h | 1 + src/method.c | 3 ++- src/module.c | 28 ++++++++++++++++++------- stdlib/SharedArrays/src/SharedArrays.jl | 1 + test/arrayops.jl | 2 +- test/errorshow.jl | 2 +- test/intrinsics.jl | 2 +- 10 files changed, 41 insertions(+), 37 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 16cedabed107a..b57fc7d90eb29 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1005,7 +1005,7 @@ static const auto jlgenericfunction_func = new JuliaFunction<>{ auto T_jlvalue = JuliaType::get_jlvalue_ty(C); auto T_pjlvalue = PointerType::get(T_jlvalue, 0); auto T_prjlvalue = PointerType::get(T_jlvalue, AddressSpace::Tracked); - return FunctionType::get(T_prjlvalue, {T_pjlvalue, T_pjlvalue, T_pjlvalue}, false); + return FunctionType::get(T_prjlvalue, {T_pjlvalue, T_pjlvalue}, false); }, nullptr, }; @@ -6853,8 +6853,6 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaidx_ jl_value_t *mn = args[0]; assert(jl_is_symbol(mn) || jl_is_slotnumber(mn) || jl_is_globalref(mn)); - Value *bp = NULL, *name; - jl_binding_t *bnd = NULL; bool issym = jl_is_symbol(mn); bool isglobalref = !issym && jl_is_globalref(mn); jl_module_t *mod = ctx.module; @@ -6863,26 +6861,11 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaidx_ mod = jl_globalref_mod(mn); mn = (jl_value_t*)jl_globalref_name(mn); } - JL_TRY { - if (jl_symbol_name((jl_sym_t*)mn)[0] == '@') - jl_errorf("macro definition not allowed inside a local scope"); - name = literal_pointer_val(ctx, mn); - bnd = jl_get_binding_for_method_def(mod, (jl_sym_t*)mn); - } - JL_CATCH { - jl_value_t *e = jl_current_exception(jl_current_task); - // errors. boo. :( - JL_GC_PUSH1(&e); - e = jl_as_global_root(e, 1); - JL_GC_POP(); - raise_exception(ctx, literal_pointer_val(ctx, e)); - return ghostValue(ctx, jl_nothing_type); - } - bp = julia_binding_gv(ctx, bnd); jl_cgval_t gf = mark_julia_type( ctx, - ctx.builder.CreateCall(prepare_call(jlgenericfunction_func), { bp, - literal_pointer_val(ctx, (jl_value_t*)mod), name + ctx.builder.CreateCall(prepare_call(jlgenericfunction_func), { + literal_pointer_val(ctx, (jl_value_t*)mod), + literal_pointer_val(ctx, (jl_value_t*)mn) }), true, jl_function_type); diff --git a/src/interpreter.c b/src/interpreter.c index 513fe58f7b5cc..7ab284df78dff 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -93,8 +93,7 @@ static jl_value_t *eval_methoddef(jl_expr_t *ex, interpreter_state *s) if (!jl_is_symbol(fname)) { jl_error("method: invalid declaration"); } - jl_binding_t *b = jl_get_binding_for_method_def(modu, fname); - return jl_declare_const_gf(b, modu, fname); + return jl_declare_const_gf(modu, fname); } jl_value_t *atypes = NULL, *meth = NULL, *fname = NULL; diff --git a/src/julia.h b/src/julia.h index dd3bc713a517f..1fd709f42ee31 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1475,6 +1475,13 @@ STATIC_INLINE char *jl_symbol_name_(jl_sym_t *s) JL_NOTSAFEPOINT } #define jl_symbol_name(s) jl_symbol_name_(s) +STATIC_INLINE const char *jl_module_debug_name(jl_module_t *mod) JL_NOTSAFEPOINT +{ + if (!mod) + return ""; + return jl_symbol_name(mod->name); +} + static inline uint32_t jl_fielddesc_size(int8_t fielddesc_type) JL_NOTSAFEPOINT { assert(fielddesc_type >= 0 && fielddesc_type <= 2); @@ -1901,7 +1908,7 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value(jl_binding_t *b JL_PROPAGATES_ROOT JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_const(jl_binding_t *b JL_PROPAGATES_ROOT); JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_resolved(jl_binding_t *b JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_resolved_and_const(jl_binding_t *b JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; -JL_DLLEXPORT jl_value_t *jl_declare_const_gf(jl_binding_t *b, jl_module_t *mod, jl_sym_t *name); +JL_DLLEXPORT jl_value_t *jl_declare_const_gf(jl_module_t *mod, jl_sym_t *name); JL_DLLEXPORT jl_method_t *jl_method_def(jl_svec_t *argdata, jl_methtable_t *mt, jl_code_info_t *f, jl_module_t *module); JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo, size_t world, jl_code_instance_t **cache); JL_DLLEXPORT jl_code_info_t *jl_copy_code_info(jl_code_info_t *src); @@ -2051,7 +2058,7 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_type(jl_module_t *m, jl_sym_t *var); // get binding for assignment JL_DLLEXPORT void jl_check_binding_currently_writable(jl_binding_t *b, jl_module_t *m, jl_sym_t *s); JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var); -JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var); +JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, size_t new_world); JL_DLLEXPORT int jl_boundp(jl_module_t *m, jl_sym_t *var, int allow_import); JL_DLLEXPORT int jl_defines_or_exports_p(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var); diff --git a/src/julia_internal.h b/src/julia_internal.h index 5fe6cad0d096c..6d83000184880 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -876,6 +876,7 @@ STATIC_INLINE size_t module_usings_max(jl_module_t *m) JL_NOTSAFEPOINT { return m->usings.max/3; } +JL_DLLEXPORT jl_sym_t *jl_module_name(jl_module_t *m) JL_NOTSAFEPOINT; jl_value_t *jl_eval_global_var(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *e); jl_value_t *jl_interpret_opaque_closure(jl_opaque_closure_t *clos, jl_value_t **args, size_t nargs); jl_value_t *jl_interpret_toplevel_thunk(jl_module_t *m, jl_code_info_t *src); diff --git a/src/method.c b/src/method.c index 1b38a16649d8a..68542fdacabb6 100644 --- a/src/method.c +++ b/src/method.c @@ -1050,10 +1050,11 @@ JL_DLLEXPORT void jl_check_gf(jl_value_t *gf, jl_sym_t *name) jl_errorf("cannot define function %s; it already has a value", jl_symbol_name(name)); } -JL_DLLEXPORT jl_value_t *jl_declare_const_gf(jl_binding_t *b, jl_module_t *mod, jl_sym_t *name) +JL_DLLEXPORT jl_value_t *jl_declare_const_gf(jl_module_t *mod, jl_sym_t *name) { JL_LOCK(&world_counter_lock); size_t new_world = jl_atomic_load_relaxed(&jl_world_counter) + 1; + jl_binding_t *b = jl_get_binding_for_method_def(mod, name, new_world); jl_binding_partition_t *bpart = jl_get_binding_partition(b, new_world); jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); jl_value_t *gf = NULL; diff --git a/src/module.c b/src/module.c index 1b6b37e49949e..402a86dfd4aef 100644 --- a/src/module.c +++ b/src/module.c @@ -588,10 +588,10 @@ JL_DLLEXPORT jl_value_t *jl_reresolve_binding_value_seqcst(jl_binding_t *b) // get binding for adding a method // like jl_get_binding_wr, but has different error paths and messages -JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_t *var) +JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_t *var, size_t new_world) { jl_binding_t *b = jl_get_module_binding(m, var, 1); - jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); + jl_binding_partition_t *bpart = jl_get_binding_partition(b, new_world); jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); enum jl_partition_kind kind = decode_restriction_kind(pku); if (kind == BINDING_KIND_GLOBAL || kind == BINDING_KIND_DECLARED || jl_bkind_is_some_constant(decode_restriction_kind(pku))) @@ -601,7 +601,7 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_ return b; } jl_binding_t *ownerb = b; - pku = jl_walk_binding_inplace(&ownerb, &bpart, jl_current_task->world_age); + pku = jl_walk_binding_inplace(&ownerb, &bpart, new_world); jl_value_t *f = NULL; if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) f = decode_restriction_value(pku); @@ -613,7 +613,7 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_ jl_module_t *from = jl_binding_dbgmodule(b, m, var); // we must have implicitly imported this with using, so call jl_binding_dbgmodule to try to get the name of the module we got this from jl_errorf("invalid method definition in %s: exported function %s.%s does not exist", - jl_symbol_name(m->name), from ? jl_symbol_name(from->name) : "", jl_symbol_name(var)); + jl_module_debug_name(m), jl_module_debug_name(from), jl_symbol_name(var)); } int istype = f && jl_is_type(f); if (!istype) { @@ -626,13 +626,25 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_ // or we might want to drop this error entirely jl_module_t *from = jl_binding_dbgmodule(b, m, var); jl_errorf("invalid method definition in %s: function %s.%s must be explicitly imported to be extended", - jl_symbol_name(m->name), from ? jl_symbol_name(from->name) : "", jl_symbol_name(var)); + jl_module_debug_name(m), jl_module_debug_name(from), jl_symbol_name(var)); } } - else if (strcmp(jl_symbol_name(var), "=>") == 0 && (kind == BINDING_KIND_IMPLICIT || kind == BINDING_KIND_EXPLICIT)) { + else if (kind != BINDING_KIND_IMPORTED) { + int should_error = strcmp(jl_symbol_name(var), "=>") == 0; jl_module_t *from = jl_binding_dbgmodule(b, m, var); - jl_errorf("invalid method definition in %s: function %s.%s must be explicitly imported to be extended", - jl_symbol_name(m->name), from ? jl_symbol_name(from->name) : "", jl_symbol_name(var)); + if (should_error) + jl_errorf("invalid method definition in %s: function %s.%s must be explicitly imported to be extended", + jl_module_debug_name(m), jl_module_debug_name(from), jl_symbol_name(var)); + else + jl_printf(JL_STDERR, "WARNING: Constructor for type \"%s\" was extended in `%s` without explicit qualification or import.\n" + " NOTE: Assumed \"%s\" refers to `%s.%s`. This behavior is deprecated and may differ in future versions.`\n" + " NOTE: This behavior may have differed in Julia versions prior to 1.12.\n" + " Hint: If you intended to create a new generic function of the same name, use `function %s end`.\n" + " Hint: To silence the warning, qualify `%s` as `%s.%s` or explicitly `import %s: %s`\n", + jl_symbol_name(var), jl_module_debug_name(m), + jl_symbol_name(var), jl_module_debug_name(from), jl_symbol_name(var), + jl_symbol_name(var), jl_symbol_name(var), jl_module_debug_name(from), jl_symbol_name(var), + jl_module_debug_name(from), jl_symbol_name(var)); } return ownerb; } diff --git a/stdlib/SharedArrays/src/SharedArrays.jl b/stdlib/SharedArrays/src/SharedArrays.jl index 93ce396277af7..6106bc9c3c81a 100644 --- a/stdlib/SharedArrays/src/SharedArrays.jl +++ b/stdlib/SharedArrays/src/SharedArrays.jl @@ -9,6 +9,7 @@ using Mmap, Distributed, Random import Base: length, size, elsize, ndims, IndexStyle, reshape, convert, deepcopy_internal, show, getindex, setindex!, fill!, similar, reduce, map!, copyto!, cconvert +import Base: Array import Random using Serialization using Serialization: serialize_cycle_header, serialize_type, writetag, UNDEFREF_TAG, serialize, deserialize diff --git a/test/arrayops.jl b/test/arrayops.jl index 655e14675bfb4..b2da3eac6386b 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -2948,7 +2948,7 @@ end Base.ArithmeticStyle(::Type{F21666{T}}) where {T} = T() Base.:+(x::F, y::F) where {F <: F21666} = F(x.x + y.x) -Float64(x::F21666) = Float64(x.x) +Base.Float64(x::F21666) = Float64(x.x) @testset "Exactness of cumsum # 21666" begin # test that cumsum uses more stable algorithm # for types with unknown/rounding arithmetic diff --git a/test/errorshow.jl b/test/errorshow.jl index 8f7482ce3235e..8e13d0242ae35 100644 --- a/test/errorshow.jl +++ b/test/errorshow.jl @@ -438,7 +438,7 @@ let err_str @test occursin("For element-wise subtraction, use broadcasting with dot syntax: array .- scalar", err_str) end - +import Core: String method_defs_lineno = @__LINE__() + 1 String() = throw(ErrorException("1")) (::String)() = throw(ErrorException("2")) diff --git a/test/intrinsics.jl b/test/intrinsics.jl index c3e9bb1680d48..12867908bf5a4 100644 --- a/test/intrinsics.jl +++ b/test/intrinsics.jl @@ -66,7 +66,7 @@ end # test functionality of non-power-of-2 primitive type constants primitive type Int24 24 end Int24(x::Int) = Core.Intrinsics.trunc_int(Int24, x) -Int(x::Int24) = Core.Intrinsics.zext_int(Int, x) +Base.Int(x::Int24) = Core.Intrinsics.zext_int(Int, x) let x, y, f x = Int24(Int(0x12345678)) # create something (via truncation) @test Int(0x345678) === Int(x) From dd1387854540977a77725821c2ce0249bde1e443 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Mon, 10 Feb 2025 21:51:02 +0100 Subject: [PATCH 308/342] fix typo in Float32 random number generation (#57338) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit introduced in https://github.com/JuliaLang/julia/pull/56144 --------- Co-authored-by: Mosè Giordano <765740+giordano@users.noreply.github.com> --- stdlib/Random/src/XoshiroSimd.jl | 2 +- stdlib/Random/test/runtests.jl | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/stdlib/Random/src/XoshiroSimd.jl b/stdlib/Random/src/XoshiroSimd.jl index f77be4a347111..a23f5d7590b40 100644 --- a/stdlib/Random/src/XoshiroSimd.jl +++ b/stdlib/Random/src/XoshiroSimd.jl @@ -46,7 +46,7 @@ simdThreshold(::Type{Bool}) = 640 ui = (x>>>32) % UInt32 li = x % UInt32 u = _uint2float(ui, Float32) - l = _uint2float(ui, Float32) + l = _uint2float(li, Float32) (UInt64(reinterpret(UInt32, u)) << 32) | UInt64(reinterpret(UInt32, l)) end @inline function _bits2float(x::UInt64, ::Type{Float16}) diff --git a/stdlib/Random/test/runtests.jl b/stdlib/Random/test/runtests.jl index 13edf2e6553ec..a28197bdfe833 100644 --- a/stdlib/Random/test/runtests.jl +++ b/stdlib/Random/test/runtests.jl @@ -1250,6 +1250,16 @@ end @test length(xs) == 3 end +@testset "Float32 RNG typo" begin + for T in (Float16, Float32, Float64) + # Make sure generated numbers are sufficiently diverse + # for both SIMD and non-SIMD RNG code paths for all types. + @test length(unique!(rand(T, 7))) > 3 + @test length(unique!(rand(T, 14))) > 10 + @test length(unique!(rand(T, 34))) > 20 + end +end + @testset "Docstrings" begin @test isempty(Docs.undocumented_names(Random)) end From 53431309e20eb057709a4f0d4de5663f4a233afd Mon Sep 17 00:00:00 2001 From: Sam Schweigel <33556084+xal-0@users.noreply.github.com> Date: Mon, 10 Feb 2025 14:20:43 -0800 Subject: [PATCH 309/342] Fix getfield_tfunc when order or boundscheck is Vararg (#57293) Even if T has no intersection with the type we want, we don't know that we will throw because the arguments are optional. Fixes #57292. --- Compiler/src/tfuncs.jl | 12 +++++------- Compiler/test/inference.jl | 6 ++++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Compiler/src/tfuncs.jl b/Compiler/src/tfuncs.jl index 50b88bb0222ce..cacee7a7d29ac 100644 --- a/Compiler/src/tfuncs.jl +++ b/Compiler/src/tfuncs.jl @@ -1073,17 +1073,15 @@ end end @nospecs function getfield_tfunc(𝕃::AbstractLattice, s00, name, boundscheck_or_order) - t = isvarargtype(boundscheck_or_order) ? unwrapva(boundscheck_or_order) : - widenconst(boundscheck_or_order) - hasintersect(t, Symbol) || hasintersect(t, Bool) || return Bottom + if !isvarargtype(boundscheck_or_order) + t = widenconst(boundscheck_or_order) + hasintersect(t, Symbol) || hasintersect(t, Bool) || return Bottom + end return getfield_tfunc(𝕃, s00, name) end @nospecs function getfield_tfunc(𝕃::AbstractLattice, s00, name, order, boundscheck) hasintersect(widenconst(order), Symbol) || return Bottom - if isvarargtype(boundscheck) - t = unwrapva(boundscheck) - hasintersect(t, Symbol) || hasintersect(t, Bool) || return Bottom - else + if !isvarargtype(boundscheck) hasintersect(widenconst(boundscheck), Bool) || return Bottom end return getfield_tfunc(𝕃, s00, name) diff --git a/Compiler/test/inference.jl b/Compiler/test/inference.jl index 563828ac77296..b77c99513a8b6 100644 --- a/Compiler/test/inference.jl +++ b/Compiler/test/inference.jl @@ -6188,3 +6188,9 @@ end == Union{Float64,DomainError} @test Compiler.argtypes_to_type(Any[ Int, UnitRange{Int}, Vararg{Pair{Any, Union{}}}, Float64 ]) === Tuple{Int, UnitRange{Int}, Float64} @test Compiler.argtypes_to_type(Any[ Int, UnitRange{Int}, Vararg{Pair{Any, Union{}}}, Float64, Memory{2} ]) === Union{} @test Base.return_types(Tuple{Tuple{Int, Vararg{Pair{Any, Union{}}}}},) do x; Returns(true)(x...); end |> only === Bool + +# issue #57292 +f57292(xs::Union{Tuple{String}, Int}...) = getfield(xs...) +g57292(xs::String...) = getfield(("abc",), 1, :not_atomic, xs...) +@test Base.infer_return_type(f57292) == String +@test Base.infer_return_type(g57292) == String From 751a0d728e32932a3f6f57065e9e792ce9325a8c Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Mon, 10 Feb 2025 19:57:55 -0500 Subject: [PATCH 310/342] docs: fix-up world-age handling for META access (#57349) This should be enough to get rid of the 3 lingering warnings in our main test suite. --- base/docs/Docs.jl | 8 ++++---- test/testhelpers/OffsetDenseArrays.jl | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/base/docs/Docs.jl b/base/docs/Docs.jl index 061a94bffd9cf..ae3891e218824 100644 --- a/base/docs/Docs.jl +++ b/base/docs/Docs.jl @@ -75,8 +75,8 @@ const META = gensym(:meta) const METAType = IdDict{Any,Any} function meta(m::Module; autoinit::Bool=true) - if !isdefinedglobal(m, META) - return autoinit ? invokelatest(initmeta, m) : nothing + if !invokelatest(isdefinedglobal, m, META) + return autoinit ? initmeta(m) : nothing end # TODO: This `invokelatest` is not technically required, but because # of the automatic constant backdating is currently required to avoid @@ -85,13 +85,13 @@ function meta(m::Module; autoinit::Bool=true) end function initmeta(m::Module) - if !isdefinedglobal(m, META) + if !invokelatest(isdefinedglobal, m, META) val = METAType() Core.eval(m, :(const $META = $val)) push!(modules, m) return val end - return getglobal(m, META) + return invokelatest(getglobal, m, META) end function signature!(tv::Vector{Any}, expr::Expr) diff --git a/test/testhelpers/OffsetDenseArrays.jl b/test/testhelpers/OffsetDenseArrays.jl index 44a1b8d627800..fb256234e2099 100644 --- a/test/testhelpers/OffsetDenseArrays.jl +++ b/test/testhelpers/OffsetDenseArrays.jl @@ -24,7 +24,7 @@ function Base.setindex(x::OffsetDenseArray, v, i::Integer) x.x[i - x.offset] = v end -IndexStyle(::Type{<:OffsetDenseArray}) = Base.IndexLinear() +Base.IndexStyle(::Type{<:OffsetDenseArray}) = Base.IndexLinear() Base.axes(x::OffsetDenseArray) = (x.offset + 1 : x.offset + length(x.x),) Base.keys(x::OffsetDenseArray) = only(axes(x)) From 90662b669e6b0a25f8b276fe60efba2a8018711c Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Mon, 10 Feb 2025 23:32:33 -0300 Subject: [PATCH 311/342] Add missing type asserts when taking the queue out of the task struct (#57344) This was causing some dynamic dispatches (caught by the juliac test) --- base/experimental.jl | 2 +- base/lock.jl | 2 +- stdlib/REPL/test/repl.jl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/base/experimental.jl b/base/experimental.jl index e35e920298c3d..f56f8d8234282 100644 --- a/base/experimental.jl +++ b/base/experimental.jl @@ -658,7 +658,7 @@ function wait_with_timeout(c::GenericCondition; first::Bool=false, timeout::Real # Confirm that the waiting task is still in the wait queue and remove it. If # the task is not in the wait queue, it must have been notified already so we # don't do anything here. - if !waiter_left[] && ct.queue == c.waitq + if !waiter_left[] && ct.queue === c.waitq dosched = true Base.list_deletefirst!(c.waitq, ct) end diff --git a/base/lock.jl b/base/lock.jl index 17a08888bf711..869e61599b443 100644 --- a/base/lock.jl +++ b/base/lock.jl @@ -252,7 +252,7 @@ function wait_no_relock(c::GenericCondition) try return wait() catch - ct.queue === nothing || list_deletefirst!(ct.queue, ct) + ct.queue === nothing || list_deletefirst!(ct.queue::IntrusiveLinkedList{Task}, ct) rethrow() end end diff --git a/stdlib/REPL/test/repl.jl b/stdlib/REPL/test/repl.jl index 018cf9c36430e..c1c5c7844bc96 100644 --- a/stdlib/REPL/test/repl.jl +++ b/stdlib/REPL/test/repl.jl @@ -32,7 +32,7 @@ function kill_timer(delay) # **DON'T COPY ME.** # The correct way to handle timeouts is to close the handle: # e.g. `close(stdout_read); close(stdin_write)` - test_task.queue === nothing || Base.list_deletefirst!(test_task.queue, test_task) + test_task.queue === nothing || Base.list_deletefirst!(test_task.queue::IntrusiveLinkedList{Task}, test_task) schedule(test_task, "hard kill repl test"; error=true) print(stderr, "WARNING: attempting hard kill of repl test after exceeding timeout\n") end From ac79b9f413784be185db0487e785c526c57d7daa Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Mon, 10 Feb 2025 21:54:40 -0500 Subject: [PATCH 312/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?SparseArrays=20stdlib=20from=20212981b=20to=2072c7cac=20(#57348?= =?UTF-8?q?)?= 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: main Julia branch: master Old commit: 212981b New commit: 72c7cac Julia version: 1.13.0-DEV SparseArrays version: 1.12.0(Does not match) Bump invoked by: @ViralBShah Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaSparse/SparseArrays.jl/compare/212981bf29b03ba460d3251ee9aa4399931b3f2d...72c7cac6bbf21367a3c2fbc5c50e908aea5984bb ``` $ git log --oneline 212981b..72c7cac 72c7cac Explicitly declare type constructor imports (#598) ff083ce README: update github action badge (#596) ``` Co-authored-by: ViralBShah <744411+ViralBShah@users.noreply.github.com> --- .../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-212981bf29b03ba460d3251ee9aa4399931b3f2d.tar.gz/md5 delete mode 100644 deps/checksums/SparseArrays-212981bf29b03ba460d3251ee9aa4399931b3f2d.tar.gz/sha512 create mode 100644 deps/checksums/SparseArrays-72c7cac6bbf21367a3c2fbc5c50e908aea5984bb.tar.gz/md5 create mode 100644 deps/checksums/SparseArrays-72c7cac6bbf21367a3c2fbc5c50e908aea5984bb.tar.gz/sha512 diff --git a/deps/checksums/SparseArrays-212981bf29b03ba460d3251ee9aa4399931b3f2d.tar.gz/md5 b/deps/checksums/SparseArrays-212981bf29b03ba460d3251ee9aa4399931b3f2d.tar.gz/md5 deleted file mode 100644 index 3fddcf07235f8..0000000000000 --- a/deps/checksums/SparseArrays-212981bf29b03ba460d3251ee9aa4399931b3f2d.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -621e67dc98707b587fb0f6e319dadbb2 diff --git a/deps/checksums/SparseArrays-212981bf29b03ba460d3251ee9aa4399931b3f2d.tar.gz/sha512 b/deps/checksums/SparseArrays-212981bf29b03ba460d3251ee9aa4399931b3f2d.tar.gz/sha512 deleted file mode 100644 index 68885439a1213..0000000000000 --- a/deps/checksums/SparseArrays-212981bf29b03ba460d3251ee9aa4399931b3f2d.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -5608adf92eaf7479eacf5ed75b3139438d0d4acf53d55a38c73a553c7fd899f553e1648fa657d35b9a0289e69fc461025dae5f8d15ec891eafcab3a663a8413a diff --git a/deps/checksums/SparseArrays-72c7cac6bbf21367a3c2fbc5c50e908aea5984bb.tar.gz/md5 b/deps/checksums/SparseArrays-72c7cac6bbf21367a3c2fbc5c50e908aea5984bb.tar.gz/md5 new file mode 100644 index 0000000000000..12c4f2ff97697 --- /dev/null +++ b/deps/checksums/SparseArrays-72c7cac6bbf21367a3c2fbc5c50e908aea5984bb.tar.gz/md5 @@ -0,0 +1 @@ +3f25f8a47a7945b55c9cc53ef489a55f diff --git a/deps/checksums/SparseArrays-72c7cac6bbf21367a3c2fbc5c50e908aea5984bb.tar.gz/sha512 b/deps/checksums/SparseArrays-72c7cac6bbf21367a3c2fbc5c50e908aea5984bb.tar.gz/sha512 new file mode 100644 index 0000000000000..5daf7514ff4ed --- /dev/null +++ b/deps/checksums/SparseArrays-72c7cac6bbf21367a3c2fbc5c50e908aea5984bb.tar.gz/sha512 @@ -0,0 +1 @@ +5fd827602430e79846d974661b039902a5ab6495f94af8292a3d66c3c3a07a0c59858bfa5bfa941bf8bf6418af98d1dd41b88aad4cc7c7355a8e56cad7f1f3ac diff --git a/stdlib/SparseArrays.version b/stdlib/SparseArrays.version index 0234c754191f8..f690a34eb5ae4 100644 --- a/stdlib/SparseArrays.version +++ b/stdlib/SparseArrays.version @@ -1,4 +1,4 @@ SPARSEARRAYS_BRANCH = main -SPARSEARRAYS_SHA1 = 212981bf29b03ba460d3251ee9aa4399931b3f2d +SPARSEARRAYS_SHA1 = 72c7cac6bbf21367a3c2fbc5c50e908aea5984bb SPARSEARRAYS_GIT_URL := https://github.com/JuliaSparse/SparseArrays.jl.git SPARSEARRAYS_TAR_URL = https://api.github.com/repos/JuliaSparse/SparseArrays.jl/tarball/$1 From 55d5a4be999cab0ee377a94698ebaa5d4929f53e Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Tue, 11 Feb 2025 08:08:44 -0500 Subject: [PATCH 313/342] replace `Linking.__init__` with `OncePerProcess` (#57351) This will cause these values to be populated at slightly different times than now, but I don't think it will matter. --- base/linking.jl | 55 ++++++++++++++++++------------------------------- 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/base/linking.jl b/base/linking.jl index 953d80c82cc42..f3dbe6abba3ec 100644 --- a/base/linking.jl +++ b/base/linking.jl @@ -3,15 +3,8 @@ module Linking import Base.Libc: Libdl -# inlined LLD_jll -# These get calculated in __init__() -const PATH = Ref("") -const LIBPATH = Ref("") -const PATH_list = String[] -const LIBPATH_list = String[] -const lld_path = Ref{String}() +# from LLD_jll const lld_exe = Sys.iswindows() ? "lld.exe" : "lld" -const dsymutil_path = Ref{String}() const dsymutil_exe = Sys.iswindows() ? "dsymutil.exe" : "dsymutil" if Sys.iswindows() @@ -47,61 +40,51 @@ function adjust_ENV!(env::Dict, PATH::String, LIBPATH::String, adjust_PATH::Bool return env end -function __init_lld_path() +const lld_path = OncePerProcess{String}() do # Prefer our own bundled lld, but if we don't have one, pick it up off of the PATH # If this is an in-tree build, `lld` will live in `tools`. Otherwise, it'll be in `private_libexecdir` for bundled_lld_path in (joinpath(Sys.BINDIR, Base.PRIVATE_LIBEXECDIR, lld_exe), joinpath(Sys.BINDIR, "..", "tools", lld_exe), joinpath(Sys.BINDIR, lld_exe)) if isfile(bundled_lld_path) - lld_path[] = abspath(bundled_lld_path) - return + return abspath(bundled_lld_path) end end - lld_path[] = something(Sys.which(lld_exe), lld_exe) - return + return something(Sys.which(lld_exe), lld_exe) end -function __init_dsymutil_path() - #Same as with lld but for dsymutil +const dsymutil_path = OncePerProcess{String}() do + # Same as with lld but for dsymutil for bundled_dsymutil_path in (joinpath(Sys.BINDIR, Base.PRIVATE_LIBEXECDIR, dsymutil_exe), joinpath(Sys.BINDIR, "..", "tools", dsymutil_exe), joinpath(Sys.BINDIR, dsymutil_exe)) if isfile(bundled_dsymutil_path) - dsymutil_path[] = abspath(bundled_dsymutil_path) - return + return abspath(bundled_dsymutil_path) end end - dsymutil_path[] = something(Sys.which(dsymutil_exe), dsymutil_exe) - return + return something(Sys.which(dsymutil_exe), dsymutil_exe) end -const VERBOSE = Ref{Bool}(false) +PATH() = dirname(lld_path()) -function __init__() - VERBOSE[] = something(Base.get_bool_env("JULIA_VERBOSE_LINKING", false), false) - - __init_lld_path() - __init_dsymutil_path() - PATH[] = dirname(lld_path[]) +const LIBPATH = OncePerProcess{String}() do if Sys.iswindows() # On windows, the dynamic libraries (.dll) are in Sys.BINDIR ("usr\\bin") - append!(LIBPATH_list, [abspath(Sys.BINDIR, Base.LIBDIR, "julia"), Sys.BINDIR]) + LIBPATH_list = [abspath(Sys.BINDIR, Base.LIBDIR, "julia"), Sys.BINDIR] else - append!(LIBPATH_list, [abspath(Sys.BINDIR, Base.LIBDIR, "julia"), abspath(Sys.BINDIR, Base.LIBDIR)]) + LIBPATH_list = [abspath(Sys.BINDIR, Base.LIBDIR, "julia"), abspath(Sys.BINDIR, Base.LIBDIR)] end - LIBPATH[] = join(LIBPATH_list, pathsep) - return + return join(LIBPATH_list, pathsep) end function lld(; adjust_PATH::Bool = true, adjust_LIBPATH::Bool = true) - env = adjust_ENV!(copy(ENV), PATH[], LIBPATH[], adjust_PATH, adjust_LIBPATH) - return Cmd(Cmd([lld_path[]]); env) + env = adjust_ENV!(copy(ENV), PATH(), LIBPATH(), adjust_PATH, adjust_LIBPATH) + return Cmd(Cmd([lld_path()]); env) end function dsymutil(; adjust_PATH::Bool = true, adjust_LIBPATH::Bool = true) - env = adjust_ENV!(copy(ENV), PATH[], LIBPATH[], adjust_PATH, adjust_LIBPATH) - return Cmd(Cmd([dsymutil_path[]]); env) + env = adjust_ENV!(copy(ENV), PATH(), LIBPATH(), adjust_PATH, adjust_LIBPATH) + return Cmd(Cmd([dsymutil_path()]); env) end function ld() @@ -149,6 +132,8 @@ else shlibdir() = libdir() end +verbose_linking() = something(Base.get_bool_env("JULIA_VERBOSE_LINKING", false), false) + function link_image_cmd(path, out) PRIVATE_LIBDIR = "-L$(private_libdir())" SHLIBDIR = "-L$(shlibdir())" @@ -158,7 +143,7 @@ function link_image_cmd(path, out) LIBS = (LIBS..., "-lopenlibm", "-lssp", "-lgcc_s", "-lgcc", "-lmsvcrt") end - V = VERBOSE[] ? "--verbose" : "" + V = verbose_linking() ? "--verbose" : "" `$(ld()) $V $SHARED -o $out $WHOLE_ARCHIVE $path $NO_WHOLE_ARCHIVE $PRIVATE_LIBDIR $SHLIBDIR $LIBS` end From 0b74d1752e4a02f9078e95bc9893619b2e52a0b6 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Tue, 11 Feb 2025 08:10:01 -0500 Subject: [PATCH 314/342] trimming: make sure to fail / warn on `Expr(:call, ...)` (#57342) This dispatch should not be treated as resolved just because arg0 is constant. With the previous code, that meant it was eligible for last-minute call resolution, but call-resolution in codegen is now forbidden so this needs to fail unilaterally. --- src/codegen.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/codegen.cpp b/src/codegen.cpp index b57fc7d90eb29..73c083e1cac2c 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5908,6 +5908,7 @@ static jl_cgval_t emit_call(jl_codectx_t &ctx, jl_expr_t *ex, jl_value_t *rt, bo if (ctx.params->trim != JL_TRIM_NO) { // TODO: Implement the last-minute call resolution that used to be here // in inference instead. + failed_dispatch = 1; } if (failed_dispatch && trim_may_error(ctx.params->trim)) { From 420608056ff1b9868f9d0dd5b6c9214fba8f8ce1 Mon Sep 17 00:00:00 2001 From: Niklas Haag <56864882+niklashaa@users.noreply.github.com> Date: Tue, 11 Feb 2025 16:46:37 +0100 Subject: [PATCH 315/342] Fix link to docs in index.md (#57354) --- stdlib/Test/docs/src/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/Test/docs/src/index.md b/stdlib/Test/docs/src/index.md index c1fe9e8e20c63..4989baa31d55e 100644 --- a/stdlib/Test/docs/src/index.md +++ b/stdlib/Test/docs/src/index.md @@ -24,7 +24,7 @@ The `Test` module provides simple *unit testing* functionality. Unit testing is see if your code is correct by checking that the results are what you expect. It can be helpful to ensure your code still works after you make changes, and can be used when developing as a way of specifying the behaviors your code should have when complete. You may also want to look at the -documentation for [adding tests to your Julia Package](https://pkgdocs.julialang.org/dev/creating-packages/#Adding-tests-to-the-package). +documentation for [adding tests to your Julia Package](https://pkgdocs.julialang.org/dev/creating-packages/#adding-tests-to-packages). Simple unit testing can be performed with the `@test` and `@test_throws` macros: From 73506ed5e7f6f40028d4851c99ec45b5dc452adc Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Tue, 11 Feb 2025 17:46:20 +0100 Subject: [PATCH 316/342] add a missing type assert to `OncePerTask` callable (#57356) also test that the difference `OncePerX` infer --- base/lock.jl | 4 +++- test/threads.jl | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/base/lock.jl b/base/lock.jl index 869e61599b443..79a2d1491bc00 100644 --- a/base/lock.jl +++ b/base/lock.jl @@ -933,4 +933,6 @@ mutable struct OncePerTask{T, F} <: Function OncePerTask{T,F}(initializer::F) where {T, F} = new{T,F}(initializer) OncePerTask(initializer) = new{Base.promote_op(initializer), typeof(initializer)}(initializer) end -@inline (once::OncePerTask)() = get!(once.initializer, task_local_storage(), once) +@inline function (once::OncePerTask{T})() where {T} + get!(once.initializer, task_local_storage(), once)::T +end diff --git a/test/threads.jl b/test/threads.jl index a1da408252fc4..52d0546f0e31b 100644 --- a/test/threads.jl +++ b/test/threads.jl @@ -439,7 +439,7 @@ end let once = OncePerProcess(() -> return [nothing]) @test typeof(once) <: OncePerProcess{Vector{Nothing}} - x = once() + x = @inferred once() @test x === once() @atomic once.state = 0xff @test_throws ErrorException("invalid state for OncePerProcess") once() @@ -456,7 +456,7 @@ let e = Base.Event(true), started = Channel{Int16}(Inf), finish = Channel{Nothing}(Inf), exiting = Channel{Nothing}(Inf), - starttest2 = Event(), + starttest2 = Base.Event(), once = OncePerThread() do push!(started, threadid()) take!(finish) @@ -468,7 +468,7 @@ let e = Base.Event(true), @test typeof(once) <: OncePerThread{Vector{Nothing}} push!(finish, nothing) @test_throws ArgumentError once[0] - x = once() + x = @inferred once() @test_throws ArgumentError once[0] @test x === once() === fetch(@async once()) === once[threadid()] @test take!(started) == threadid() @@ -558,7 +558,7 @@ end let once = OncePerTask(() -> return [nothing]) @test typeof(once) <: OncePerTask{Vector{Nothing}} - x = once() + x = @inferred once() @test x === once() !== fetch(@async once()) delete!(task_local_storage(), once) @test x !== once() === once() From 1de5880636f16c2196bea6a90243f69f65661d41 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Tue, 11 Feb 2025 14:42:51 -0300 Subject: [PATCH 317/342] Emit enter handler during codegen instead of after optimization (#57308) This means that the lowerHandlers pass is now useless. Which is good because it relied too much on optimizations not happening. Thanks @topolarity for all the knowledge on try catch lowering --- doc/src/devdocs/llvm-passes.md | 9 - doc/src/devdocs/llvm.md | 1 - src/Makefile | 3 +- src/codegen.cpp | 44 ++-- src/llvm-julia-passes.inc | 1 - src/llvm-lower-handlers.cpp | 257 ------------------- src/passes.h | 4 - src/pipeline.cpp | 1 - test/llvmpasses/lower-handlers-addrspaces.ll | 32 --- test/llvmpasses/lower-handlers.ll | 31 --- test/llvmpasses/parsing.ll | 2 +- 11 files changed, 26 insertions(+), 359 deletions(-) delete mode 100644 src/llvm-lower-handlers.cpp delete mode 100644 test/llvmpasses/lower-handlers-addrspaces.ll delete mode 100644 test/llvmpasses/lower-handlers.ll diff --git a/doc/src/devdocs/llvm-passes.md b/doc/src/devdocs/llvm-passes.md index 7b847abaa2149..641abb864e703 100644 --- a/doc/src/devdocs/llvm-passes.md +++ b/doc/src/devdocs/llvm-passes.md @@ -37,15 +37,6 @@ This pass performs most of the GC rooting work required to track pointers betwee * Opt Name: `module(FinalLowerGC)` This pass lowers a few last intrinsics to their final form targeting functions in the `libjulia` library. Separating this from `LateGCLowering` enables other backends (GPU compilation) to supply their own custom lowerings for these intrinsics, enabling the Julia pipeline to be used on those backends as well. - -### LowerHandlers - -* Filename: `llvm-lower-handlers.cpp` -* Class Name: `LowerExcHandlersPass` -* Opt Name: `function(LowerExcHandlers)` - -This pass lowers exception handling intrinsics into calls to runtime functions that are actually called when handling exceptions. - ### RemoveNI * Filename: `llvm-remove-ni.cpp` diff --git a/doc/src/devdocs/llvm.md b/doc/src/devdocs/llvm.md index 2155e5da6fd7b..480bca6fa6ecf 100644 --- a/doc/src/devdocs/llvm.md +++ b/doc/src/devdocs/llvm.md @@ -29,7 +29,6 @@ The code for lowering Julia AST to LLVM IR or interpreting it directly is in dir | `llvm-gc-invariant-verifier.cpp` | Custom LLVM pass to verify Julia GC invariants | | `llvm-julia-licm.cpp` | Custom LLVM pass to hoist/sink Julia-specific intrinsics | | `llvm-late-gc-lowering.cpp` | Custom LLVM pass to root GC-tracked values | -| `llvm-lower-handlers.cpp` | Custom LLVM pass to lower try-catch blocks | | `llvm-multiversioning.cpp` | Custom LLVM pass to generate sysimg code on multiple architectures | | `llvm-propagate-addrspaces.cpp` | Custom LLVM pass to canonicalize addrspaces | | `llvm-ptls.cpp` | Custom LLVM pass to lower TLS operations | diff --git a/src/Makefile b/src/Makefile index b49d27e05ff28..130c35960f2d0 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-propagate-addrspaces \ 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) @@ -360,7 +360,6 @@ $(BUILDDIR)/llvm-final-gc-lowering.o $(BUILDDIR)/llvm-final-gc-lowering.dbg.obj: $(BUILDDIR)/llvm-gc-invariant-verifier.o $(BUILDDIR)/llvm-gc-invariant-verifier.dbg.obj: $(SRCDIR)/llvm-codegen-shared.h $(BUILDDIR)/llvm-julia-licm.o $(BUILDDIR)/llvm-julia-licm.dbg.obj: $(SRCDIR)/llvm-codegen-shared.h $(SRCDIR)/llvm-alloc-helpers.h $(SRCDIR)/llvm-pass-helpers.h $(BUILDDIR)/llvm-late-gc-lowering.o $(BUILDDIR)/llvm-late-gc-lowering.dbg.obj: $(SRCDIR)/llvm-gc-interface-passes.h -$(BUILDDIR)/llvm-lower-handlers.o $(BUILDDIR)/llvm-lower-handlers.dbg.obj: $(SRCDIR)/llvm-codegen-shared.h $(BUILDDIR)/llvm-multiversioning.o $(BUILDDIR)/llvm-multiversioning.dbg.obj: $(SRCDIR)/llvm-codegen-shared.h $(SRCDIR)/processor.h $(BUILDDIR)/llvm-pass-helpers.o $(BUILDDIR)/llvm-pass-helpers.dbg.obj: $(SRCDIR)/llvm-pass-helpers.h $(SRCDIR)/llvm-codegen-shared.h $(BUILDDIR)/llvm-propagate-addrspaces.o $(BUILDDIR)/llvm-propagate-addrspaces.dbg.obj: $(SRCDIR)/llvm-codegen-shared.h diff --git a/src/codegen.cpp b/src/codegen.cpp index 73c083e1cac2c..025bb7c792443 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1464,17 +1464,6 @@ static const auto gc_preserve_end_func = new JuliaFunction<> { [](LLVMContext &C) { return FunctionType::get(getVoidTy(C), {Type::getTokenTy(C)}, false); }, nullptr, }; -static const auto except_enter_func = new JuliaFunction<>{ - "julia.except_enter", - [](LLVMContext &C) { - auto T_pjlvalue = JuliaType::get_pjlvalue_ty(C); - auto RT = StructType::get(getInt32Ty(C), getPointerTy(C)); - return FunctionType::get(RT, {T_pjlvalue}, false); }, - [](LLVMContext &C) { return AttributeList::get(C, - Attributes(C, {Attribute::ReturnsTwice}), - AttributeSet(), - None); }, -}; static const auto pointer_from_objref_func = new JuliaFunction<>{ "julia.pointer_from_objref", [](LLVMContext &C) { return FunctionType::get(JuliaType::get_pjlvalue_ty(C), @@ -1931,6 +1920,7 @@ class jl_codectx_t { SmallVector slots; std::map phic_slots; std::map > scope_restore; + std::map eh_buffers; SmallVector SAvalues; SmallVector, jl_value_t *>, 0> PhiNodes; SmallVector ssavalue_assigned; @@ -6561,8 +6551,8 @@ static void emit_stmtpos(jl_codectx_t &ctx, jl_value_t *expr, int ssaval_result) return; } else if (head == jl_leave_sym) { - int hand_n_leave = 0; Value *scope_to_restore = nullptr, *token = nullptr; + SmallVector handler_to_end; for (size_t i = 0; i < jl_expr_nargs(ex); ++i) { jl_value_t *arg = args[i]; if (arg == jl_nothing) @@ -6588,13 +6578,18 @@ static void emit_stmtpos(jl_codectx_t &ctx, jl_value_t *expr, int ssaval_result) ctx.builder.CreateCall(prepare_call(gc_preserve_end_func), {token}); } if (jl_enternode_catch_dest(enter_stmt)) { + handler_to_end.push_back(ctx.eh_buffers[enter_stmt]); // We're not actually setting up the exception frames for these, so // we don't need to exit them. - hand_n_leave += 1; scope_to_restore = nullptr; // restored by exception handler } } - ctx.builder.CreateCall(prepare_call(jlleave_noexcept_func), {get_current_task(ctx), ConstantInt::get(getInt32Ty(ctx.builder.getContext()), hand_n_leave)}); + ctx.builder.CreateCall(prepare_call(jlleave_noexcept_func), {get_current_task(ctx), ConstantInt::get(getInt32Ty(ctx.builder.getContext()), handler_to_end.size())}); + auto *handler_sz64 = ConstantInt::get(Type::getInt64Ty(ctx.builder.getContext()), + sizeof(jl_handler_t)); + for (AllocaInst *handler : handler_to_end) { + ctx.builder.CreateLifetimeEnd(handler, handler_sz64); + } if (scope_to_restore) { Value *scope_ptr = get_scope_field(ctx); jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe).decorateInst( @@ -9759,13 +9754,22 @@ static jl_llvm_functions_t ctx.ssavalue_assigned[cursor] = true; // Actually enter the exception frame auto ct = get_current_task(ctx); - CallInst *sj = ctx.builder.CreateCall(prepare_call(except_enter_func), {ct}); + auto *handler_sz64 = ConstantInt::get(Type::getInt64Ty(ctx.builder.getContext()), + sizeof(jl_handler_t)); + AllocaInst* ehbuff = emit_static_alloca(ctx, sizeof(jl_handler_t), Align(16)); + ctx.eh_buffers[stmt] = ehbuff; + ctx.builder.CreateLifetimeStart(ehbuff, handler_sz64); + ctx.builder.CreateCall(prepare_call(jlenter_func), {ct, ehbuff}); + CallInst *sj; + if (ctx.emission_context.TargetTriple.isOSWindows()) + sj = ctx.builder.CreateCall(prepare_call(setjmp_func), {ehbuff}); + else + sj = ctx.builder.CreateCall(prepare_call(setjmp_func), {ehbuff, ConstantInt::get(Type::getInt32Ty(ctx.builder.getContext()), 0)}); // We need to mark this on the call site as well. See issue #6757 sj->setCanReturnTwice(); - Value *isz = ctx.builder.CreateICmpEQ(ctx.builder.CreateExtractValue(sj, 0), ConstantInt::get(getInt32Ty(ctx.builder.getContext()), 0)); - Value *ehbuf = ctx.builder.CreateExtractValue(sj, 1); + Value *isz = ctx.builder.CreateICmpEQ(sj, ConstantInt::get(getInt32Ty(ctx.builder.getContext()), 0)); BasicBlock *tryblk = BasicBlock::Create(ctx.builder.getContext(), "try", f); - BasicBlock *catchpop = BasicBlock::Create(ctx.builder.getContext(), "catch_pop", f); + BasicBlock *catchpop = BasicBlock::Create(ctx.builder.getContext(), "catch_enter", f); BasicBlock *handlr = NULL; handlr = BB[lname]; workstack.push_back(lname - 1); @@ -9774,11 +9778,12 @@ static jl_llvm_functions_t ctx.builder.SetInsertPoint(catchpop); { ctx.builder.CreateCall(prepare_call(jlleave_func), {get_current_task(ctx), ConstantInt::get(getInt32Ty(ctx.builder.getContext()), 1)}); + ctx.builder.CreateLifetimeEnd(ehbuff, handler_sz64); ctx.builder.CreateBr(handlr); } ctx.builder.SetInsertPoint(tryblk); auto ehptr = emit_ptrgep(ctx, ct, offsetof(jl_task_t, eh)); - ctx.builder.CreateAlignedStore(ehbuf, ehptr, ctx.types().alignof_ptr); + ctx.builder.CreateAlignedStore(ehbuff, ehptr, ctx.types().alignof_ptr); } // For the two-arg version of :enter, twiddle the scope if (jl_enternode_scope(stmt)) { @@ -10354,7 +10359,6 @@ static void init_jit_functions(void) add_named_global(gc_preserve_begin_func, (void*)NULL); add_named_global(gc_preserve_end_func, (void*)NULL); add_named_global(pointer_from_objref_func, (void*)NULL); - add_named_global(except_enter_func, (void*)NULL); add_named_global(julia_call, (void*)NULL); add_named_global(julia_call2, (void*)NULL); add_named_global(jllockvalue_func, &jl_lock_value); diff --git a/src/llvm-julia-passes.inc b/src/llvm-julia-passes.inc index 523c9fbcd3402..0cc36f799db00 100644 --- a/src/llvm-julia-passes.inc +++ b/src/llvm-julia-passes.inc @@ -14,7 +14,6 @@ FUNCTION_PASS("DemoteFloat16", DemoteFloat16Pass()) FUNCTION_PASS("LateLowerGCFrame", LateLowerGCPass()) FUNCTION_PASS("AllocOpt", AllocOptPass()) FUNCTION_PASS("PropagateJuliaAddrspaces", PropagateJuliaAddrspacesPass()) -FUNCTION_PASS("LowerExcHandlers", LowerExcHandlersPass()) FUNCTION_PASS("GCInvariantVerifier", GCInvariantVerifierPass()) FUNCTION_PASS("FinalLowerGC", FinalLowerGCPass()) #endif diff --git a/src/llvm-lower-handlers.cpp b/src/llvm-lower-handlers.cpp deleted file mode 100644 index c359bf6c117ce..0000000000000 --- a/src/llvm-lower-handlers.cpp +++ /dev/null @@ -1,257 +0,0 @@ -// This file is a part of Julia. License is MIT: https://julialang.org/license - -#include "llvm-version.h" -#include "passes.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "julia.h" -#include "julia_assert.h" -#include "llvm-codegen-shared.h" -#include - -#define DEBUG_TYPE "lower_handlers" -#undef DEBUG -STATISTIC(MaxExceptionHandlerDepth, "Maximum nesting of exception handlers"); -STATISTIC(ExceptionHandlerBuffers, "Number of exception handler buffers inserted"); - -using namespace llvm; - -/* Lowers Julia Exception Handlers and colors EH frames. - * - * Our task is to lower: - * call {i32, ptr} @julia.except_enter(ct) - * <...> - * call void jl_pop_handler(1) - * - * to - * - * call void @jl_enter_handler(ct, jl_handler *%buff) - * call i32 @jl_setjmp(jmpbuf[] %buff, 0) - * <...> - * call void jl_pop_handler(1) - * - * Where buff is an appropriate stack slot handler. - * - * We make the following assumptions: - * - All EH frames are completely nested. - * - The exception nestedness of a BB is not dynamic. I.e. we don't allow - * the following: - * br i1 %cond, %left, %right - * / \ - * except.enter br mid - * br mid | - * \ / - * br i1 %cond, %left2, %right2 - * / \ - * jl_pop_handler ret - * ret - * - * The frontend doesn't emit structures like this. However, the optimizer - * could easily introduce them, so this pass should run early after IRGen. - * - * Because of these assumptions, the algorithm is very simple. We simply label - * the handler depth at every basic block using a DFS search. For each enter - * we encounter, we record the current depth and then allocate an exception - * handler frame for every level. - * - * As an additional optimization, we also insert lifetime intrinsics for the - * handler structures to tell LLVM that it is free to re-use the stack slot - * while the handler is not being used. - */ - -namespace { -/* - * If the module doesn't have declarations for the jl_enter_handler and setjmp - * functions, insert them. - */ -static void ensure_enter_function(Module &M, Type *T_pjlvalue, const Triple &TT) -{ - auto T_ptr = PointerType::get(M.getContext(), 0); - auto T_void = Type::getVoidTy(M.getContext()); - auto T_int32 = Type::getInt32Ty(M.getContext()); - if (!M.getNamedValue(XSTR(jl_enter_handler))) { - Function::Create(FunctionType::get(T_void, {T_pjlvalue, T_ptr}, false), - Function::ExternalLinkage, XSTR(jl_enter_handler), &M); - } - if (!M.getNamedValue(jl_setjmp_name)) { - Type *args2[] = {T_ptr, T_int32}; - Function::Create(FunctionType::get(T_int32, ArrayRef(args2, TT.isOSWindows() ? 1 : 2), false), - Function::ExternalLinkage, jl_setjmp_name, &M) - ->addFnAttr(Attribute::ReturnsTwice); - } -} - -static bool lowerExcHandlers(Function &F) { - Module &M = *F.getParent(); - Triple TT(M.getTargetTriple()); - Function *except_enter_func = M.getFunction("julia.except_enter"); - if (!except_enter_func) - return false; // No EH frames in this module - ensure_enter_function(M, except_enter_func->getFunctionType()->getParamType(0), TT); - Function *leave_func = M.getFunction(XSTR(jl_pop_handler)); - Function *leave_noexcept_func = M.getFunction(XSTR(jl_pop_handler_noexcept)); - Function *jlenter_func = M.getFunction(XSTR(jl_enter_handler)); - Function *setjmp_func = M.getFunction(jl_setjmp_name); - auto T_ptr = PointerType::get(M.getContext(), 0); - Function *lifetime_start = Intrinsic::getDeclaration(&M, Intrinsic::lifetime_start, { T_ptr }); - Function *lifetime_end = Intrinsic::getDeclaration(&M, Intrinsic::lifetime_end, { T_ptr }); - - /* Step 1: EH Depth Numbering */ - std::map EnterDepth; - std::map LeaveDepth; - std::map ExitDepth; - int MaxDepth = 0; - // Compute EH Depth at each basic block using a DFS traversal. - for (df_iterator I = df_begin(&F.getEntryBlock()), - E = df_end(&F.getEntryBlock()); I != E; ++I) { - auto *BB = *I; - int Depth = 0; - /* Here we use the assumption that all incoming edges have the same - * EH depth. - */ - for (auto *Pred : predecessors(BB)) { - auto it = ExitDepth.find(Pred); - if (it != ExitDepth.end()) { - Depth = it->second; - break; - } - } - /* Compute the depth within the basic block */ - for (auto &I : *BB) { - auto *CI = dyn_cast(&I); - if (!CI) - continue; - Function *Callee = CI->getCalledFunction(); - if (!Callee) - continue; - if (Callee == except_enter_func) - EnterDepth[CI] = Depth++; - else if (Callee == leave_func || Callee == leave_noexcept_func) { - LeaveDepth[CI] = Depth; - Depth -= cast(CI->getArgOperand(1))->getLimitedValue(); - } - assert(Depth >= 0); - if (Depth > MaxDepth) - MaxDepth = Depth; - } - /* Remember the depth at the BB boundary */ - ExitDepth[BB] = Depth; - } - MaxExceptionHandlerDepth.updateMax(MaxDepth); - ExceptionHandlerBuffers += MaxDepth; - - /* Step 2: EH Frame lowering */ - // Allocate stack space for each handler. We allocate these as separate - // allocas so the optimizer can later merge and rearrange them if it wants - // to. - Value *handler_sz = ConstantInt::get(Type::getInt32Ty(F.getContext()), - sizeof(jl_handler_t)); - Value *handler_sz64 = ConstantInt::get(Type::getInt64Ty(F.getContext()), - sizeof(jl_handler_t)); - Instruction *firstInst = &F.getEntryBlock().front(); - SmallVector buffs; - unsigned allocaAddressSpace = F.getParent()->getDataLayout().getAllocaAddrSpace(); - for (int i = 0; i < MaxDepth; ++i) { - auto *buff = new AllocaInst(Type::getInt8Ty(F.getContext()), allocaAddressSpace, - handler_sz, Align(16), "", firstInst); - if (allocaAddressSpace) { - AddrSpaceCastInst *buff_casted = new AddrSpaceCastInst(buff, PointerType::get(F.getContext(), AddressSpace::Generic)); - buff_casted->insertAfter(buff); - buffs.push_back(buff_casted); - } else { - buffs.push_back(buff); - } - } - - // Lower enter funcs - for (auto it : EnterDepth) { - assert(it.second >= 0); - Instruction *buff = buffs[it.second]; - CallInst *enter = it.first; - auto new_enter = CallInst::Create(jlenter_func, {enter->getArgOperand(0), buff}, "", enter); - Value *lifetime_args[] = { - handler_sz64, - buff - }; - CallInst::Create(lifetime_start, lifetime_args, "", new_enter); - CallInst *sj; - if (!TT.isOSWindows()) { - sj = CallInst::Create(setjmp_func, {buff, ConstantInt::get(Type::getInt32Ty(F.getContext()), 0)}, "", enter); - } else { - sj = CallInst::Create(setjmp_func, buff, "", enter); - } - // We need to mark this on the call site as well. See issue #6757 - sj->setCanReturnTwice(); - if (auto dbg = enter->getMetadata(LLVMContext::MD_dbg)) { - new_enter->setMetadata(LLVMContext::MD_dbg, dbg); - sj->setMetadata(LLVMContext::MD_dbg, dbg); - } - SmallVector ToErase; - for (auto *U : enter->users()) { - if (auto *EEI = dyn_cast(U)) { - if (EEI->getNumIndices() == 1) { - if (EEI->getIndices()[0] == 0) - EEI->replaceAllUsesWith(sj); - else - EEI->replaceAllUsesWith(buff); - ToErase.push_back(EEI); - } - } - } - for (auto *EEI : ToErase) - EEI->eraseFromParent(); - if (!enter->use_empty()) { - Value *agg = InsertValueInst::Create(UndefValue::get(enter->getType()), sj, ArrayRef(0), "", enter); - agg = InsertValueInst::Create(agg, buff, ArrayRef(1), "", enter); - enter->replaceAllUsesWith(agg); - } - enter->eraseFromParent(); - } - // Insert lifetime end intrinsics after every leave. - for (auto it : LeaveDepth) { - int StartDepth = it.second - 1; - int npops = cast(it.first->getArgOperand(1))->getLimitedValue(); - for (int i = 0; i < npops; ++i) { - assert(StartDepth-i >= 0); - Value *lifetime_args[] = { - handler_sz64, - buffs[StartDepth-i] - }; - auto LifetimeEnd = CallInst::Create(lifetime_end, lifetime_args); - LifetimeEnd->insertAfter(it.first); - } - } - return true; -} - -} // anonymous namespace - -PreservedAnalyses LowerExcHandlersPass::run(Function &F, FunctionAnalysisManager &AM) -{ - bool modified = lowerExcHandlers(F); -#ifdef JL_VERIFY_PASSES - assert(!verifyLLVMIR(F)); -#endif - if (modified) { - return PreservedAnalyses::allInSet(); - } - return PreservedAnalyses::all(); -} diff --git a/src/passes.h b/src/passes.h index 4c9cba164d049..83721525d6f7e 100644 --- a/src/passes.h +++ b/src/passes.h @@ -29,10 +29,6 @@ struct PropagateJuliaAddrspacesPass : PassInfoMixin { - PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) JL_NOTSAFEPOINT; - static bool isRequired() { return true; } -}; struct GCInvariantVerifierPass : PassInfoMixin { bool Strong; diff --git a/src/pipeline.cpp b/src/pipeline.cpp index 39f896ba656d2..d0456844e92c6 100644 --- a/src/pipeline.cpp +++ b/src/pipeline.cpp @@ -514,7 +514,6 @@ static void buildIntrinsicLoweringPipeline(ModulePassManager &MPM, PassBuilder * //TODO barrier pass? { FunctionPassManager FPM; - JULIA_PASS(FPM.addPass(LowerExcHandlersPass())); JULIA_PASS(FPM.addPass(GCInvariantVerifierPass(false))); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } diff --git a/test/llvmpasses/lower-handlers-addrspaces.ll b/test/llvmpasses/lower-handlers-addrspaces.ll deleted file mode 100644 index ce3bdc6401b91..0000000000000 --- a/test/llvmpasses/lower-handlers-addrspaces.ll +++ /dev/null @@ -1,32 +0,0 @@ -; This file is a part of Julia. License is MIT: https://julialang.org/license - -; RUN: opt --load-pass-plugin=libjulia-codegen%shlibext -passes='function(LowerExcHandlers)' -S %s | FileCheck %s - -target triple = "amdgcn-amd-amdhsa" -target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7-ni:10:11:12:13" - -attributes #1 = { returns_twice } -declare {i32, i8*} @julia.except_enter({}*) #1 -declare void @ijl_pop_handler({}*, i32) -declare i8**** @julia.ptls_states() -declare i8**** @julia.get_pgcstack() - -define void @simple() { -top: - %pgcstack = call i8**** @julia.get_pgcstack() -; CHECK: call void @llvm.lifetime.start -; CHECK: call void @ijl_enter_handler -; CHECK: setjmp - %rb = call {i32, i8*} @julia.except_enter({}* null) - %r = extractvalue {i32, i8*} %rb, 0 - %cmp = icmp eq i32 %r, 0 - br i1 %cmp, label %try, label %catch -try: - br label %after -catch: - br label %after -after: - call void @ijl_pop_handler({}* null, i32 1) -; CHECK: llvm.lifetime.end - ret void -} diff --git a/test/llvmpasses/lower-handlers.ll b/test/llvmpasses/lower-handlers.ll deleted file mode 100644 index 7f0648a1a8bf5..0000000000000 --- a/test/llvmpasses/lower-handlers.ll +++ /dev/null @@ -1,31 +0,0 @@ -; This file is a part of Julia. License is MIT: https://julialang.org/license - -; RUN: opt --load-pass-plugin=libjulia-codegen%shlibext -passes='function(LowerExcHandlers)' -S %s | FileCheck %s - -attributes #1 = { returns_twice } -declare {i32, i8*} @julia.except_enter({}*) #1 -declare void @ijl_pop_handler({}*, i32) -declare i8**** @julia.ptls_states() -declare i8**** @julia.get_pgcstack() - -define void @simple() { -top: - %pgcstack = call i8**** @julia.get_pgcstack() -; CHECK: call void @llvm.lifetime.start -; CHECK: call void @ijl_enter_handler -; CHECK: setjmp - %rb = call {i32, i8*} @julia.except_enter({}* null) - %r = extractvalue {i32, i8*} %rb, 0 - %b = extractvalue {i32, i8*} %rb, 1 - %cmp = icmp eq i32 %r, 0 - br i1 %cmp, label %try, label %catch -try: - %lcssa = phi {i32, i8*} [ %rb, %top ] - br label %after -catch: - br label %after -after: - call void @ijl_pop_handler({}* null, i32 1) -; CHECK: llvm.lifetime.end - ret void -} diff --git a/test/llvmpasses/parsing.ll b/test/llvmpasses/parsing.ll index b8aec5ee2fa71..6f9ed186a2dd0 100644 --- a/test/llvmpasses/parsing.ll +++ b/test/llvmpasses/parsing.ll @@ -1,6 +1,6 @@ ; COM: NewPM-only test, tests for ability to parse Julia passes -; RUN: opt --load-pass-plugin=libjulia-codegen%shlibext -passes='module(CPUFeatures,RemoveNI,JuliaMultiVersioning,RemoveJuliaAddrspaces,LowerPTLSPass,function(DemoteFloat16,LateLowerGCFrame,FinalLowerGC,AllocOpt,PropagateJuliaAddrspaces,LowerExcHandlers,GCInvariantVerifier,loop(LowerSIMDLoop,JuliaLICM),GCInvariantVerifier,GCInvariantVerifier),LowerPTLSPass,LowerPTLSPass,JuliaMultiVersioning,JuliaMultiVersioning)' -S %s -o /dev/null +; RUN: opt --load-pass-plugin=libjulia-codegen%shlibext -passes='module(CPUFeatures,RemoveNI,JuliaMultiVersioning,RemoveJuliaAddrspaces,LowerPTLSPass,function(DemoteFloat16,LateLowerGCFrame,FinalLowerGC,AllocOpt,PropagateJuliaAddrspaces,GCInvariantVerifier,loop(LowerSIMDLoop,JuliaLICM),GCInvariantVerifier,GCInvariantVerifier),LowerPTLSPass,LowerPTLSPass,JuliaMultiVersioning,JuliaMultiVersioning)' -S %s -o /dev/null ; RUN: opt --load-pass-plugin=libjulia-codegen%shlibext -passes="julia" -S %s -o /dev/null ; RUN: opt --load-pass-plugin=libjulia-codegen%shlibext -passes="julia" -S %s -o /dev/null ; RUN: opt --load-pass-plugin=libjulia-codegen%shlibext -passes="julia" -S %s -o /dev/null From 7ec984a738630d11ea976da5409553eafc4e75bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= <765740+giordano@users.noreply.github.com> Date: Tue, 11 Feb 2025 23:36:11 +0100 Subject: [PATCH 318/342] [OpenSSL_jll] Update to v3.0.16 (#57363) https://github.com/openssl/openssl/releases/tag/openssl-3.0.16 --- deps/checksums/openssl | 76 ++++++++++++++--------------- deps/openssl.version | 2 +- stdlib/OpenSSL_jll/Project.toml | 2 +- stdlib/OpenSSL_jll/test/runtests.jl | 2 +- 4 files changed, 41 insertions(+), 41 deletions(-) diff --git a/deps/checksums/openssl b/deps/checksums/openssl index c973f592861f3..134ad867cbd3f 100644 --- a/deps/checksums/openssl +++ b/deps/checksums/openssl @@ -1,38 +1,38 @@ -OpenSSL.v3.0.15+2.aarch64-apple-darwin.tar.gz/md5/d11d92e6530705e3d93925bbb4dfccff -OpenSSL.v3.0.15+2.aarch64-apple-darwin.tar.gz/sha512/e30d763d956f930c3dab961ef1b382385b78cbb2324ae7f5e943420b9178bc2b086d9877c2d2b41b30a92ca109d7832a2ae50f70547fcc9788e25889d8252ffc -OpenSSL.v3.0.15+2.aarch64-linux-gnu.tar.gz/md5/d29f0d3a35d592488ba3a8bbb0dc8d0e -OpenSSL.v3.0.15+2.aarch64-linux-gnu.tar.gz/sha512/67c527c1930b903d2fbb55df1bd3fc1b8394bc4fadd15dd8fb84e776bae8c448487c117492e22b9b014f823cc7fe709695f4064639066b10427b06355540e997 -OpenSSL.v3.0.15+2.aarch64-linux-musl.tar.gz/md5/4f5313f1f18e29585951e95372a7a0fe -OpenSSL.v3.0.15+2.aarch64-linux-musl.tar.gz/sha512/48007a1f6667d6aeb87cc7287723ed00e39fe2bc9c353ff33348442516f1a28961985cc4a29a2a8f76b3a7049bd955973562d7c6c4af43af884596def636f7f8 -OpenSSL.v3.0.15+2.aarch64-unknown-freebsd.tar.gz/md5/5b6041353197bb8f75b39ed8f58cf4e9 -OpenSSL.v3.0.15+2.aarch64-unknown-freebsd.tar.gz/sha512/9be617d51fdc167085887380e720e6baf8e1e180f455b297f44d0bc0862fd490f015b5292d952d4ad095750cde796cc7dac4f901389b73135cb399b3a9d378c1 -OpenSSL.v3.0.15+2.armv6l-linux-gnueabihf.tar.gz/md5/858f548a28e289153842226473138a3e -OpenSSL.v3.0.15+2.armv6l-linux-gnueabihf.tar.gz/sha512/f9385678fca65d1fb8d96756442518b16607a57a9b6d76991414b37dfc4e30a7e1eebe5f3977b088b491216af4a34f958b64fe95062ee9ae23a9212f46c4e923 -OpenSSL.v3.0.15+2.armv6l-linux-musleabihf.tar.gz/md5/c4e52ecb4f9e24d948724424f1070071 -OpenSSL.v3.0.15+2.armv6l-linux-musleabihf.tar.gz/sha512/12f9276c68049026f2741c7d97e62d24525e5e832911546e1ea3868362034e6384304d749730122edf828b8c5573084055d59cc0bd75bda32f000ce630837c2b -OpenSSL.v3.0.15+2.armv7l-linux-gnueabihf.tar.gz/md5/767d3f3047366ccd6e2aa275f80d9f6c -OpenSSL.v3.0.15+2.armv7l-linux-gnueabihf.tar.gz/sha512/17700fd33c221070a7dd2db79d045e102591b85e16b3d4099356fb6a8635aea297b5fcef91740f75c55344a12ed356772b3b85c0cc68627856093ceb53ea8eb3 -OpenSSL.v3.0.15+2.armv7l-linux-musleabihf.tar.gz/md5/3ef2385cb1fec9e2d3af2ba9385ac733 -OpenSSL.v3.0.15+2.armv7l-linux-musleabihf.tar.gz/sha512/6156e9431fa8269b8d037149271be6cca0b119be67be01cfd958dabf59cdd468ef2a5ebf885e5835585006efdedd29afc308076283d070d4ae743146b57cd2b1 -OpenSSL.v3.0.15+2.i686-linux-gnu.tar.gz/md5/e62992d214cec6b1970f9fbd04cb8ecd -OpenSSL.v3.0.15+2.i686-linux-gnu.tar.gz/sha512/dfdb3d2d1d5fed7bf1c322899d6138c81f0653350f4b918858dd51bf7bcc86d2d04de824533925fa5f8d366a5c18ee33ade883f50a538b657717f8a428be8c60 -OpenSSL.v3.0.15+2.i686-linux-musl.tar.gz/md5/186a6bb8055ce089ac0c9897bd2cd697 -OpenSSL.v3.0.15+2.i686-linux-musl.tar.gz/sha512/f3c8d608113e9b0e91dd6af697172a46892d4a66572e35e13ad394397291dded3042667c1ec4fafe051778e71ff56a876dc3e848a2b85cef9f925ef3969ab950 -OpenSSL.v3.0.15+2.i686-w64-mingw32.tar.gz/md5/b72b8e4883337e4bc90094dce86c8b8b -OpenSSL.v3.0.15+2.i686-w64-mingw32.tar.gz/sha512/3b5ddef15ca1463ab92ef5b88df36f8418c8c44ffb123a0922e55718ab317b5fe379994aba9a5e8ca112475043d5cf99b1574702cdb30de438f458ee06ac80ea -OpenSSL.v3.0.15+2.powerpc64le-linux-gnu.tar.gz/md5/da194ce6f37f34cc19cc78d25c9af5e2 -OpenSSL.v3.0.15+2.powerpc64le-linux-gnu.tar.gz/sha512/e256a9d9a0af8764de730419281aa4d3ee9f6146692ec9105a318d8301d8fda5cca82c6ef4d0d7b70d721992361771724b237ce26ef81f92c295f6056d5a7cdd -OpenSSL.v3.0.15+2.riscv64-linux-gnu.tar.gz/md5/86825ee5f83ec0c827d5c051fe1a3d41 -OpenSSL.v3.0.15+2.riscv64-linux-gnu.tar.gz/sha512/7db4ae2f0a9491ae484da5b8b0c3698d970ada91c83f9783c9e5bd92006f52dffa1a4c7fb282b63e34760199a97c52793040dc306ad0986970cfa233e29cb195 -OpenSSL.v3.0.15+2.x86_64-apple-darwin.tar.gz/md5/271cc359f5bc4718659044ad5ac7631d -OpenSSL.v3.0.15+2.x86_64-apple-darwin.tar.gz/sha512/10e7575dc4cce6c617c96e6f94dbfe3058aad696292d3fac4bde7c92623f2a849b7d10e35b156b7582294b3cf103d61b3ea73605f958ee4c9f8ff05b647939a7 -OpenSSL.v3.0.15+2.x86_64-linux-gnu.tar.gz/md5/5d045d93d632af9914bff551f67eed9b -OpenSSL.v3.0.15+2.x86_64-linux-gnu.tar.gz/sha512/240791382d9549be029e2d404bc0e962f9876ab0597bf20cf34c87fcfafc3d75ba9f223641287895f9aee8519a5a33293910ed6d67bc1424ff3513eedaa8b699 -OpenSSL.v3.0.15+2.x86_64-linux-musl.tar.gz/md5/bb2637babf3730ed1117f89cb8aab34a -OpenSSL.v3.0.15+2.x86_64-linux-musl.tar.gz/sha512/b847539acc00870f77b242eeccfcf16f590493b7deb0089fa3654026f4016d40f9595d3bbb21ab981e9decfde4321da71f162beb1837a158fd3a884375a86fee -OpenSSL.v3.0.15+2.x86_64-unknown-freebsd.tar.gz/md5/23b69e0256e6c86e026be3ade20aed5c -OpenSSL.v3.0.15+2.x86_64-unknown-freebsd.tar.gz/sha512/1b7da1e13d325c7776b8e1a63aaa334bd633bb10604f8bed5f5f6a81955268b3d11ad221a5dd181dbdc7ad27c35d5754e6875d36226003c2fd7da6cd91854de1 -OpenSSL.v3.0.15+2.x86_64-w64-mingw32.tar.gz/md5/73cf4138ab403b7c9f91368a030590f9 -OpenSSL.v3.0.15+2.x86_64-w64-mingw32.tar.gz/sha512/052bb52837c29b4b18a97df71a80ad77486bd6ccef6e2e57dfa68a02754180976dc0302a158886393ef13fe91904f963119b17429a4ecc6f8b6c80ff878df05d -openssl-3.0.15.tar.gz/md5/08f458c00fff496a52ef931c481045cd -openssl-3.0.15.tar.gz/sha512/acd80f2f7924d90c1416946a5c61eff461926ad60f4821bb6b08845ea18f8452fd5e88a2c2c5bd0d7590a792cb8341a3f3be042fd0a5b6c9c1b84a497c347bbf +OpenSSL.v3.0.16+0.aarch64-apple-darwin.tar.gz/md5/72c29fd0048b0fee44410cfb82ed6235 +OpenSSL.v3.0.16+0.aarch64-apple-darwin.tar.gz/sha512/a1d23c15c16d577e7f350004c3e3e8c9f14375ca31256f4e42dcd828b610eeea269eecac58e1c3449c99dcc80b7a8885bbbd39beb5d5ff85167d953c26c10d00 +OpenSSL.v3.0.16+0.aarch64-linux-gnu.tar.gz/md5/29bf1097dbe8ac0c42ffb0c1ff9234cf +OpenSSL.v3.0.16+0.aarch64-linux-gnu.tar.gz/sha512/b388a13fbfd416feb95bac4f2f4f47605ac8ad971551ec218a8822618cd6e127ad538782524fed5c5f75ab3caf5b86107598967993ae03516706efa6a3af1010 +OpenSSL.v3.0.16+0.aarch64-linux-musl.tar.gz/md5/971ba30a9e0be025433afe3b0aae6260 +OpenSSL.v3.0.16+0.aarch64-linux-musl.tar.gz/sha512/43b6bea8d3e0ab783ed2ec1140fb9054ef0cdd0ddd34e5e95fb36c7b1b72d7e988b2bb17c878c57b0721c44b7783b2db9d4fc614a63bb557b1c32088dd01d506 +OpenSSL.v3.0.16+0.aarch64-unknown-freebsd.tar.gz/md5/3a3d963e16c7efbacdaea9754db640e3 +OpenSSL.v3.0.16+0.aarch64-unknown-freebsd.tar.gz/sha512/7c3d0ed3a7f37e879e3b8f4c5c67cf2766b5e421fab273806a0412ba12ab4de421bce094713aeb3f6c3915260cb8d7fcb35e214344131e9a5b0081cb7bf0d5dc +OpenSSL.v3.0.16+0.armv6l-linux-gnueabihf.tar.gz/md5/c94d4882e57cb9d3688127f5f82331a5 +OpenSSL.v3.0.16+0.armv6l-linux-gnueabihf.tar.gz/sha512/b8133e873a960b125d0ab8ddd5b4071a6ab269e2b2f5b36e0d723e759875d21f734ac44f4baa4122bc6b94e23f0d82d401f16c88d9c70dac4031f07dcd20597a +OpenSSL.v3.0.16+0.armv6l-linux-musleabihf.tar.gz/md5/149aacf601e86ed15cd4305d035fb7b2 +OpenSSL.v3.0.16+0.armv6l-linux-musleabihf.tar.gz/sha512/dad7bade8fdf62c642ba1a8553f8a02218dbddd15040388b0a0eaac5391fb3c606860378c5dc40b16978c2f8f3837a1698788788d83006a4b312b1c6e73b2a53 +OpenSSL.v3.0.16+0.armv7l-linux-gnueabihf.tar.gz/md5/a1d45f34e463df42c2ea77d9084a4360 +OpenSSL.v3.0.16+0.armv7l-linux-gnueabihf.tar.gz/sha512/5f5ba285564b1ff1c5db3a2fe4d2051b9b17a77e6c6da37bc739f64051d64a5bff3968d5326760c102f9ddbc3509bf3eeb3ae267acfecbd0a55ff86ec90b5cb0 +OpenSSL.v3.0.16+0.armv7l-linux-musleabihf.tar.gz/md5/81ed6b1188a7ccda1768b67fdfc6e094 +OpenSSL.v3.0.16+0.armv7l-linux-musleabihf.tar.gz/sha512/2424620b462b5596e317e77ebc294377811ec1210c65baf4cd072b62f8d303aa77b2b4f799611ca91202dc371ea4575c2c13cb222e6edd809a036b639c1595c0 +OpenSSL.v3.0.16+0.i686-linux-gnu.tar.gz/md5/714bab6e53849d0bf6d9922be51871e2 +OpenSSL.v3.0.16+0.i686-linux-gnu.tar.gz/sha512/141102d20810986b75ba3b2b4446e4a260f4ae38583b7f8dd8a59b8e0ec8b2bac03ee83127b8f4cdb67bd8fd5ebbb102cb581ed182735283109ff85d049cc55b +OpenSSL.v3.0.16+0.i686-linux-musl.tar.gz/md5/e4f5f918c011d87626a0f830243324f9 +OpenSSL.v3.0.16+0.i686-linux-musl.tar.gz/sha512/128e6c29f0537818a68cbbd262a3735ee99ccca2377874c22978782abd43c3d0f9bd49d68c05d09f37293df52c238aa33d87244276eef080959aefe42fe8c92f +OpenSSL.v3.0.16+0.i686-w64-mingw32.tar.gz/md5/a68b80b7725887ef33ea36e7d19f7cd1 +OpenSSL.v3.0.16+0.i686-w64-mingw32.tar.gz/sha512/91aeb66c49f73eaa00114a61fc2b644e278bc39948f408806c66f61529ad98d3bc1f885152e1cc275a8374dde2d5ace3695e6f70eec718bacb0269560bce83b0 +OpenSSL.v3.0.16+0.powerpc64le-linux-gnu.tar.gz/md5/ec36f9b42c64ab4b1ce862229bc06924 +OpenSSL.v3.0.16+0.powerpc64le-linux-gnu.tar.gz/sha512/71470814b096ca9127fc2055b4ecc6e6acb30f03fe16754010c5c860f8d82cb37c2e723dca3f92f2aa2e9604fd1f4d141eca333d2c7524274e33d98da34326df +OpenSSL.v3.0.16+0.riscv64-linux-gnu.tar.gz/md5/5aecf142b6849b8c2cca957830d49f4e +OpenSSL.v3.0.16+0.riscv64-linux-gnu.tar.gz/sha512/d25879a4d6b8cc76c8fc4ed49b38d48938c80ba163e7ffe276bb86fdc4bb76cd596f150564bfa3bd88fa90451916a086ca04d31ba884bd978f40f57f0e4332f7 +OpenSSL.v3.0.16+0.x86_64-apple-darwin.tar.gz/md5/41c847ee490a5935fac8c4b663d8e325 +OpenSSL.v3.0.16+0.x86_64-apple-darwin.tar.gz/sha512/04979622fae5b24b0f0d79b0853ea311e872a7ca465c6e6700e713a34fa90a182ad78db8babacf322fb288cb62caed1a73f8d47e55fd2b074238191649e0141f +OpenSSL.v3.0.16+0.x86_64-linux-gnu.tar.gz/md5/b3c143deff5a311740ccc592a1a433e9 +OpenSSL.v3.0.16+0.x86_64-linux-gnu.tar.gz/sha512/31819e2e78dbd7aeb95b84664eac9ee29b0ec4e1b0bc9e06a4ea8f7cb65c21929414d9e4e3fa6ce15944bfd7fc68d699d4016cbe5ace16e98394a60fe369541f +OpenSSL.v3.0.16+0.x86_64-linux-musl.tar.gz/md5/bed866803232e6ada4e22eadfd2b98d1 +OpenSSL.v3.0.16+0.x86_64-linux-musl.tar.gz/sha512/ee6f26d150c81e30c93f08de5428d2f92e02e12565e6dcef09bbd1029ff5477bb2176b6cc7616a7cc898dfec8c5d8263108c3558460397c71ca90af8b230e0c1 +OpenSSL.v3.0.16+0.x86_64-unknown-freebsd.tar.gz/md5/ee6f11020b0ce6eac8016877d1635a04 +OpenSSL.v3.0.16+0.x86_64-unknown-freebsd.tar.gz/sha512/dd154fe1e8c537d42919c0889036ac79e181b765c87130edfeffd2ef8414da902995469167812664e6f77f3c89379c799d4311336f4233b05796b6823838e01c +OpenSSL.v3.0.16+0.x86_64-w64-mingw32.tar.gz/md5/d08f7d27c775eec9c7e4709d0898d60e +OpenSSL.v3.0.16+0.x86_64-w64-mingw32.tar.gz/sha512/4806c67ff8f629ee6b3a7c358146675310f0812772773aad7e30d0ccee0cc085741c06d252ed16bf8f874fe794d1b8291e0cbcd65c8eacb9e87c0a5f65742c5f +openssl-3.0.16.tar.gz/md5/7b6a9cded21b9fa51877444f5defebd4 +openssl-3.0.16.tar.gz/sha512/5eea2b0c60d870549fc2b8755f1220a57f870d95fbc8d5cc5abb9589f212d10945f355c3e88ff48540a7ee1c4db774b936023ca33d7c799ea82d91eef9c1c16d diff --git a/deps/openssl.version b/deps/openssl.version index 7253e063167db..48831039a313e 100644 --- a/deps/openssl.version +++ b/deps/openssl.version @@ -3,4 +3,4 @@ OPENSSL_JLL_NAME := OpenSSL ## source build -OPENSSL_VER := 3.0.15 +OPENSSL_VER := 3.0.16 diff --git a/stdlib/OpenSSL_jll/Project.toml b/stdlib/OpenSSL_jll/Project.toml index 0773311e11043..7c8067261c253 100644 --- a/stdlib/OpenSSL_jll/Project.toml +++ b/stdlib/OpenSSL_jll/Project.toml @@ -1,6 +1,6 @@ name = "OpenSSL_jll" uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" -version = "3.0.15+2" +version = "3.0.16+0" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" diff --git a/stdlib/OpenSSL_jll/test/runtests.jl b/stdlib/OpenSSL_jll/test/runtests.jl index 35431d04bfcac..8bf67288834c9 100644 --- a/stdlib/OpenSSL_jll/test/runtests.jl +++ b/stdlib/OpenSSL_jll/test/runtests.jl @@ -6,5 +6,5 @@ using Test, Libdl, OpenSSL_jll major = ccall((:OPENSSL_version_major, libcrypto), Cuint, ()) minor = ccall((:OPENSSL_version_minor, libcrypto), Cuint, ()) patch = ccall((:OPENSSL_version_patch, libcrypto), Cuint, ()) - @test VersionNumber(major, minor, patch) == v"3.0.15" + @test VersionNumber(major, minor, patch) == v"3.0.16" end From c46b5334547293fdc93fb9b5116d061bb84e9d0c Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Tue, 11 Feb 2025 23:47:09 +0100 Subject: [PATCH 319/342] use an empty symbol instead of module name as placeholder for module `file` metadata (#57359) Based on the discussion in https://github.com/JuliaLang/julia/pull/55963#discussion_r1786421289 --- src/module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/module.c b/src/module.c index 402a86dfd4aef..7fb2af14ef271 100644 --- a/src/module.c +++ b/src/module.c @@ -229,7 +229,7 @@ JL_DLLEXPORT jl_module_t *jl_new_module_(jl_sym_t *name, jl_module_t *parent, ui m->compile = -1; m->infer = -1; m->max_methods = -1; - m->file = name; // Using the name as a placeholder is better than nothing + m->file = jl_empty_sym; m->line = 0; m->hash = parent == NULL ? bitmix(name->hash, jl_module_type->hash) : bitmix(name->hash, parent->hash); From 866c61de6ed976eb32d82e51ffdaf1b00931bec6 Mon Sep 17 00:00:00 2001 From: Neven Sajko <4944410+nsajko@users.noreply.github.com> Date: Wed, 12 Feb 2025 00:02:40 +0100 Subject: [PATCH 320/342] don't taint `:terminates` because of the loop in `afoldl` (#57353) The iteration count is always finite. --- base/operators.jl | 1 + test/operators.jl | 1 + 2 files changed, 2 insertions(+) diff --git a/base/operators.jl b/base/operators.jl index d01902e302359..452a7b043774d 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -593,6 +593,7 @@ const ⊽ = nor # method count limit in inference afoldl(op, a) = a function afoldl(op, a, bs...) + @_terminates_locally_meta l = length(bs) i = 0; y = a; l == i && return y #@nexprs 31 i -> (y = op(y, bs[i]); l == i && return y) diff --git a/test/operators.jl b/test/operators.jl index 2e22238c3e9d9..366820eebe28a 100644 --- a/test/operators.jl +++ b/test/operators.jl @@ -350,6 +350,7 @@ end end @test [Base.afoldl(+, 1:i...) for i = 1:40] == [i * (i + 1) ÷ 2 for i = 1:40] +@test Core.Compiler.is_terminates(Base.infer_effects(Base.afoldl, Tuple{typeof(+), Vararg{Int, 100}})) @testset "Returns" begin @test @inferred(Returns(1)() ) === 1 From 796a849d11e5a5b72df327e005dac6ff84307b65 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Tue, 11 Feb 2025 21:14:04 -0500 Subject: [PATCH 321/342] Bump Documenter to v1.8.1 (#57362) This should get fix the binding world-age warnings in our `doctest` CI --- doc/Manifest.toml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/Manifest.toml b/doc/Manifest.toml index 481b7240c0caf..05dd8edebe5a6 100644 --- a/doc/Manifest.toml +++ b/doc/Manifest.toml @@ -45,9 +45,9 @@ version = "0.9.3" [[deps.Documenter]] deps = ["ANSIColoredPrinters", "AbstractTrees", "Base64", "CodecZlib", "Dates", "DocStringExtensions", "Downloads", "Git", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "MarkdownAST", "Pkg", "PrecompileTools", "REPL", "RegistryInstances", "SHA", "TOML", "Test", "Unicode"] -git-tree-sha1 = "d0ea2c044963ed6f37703cead7e29f70cba13d7e" +git-tree-sha1 = "182a9a3fe886587ba230a417f1651a4cbc2b92d4" uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" -version = "1.8.0" +version = "1.8.1" [[deps.Downloads]] deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] @@ -117,7 +117,7 @@ version = "0.6.4" [[deps.LibCURL_jll]] deps = ["Artifacts", "LibSSH2_jll", "Libdl", "OpenSSL_jll", "Zlib_jll", "nghttp2_jll"] uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" -version = "8.9.1+0" +version = "8.11.1+1" [[deps.LibGit2]] deps = ["LibGit2_jll", "NetworkOptions", "Printf", "SHA"] @@ -127,12 +127,12 @@ version = "1.11.0" [[deps.LibGit2_jll]] deps = ["Artifacts", "LibSSH2_jll", "Libdl", "OpenSSL_jll"] uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" -version = "1.8.4+0" +version = "1.9.0+0" [[deps.LibSSH2_jll]] deps = ["Artifacts", "Libdl", "OpenSSL_jll"] uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" -version = "1.11.3+0" +version = "1.11.3+1" [[deps.Libdl]] uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" @@ -165,21 +165,21 @@ version = "1.11.0" [[deps.MozillaCACerts_jll]] uuid = "14a3606d-f60d-562e-9121-12d972cd8159" -version = "2024.3.11" +version = "2024.12.31" [[deps.NetworkOptions]] uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" -version = "1.2.0" +version = "1.3.0" [[deps.OpenSSL_jll]] -deps = ["Artifacts", "Libdl", "NetworkOptions"] +deps = ["Artifacts", "Libdl"] uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" -version = "3.0.15+1" +version = "3.0.15+2" [[deps.PCRE2_jll]] deps = ["Artifacts", "Libdl"] uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15" -version = "10.43.0+1" +version = "10.44.0+1" [[deps.Parsers]] deps = ["Dates", "PrecompileTools", "UUIDs"] @@ -277,14 +277,14 @@ version = "1.11.0" [[deps.Zlib_jll]] deps = ["Libdl"] uuid = "83775a58-1f1d-513f-b197-d71354ab007a" -version = "1.3.1+1" +version = "1.3.1+2" [[deps.nghttp2_jll]] deps = ["Artifacts", "Libdl"] uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" -version = "1.63.0+1" +version = "1.64.0+1" [[deps.p7zip_jll]] deps = ["Artifacts", "Libdl"] uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" -version = "17.5.0+1" +version = "17.5.0+2" From 9339dea0426c5416e97b9a4bf2a2b52bb678ad91 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Wed, 12 Feb 2025 13:11:04 +0100 Subject: [PATCH 322/342] update path to Compiler stdlib to a valid one similar to how it is done for other stdlibs (#57274) Fixes #56865. The Compiler "stdlib" resides in a different location so the current logic didn't handle updating it. --- base/methodshow.jl | 14 +++++++++----- stdlib/InteractiveUtils/test/runtests.jl | 4 ++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/base/methodshow.jl b/base/methodshow.jl index a2158cb9180e4..7fdefc9b7311f 100644 --- a/base/methodshow.jl +++ b/base/methodshow.jl @@ -131,13 +131,17 @@ function fixup_stdlib_path(path::String) # The file defining Base.Sys gets included after this file is included so make sure # this function is valid even in this intermediary state if isdefined(@__MODULE__, :Sys) - BUILD_STDLIB_PATH = Sys.BUILD_STDLIB_PATH::String - STDLIB = Sys.STDLIB::String - if BUILD_STDLIB_PATH != STDLIB + if Sys.BUILD_STDLIB_PATH != Sys.STDLIB # BUILD_STDLIB_PATH gets defined in sysinfo.jl npath = normpath(path) - npath′ = replace(npath, normpath(BUILD_STDLIB_PATH) => normpath(STDLIB)) - return npath == npath′ ? path : npath′ + npath′ = replace(npath, normpath(Sys.BUILD_STDLIB_PATH) => normpath(Sys.STDLIB)) + path = npath == npath′ ? path : npath′ + end + if isdefined(@__MODULE__, :Core) && isdefined(Core, :Compiler) + compiler_folder = dirname(String(Base.moduleloc(Core.Compiler).file)) + if dirname(path) == compiler_folder + return abspath(Sys.STDLIB, "..", "..", "Compiler", "src", basename(path)) + end end end return path diff --git a/stdlib/InteractiveUtils/test/runtests.jl b/stdlib/InteractiveUtils/test/runtests.jl index 0de67fea69dea..739ed5fac9ef2 100644 --- a/stdlib/InteractiveUtils/test/runtests.jl +++ b/stdlib/InteractiveUtils/test/runtests.jl @@ -658,6 +658,10 @@ file, ln = functionloc(versioninfo, Tuple{}) @test isfile(pathof(InteractiveUtils)) @test isdir(pkgdir(InteractiveUtils)) +# compiler stdlib path updating +file, ln = functionloc(Core.Compiler.tmeet, Tuple{Int, Float64}) +@test isfile(file) + @testset "buildbot path updating" begin file, ln = functionloc(versioninfo, Tuple{}) @test isfile(file) From 6dca4f4eda08df9cff9626dba8cb9539818b28f8 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Wed, 12 Feb 2025 07:12:00 -0500 Subject: [PATCH 323/342] cconvert(Ref{BigFloat}, x) should return BigFloatData (#57367) #55906 changed `cconvert(Ref{BigFloat}, x::BigFloat)` to return `x.d`, but neglected to do so for other types of `x`, where it still returns a `Ref{BigFloat}` and hence is now returning the wrong type for `ccall`. Not only does this break backwards compatibility (https://github.com/JuliaMath/SpecialFunctions.jl/issues/485), but it also seems simply wrong: the *whole* job of `cconvert` is to convert objects to the correct type for use with `ccall`. This PR does so (at least for `Number` and `Ref{BigFloat}`). --- base/mpfr.jl | 2 ++ test/mpfr.jl | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/base/mpfr.jl b/base/mpfr.jl index e8380577190aa..0d52510447b2f 100644 --- a/base/mpfr.jl +++ b/base/mpfr.jl @@ -214,6 +214,8 @@ end Base.unsafe_convert(::Type{Ref{BigFloat}}, x::Ptr{BigFloat}) = error("not compatible with mpfr") Base.unsafe_convert(::Type{Ref{BigFloat}}, x::Ref{BigFloat}) = error("not compatible with mpfr") Base.cconvert(::Type{Ref{BigFloat}}, x::BigFloat) = x.d # BigFloatData is the Ref type for BigFloat +Base.cconvert(::Type{Ref{BigFloat}}, x::Number) = convert(BigFloat, x).d # avoid default conversion to Ref(BigFloat(x)) +Base.cconvert(::Type{Ref{BigFloat}}, x::Ref{BigFloat}) = x[].d function Base.unsafe_convert(::Type{Ref{BigFloat}}, x::BigFloatData) d = getfield(x, :d) p = Base.unsafe_convert(Ptr{Limb}, d) diff --git a/test/mpfr.jl b/test/mpfr.jl index c212bdfc92821..3bb8768b280d5 100644 --- a/test/mpfr.jl +++ b/test/mpfr.jl @@ -1097,3 +1097,10 @@ end end end end + +# BigFloatData is the Ref type for BigFloat in ccall: +@testset "cconvert(Ref{BigFloat}, x)" begin + for x in (1.0, big"1.0", Ref(big"1.0")) + @test Base.cconvert(Ref{BigFloat}, x) isa Base.MPFR.BigFloatData + end +end From 3f2eed34c4831a364c79817d8a9582e91dec4bc6 Mon Sep 17 00:00:00 2001 From: michele_mattiello <60945256+mikymatt01@users.noreply.github.com> Date: Wed, 12 Feb 2025 19:23:24 +0100 Subject: [PATCH 324/342] Refactored get function to use ternary operator for cleaner syntax (#57371) --- base/strings/basic.jl | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/base/strings/basic.jl b/base/strings/basic.jl index 3f26aed736b8d..6c93ff881e6aa 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -196,12 +196,7 @@ getindex(s::AbstractString, v::AbstractVector{Bool}) = throw(ArgumentError("logical indexing not supported for strings")) function get(s::AbstractString, i::Integer, default) -# TODO: use ternary once @inbounds is expression-like - if checkbounds(Bool, s, i) - @inbounds return s[i] - else - return default - end + checkbounds(Bool, s, i) ? (@inbounds s[i]) : default end ## bounds checking ## From 512eb5e2c9202562321096c26c9b4fe5c6ac48f6 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Wed, 12 Feb 2025 15:30:47 -0500 Subject: [PATCH 325/342] lowering: Only try to define the method once (#57346) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before: ``` :($(Expr(:thunk, CodeInfo( 1 ─ $(Expr(:thunk, CodeInfo( 1 ─ return $(Expr(:method, :(Main.f))) ))) │ $(Expr(:method, :(Main.f))) │ %3 = Main.f │ %4 = dynamic Core.Typeof(%3) │ %5 = builtin Core.svec(%4, Core.Any) │ %6 = builtin Core.svec() │ %7 = builtin Core.svec(%5, %6, $(QuoteNode(:(#= REPL[2]:1 =#)))) │ $(Expr(:method, :(Main.f), :(%7), CodeInfo( 1 ─ return 1 ))) │ $(Expr(:latestworld)) │ %10 = Main.f └── return %10 )))) ``` After: ``` julia> @Meta.lower f(x)=1 :($(Expr(:thunk, CodeInfo( 1 ─ $(Expr(:method, :(Main.f))) │ $(Expr(:latestworld)) │ Main.f │ $(Expr(:latestworld)) │ %5 = Main.f │ %6 = dynamic Core.Typeof(%5) │ %7 = builtin Core.svec(%6, Core.Any) │ %8 = builtin Core.svec() │ %9 = builtin Core.svec(%7, %8, $(QuoteNode(:(#= REPL[1]:1 =#)))) │ $(Expr(:method, :(Main.f), :(%9), CodeInfo( 1 ─ return 1 ))) │ $(Expr(:latestworld)) │ %12 = Main.f └── return %12 )))) ``` This doesn't really make a semantic difference, but if `f` is a type, we may now give a warning, so the prior definition would give the warning twice (https://github.com/JuliaLang/julia/pull/57311#issuecomment-2648045510). We may want to consider rate-limiting the warning independently, but for now at least give the correct number of warnings. --- doc/src/manual/modules.md | 2 -- src/julia-syntax.scm | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/src/manual/modules.md b/doc/src/manual/modules.md index cf24474916bef..b4d1cde9527be 100644 --- a/doc/src/manual/modules.md +++ b/doc/src/manual/modules.md @@ -192,8 +192,6 @@ julia> nice(::Cat) = "nice 😸" ERROR: invalid method definition in Main: function NiceStuff.nice must be explicitly imported to be extended Stacktrace: [1] top-level scope - @ none:0 - [2] top-level scope @ none:1 ``` diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 035d2a84e729d..00057498bbf9b 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -4131,8 +4131,9 @@ f(x) = yt(x) `(toplevel-butfirst ;; wrap in toplevel-butfirst so it gets moved higher along with ;; closure type definitions + (unnecessary ,(cadr e)) ,e - (thunk (lambda () (() () 0 ()) (block (return ,e)))))))) + (latestworld))))) ((null? cvs) `(block ,@sp-inits From 17fff87f583c2fd0bbb85b63d76e5b9be634f2bd Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Wed, 12 Feb 2025 18:23:41 -0300 Subject: [PATCH 326/342] Respect JULIA_CPU_TARGET when doing trimming (#57373) We could make this have a nicer API but for now lets just do what we've done for pkgimages/sysimages and use the envar --- contrib/juliac.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contrib/juliac.jl b/contrib/juliac.jl index 8b413fccd6231..6639eb2871d2d 100644 --- a/contrib/juliac.jl +++ b/contrib/juliac.jl @@ -6,6 +6,8 @@ module JuliaConfig end julia_cmd = `$(Base.julia_cmd()) --startup-file=no --history-file=no` +cpu_target = get(ENV, "JULIA_CPU_TARGET", nothing) +julia_cmd_target = `$(Base.julia_cmd(;cpu_target)) --startup-file=no --history-file=no` output_type = nothing # exe, sharedlib, sysimage outname = nothing file = nothing @@ -102,7 +104,7 @@ end function compile_products() # Compile the Julia code - cmd = addenv(`$julia_cmd --project=$(Base.active_project()) --output-o $img_path --output-incremental=no --strip-ir --strip-metadata $julia_args $(joinpath(@__DIR__,"juliac-buildscript.jl")) $absfile $output_type $add_ccallables`, "OPENBLAS_NUM_THREADS" => 1, "JULIA_NUM_THREADS" => 1) + cmd = addenv(`$julia_cmd_target --project=$(Base.active_project()) --output-o $img_path --output-incremental=no --strip-ir --strip-metadata $julia_args $(joinpath(@__DIR__,"juliac-buildscript.jl")) $absfile $output_type $add_ccallables`, "OPENBLAS_NUM_THREADS" => 1, "JULIA_NUM_THREADS" => 1) verbose && println("Running: $cmd") if !success(pipeline(cmd; stdout, stderr)) println(stderr, "\nFailed to compile $file") From 90046a055f39a0f1077d5073b6be47a33494ef49 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Wed, 12 Feb 2025 18:01:06 -0500 Subject: [PATCH 327/342] bpart: When backdating replace the entire bpart chain (#57341) Rather than rewriting the `restriction` of the bparts. With this, I believe this removes that last point where `restriction` is overwritten after construction, hopefully allowing us to go back to the original design where `restriction` is `const` after construction. --- src/module.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/toplevel.c | 76 ------------------------------------------------- 2 files changed, 75 insertions(+), 78 deletions(-) diff --git a/src/module.c b/src/module.c index 7fb2af14ef271..dafcbcbceaab2 100644 --- a/src/module.c +++ b/src/module.c @@ -248,6 +248,80 @@ JL_DLLEXPORT jl_module_t *jl_new_module_(jl_sym_t *name, jl_module_t *parent, ui return m; } +// Precondition: world_counter_lock is held +JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val3( + jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *val, + enum jl_partition_kind constant_kind, size_t new_world) +{ + JL_GC_PUSH1(&val); + if (!b) { + b = jl_get_module_binding(mod, var, 1); + } + jl_binding_partition_t *new_bpart = NULL; + jl_binding_partition_t *bpart = jl_get_binding_partition(b, new_world); + jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); + while (!new_bpart) { + enum jl_partition_kind kind = decode_restriction_kind(pku); + if (jl_bkind_is_some_constant(kind)) { + if (!val) { + new_bpart = bpart; + break; + } + jl_value_t *old = decode_restriction_value(pku); + JL_GC_PROMISE_ROOTED(old); + if (jl_egal(val, old)) { + new_bpart = bpart; + break; + } + } else if (jl_bkind_is_some_import(kind) && kind != BINDING_KIND_IMPLICIT) { + jl_errorf("cannot declare %s.%s constant; it was already declared as an import", + jl_symbol_name(mod->name), jl_symbol_name(var)); + } else if (kind == BINDING_KIND_GLOBAL) { + jl_errorf("cannot declare %s.%s constant; it was already declared global", + jl_symbol_name(mod->name), jl_symbol_name(var)); + } + if (bpart->min_world == new_world) { + if (!jl_atomic_cmpswap(&bpart->restriction, &pku, encode_restriction(val, constant_kind))) { + continue; + } else if (val) { + jl_gc_wb(bpart, val); + } + new_bpart = bpart; + } else { + new_bpart = jl_replace_binding_locked(b, bpart, val, constant_kind, new_world); + } + int need_backdate = new_world && val; + if (need_backdate) { + // We will backdate as long as this partition was never explicitly + // declared const, global, or imported. + jl_binding_partition_t *prev_bpart = bpart; + for (;;) { + jl_ptr_kind_union_t prev_pku = jl_atomic_load_relaxed(&prev_bpart->restriction); + enum jl_partition_kind prev_kind = decode_restriction_kind(prev_pku); + if (jl_bkind_is_some_constant(prev_kind) || prev_kind == BINDING_KIND_GLOBAL || + (jl_bkind_is_some_import(prev_kind))) { + need_backdate = 0; + break; + } + if (prev_bpart->min_world == 0) + break; + prev_bpart = jl_get_binding_partition(b, prev_bpart->min_world - 1); + } + } + // If backdate is required, create one new binding partition to cover + // the entire backdate range. + if (need_backdate) { + jl_binding_partition_t *backdate_bpart = new_binding_partition(); + jl_atomic_store_relaxed(&backdate_bpart->restriction, encode_restriction(val, BINDING_KIND_BACKDATED_CONST)); + jl_atomic_store_relaxed(&backdate_bpart->max_world, new_world - 1); + jl_atomic_store_release(&new_bpart->next, backdate_bpart); + jl_gc_wb(new_bpart, backdate_bpart); + } + } + JL_GC_POP(); + return new_bpart; +} + JL_DLLEXPORT jl_module_t *jl_new_module(jl_sym_t *name, jl_module_t *parent) { return jl_new_module_(name, parent, 1); @@ -1171,7 +1245,7 @@ JL_DLLEXPORT jl_binding_partition_t *jl_replace_binding_locked(jl_binding_t *b, new_bpart->min_world = new_world; if (kind == BINDING_KIND_IMPLICIT_RECOMPUTE) { assert(!restriction_val); - jl_check_new_binding_implicit(new_bpart, b, NULL, new_world); + jl_check_new_binding_implicit(new_bpart /* callee rooted */, b, NULL, new_world); } else jl_atomic_store_relaxed(&new_bpart->restriction, encode_restriction(restriction_val, kind)); @@ -1181,7 +1255,6 @@ JL_DLLEXPORT jl_binding_partition_t *jl_replace_binding_locked(jl_binding_t *b, jl_atomic_store_release(&b->partitions, new_bpart); jl_gc_wb(b, new_bpart); - if (jl_typeinf_world != 1) { jl_task_t *ct = jl_current_task; size_t last_world = ct->world_age; diff --git a/src/toplevel.c b/src/toplevel.c index 321ef8c79dac0..904b7c15afcde 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -754,82 +754,6 @@ static void jl_eval_errorf(jl_module_t *m, const char *filename, int lineno, con JL_GC_POP(); } -JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val3( - jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *val, - enum jl_partition_kind constant_kind, size_t new_world) -{ - JL_GC_PUSH1(&val); - if (!b) { - b = jl_get_module_binding(mod, var, 1); - } - jl_binding_partition_t *new_bpart = NULL; - jl_binding_partition_t *bpart = jl_get_binding_partition(b, new_world); - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - while (!new_bpart) { - enum jl_partition_kind kind = decode_restriction_kind(pku); - if (jl_bkind_is_some_constant(kind)) { - if (!val) { - new_bpart = bpart; - break; - } - jl_value_t *old = decode_restriction_value(pku); - JL_GC_PROMISE_ROOTED(old); - if (jl_egal(val, old)) { - new_bpart = bpart; - break; - } - } else if (jl_bkind_is_some_import(kind) && kind != BINDING_KIND_IMPLICIT) { - jl_errorf("cannot declare %s.%s constant; it was already declared as an import", - jl_symbol_name(mod->name), jl_symbol_name(var)); - } else if (kind == BINDING_KIND_GLOBAL) { - jl_errorf("cannot declare %s.%s constant; it was already declared global", - jl_symbol_name(mod->name), jl_symbol_name(var)); - } - if (bpart->min_world == new_world) { - if (!jl_atomic_cmpswap(&bpart->restriction, &pku, encode_restriction(val, constant_kind))) { - continue; - } - jl_gc_wb(bpart, val); - new_bpart = bpart; - } else { - new_bpart = jl_replace_binding_locked(b, bpart, val, constant_kind, new_world); - } - int need_backdate = new_world && val; - if (need_backdate) { - // We will backdate as long as this partition was never explicitly - // declared const, global, or imported. - jl_binding_partition_t *prev_bpart = bpart; - for (;;) { - jl_ptr_kind_union_t prev_pku = jl_atomic_load_relaxed(&prev_bpart->restriction); - enum jl_partition_kind prev_kind = decode_restriction_kind(prev_pku); - if (jl_bkind_is_some_constant(prev_kind) || prev_kind == BINDING_KIND_GLOBAL || - (jl_bkind_is_some_import(prev_kind))) { - need_backdate = 0; - break; - } - if (prev_bpart->min_world == 0) - break; - prev_bpart = jl_get_binding_partition(b, prev_bpart->min_world - 1); - } - } - // If backdate is required, rewrite all previous binding partitions to - // backdated const - if (need_backdate) { - // We will backdate as long as this partition was never explicitly - // declared const, global, or *explicitly* imported. - jl_binding_partition_t *prev_bpart = bpart; - for (;;) { - jl_atomic_store_relaxed(&prev_bpart->restriction, encode_restriction(val, BINDING_KIND_BACKDATED_CONST)); - if (prev_bpart->min_world == 0) - break; - prev_bpart = jl_get_binding_partition(b, prev_bpart->min_world - 1); - } - } - } - JL_GC_POP(); - return new_bpart; -} - JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val2( jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *val, enum jl_partition_kind constant_kind) From c6805e2c702e21477c3457f381e3ed81ef325cb0 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Thu, 13 Feb 2025 00:38:51 -0500 Subject: [PATCH 328/342] staticdata: Set min validation world to require world (#57381) When we have implicit binding edges from literal GlobalRefs, these edges imply a implicit minimum world age of jl_require_age (which is what all bindings loaded from pkgimages get their definition age set to). In #57318, the `cpuid_llvm` minimum world age got set to `1` rather than `jl_require_world`, so codegen would refuse to perform the llvmcall special codegen, since it couldn't guarantee that the binding would actually resolve to `llvmcall` in all worlds. Fix that by adjusting staticdata.jl to set the appropriate minworld. That said, there are a few complicating factors here: 1. In general, most of our code doesn't handle world ranges with more than one partition. But for example, codegen could have checked the current world age and implicitly partitioned the binding at codegen time (in practice just adding an appropraite error check). 2. The included test case uses a cached inference. However, in the original issue it appeared that inlining was also creating new references to this replaced binding, which should not have been permitted. I have not fully investigated this behavior yet and this might be another bug. 3. In the original issue, the specialization had its max_world terminated a few ages past jl_require_world. I do not understand this behavior yet. Still, fixes #57318. --- base/loading.jl | 4 ++-- base/staticdata.jl | 14 +++++++++++--- test/precompile.jl | 25 +++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/base/loading.jl b/base/loading.jl index 47741da26a1b2..818bd2366b2d0 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -3157,11 +3157,11 @@ This can be used to reduce package load times. Cache files are stored in `DEPOT_PATH[1]/compiled`. See [Module initialization and precompilation](@ref) for important notes. """ -function compilecache(pkg::PkgId, internal_stderr::IO = stderr, internal_stdout::IO = stdout; flags::Cmd=``, reasons::Union{Dict{String,Int},Nothing}=Dict{String,Int}(), loadable_exts::Union{Vector{PkgId},Nothing}=nothing) +function compilecache(pkg::PkgId, internal_stderr::IO = stderr, internal_stdout::IO = stdout; flags::Cmd=``, cacheflags::CacheFlags=CacheFlags(), reasons::Union{Dict{String,Int},Nothing}=Dict{String,Int}(), loadable_exts::Union{Vector{PkgId},Nothing}=nothing) @nospecialize internal_stderr internal_stdout path = locate_package(pkg) path === nothing && throw(ArgumentError("$(repr("text/plain", pkg)) not found during precompilation")) - return compilecache(pkg, path, internal_stderr, internal_stdout; flags, reasons, loadable_exts) + return compilecache(pkg, path, internal_stderr, internal_stdout; flags, cacheflags, reasons, loadable_exts) end const MAX_NUM_PRECOMPILE_FILES = Ref(10) diff --git a/base/staticdata.jl b/base/staticdata.jl index 7283a93dd8b3b..45504622fe0ec 100644 --- a/base/staticdata.jl +++ b/base/staticdata.jl @@ -70,6 +70,8 @@ function verify_method_graph(codeinst::CodeInstance, stack::Vector{CodeInstance} nothing end +get_require_world() = unsafe_load(cglobal(:jl_require_world, UInt)) + # Test all edges relevant to a method: # - Visit the entire call graph, starting from edges[idx] to determine if that method is valid # - Implements Tarjan's SCC (strongly connected components) algorithm, simplified to remove the count variable @@ -81,7 +83,14 @@ function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visi return 0, world, max_valid2 end end - local minworld::UInt, maxworld::UInt = 1, validation_world + # Implicitly referenced bindings in the current module do not get explicit edges. + # If they were invalidated, they'll be in `mwis`. If they weren't, they imply a minworld + # of `get_require_world`. In principle, this is only required for methods that do reference + # an implicit globalref. However, we already don't perform this validation for methods that + # don't have any (implicit or explicit) edges at all. The remaining corner case (some explicit, + # but no implicit edges) is rare and there would be little benefit to lower the minworld for it + # in any case, so we just always use `get_require_world` here. + local minworld::UInt, maxworld::UInt = get_require_world(), validation_world def = get_ci_mi(codeinst).def @assert def isa Method if haskey(visiting, codeinst) @@ -103,9 +112,8 @@ function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visi # verify current edges if isempty(callees) # quick return: no edges to verify (though we probably shouldn't have gotten here from WORLD_AGE_REVALIDATION_SENTINEL) - elseif maxworld == unsafe_load(cglobal(:jl_require_world, UInt)) + elseif maxworld == get_require_world() # if no new worlds were allocated since serializing the base module, then no new validation is worth doing right now either - minworld = maxworld else j = 1 while j ≤ length(callees) diff --git a/test/precompile.jl b/test/precompile.jl index e6c987326e44c..7506af9ae50d9 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -2285,4 +2285,29 @@ precompile_test_harness("Constprop CodeInstance invalidation") do load_path end end +precompile_test_harness("llvmcall validation") do load_path + write(joinpath(load_path, "LLVMCall.jl"), + """ + module LLVMCall + using Base: llvmcall + @noinline do_llvmcall() = llvmcall("ret i32 0", UInt32, Tuple{}) + do_llvmcall2() = do_llvmcall() + do_llvmcall2() + end + """) + # Also test with --pkgimages=no + testcode = """ + insert!(LOAD_PATH, 1, $(repr(load_path))) + insert!(DEPOT_PATH, 1, $(repr(load_path))) + using LLVMCall + LLVMCall.do_llvmcall2() + """ + @test readchomp(`$(Base.julia_cmd()) --pkgimages=no -E $(testcode)`) == repr(UInt32(0)) + # Now the regular way + @eval using LLVMCall + invokelatest() do + @test LLVMCall.do_llvmcall2() == UInt32(0) + end +end + finish_precompile_test!() From 20162ea3949c5e9cf8c803b5b2b7b249c57108e4 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Thu, 13 Feb 2025 00:53:09 -0500 Subject: [PATCH 329/342] Only implicitly `using` Base, not Core (#57357) Inspired by the question in https://github.com/JuliaLang/julia/pull/57311#issuecomment-2648144227, I want to revisit the basic setup where every module `using`s both `Core` and `Base`. In general, I think we mostly expect users to inferface with `Base`, not `Core`, so this PR changes things to only have new modules `using` Base (while re-exporting all `Core` names from `Base`). There should be little user-visible impact from these changes. The only situation I can think of where it makes a difference is if somebody were to make their own Base/toplevel module that does not re-export Core. However, we don't really support that situation in the first place, and I actually think it's a feature that such toplevel modules can more closely control the set of implicitly exposed names. --- Compiler/src/typeinfer.jl | 1 + base/Base_compiler.jl | 5 ++++- base/boot.jl | 5 +++-- base/exports.jl | 39 +++++++++++++++++++++++++++++++++++++++ base/show.jl | 2 +- src/julia_internal.h | 1 + src/module.c | 26 ++++++++++++++++---------- src/toplevel.c | 5 ++++- test/misc.jl | 7 ++++++- 9 files changed, 75 insertions(+), 16 deletions(-) diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index 427f485f9118b..ddcca9a6ffaa1 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -10,6 +10,7 @@ being used for this purpose alone. """ module Timings +using ..Core using ..Compiler: -, +, :, Vector, length, first, empty!, push!, pop!, @inline, @inbounds, copy, backtrace diff --git a/base/Base_compiler.jl b/base/Base_compiler.jl index 20aa1f5a793ef..a1ae14427e754 100644 --- a/base/Base_compiler.jl +++ b/base/Base_compiler.jl @@ -2,6 +2,7 @@ baremodule Base +using Core using Core.Intrinsics, Core.IR # to start, we're going to use a very simple definition of `include` @@ -135,6 +136,9 @@ include("coreio.jl") import Core: @doc, @__doc__, WrappedException, @int128_str, @uint128_str, @big_str, @cmd +# Export list +include("exports.jl") + # core docsystem include("docs/core.jl") Core.atdoc!(CoreDocs.docm) @@ -142,7 +146,6 @@ Core.atdoc!(CoreDocs.docm) eval(x) = Core.eval(Base, x) eval(m::Module, x) = Core.eval(m, x) -include("exports.jl") include("public.jl") if false diff --git a/base/boot.jl b/base/boot.jl index 26a405f92f884..93d73679d65ed 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -238,7 +238,9 @@ export # method reflection applicable, invoke, # constants - nothing, Main + nothing, Main, + # backwards compatibility + arrayref, arrayset, arraysize, const_arrayref const getproperty = getfield # TODO: use `getglobal` for modules instead const setproperty! = setfield! @@ -1040,7 +1042,6 @@ const_arrayref(inbounds::Bool, A::Array, i::Int...) = Main.Base.getindex(A, i... arrayset(inbounds::Bool, A::Array{T}, x::Any, i::Int...) where {T} = Main.Base.setindex!(A, x::T, i...) arraysize(a::Array) = a.size arraysize(a::Array, i::Int) = sle_int(i, nfields(a.size)) ? getfield(a.size, i) : 1 -export arrayref, arrayset, arraysize, const_arrayref const check_top_bit = check_sign_bit # For convenience diff --git a/base/exports.jl b/base/exports.jl index d81067478dd55..2e0bb3ccfe4cf 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -1,5 +1,44 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +# Re-exports from `Core` +export Core, + # key types + Any, DataType, Vararg, NTuple, + Tuple, Type, UnionAll, TypeVar, Union, Nothing, Cvoid, + AbstractArray, DenseArray, NamedTuple, Pair, + # special objects + Function, Method, Module, Symbol, Task, UndefInitializer, undef, WeakRef, VecElement, + Array, Memory, MemoryRef, AtomicMemory, AtomicMemoryRef, GenericMemory, GenericMemoryRef, + # numeric types + Number, Real, Integer, Bool, Ref, Ptr, + AbstractFloat, Float16, Float32, Float64, + Signed, Int, Int8, Int16, Int32, Int64, Int128, + Unsigned, UInt, UInt8, UInt16, UInt32, UInt64, UInt128, + # string types + AbstractChar, Char, AbstractString, String, IO, + # errors + ErrorException, BoundsError, DivideError, DomainError, Exception, + InterruptException, InexactError, OutOfMemoryError, ReadOnlyMemoryError, + OverflowError, StackOverflowError, SegmentationFault, UndefRefError, UndefVarError, + TypeError, ArgumentError, MethodError, AssertionError, LoadError, InitError, + UndefKeywordError, ConcurrencyViolationError, FieldError, + # AST representation + Expr, QuoteNode, LineNumberNode, GlobalRef, + # object model functions + fieldtype, getfield, setfield!, swapfield!, modifyfield!, replacefield!, setfieldonce!, + nfields, throw, tuple, ===, isdefined, + # access to globals + getglobal, setglobal!, swapglobal!, modifyglobal!, replaceglobal!, setglobalonce!, isdefinedglobal, + # ifelse, sizeof # not exported, to avoid conflicting with Base + # type reflection + <:, typeof, isa, typeassert, + # method reflection + applicable, invoke, + # constants + nothing, Main, + # backwards compatibility + arrayref, arrayset, arraysize, const_arrayref + export # Modules Meta, diff --git a/base/show.jl b/base/show.jl index c1d5cf9035773..09b232e54ade6 100644 --- a/base/show.jl +++ b/base/show.jl @@ -618,7 +618,7 @@ function make_typealias(@nospecialize(x::Type)) Any === x && return nothing x <: Tuple && return nothing mods = modulesof!(Set{Module}(), x) - Core in mods && push!(mods, Base) + replace!(mods, Core=>Base) aliases = Tuple{GlobalRef,SimpleVector}[] xenv = UnionAll[] for p in uniontypes(unwrap_unionall(x)) diff --git a/src/julia_internal.h b/src/julia_internal.h index 6d83000184880..02729b7a4c6e7 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -1238,6 +1238,7 @@ _Atomic(jl_value_t*) *jl_table_peek_bp(jl_genericmemory_t *a, jl_value_t *key) J JL_DLLEXPORT jl_method_t *jl_new_method_uninit(jl_module_t*); +JL_DLLEXPORT jl_module_t *jl_new_module_(jl_sym_t *name, jl_module_t *parent, uint8_t default_using_core, uint8_t self_name); JL_DLLEXPORT jl_methtable_t *jl_new_method_table(jl_sym_t *name, jl_module_t *module); JL_DLLEXPORT jl_method_instance_t *jl_get_specialization1(jl_tupletype_t *types JL_PROPAGATES_ROOT, size_t world, int mt_cache); jl_method_instance_t *jl_get_specialized(jl_method_t *m, jl_value_t *types, jl_svec_t *sp) JL_PROPAGATES_ROOT; diff --git a/src/module.c b/src/module.c index dafcbcbceaab2..dda43546927c5 100644 --- a/src/module.c +++ b/src/module.c @@ -205,7 +205,7 @@ jl_binding_partition_t *jl_get_binding_partition_all(jl_binding_t *b, size_t min return bpart; } -JL_DLLEXPORT jl_module_t *jl_new_module_(jl_sym_t *name, jl_module_t *parent, uint8_t default_names) +JL_DLLEXPORT jl_module_t *jl_new_module_(jl_sym_t *name, jl_module_t *parent, uint8_t default_using_core, uint8_t self_name) { jl_task_t *ct = jl_current_task; const jl_uuid_t uuid_zero = {0, 0}; @@ -237,14 +237,20 @@ JL_DLLEXPORT jl_module_t *jl_new_module_(jl_sym_t *name, jl_module_t *parent, ui jl_atomic_store_relaxed(&m->bindings, jl_emptysvec); jl_atomic_store_relaxed(&m->bindingkeyset, (jl_genericmemory_t*)jl_an_empty_memory_any); arraylist_new(&m->usings, 0); - if (jl_core_module && default_names) { - JL_GC_PUSH1(&m); - jl_module_using(m, jl_core_module); - // export own name, so "using Foo" makes "Foo" itself visible - jl_set_const(m, name, (jl_value_t*)m); - jl_module_public(m, name, 1); - JL_GC_POP(); + JL_GC_PUSH1(&m); + if (jl_core_module) { + // Bootstrap: Before jl_core_module is defined, we don't have enough infrastructure + // for bindings, so Core itself gets special handling in jltypes.c + if (default_using_core) { + jl_module_using(m, jl_core_module); + } + if (self_name) { + // export own name, so "using Foo" makes "Foo" itself visible + jl_set_const(m, name, (jl_value_t*)m); + jl_module_public(m, name, 1); + } } + JL_GC_POP(); return m; } @@ -324,7 +330,7 @@ JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val3( JL_DLLEXPORT jl_module_t *jl_new_module(jl_sym_t *name, jl_module_t *parent) { - return jl_new_module_(name, parent, 1); + return jl_new_module_(name, parent, 1, 1); } uint32_t jl_module_next_counter(jl_module_t *m) @@ -336,7 +342,7 @@ JL_DLLEXPORT jl_value_t *jl_f_new_module(jl_sym_t *name, uint8_t std_imports, ui { // TODO: should we prohibit this during incremental compilation? // TODO: the parent module is a lie - jl_module_t *m = jl_new_module_(name, jl_main_module, default_names); + jl_module_t *m = jl_new_module_(name, jl_main_module, default_names, default_names); JL_GC_PUSH1(&m); if (std_imports) jl_add_standard_imports(m); diff --git a/src/toplevel.c b/src/toplevel.c index 904b7c15afcde..e2c58b6345c8d 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -135,7 +135,10 @@ static jl_value_t *jl_eval_module_expr(jl_module_t *parent_module, jl_expr_t *ex } int is_parent__toplevel__ = jl_is__toplevel__mod(parent_module); - jl_module_t *newm = jl_new_module(name, is_parent__toplevel__ ? NULL : parent_module); + // If we have `Base`, don't also try to import `Core` - the `Base` exports are a superset. + // While we allow multiple imports of the same binding from different modules, various error printing + // performs reflection on which module a binding came from and we'd prefer users see "Base" here. + jl_module_t *newm = jl_new_module_(name, is_parent__toplevel__ ? NULL : parent_module, std_imports && jl_base_module != NULL ? 0 : 1, 1); jl_value_t *form = (jl_value_t*)newm; JL_GC_PUSH1(&form); JL_LOCK(&jl_modules_mutex); diff --git a/test/misc.jl b/test/misc.jl index fef573e9fc747..bcc7ff69339a9 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -1574,7 +1574,12 @@ end @testset "Base docstrings" begin undoc = Docs.undocumented_names(Base) @test_broken isempty(undoc) - @test undoc == [:BufferStream, :CanonicalIndexError, :CapturedException, :Filesystem, :IOServer, :InvalidStateException, :Order, :PipeEndpoint, :ScopedValues, :Sort, :TTY] + @test isempty(setdiff(undoc, [:BufferStream, :CanonicalIndexError, :CapturedException, :Filesystem, :IOServer, :InvalidStateException, :Order, :PipeEndpoint, :ScopedValues, :Sort, :TTY, :AtomicMemoryRef, :Exception, :GenericMemoryRef, :GlobalRef, :IO, :LineNumberNode, :MemoryRef, :Method, :SegmentationFault, :TypeVar, :arrayref, :arrayset, :arraysize, :const_arrayref])) +end + +exported_names(m) = filter(s -> Base.isexported(m, s), names(m)) +@testset "Base re-exports Core" begin + @test issubset(exported_names(Core), exported_names(Base)) end @testset "Base.Libc docstrings" begin From cff8bd673513623a9876a76a0526c0899a0018bb Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Thu, 13 Feb 2025 08:50:14 -0500 Subject: [PATCH 330/342] staticdata: Fix typo in recursive edge revalidation (#57383) Addresses mystery #3 in #57381 (and extends the test from that issue). --- src/staticdata.c | 2 +- test/precompile.jl | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/staticdata.c b/src/staticdata.c index 36ebaa1c1b247..0c1405581debe 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -4390,7 +4390,7 @@ JL_DLLEXPORT void _jl_promote_ci_to_current(jl_code_instance_t *ci, size_t valid jl_value_t *edge = jl_svecref(edges, i); if (!jl_is_code_instance(edge)) continue; - _jl_promote_ci_to_current(ci, validated_world); + _jl_promote_ci_to_current((jl_code_instance_t *)edge, validated_world); } } diff --git a/test/precompile.jl b/test/precompile.jl index 7506af9ae50d9..6d106acc185f5 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -2307,6 +2307,7 @@ precompile_test_harness("llvmcall validation") do load_path @eval using LLVMCall invokelatest() do @test LLVMCall.do_llvmcall2() == UInt32(0) + @test first(methods(LLVMCall.do_llvmcall)).specializations.cache.max_world === typemax(UInt) end end From 40fbc8893a1daf935b1a77d597a3f638db61b03d Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Thu, 13 Feb 2025 08:56:47 -0500 Subject: [PATCH 331/342] bpart: Move kind enum into its intended place (#57385) The original design for the BindingPartition datastructure had ->restriction and ->kind as separate non-atomic fields. However, to support the old semantics, we created an intermediate state where both the restriciton and the kind were placed into ->restriction as a pointer-int-union (i.e. using the low three bits of the pointer to store an int). In #57341, I removed that last semantic place that needed to update these both atomically. This PR removes all the remaining non-semantic places and changes the datastructure back to its indended design. This is a necessary prerequisitve to be able to use more than three ->kind bits, which will be required for export invalidation (#57377), as well as some nicer error messages in failure cases. --- src/ast.c | 2 +- src/clangsa/GCChecker.cpp | 1 - src/codegen.cpp | 63 ++++++------- src/gc-stock.c | 10 -- src/jltypes.c | 4 +- src/julia.h | 10 +- src/julia_internal.h | 86 +++-------------- src/method.c | 9 +- src/module.c | 192 +++++++++++++++++--------------------- src/staticdata.c | 42 +-------- src/toplevel.c | 54 +++-------- test/syntax.jl | 2 +- 12 files changed, 156 insertions(+), 319 deletions(-) diff --git a/src/ast.c b/src/ast.c index 0f24d96393f2f..f643f4a2f40fe 100644 --- a/src/ast.c +++ b/src/ast.c @@ -178,7 +178,7 @@ static value_t fl_defined_julia_global(fl_context_t *fl_ctx, value_t *args, uint jl_sym_t *var = scmsym_to_julia(fl_ctx, args[0]); jl_binding_t *b = jl_get_module_binding(ctx->module, var, 0); jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - return (bpart != NULL && decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)) == BINDING_KIND_GLOBAL) ? fl_ctx->T : fl_ctx->F; + return (bpart != NULL && bpart->kind == BINDING_KIND_GLOBAL) ? fl_ctx->T : fl_ctx->F; } // Used to generate a unique suffix for a given symbol (e.g. variable or type name) diff --git a/src/clangsa/GCChecker.cpp b/src/clangsa/GCChecker.cpp index fdbe5ec9d9e29..af07ca2227839 100644 --- a/src/clangsa/GCChecker.cpp +++ b/src/clangsa/GCChecker.cpp @@ -856,7 +856,6 @@ bool GCChecker::isGCTrackedType(QualType QT) { Name.ends_with_insensitive("jl_stenv_t") || Name.ends_with_insensitive("jl_varbinding_t") || Name.ends_with_insensitive("set_world") || - Name.ends_with_insensitive("jl_ptr_kind_union_t") || Name.ends_with_insensitive("jl_codectx_t")) { return true; } diff --git a/src/codegen.cpp b/src/codegen.cpp index 025bb7c792443..26f34d63e578f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -926,7 +926,7 @@ static const auto jlcheckbpwritable_func = new JuliaFunction<>{ nullptr, }; static const auto jlgetbindingvalue_func = new JuliaFunction<>{ - XSTR(jl_reresolve_binding_value_seqcst), + XSTR(jl_get_binding_value_seqcst), [](LLVMContext &C) { auto T_pjlvalue = JuliaType::get_pjlvalue_ty(C); auto T_prjlvalue = JuliaType::get_prjlvalue_ty(C); @@ -3113,9 +3113,9 @@ static jl_value_t *static_eval(jl_codectx_t &ctx, jl_value_t *ex) jl_sym_t *sym = (jl_sym_t*)ex; jl_binding_t *bnd = jl_get_module_binding(ctx.module, sym, 0); jl_binding_partition_t *bpart = jl_get_binding_partition_all(bnd, ctx.min_world, ctx.max_world); - jl_ptr_kind_union_t pku = jl_walk_binding_inplace_all(&bnd, &bpart, ctx.min_world, ctx.max_world); - if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) - return decode_restriction_value(pku); + jl_walk_binding_inplace_all(&bnd, &bpart, ctx.min_world, ctx.max_world); + if (bpart && jl_bkind_is_some_constant(bpart->kind)) + return bpart->restriction; return NULL; } if (jl_is_slotnumber(ex) || jl_is_argument(ex)) @@ -3138,10 +3138,10 @@ static jl_value_t *static_eval(jl_codectx_t &ctx, jl_value_t *ex) s = jl_globalref_name(ex); jl_binding_t *bnd = jl_get_module_binding(jl_globalref_mod(ex), s, 0); jl_binding_partition_t *bpart = jl_get_binding_partition_all(bnd, ctx.min_world, ctx.max_world); - jl_ptr_kind_union_t pku = jl_walk_binding_inplace_all(&bnd, &bpart, ctx.min_world, ctx.max_world); + jl_walk_binding_inplace_all(&bnd, &bpart, ctx.min_world, ctx.max_world); jl_value_t *v = NULL; - if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) - v = decode_restriction_value(pku); + if (bpart && jl_bkind_is_some_constant(bpart->kind)) + v = bpart->restriction; if (v) { if (bnd->deprecated) cg_bdw(ctx, s, bnd); @@ -3165,10 +3165,10 @@ static jl_value_t *static_eval(jl_codectx_t &ctx, jl_value_t *ex) if (s && jl_is_symbol(s)) { jl_binding_t *bnd = jl_get_module_binding(m, s, 0); jl_binding_partition_t *bpart = jl_get_binding_partition_all(bnd, ctx.min_world, ctx.max_world); - jl_ptr_kind_union_t pku = jl_walk_binding_inplace_all(&bnd, &bpart, ctx.min_world, ctx.max_world); + jl_walk_binding_inplace_all(&bnd, &bpart, ctx.min_world, ctx.max_world); jl_value_t *v = NULL; - if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) - v = decode_restriction_value(pku); + if (bpart && jl_bkind_is_some_constant(bpart->kind)) + v = bpart->restriction; if (v) { if (bnd->deprecated) cg_bdw(ctx, s, bnd); @@ -3418,50 +3418,44 @@ static jl_cgval_t emit_globalref(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t * if (!bpart) { return emit_globalref_runtime(ctx, bnd, mod, name); } - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) { - // try to look this up now. - // TODO: This is bad and we'd like to delete it. - jl_get_binding(mod, name); - } // bpart was updated in place - this will change with full partition - pku = jl_atomic_load_acquire(&bpart->restriction); - if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) { + if (jl_bkind_is_some_guard(bpart->kind)) { // Redo the lookup at runtime return emit_globalref_runtime(ctx, bnd, mod, name); } else { while (true) { if (!bpart) break; - if (!jl_bkind_is_some_import(decode_restriction_kind(pku))) + if (!jl_bkind_is_some_import(bpart->kind)) break; if (bnd->deprecated) { cg_bdw(ctx, name, bnd); } - bnd = (jl_binding_t*)decode_restriction_value(pku); + bnd = (jl_binding_t*)bpart->restriction; bpart = jl_get_binding_partition_all(bnd, ctx.min_world, ctx.max_world); if (!bpart) break; - pku = jl_atomic_load_acquire(&bpart->restriction); } - enum jl_partition_kind kind = decode_restriction_kind(pku); - if (bpart && (jl_bkind_is_some_constant(kind) && kind != BINDING_KIND_BACKDATED_CONST)) { - jl_value_t *constval = decode_restriction_value(pku); - if (!constval) { - undef_var_error_ifnot(ctx, ConstantInt::get(getInt1Ty(ctx.builder.getContext()), 0), name, (jl_value_t*)mod); - return jl_cgval_t(); + if (bpart) { + enum jl_partition_kind kind = bpart->kind; + if (jl_bkind_is_some_constant(kind) && kind != BINDING_KIND_BACKDATED_CONST) { + jl_value_t *constval = bpart->restriction; + if (!constval) { + undef_var_error_ifnot(ctx, ConstantInt::get(getInt1Ty(ctx.builder.getContext()), 0), name, (jl_value_t*)mod); + return jl_cgval_t(); + } + return mark_julia_const(ctx, constval); } - return mark_julia_const(ctx, constval); } } - if (!bpart || decode_restriction_kind(pku) != BINDING_KIND_GLOBAL) { + if (!bpart || bpart->kind != BINDING_KIND_GLOBAL) { return emit_globalref_runtime(ctx, bnd, mod, name); } Value *bp = julia_binding_gv(ctx, bnd); if (bnd->deprecated) { cg_bdw(ctx, name, bnd); } - jl_value_t *ty = decode_restriction_value(pku); + jl_value_t *ty = bpart->restriction; bp = julia_binding_pvalue(ctx, bp); if (ty == nullptr) ty = (jl_value_t*)jl_any_type; @@ -3477,9 +3471,8 @@ static jl_cgval_t emit_globalop(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *s jl_binding_partition_t *bpart = jl_get_binding_partition_all(bnd, ctx.min_world, ctx.max_world); Value *bp = julia_binding_gv(ctx, bnd); if (bpart) { - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - if (decode_restriction_kind(pku) == BINDING_KIND_GLOBAL) { - jl_value_t *ty = decode_restriction_value(pku); + if (bpart->kind == BINDING_KIND_GLOBAL) { + jl_value_t *ty = bpart->restriction; if (ty != nullptr) { const std::string fname = issetglobal ? "setglobal!" : isreplaceglobal ? "replaceglobal!" : isswapglobal ? "swapglobal!" : ismodifyglobal ? "modifyglobal!" : "setglobalonce!"; if (!ismodifyglobal) { @@ -4164,8 +4157,8 @@ static jl_cgval_t emit_isdefinedglobal(jl_codectx_t &ctx, jl_module_t *modu, jl_ Value *isnull = NULL; jl_binding_t *bnd = allow_import ? jl_get_binding(modu, name) : jl_get_module_binding(modu, name, 0); jl_binding_partition_t *bpart = jl_get_binding_partition_all(bnd, ctx.min_world, ctx.max_world); - jl_ptr_kind_union_t pku = bpart ? jl_atomic_load_relaxed(&bpart->restriction) : encode_restriction(NULL, BINDING_KIND_GUARD); - if (decode_restriction_kind(pku) == BINDING_KIND_GLOBAL || jl_bkind_is_some_constant(decode_restriction_kind(pku))) { + enum jl_partition_kind kind = bpart ? bpart->kind : BINDING_KIND_GUARD; + if (kind == BINDING_KIND_GLOBAL || jl_bkind_is_some_constant(kind)) { if (jl_get_binding_value_if_const(bnd)) return mark_julia_const(ctx, jl_true); Value *bp = julia_binding_gv(ctx, bnd); diff --git a/src/gc-stock.c b/src/gc-stock.c index d0f0baf4f4715..3d3bc9f485e51 100644 --- a/src/gc-stock.c +++ b/src/gc-stock.c @@ -2448,16 +2448,6 @@ FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_ if (npointers == 0) return; uintptr_t nptr = (npointers << 2 | (bits & GC_OLD)); - if (vt == jl_binding_partition_type) { - // BindingPartition has a special union of jl_value_t and flag bits - // but is otherwise regular. - jl_binding_partition_t *bpart = (jl_binding_partition_t*)jl_valueof(o); - jl_value_t *val = decode_restriction_value( - jl_atomic_load_relaxed(&bpart->restriction)); - if (val) - gc_heap_snapshot_record_binding_partition_edge((jl_value_t*)bpart, val); - gc_try_claim_and_push(mq, val, &nptr); - } assert((layout->nfields > 0 || layout->flags.fielddesc_type == 3) && "opaque types should have been handled specially"); if (layout->flags.fielddesc_type == 0) { diff --git a/src/jltypes.c b/src/jltypes.c index dc7422460c0cf..e21d8ac184302 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3262,8 +3262,8 @@ void jl_init_types(void) JL_GC_DISABLED jl_binding_partition_type = jl_new_datatype(jl_symbol("BindingPartition"), core, jl_any_type, jl_emptysvec, - jl_perm_symsvec(5, "restriction", "min_world", "max_world", "next", "reserved"), - jl_svec(5, jl_uint64_type /* Special GC-supported union of Any and flags*/, + jl_perm_symsvec(5, "restriction", "min_world", "max_world", "next", "kind"), + jl_svec(5, jl_any_type, jl_ulong_type, jl_ulong_type, jl_any_type/*jl_binding_partition_type*/, jl_ulong_type), jl_emptysvec, 0, 1, 0); const static uint32_t binding_partition_atomicfields[] = { 0b01101 }; // Set fields 1, 3, 4 as atomic diff --git a/src/julia.h b/src/julia.h index 1fd709f42ee31..2d50bbb1cf3b6 100644 --- a/src/julia.h +++ b/src/julia.h @@ -706,12 +706,6 @@ enum jl_partition_kind { BINDING_KIND_IMPLICIT_RECOMPUTE = 0xb }; -#ifdef _P64 -// Union of a ptr and a 3 bit field. -typedef uintptr_t jl_ptr_kind_union_t; -#else -typedef struct __attribute__((aligned(8))) { jl_value_t *val; size_t kind; } jl_ptr_kind_union_t; -#endif typedef struct __attribute__((aligned(8))) _jl_binding_partition_t { JL_DATA_TYPE /* union { @@ -727,11 +721,11 @@ typedef struct __attribute__((aligned(8))) _jl_binding_partition_t { * * This field is updated atomically with both kind and restriction */ - _Atomic(jl_ptr_kind_union_t) restriction; + jl_value_t *restriction; size_t min_world; _Atomic(size_t) max_world; _Atomic(struct _jl_binding_partition_t *) next; - size_t reserved; // Reserved for ->kind. Currently this holds the low bits of ->restriction during serialization + enum jl_partition_kind kind; } jl_binding_partition_t; typedef struct _jl_binding_t { diff --git a/src/julia_internal.h b/src/julia_internal.h index 02729b7a4c6e7..0f52f82ac8230 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -932,62 +932,6 @@ jl_method_t *jl_make_opaque_closure_method(jl_module_t *module, jl_value_t *name int nargs, jl_value_t *functionloc, jl_code_info_t *ci, int isva, int isinferred); JL_DLLEXPORT int jl_is_valid_oc_argtype(jl_tupletype_t *argt, jl_method_t *source); -EXTERN_INLINE_DECLARE enum jl_partition_kind decode_restriction_kind(jl_ptr_kind_union_t pku) JL_NOTSAFEPOINT -{ -#ifdef _P64 - uint8_t bits = (pku & 0x7); - jl_value_t *val = (jl_value_t*)(pku & ~0x7); - - if (val == NULL) { - if (bits == BINDING_KIND_IMPLICIT) { - return BINDING_KIND_GUARD; - } - if (bits == BINDING_KIND_CONST) { - return BINDING_KIND_UNDEF_CONST; - } - } else { - if (bits == BINDING_KIND_DECLARED) { - return BINDING_KIND_BACKDATED_CONST; - } - } - - return (enum jl_partition_kind)bits; -#else - return (enum jl_partition_kind)pku.kind; -#endif -} - -STATIC_INLINE jl_value_t *decode_restriction_value(jl_ptr_kind_union_t JL_PROPAGATES_ROOT pku) JL_NOTSAFEPOINT -{ -#ifdef _P64 - jl_value_t *val = (jl_value_t*)(pku & ~0x7); - return val; -#else - return pku.val; -#endif -} - -STATIC_INLINE jl_ptr_kind_union_t encode_restriction(jl_value_t *val, enum jl_partition_kind kind) JL_NOTSAFEPOINT -{ -#ifdef _P64 - if (kind == BINDING_KIND_GUARD || kind == BINDING_KIND_DECLARED || kind == BINDING_KIND_FAILED || kind == BINDING_KIND_UNDEF_CONST) - assert(val == NULL); - else if (kind == BINDING_KIND_IMPLICIT || kind == BINDING_KIND_CONST || kind == BINDING_KIND_BACKDATED_CONST) - assert(val != NULL); - if (kind == BINDING_KIND_GUARD) - kind = BINDING_KIND_IMPLICIT; - else if (kind == BINDING_KIND_UNDEF_CONST) - kind = BINDING_KIND_CONST; - else if (kind == BINDING_KIND_BACKDATED_CONST) - kind = BINDING_KIND_DECLARED; - assert((((uintptr_t)val) & 0x7) == 0); - return ((jl_ptr_kind_union_t)val) | kind; -#else - jl_ptr_kind_union_t ret = { val, kind }; - return ret; -#endif -} - STATIC_INLINE int jl_bkind_is_some_import(enum jl_partition_kind kind) JL_NOTSAFEPOINT { return kind == BINDING_KIND_IMPLICIT || kind == BINDING_KIND_EXPLICIT || kind == BINDING_KIND_IMPORTED; } @@ -1008,35 +952,31 @@ JL_DLLEXPORT jl_binding_partition_t *jl_get_binding_partition(jl_binding_t *b JL JL_DLLEXPORT jl_binding_partition_t *jl_get_binding_partition_all(jl_binding_t *b JL_PROPAGATES_ROOT, size_t min_world, size_t max_world) JL_GLOBALLY_ROOTED; EXTERN_INLINE_DECLARE uint8_t jl_bpart_get_kind(jl_binding_partition_t *bpart) JL_NOTSAFEPOINT { - return decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)); + return (uint8_t)bpart->kind; } -STATIC_INLINE jl_ptr_kind_union_t jl_walk_binding_inplace(jl_binding_t **bnd, jl_binding_partition_t **bpart JL_PROPAGATES_ROOT, size_t world) JL_NOTSAFEPOINT; -STATIC_INLINE jl_ptr_kind_union_t jl_walk_binding_inplace_all(jl_binding_t **bnd, jl_binding_partition_t **bpart JL_PROPAGATES_ROOT, size_t min_world, size_t max_world) JL_NOTSAFEPOINT; +STATIC_INLINE void jl_walk_binding_inplace(jl_binding_t **bnd, jl_binding_partition_t **bpart JL_PROPAGATES_ROOT, size_t world) JL_NOTSAFEPOINT; +STATIC_INLINE void jl_walk_binding_inplace_all(jl_binding_t **bnd, jl_binding_partition_t **bpart JL_PROPAGATES_ROOT, size_t min_world, size_t max_world) JL_NOTSAFEPOINT; #ifndef __clang_analyzer__ -STATIC_INLINE jl_ptr_kind_union_t jl_walk_binding_inplace(jl_binding_t **bnd, jl_binding_partition_t **bpart, size_t world) JL_NOTSAFEPOINT +STATIC_INLINE void jl_walk_binding_inplace(jl_binding_t **bnd, jl_binding_partition_t **bpart, size_t world) JL_NOTSAFEPOINT { while (1) { - if (!*bpart) - return encode_restriction(NULL, BINDING_KIND_GUARD); - jl_ptr_kind_union_t pku = jl_atomic_load_acquire(&(*bpart)->restriction); - if (!jl_bkind_is_some_import(decode_restriction_kind(pku))) - return pku; - *bnd = (jl_binding_t*)decode_restriction_value(pku); + if (!jl_bkind_is_some_import((*bpart)->kind)) + return; + *bnd = (jl_binding_t*)(*bpart)->restriction; *bpart = jl_get_binding_partition(*bnd, world); } } -STATIC_INLINE jl_ptr_kind_union_t jl_walk_binding_inplace_all(jl_binding_t **bnd, jl_binding_partition_t **bpart, size_t min_world, size_t max_world) JL_NOTSAFEPOINT +STATIC_INLINE void jl_walk_binding_inplace_all(jl_binding_t **bnd, jl_binding_partition_t **bpart, size_t min_world, size_t max_world) JL_NOTSAFEPOINT { while (1) { - if (!*bpart) - return encode_restriction(NULL, BINDING_KIND_GUARD); - jl_ptr_kind_union_t pku = jl_atomic_load_acquire(&(*bpart)->restriction); - if (!jl_bkind_is_some_import(decode_restriction_kind(pku))) - return pku; - *bnd = (jl_binding_t*)decode_restriction_value(pku); + if (!(*bpart)) + return; + if (!jl_bkind_is_some_import((*bpart)->kind)) + return; + *bnd = (jl_binding_t*)(*bpart)->restriction; *bpart = jl_get_binding_partition_all(*bnd, min_world, max_world); } } diff --git a/src/method.c b/src/method.c index 68542fdacabb6..0fc0e0ca1f87d 100644 --- a/src/method.c +++ b/src/method.c @@ -1056,13 +1056,12 @@ JL_DLLEXPORT jl_value_t *jl_declare_const_gf(jl_module_t *mod, jl_sym_t *name) size_t new_world = jl_atomic_load_relaxed(&jl_world_counter) + 1; jl_binding_t *b = jl_get_binding_for_method_def(mod, name, new_world); jl_binding_partition_t *bpart = jl_get_binding_partition(b, new_world); - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); jl_value_t *gf = NULL; - enum jl_partition_kind kind = decode_restriction_kind(pku); + enum jl_partition_kind kind = bpart->kind; if (!jl_bkind_is_some_guard(kind) && kind != BINDING_KIND_DECLARED && kind != BINDING_KIND_IMPLICIT) { - pku = jl_walk_binding_inplace(&b, &bpart, new_world); - if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) { - gf = decode_restriction_value(pku); + jl_walk_binding_inplace(&b, &bpart, new_world); + if (jl_bkind_is_some_constant(bpart->kind)) { + gf = bpart->restriction; JL_GC_PROMISE_ROOTED(gf); jl_check_gf(gf, b->globalref->name); JL_UNLOCK(&world_counter_lock); diff --git a/src/module.c b/src/module.c index dda43546927c5..a5a9481d15e72 100644 --- a/src/module.c +++ b/src/module.c @@ -14,18 +14,15 @@ extern "C" { // In this translation unit and this translation unit only emit this symbol `extern` for use by julia EXTERN_INLINE_DEFINE uint8_t jl_bpart_get_kind(jl_binding_partition_t *bpart) JL_NOTSAFEPOINT; -extern inline enum jl_partition_kind decode_restriction_kind(jl_ptr_kind_union_t pku) JL_NOTSAFEPOINT; static jl_binding_partition_t *new_binding_partition(void) { jl_binding_partition_t *bpart = (jl_binding_partition_t*)jl_gc_alloc(jl_current_task->ptls, sizeof(jl_binding_partition_t), jl_binding_partition_type); - jl_atomic_store_relaxed(&bpart->restriction, encode_restriction(NULL, BINDING_KIND_GUARD)); + bpart->restriction = NULL; + bpart->kind = BINDING_KIND_GUARD; bpart->min_world = 0; jl_atomic_store_relaxed(&bpart->max_world, (size_t)-1); jl_atomic_store_relaxed(&bpart->next, NULL); -#ifdef _P64 - bpart->reserved = 0; -#endif return bpart; } @@ -38,12 +35,12 @@ static int eq_bindings(jl_binding_partition_t *owner, jl_binding_t *alias, size_ jl_binding_partition_t *alias_bpart = jl_get_binding_partition(alias, world); if (owner == alias_bpart) return 1; - jl_ptr_kind_union_t owner_pku = jl_walk_binding_inplace(&ownerb, &owner, world); - jl_ptr_kind_union_t alias_pku = jl_walk_binding_inplace(&alias, &alias_bpart, world); - if (jl_bkind_is_some_constant(decode_restriction_kind(owner_pku)) && - jl_bkind_is_some_constant(decode_restriction_kind(alias_pku)) && - decode_restriction_value(owner_pku) && - decode_restriction_value(alias_pku) == decode_restriction_value(owner_pku)) + jl_walk_binding_inplace(&ownerb, &owner, world); + jl_walk_binding_inplace(&alias, &alias_bpart, world); + if (jl_bkind_is_some_constant(owner->kind) && + jl_bkind_is_some_constant(alias_bpart->kind) && + owner->restriction && + alias_bpart->restriction == owner->restriction) return 1; return owner == alias_bpart; } @@ -56,7 +53,8 @@ void jl_check_new_binding_implicit( modstack_t *tmp = st; for (; tmp != NULL; tmp = tmp->prev) { if (tmp->b == b) { - jl_atomic_store_relaxed(&new_bpart->restriction, encode_restriction(NULL, BINDING_KIND_FAILED /* BINDING_KIND_CYCLE */)); + new_bpart->restriction = NULL; + new_bpart->kind = BINDING_KIND_FAILED; /* BINDING_KIND_CYCLE */ return; } } @@ -142,10 +140,13 @@ void jl_check_new_binding_implicit( new_bpart->min_world = min_world; jl_atomic_store_relaxed(&new_bpart->max_world, max_world); if (impb) { - jl_atomic_store_relaxed(&new_bpart->restriction, encode_restriction((jl_value_t*)impb, BINDING_KIND_IMPLICIT)); + new_bpart->kind = BINDING_KIND_IMPLICIT; + new_bpart->restriction = (jl_value_t*)impb; + jl_gc_wb(new_bpart, impb); // TODO: World age constraints? } else { - jl_atomic_store_relaxed(&new_bpart->restriction, encode_restriction(NULL, guard_kind)); + new_bpart->kind = guard_kind; + new_bpart->restriction = NULL; } JL_GC_POP(); return; @@ -265,15 +266,14 @@ JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val3( } jl_binding_partition_t *new_bpart = NULL; jl_binding_partition_t *bpart = jl_get_binding_partition(b, new_world); - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); while (!new_bpart) { - enum jl_partition_kind kind = decode_restriction_kind(pku); + enum jl_partition_kind kind = bpart->kind; if (jl_bkind_is_some_constant(kind)) { if (!val) { new_bpart = bpart; break; } - jl_value_t *old = decode_restriction_value(pku); + jl_value_t *old = bpart->restriction; JL_GC_PROMISE_ROOTED(old); if (jl_egal(val, old)) { new_bpart = bpart; @@ -287,11 +287,10 @@ JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val3( jl_symbol_name(mod->name), jl_symbol_name(var)); } if (bpart->min_world == new_world) { - if (!jl_atomic_cmpswap(&bpart->restriction, &pku, encode_restriction(val, constant_kind))) { - continue; - } else if (val) { + bpart->kind = constant_kind; + bpart->restriction = val; + if (val) jl_gc_wb(bpart, val); - } new_bpart = bpart; } else { new_bpart = jl_replace_binding_locked(b, bpart, val, constant_kind, new_world); @@ -302,8 +301,7 @@ JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val3( // declared const, global, or imported. jl_binding_partition_t *prev_bpart = bpart; for (;;) { - jl_ptr_kind_union_t prev_pku = jl_atomic_load_relaxed(&prev_bpart->restriction); - enum jl_partition_kind prev_kind = decode_restriction_kind(prev_pku); + enum jl_partition_kind prev_kind = prev_bpart->kind; if (jl_bkind_is_some_constant(prev_kind) || prev_kind == BINDING_KIND_GLOBAL || (jl_bkind_is_some_import(prev_kind))) { need_backdate = 0; @@ -318,7 +316,9 @@ JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val3( // the entire backdate range. if (need_backdate) { jl_binding_partition_t *backdate_bpart = new_binding_partition(); - jl_atomic_store_relaxed(&backdate_bpart->restriction, encode_restriction(val, BINDING_KIND_BACKDATED_CONST)); + backdate_bpart->kind = BINDING_KIND_BACKDATED_CONST; + backdate_bpart->restriction = val; + jl_gc_wb_fresh(backdate_bpart, val); jl_atomic_store_relaxed(&backdate_bpart->max_world, new_world - 1); jl_atomic_store_release(&new_bpart->next, backdate_bpart); jl_gc_wb(new_bpart, backdate_bpart); @@ -499,8 +499,7 @@ static jl_module_t *jl_binding_dbgmodule(jl_binding_t *b, jl_module_t *m, jl_sym JL_DLLEXPORT void jl_check_binding_currently_writable(jl_binding_t *b, jl_module_t *m, jl_sym_t *s) { jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - enum jl_partition_kind kind = decode_restriction_kind(pku); + enum jl_partition_kind kind = bpart->kind; if (kind != BINDING_KIND_GLOBAL && kind != BINDING_KIND_DECLARED && !jl_bkind_is_some_constant(kind)) { if (jl_bkind_is_some_guard(kind)) { jl_errorf("Global %s.%s does not exist and cannot be assigned.\n" @@ -559,13 +558,13 @@ static inline void check_backdated_binding(jl_binding_t *b, enum jl_partition_ki JL_DLLEXPORT jl_value_t *jl_get_binding_value(jl_binding_t *b) { jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - jl_ptr_kind_union_t pku = jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); - enum jl_partition_kind kind = decode_restriction_kind(pku); + jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); + enum jl_partition_kind kind = bpart->kind; if (jl_bkind_is_some_guard(kind)) return NULL; if (jl_bkind_is_some_constant(kind)) { check_backdated_binding(b, kind); - return decode_restriction_value(pku); + return bpart->restriction; } assert(!jl_bkind_is_some_import(kind)); return jl_atomic_load_relaxed(&b->value); @@ -574,13 +573,13 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value(jl_binding_t *b) JL_DLLEXPORT jl_value_t *jl_get_binding_value_seqcst(jl_binding_t *b) { jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - jl_ptr_kind_union_t pku = jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); - enum jl_partition_kind kind = decode_restriction_kind(pku); + jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); + enum jl_partition_kind kind = bpart->kind; if (jl_bkind_is_some_guard(kind)) return NULL; if (jl_bkind_is_some_constant(kind)) { check_backdated_binding(b, kind); - return decode_restriction_value(pku); + return bpart->restriction; } assert(!jl_bkind_is_some_import(kind)); return jl_atomic_load(&b->value); @@ -589,14 +588,14 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_seqcst(jl_binding_t *b) JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_const(jl_binding_t *b) { jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - jl_ptr_kind_union_t pku = jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); - enum jl_partition_kind kind = decode_restriction_kind(pku); + jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); + enum jl_partition_kind kind = bpart->kind; if (jl_bkind_is_some_guard(kind)) return NULL; if (!jl_bkind_is_some_constant(kind)) return NULL; check_backdated_binding(b, kind); - return decode_restriction_value(pku); + return bpart->restriction; } JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_resolved_and_const(jl_binding_t *b) @@ -611,14 +610,13 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_resolved_and_const(jl_binding_t size_t max_world = jl_atomic_load_relaxed(&bpart->max_world); if (bpart->min_world > jl_current_task->world_age || jl_current_task->world_age > max_world) return NULL; - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - enum jl_partition_kind kind = decode_restriction_kind(pku); + enum jl_partition_kind kind = bpart->kind; if (jl_bkind_is_some_guard(kind)) return NULL; if (!jl_bkind_is_some_constant(kind)) return NULL; check_backdated_binding(b, kind); - return decode_restriction_value(pku); + return bpart->restriction; } JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_resolved(jl_binding_t *b) @@ -633,58 +631,44 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_value_if_resolved(jl_binding_t *b) size_t max_world = jl_atomic_load_relaxed(&bpart->max_world); if (bpart->min_world > jl_current_task->world_age || jl_current_task->world_age > max_world) return NULL; - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - enum jl_partition_kind kind = decode_restriction_kind(pku); + enum jl_partition_kind kind = bpart->kind; if (jl_bkind_is_some_guard(kind)) return NULL; if (jl_bkind_is_some_import(kind)) return NULL; if (jl_bkind_is_some_constant(kind)) { check_backdated_binding(b, kind); - return decode_restriction_value(pku); + return bpart->restriction; } return jl_atomic_load_relaxed(&b->value); } JL_DLLEXPORT jl_value_t *jl_bpart_get_restriction_value(jl_binding_partition_t *bpart) { - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - jl_value_t *v = decode_restriction_value(pku); + jl_value_t *v = bpart->restriction; if (!v) jl_throw(jl_undefref_exception); return v; } -JL_DLLEXPORT jl_value_t *jl_reresolve_binding_value_seqcst(jl_binding_t *b) -{ - /* - jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - if (jl_bkind_is_some_guard(decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)))) { - jl_resolve_owner(b, b->globalref->mod, b->globalref->name, NULL, jl_current_task->world_age); - } - */ - return jl_get_binding_value_seqcst(b); -} - // get binding for adding a method // like jl_get_binding_wr, but has different error paths and messages JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_t *var, size_t new_world) { jl_binding_t *b = jl_get_module_binding(m, var, 1); jl_binding_partition_t *bpart = jl_get_binding_partition(b, new_world); - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - enum jl_partition_kind kind = decode_restriction_kind(pku); - if (kind == BINDING_KIND_GLOBAL || kind == BINDING_KIND_DECLARED || jl_bkind_is_some_constant(decode_restriction_kind(pku))) + enum jl_partition_kind kind = bpart->kind; + if (kind == BINDING_KIND_GLOBAL || kind == BINDING_KIND_DECLARED || jl_bkind_is_some_constant(kind)) return b; if (jl_bkind_is_some_guard(kind)) { check_safe_newbinding(m, var); return b; } jl_binding_t *ownerb = b; - pku = jl_walk_binding_inplace(&ownerb, &bpart, new_world); + jl_walk_binding_inplace(&ownerb, &bpart, new_world); jl_value_t *f = NULL; - if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) - f = decode_restriction_value(pku); + if (jl_bkind_is_some_constant(bpart->kind)) + f = bpart->restriction; if (f == NULL) { if (kind == BINDING_KIND_IMPLICIT) { check_safe_newbinding(m, var); @@ -734,9 +718,8 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_ static jl_module_t *jl_binding_dbgmodule(jl_binding_t *b, jl_module_t *m, jl_sym_t *var) { jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - if (jl_bkind_is_some_import(decode_restriction_kind(pku))) { - return ((jl_binding_t*)decode_restriction_value(pku))->globalref->mod; + if (jl_bkind_is_some_import(bpart->kind)) { + return ((jl_binding_t*)bpart->restriction)->globalref->mod; } return m; } @@ -750,17 +733,17 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_type(jl_module_t *m, jl_sym_t *var) jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); if (b == NULL) return jl_nothing; - jl_ptr_kind_union_t pku = jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); - if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) + jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); + if (jl_bkind_is_some_guard(bpart->kind)) return jl_nothing; - if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) { + if (jl_bkind_is_some_constant(bpart->kind)) { // TODO: We would like to return the type of the constant, but // currently code relies on this returning any to bypass conversion // before an attempted assignment to a constant. - // return jl_typeof(jl_atomic_load_relaxed(&bpart->restriction)); + // return bpart->restriction; return (jl_value_t*)jl_any_type; } - return decode_restriction_value(pku); + return bpart->restriction; } JL_DLLEXPORT jl_binding_t *jl_get_binding(jl_module_t *m, jl_sym_t *var) @@ -792,7 +775,7 @@ JL_DLLEXPORT int jl_is_imported(jl_module_t *m, jl_sym_t *var) { jl_binding_t *b = jl_get_module_binding(m, var, 0); jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - return b && decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)) == BINDING_KIND_IMPORTED; + return b && bpart->kind == BINDING_KIND_IMPORTED; } extern const char *jl_filename; @@ -853,8 +836,6 @@ static void module_import_(jl_module_t *to, jl_module_t *from, jl_sym_t *asname, { jl_binding_t *b = jl_get_binding(from, s); jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - (void)pku; if (b->deprecated) { if (jl_get_binding_value(b) == jl_nothing) { // silently skip importing deprecated values assigned to nothing (to allow later mutation) @@ -877,9 +858,9 @@ static void module_import_(jl_module_t *to, jl_module_t *from, jl_sym_t *asname, jl_binding_t *ownerb = b; jl_binding_partition_t *ownerbpart = bpart; - jl_ptr_kind_union_t owner_pku = jl_walk_binding_inplace(&ownerb, &ownerbpart, jl_current_task->world_age); + jl_walk_binding_inplace(&ownerb, &ownerbpart, jl_current_task->world_age); - if (jl_bkind_is_some_guard(decode_restriction_kind(owner_pku))) { + if (jl_bkind_is_some_guard(ownerbpart->kind)) { jl_printf(JL_STDERR, "WARNING: Imported binding %s.%s was undeclared at import time during import to %s.\n", jl_symbol_name(from->name), jl_symbol_name(s), @@ -894,10 +875,10 @@ static void module_import_(jl_module_t *to, jl_module_t *from, jl_sym_t *asname, JL_LOCK(&world_counter_lock); size_t new_world = jl_atomic_load_acquire(&jl_world_counter)+1; jl_binding_partition_t *btopart = jl_get_binding_partition(bto, new_world); - jl_ptr_kind_union_t bto_pku = jl_atomic_load_relaxed(&btopart->restriction); - if (decode_restriction_kind(bto_pku) == BINDING_KIND_GUARD || - decode_restriction_kind(bto_pku) == BINDING_KIND_IMPLICIT || - decode_restriction_kind(bto_pku) == BINDING_KIND_FAILED) { + enum jl_partition_kind btokind = btopart->kind; + if (btokind == BINDING_KIND_GUARD || + btokind == BINDING_KIND_IMPLICIT || + btokind == BINDING_KIND_FAILED) { jl_binding_partition_t *new_bpart = jl_replace_binding_locked(bto, btopart, (jl_value_t*)b, (explici != 0) ? BINDING_KIND_IMPORTED : BINDING_KIND_EXPLICIT, new_world); if (jl_atomic_load_relaxed(&new_bpart->max_world) == ~(size_t)0) @@ -907,12 +888,12 @@ static void module_import_(jl_module_t *to, jl_module_t *from, jl_sym_t *asname, else { if (eq_bindings(bpart, bto, new_world)) { // already imported - potentially upgrade _EXPLICIT to _IMPORTED - if (decode_restriction_kind(bto_pku) == BINDING_KIND_EXPLICIT && explici != 0) { + if (btokind == BINDING_KIND_EXPLICIT && explici != 0) { jl_replace_binding_locked(bto, btopart, (jl_value_t*)b, BINDING_KIND_IMPORTED, new_world); jl_atomic_store_release(&jl_world_counter, new_world); } } - else if (jl_bkind_is_some_import(decode_restriction_kind(bto_pku))) { + else if (jl_bkind_is_some_import(btokind)) { // already imported from somewhere else jl_printf(JL_STDERR, "WARNING: ignoring conflicting import of %s.%s into %s\n", @@ -1000,8 +981,7 @@ JL_DLLEXPORT void jl_module_using(jl_module_t *to, jl_module_t *from) jl_binding_t *tob = jl_get_module_binding(to, var, 0); if (tob) { jl_binding_partition_t *tobpart = jl_get_binding_partition(tob, new_world); - jl_ptr_kind_union_t tobpku = jl_atomic_load_relaxed(&tobpart->restriction); - enum jl_partition_kind kind = decode_restriction_kind(tobpku); + enum jl_partition_kind kind = tobpart->kind; if (kind == BINDING_KIND_IMPLICIT || jl_bkind_is_some_guard(kind)) { jl_replace_binding_locked(tob, tobpart, NULL, BINDING_KIND_IMPLICIT_RECOMPUTE, new_world); } @@ -1055,16 +1035,15 @@ JL_DLLEXPORT int jl_boundp(jl_module_t *m, jl_sym_t *var, int allow_import) // u jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); if (!bpart) return 0; - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); if (!allow_import) { - if (!bpart || jl_bkind_is_some_import(decode_restriction_kind(pku))) + if (!bpart || jl_bkind_is_some_import(bpart->kind)) return 0; } else { - pku = jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); + jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); } - if (jl_bkind_is_some_guard(decode_restriction_kind(pku))) + if (jl_bkind_is_some_guard(bpart->kind)) return 0; - if (jl_bkind_is_defined_constant(decode_restriction_kind(pku))) { + if (jl_bkind_is_defined_constant(bpart->kind)) { // N.B.: No backdated check for isdefined return 1; } @@ -1075,7 +1054,7 @@ JL_DLLEXPORT int jl_defines_or_exports_p(jl_module_t *m, jl_sym_t *var) { jl_binding_t *b = jl_get_module_binding(m, var, 0); jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - return b && (b->exportp || decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)) == BINDING_KIND_GLOBAL); + return b && (b->exportp || bpart->kind == BINDING_KIND_GLOBAL); } JL_DLLEXPORT int jl_module_exports_p(jl_module_t *m, jl_sym_t *var) @@ -1188,7 +1167,8 @@ JL_DLLEXPORT void jl_set_const(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var jl_binding_partition_t *bpart = jl_get_binding_partition(bp, jl_current_task->world_age); bpart->min_world = 0; jl_atomic_store_release(&bpart->max_world, ~(size_t)0); - jl_atomic_store_release(&bpart->restriction, encode_restriction(val, BINDING_KIND_CONST)); + bpart->kind = BINDING_KIND_CONST; + bpart->restriction = val; jl_gc_wb(bpart, val); } @@ -1253,10 +1233,13 @@ JL_DLLEXPORT jl_binding_partition_t *jl_replace_binding_locked(jl_binding_t *b, assert(!restriction_val); jl_check_new_binding_implicit(new_bpart /* callee rooted */, b, NULL, new_world); } - else - jl_atomic_store_relaxed(&new_bpart->restriction, encode_restriction(restriction_val, kind)); + else { + new_bpart->kind = kind; + new_bpart->restriction = restriction_val; + jl_gc_wb_fresh(new_bpart, restriction_val); + } jl_atomic_store_relaxed(&new_bpart->next, old_bpart); - jl_gc_wb(new_bpart, old_bpart); + jl_gc_wb_fresh(new_bpart, old_bpart); jl_atomic_store_release(&b->partitions, new_bpart); jl_gc_wb(b, new_bpart); @@ -1299,7 +1282,7 @@ JL_DLLEXPORT int jl_globalref_is_const(jl_globalref_t *gr) jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); if (!bpart) return 0; - return jl_bkind_is_some_constant(decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction))); + return jl_bkind_is_some_constant(bpart->kind); } JL_DLLEXPORT void jl_disable_binding(jl_globalref_t *gr) @@ -1309,7 +1292,7 @@ JL_DLLEXPORT void jl_disable_binding(jl_globalref_t *gr) b = jl_get_module_binding(gr->mod, gr->name, 1); jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - if (decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)) == BINDING_KIND_GUARD) { + if (bpart->kind == BINDING_KIND_GUARD) { // Already guard return; } @@ -1323,8 +1306,8 @@ JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var) { jl_binding_t *b = jl_get_binding(m, var); jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - jl_ptr_kind_union_t pku = jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); - return b && jl_bkind_is_some_constant(decode_restriction_kind(pku)); + jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); + return b && jl_bkind_is_some_constant(bpart->kind); } // set the deprecated flag for a binding: @@ -1375,10 +1358,9 @@ jl_value_t *jl_check_binding_assign_value(jl_binding_t *b JL_PROPAGATES_ROOT, jl { JL_GC_PUSH1(&rhs); // callee-rooted jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - enum jl_partition_kind kind = decode_restriction_kind(pku); + enum jl_partition_kind kind = bpart->kind; if (jl_bkind_is_some_constant(kind)) { - jl_value_t *old = decode_restriction_value(pku); + jl_value_t *old = bpart->restriction; JL_GC_PROMISE_ROOTED(old); if (jl_egal(rhs, old)) { JL_GC_POP(); @@ -1388,7 +1370,7 @@ jl_value_t *jl_check_binding_assign_value(jl_binding_t *b JL_PROPAGATES_ROOT, jl jl_symbol_name(mod->name), jl_symbol_name(var)); } assert(kind == BINDING_KIND_DECLARED || kind == BINDING_KIND_GLOBAL); - jl_value_t *old_ty = kind == BINDING_KIND_DECLARED ? (jl_value_t*)jl_any_type : decode_restriction_value(pku); + jl_value_t *old_ty = kind == BINDING_KIND_DECLARED ? (jl_value_t*)jl_any_type : bpart->restriction; JL_GC_PROMISE_ROOTED(old_ty); if (old_ty != (jl_value_t*)jl_any_type && jl_typeof(rhs) != old_ty) { if (!jl_isa(rhs, old_ty)) @@ -1426,12 +1408,12 @@ JL_DLLEXPORT jl_value_t *jl_checked_replace(jl_binding_t *b, jl_module_t *mod, j JL_DLLEXPORT jl_value_t *jl_checked_modify(jl_binding_t *b, jl_module_t *mod, jl_sym_t *var, jl_value_t *op, jl_value_t *rhs) { jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - assert(!jl_bkind_is_some_guard(decode_restriction_kind(pku)) && !jl_bkind_is_some_import(decode_restriction_kind(pku))); - if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) + enum jl_partition_kind kind = bpart->kind; + assert(!jl_bkind_is_some_guard(kind) && !jl_bkind_is_some_import(kind)); + if (jl_bkind_is_some_constant(kind)) jl_errorf("invalid assignment to constant %s.%s", jl_symbol_name(mod->name), jl_symbol_name(var)); - jl_value_t *ty = decode_restriction_value(pku); + jl_value_t *ty = bpart->restriction; JL_GC_PROMISE_ROOTED(ty); return modify_value(ty, &b->value, (jl_value_t*)b, op, rhs, 1, mod, var); } @@ -1478,7 +1460,7 @@ void append_module_names(jl_array_t* a, jl_module_t *m, int all, int imported, i int hidden = jl_symbol_name(asname)[0]=='#'; int main_public = (m == jl_main_module && !(asname == jl_eval_sym || asname == jl_include_sym)); jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - enum jl_partition_kind kind = decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)); + enum jl_partition_kind kind = bpart->kind; if (((b->publicp) || (imported && (kind == BINDING_KIND_CONST_IMPORT || kind == BINDING_KIND_IMPORTED)) || (usings && kind == BINDING_KIND_EXPLICIT) || @@ -1565,7 +1547,7 @@ JL_DLLEXPORT void jl_clear_implicit_imports(jl_module_t *m) if ((void*)b == jl_nothing) break; jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - if (decode_restriction_kind(jl_atomic_load_relaxed(&bpart->restriction)) == BINDING_KIND_IMPLICIT) { + if (bpart->kind == BINDING_KIND_IMPLICIT) { jl_atomic_store_relaxed(&b->partitions, NULL); } } diff --git a/src/staticdata.c b/src/staticdata.c index 0c1405581debe..c29448c491eb7 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -1001,7 +1001,7 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_ } else if (jl_is_binding_partition(v)) { jl_binding_partition_t *bpart = (jl_binding_partition_t*)v; - jl_queue_for_serialization_(s, decode_restriction_value(jl_atomic_load_relaxed(&bpart->restriction)), 1, immediate); + jl_queue_for_serialization_(s, bpart->restriction, 1, immediate); jl_queue_for_serialization_(s, get_replaceable_field((jl_value_t**)&bpart->next, 0), 1, immediate); } else if (layout->nfields > 0) { @@ -1680,13 +1680,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED } else if (jl_is_binding_partition(v)) { jl_binding_partition_t *bpart = (jl_binding_partition_t*)v; - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - jl_value_t *restriction_val = decode_restriction_value(pku); - static_assert(offsetof(jl_binding_partition_t, restriction) == 0, "BindingPartition layout mismatch"); - write_pointerfield(s, restriction_val); -#ifndef _P64 - write_uint(f, decode_restriction_kind(pku)); -#endif + write_pointerfield(s, bpart->restriction); size_t max_world = jl_atomic_load_relaxed(&bpart->max_world); if (s->incremental) { if (max_world == ~(size_t)0) { @@ -1708,13 +1702,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED write_uint(f, max_world); } write_pointerfield(s, (jl_value_t*)jl_atomic_load_relaxed(&bpart->next)); -#ifdef _P64 - write_uint(f, decode_restriction_kind(pku)); // This will be moved back into place during deserialization (if necessary) - static_assert(sizeof(jl_binding_partition_t) == 5*sizeof(void*), "BindingPartition layout mismatch"); -#else - write_uint(f, 0); - static_assert(sizeof(jl_binding_partition_t) == 6*sizeof(void*), "BindingPartition layout mismatch"); -#endif + write_uint(f, bpart->kind); } else { // Generic object::DataType serialization by field @@ -3510,11 +3498,10 @@ static void jl_validate_binding_partition(jl_binding_t *b, jl_binding_partition_ if (jl_atomic_load_relaxed(&bpart->max_world) != ~(size_t)0) return; - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - enum jl_partition_kind kind = decode_restriction_kind(pku); + enum jl_partition_kind kind = bpart->kind; if (!jl_bkind_is_some_import(kind)) return; - jl_binding_t *imported_binding = (jl_binding_t*)decode_restriction_value(pku); + jl_binding_t *imported_binding = (jl_binding_t*)bpart->restriction; jl_binding_partition_t *latest_imported_bpart = jl_atomic_load_relaxed(&imported_binding->partitions); if (!latest_imported_bpart) return; @@ -4015,25 +4002,6 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl } } } - // Move the binding bits back to their correct place -#ifdef _P64 - jl_svec_t *table = jl_atomic_load_relaxed(&mod->bindings); - for (size_t i = 0; i < jl_svec_len(table); i++) { - jl_binding_t *b = (jl_binding_t*)jl_svecref(table, i); - if ((jl_value_t*)b == jl_nothing) - continue; - jl_binding_partition_t *bpart = jl_atomic_load_relaxed(&b->partitions); - while (bpart) { - jl_ptr_kind_union_t pku = encode_restriction( - (jl_value_t*)jl_atomic_load_relaxed(&bpart->restriction), - (enum jl_partition_kind)bpart->reserved); - jl_atomic_store_relaxed(&bpart->restriction, pku); - bpart->reserved = 0; - bpart = jl_atomic_load_relaxed(&bpart->next); - } - } - -#endif } else { abort(); diff --git a/src/toplevel.c b/src/toplevel.c index e2c58b6345c8d..9bb82a3451848 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -157,32 +157,7 @@ static jl_value_t *jl_eval_module_expr(jl_module_t *parent_module, jl_expr_t *ex } } else { - jl_binding_t *b = jl_get_module_binding(parent_module, name, 1); - jl_binding_partition_t *bpart = jl_get_binding_partition(b, ct->world_age); - jl_ptr_kind_union_t pku = encode_restriction(NULL, BINDING_KIND_UNDEF_CONST); - jl_ptr_kind_union_t new_pku = encode_restriction((jl_value_t*)newm, BINDING_KIND_CONST); - if (!jl_atomic_cmpswap(&bpart->restriction, &pku, new_pku)) { - if (decode_restriction_kind(pku) != BINDING_KIND_CONST) { - jl_declare_constant_val(b, parent_module, name, (jl_value_t*)newm); - } else { - // As a special exception allow binding replacement of modules - if (!jl_is_module(decode_restriction_value(pku))) { - jl_errorf("invalid redefinition of constant %s", jl_symbol_name(name)); - } - if (jl_generating_output()) - jl_errorf("cannot replace module %s during compilation", jl_symbol_name(name)); - jl_printf(JL_STDERR, "WARNING: replacing module %s.\n", jl_symbol_name(name)); - pku = jl_atomic_exchange(&bpart->restriction, new_pku); - } - jl_gc_wb(bpart, newm); - if (decode_restriction_value(pku) != NULL && jl_is_module(decode_restriction_value(pku))) { - // create a hidden gc root for the old module - JL_LOCK(&jl_modules_mutex); - uintptr_t *refcnt = (uintptr_t*)ptrhash_bp(&jl_current_modules, decode_restriction_value(pku)); - *refcnt += 1; - JL_UNLOCK(&jl_modules_mutex); - } - } + jl_declare_constant_val(NULL, parent_module, name, (jl_value_t*)newm); } if (parent_module == jl_main_module && name == jl_symbol("Base")) { @@ -332,29 +307,27 @@ void jl_declare_global(jl_module_t *m, jl_value_t *arg, jl_value_t *set_type, in global_type = (jl_value_t*)jl_any_type; while (1) { bpart = jl_get_binding_partition(b, new_world); - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - enum jl_partition_kind kind = decode_restriction_kind(pku); + enum jl_partition_kind kind = bpart->kind; if (kind != BINDING_KIND_GLOBAL) { if (jl_bkind_is_some_guard(kind) || kind == BINDING_KIND_DECLARED || kind == BINDING_KIND_IMPLICIT) { - if (decode_restriction_kind(pku) == new_kind) { + if (kind == new_kind) { if (!set_type) goto done; goto check_type; } check_safe_newbinding(gm, gs); if (bpart->min_world == new_world) { - if (jl_atomic_cmpswap(&bpart->restriction, &pku, encode_restriction(global_type, new_kind))) { - break; - } - if (set_type) - jl_gc_wb(bpart, set_type); + bpart->kind = new_kind; + bpart->restriction = global_type; + if (global_type) + jl_gc_wb(bpart, global_type); continue; } else { jl_replace_binding_locked(b, bpart, global_type, new_kind, new_world); } break; } else if (set_type) { - if (jl_bkind_is_some_constant(decode_restriction_kind(pku))) { + if (jl_bkind_is_some_constant(kind)) { jl_errorf("cannot set type for constant %s.%s.", jl_symbol_name(gm->name), jl_symbol_name(gs)); } else { @@ -366,7 +339,7 @@ void jl_declare_global(jl_module_t *m, jl_value_t *arg, jl_value_t *set_type, in if (set_type) { check_type: ; - jl_value_t *old_ty = decode_restriction_value(pku); + jl_value_t *old_ty = bpart->restriction; JL_GC_PROMISE_ROOTED(old_ty); if (!jl_types_equal(set_type, old_ty)) { jl_errorf("cannot set type for global %s.%s. It already has a value or is already set to a different type.", @@ -682,14 +655,13 @@ static void import_module(jl_module_t *JL_NONNULL m, jl_module_t *import, jl_sym // TODO: this is a bit race-y with what error message we might print jl_binding_t *b = jl_get_module_binding(m, name, 1); jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - jl_ptr_kind_union_t pku = jl_atomic_load_relaxed(&bpart->restriction); - enum jl_partition_kind kind = decode_restriction_kind(pku); + enum jl_partition_kind kind = bpart->kind; if (kind != BINDING_KIND_GUARD && kind != BINDING_KIND_FAILED && kind != BINDING_KIND_DECLARED && kind != BINDING_KIND_IMPLICIT) { // Unlike regular constant declaration, we allow this as long as we eventually end up at a constant. - pku = jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); - if (decode_restriction_kind(pku) == BINDING_KIND_CONST || decode_restriction_kind(pku) == BINDING_KIND_BACKDATED_CONST || decode_restriction_kind(pku) == BINDING_KIND_CONST_IMPORT) { + jl_walk_binding_inplace(&b, &bpart, jl_current_task->world_age); + if (bpart->kind == BINDING_KIND_CONST || bpart->kind == BINDING_KIND_BACKDATED_CONST || bpart->kind == BINDING_KIND_CONST_IMPORT) { // Already declared (e.g. on another thread) or imported. - if (decode_restriction_value(pku) == (jl_value_t*)import) + if (bpart->restriction == (jl_value_t*)import) return; } jl_errorf("importing %s into %s conflicts with an existing global", diff --git a/test/syntax.jl b/test/syntax.jl index 5f49f13fca641..67a6976adfcec 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -3977,7 +3977,7 @@ module ReplacementContainer const x = 1 end const Old = ReplaceMe - @test_warn r"WARNING: replacing module ReplaceMe" @eval module ReplaceMe + @eval module ReplaceMe const x = 2 end end From db874ff6529d475834c83da3c7e202957ca4f6d6 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 13 Feb 2025 12:10:12 -0500 Subject: [PATCH 332/342] Compiler: fix unsoundness of getfield_tfunc on Tuple Types (#57275) This was noted in the original review of that PR by the PR author, but was for some reason not fixed at that time: https://github.com/JuliaLang/julia/pull/46693#discussion_r968785997 --- Compiler/src/typeutils.jl | 10 ++-------- Compiler/test/inline.jl | 1 + 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/Compiler/src/typeutils.jl b/Compiler/src/typeutils.jl index d588a9aee1a6c..50b3dc6b0c6f5 100644 --- a/Compiler/src/typeutils.jl +++ b/Compiler/src/typeutils.jl @@ -36,14 +36,8 @@ function isTypeDataType(@nospecialize t) isType(t) && return false # Could be Union{} at runtime t === Core.TypeofBottom && return false - if t.name === Tuple.name - # If we have a Union parameter, could have been redistributed at runtime, - # e.g. `Tuple{Union{Int, Float64}, Int}` is a DataType, but - # `Union{Tuple{Int, Int}, Tuple{Float64, Int}}` is typeequal to it and - # is not. - return all(isTypeDataType, t.parameters) - end - return true + # Return true if `t` is not covariant + return t.name !== Tuple.name end has_extended_info(@nospecialize x) = (!isa(x, Type) && !isvarargtype(x)) || isType(x) diff --git a/Compiler/test/inline.jl b/Compiler/test/inline.jl index b8ff14405391d..c5a7ab197e16e 100644 --- a/Compiler/test/inline.jl +++ b/Compiler/test/inline.jl @@ -1769,6 +1769,7 @@ let getfield_tfunc(@nospecialize xs...) = Compiler.getfield_tfunc(Compiler.fallback_lattice, xs...) @test getfield_tfunc(Type, Core.Const(:parameters)) !== Union{} @test !isa(getfield_tfunc(Type{Tuple{Union{Int, Float64}, Int}}, Core.Const(:name)), Core.Const) + @test !isa(getfield_tfunc(Type{Tuple{Any}}, Core.Const(:name)), Core.Const) end @test fully_eliminated(Base.ismutable, Tuple{Base.RefValue}) From 6b39a818bdcd302612c348785486e0a796610a83 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 13 Feb 2025 12:11:07 -0500 Subject: [PATCH 333/342] print admonition for auto-import only once per module (#57378) Quiets the build somewhat, after #57311 made it noisy. --- src/julia.h | 3 ++- src/module.c | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/julia.h b/src/julia.h index 2d50bbb1cf3b6..bf049c909d833 100644 --- a/src/julia.h +++ b/src/julia.h @@ -738,7 +738,8 @@ typedef struct _jl_binding_t { uint8_t exportp:1; // `public foo` sets `publicp`, `export foo` sets both `publicp` and `exportp` uint8_t publicp:1; // exportp without publicp is not allowed. uint8_t deprecated:2; // 0=not deprecated, 1=renamed, 2=moved to another package - uint8_t padding:3; + uint8_t did_print_implicit_import_admonition:1; + uint8_t padding:2; } jl_binding_t; typedef struct { diff --git a/src/module.c b/src/module.c index a5a9481d15e72..8adc99a5380d5 100644 --- a/src/module.c +++ b/src/module.c @@ -458,6 +458,7 @@ static jl_binding_t *new_binding(jl_module_t *mod, jl_sym_t *name) b->publicp = 0; b->deprecated = 0; b->did_print_backdate_admonition = 0; + b->did_print_implicit_import_admonition = 0; JL_GC_PUSH1(&b); b->globalref = jl_new_globalref(mod, name, b); jl_gc_wb(b, b->globalref); @@ -537,6 +538,7 @@ JL_DLLEXPORT jl_module_t *jl_get_module_of_binding(jl_module_t *m, jl_sym_t *var static NOINLINE void print_backdate_admonition(jl_binding_t *b) JL_NOTSAFEPOINT { + b->did_print_backdate_admonition = 1; jl_safe_printf( "WARNING: Detected access to binding `%s.%s` in a world prior to its definition world.\n" " Julia 1.12 has introduced more strict world age semantics for global bindings.\n" @@ -544,7 +546,6 @@ static NOINLINE void print_backdate_admonition(jl_binding_t *b) JL_NOTSAFEPOINT " !!! This code will error in future versions of Julia.\n" "Hint: Add an appropriate `invokelatest` around the access to this binding.\n", jl_symbol_name(b->globalref->mod->name), jl_symbol_name(b->globalref->name)); - b->did_print_backdate_admonition = 1; } static inline void check_backdated_binding(jl_binding_t *b, enum jl_partition_kind kind) JL_NOTSAFEPOINT @@ -696,10 +697,12 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_ else if (kind != BINDING_KIND_IMPORTED) { int should_error = strcmp(jl_symbol_name(var), "=>") == 0; jl_module_t *from = jl_binding_dbgmodule(b, m, var); - if (should_error) + if (should_error) { jl_errorf("invalid method definition in %s: function %s.%s must be explicitly imported to be extended", jl_module_debug_name(m), jl_module_debug_name(from), jl_symbol_name(var)); - else + } + else if (!b->did_print_implicit_import_admonition) { + b->did_print_implicit_import_admonition = 1; jl_printf(JL_STDERR, "WARNING: Constructor for type \"%s\" was extended in `%s` without explicit qualification or import.\n" " NOTE: Assumed \"%s\" refers to `%s.%s`. This behavior is deprecated and may differ in future versions.`\n" " NOTE: This behavior may have differed in Julia versions prior to 1.12.\n" @@ -709,6 +712,7 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_ jl_symbol_name(var), jl_module_debug_name(from), jl_symbol_name(var), jl_symbol_name(var), jl_symbol_name(var), jl_module_debug_name(from), jl_symbol_name(var), jl_module_debug_name(from), jl_symbol_name(var)); + } } return ownerb; } From 91e733384eedeab174c63362c3b8dd31d1655434 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sat, 8 Feb 2025 19:51:21 +0000 Subject: [PATCH 334/342] internals: add _defaultctor function for defining ctors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deferring this part of defining the ctor code allows it to do some value-based optimizations, without the awkwardness previously of needing to do conditional lowering of all of the possible versions that might be useful just from syntax transforms. This feels very like a generated function: how it expands just the function body, except it is flipped so that then we wrap the result in a single Method instead of being created from a Method! Avoids lowering inaccuracies where a variable appears but is not used. These warnings are now prevented: ```julia julia> struct Foo{T} x::(T; Any) end WARNING: method definition for Foo at REPL[1]:2 declares type variable T but does not use it. julia> struct Foo{T} x::Union{Any, T} end WARNING: method definition for Foo at REPL[1]:2 declares type variable T but does not use it. ``` Avoids hitting https://github.com/JuliaLang/julia/issues/31542. This lowering mistake is now avoided: ```julia julia> struct Foo{T} x::(Val{T} where T) end ERROR: syntax: invalid variable expression in "where" around REPL[1]:2 ``` As a minor optimization, this avoids generating a `convert` call when the user declares explicit `::Any` declarations, the same as if the user didn't annotate the field type: ```julia julia> struct Foo x::Any y::Int z end julia> code_lowered(Foo)[2] CodeInfo( @ REPL[1]:2 within `unknown scope` 1 ─ %1 = builtin Core.fieldtype(#ctor-self#, 2) │ %2 = y │ @_4 = %2 │ %4 = builtin @_4 isa %1 └── goto #3 if not %4 2 ─ goto #4 3 ─ @_4 = Base.convert(%1, @_4) 4 ┄ %8 = @_4 │ %9 = %new(#ctor-self#, x, %8, z) └── return %9 ) ``` --- src/ast.c | 28 +++++++++ src/builtin_proto.h | 1 + src/builtins.c | 8 +++ src/jlfrontend.scm | 6 ++ src/julia-syntax.scm | 143 +++++++++++++++---------------------------- src/julia.h | 1 + src/julia_internal.h | 3 + src/method.c | 129 ++++++++++++++++++++++++++++++++++++++ src/staticdata.c | 4 +- src/toplevel.c | 2 +- 10 files changed, 228 insertions(+), 97 deletions(-) diff --git a/src/ast.c b/src/ast.c index f643f4a2f40fe..70bf6024a2dd5 100644 --- a/src/ast.c +++ b/src/ast.c @@ -1369,6 +1369,34 @@ JL_DLLEXPORT jl_value_t *jl_expand_stmt(jl_value_t *expr, jl_module_t *inmodule) return jl_expand_stmt_with_loc(expr, inmodule, "none", 0); } +jl_code_info_t *jl_outer_ctor_body(jl_value_t *thistype, size_t nfields, size_t nsparams, jl_module_t *inmodule, const char *file, int line) +{ + JL_TIMING(LOWERING, LOWERING); + jl_timing_show_location(file, line, inmodule, JL_TIMING_DEFAULT_BLOCK); + jl_expr_t *expr = jl_exprn(jl_empty_sym, 3); + JL_GC_PUSH1(&expr); + jl_exprargset(expr, 0, thistype); + jl_exprargset(expr, 1, jl_box_long(nfields)); + jl_exprargset(expr, 2, jl_box_long(nsparams)); + jl_code_info_t *ci = (jl_code_info_t*)jl_call_scm_on_ast_and_loc("jl-default-outer-ctor-body", (jl_value_t*)expr, inmodule, file, line); + JL_GC_POP(); + assert(jl_is_code_info(ci)); + return ci; +} + +jl_code_info_t *jl_inner_ctor_body(jl_array_t *fieldkinds, jl_module_t *inmodule, const char *file, int line) +{ + JL_TIMING(LOWERING, LOWERING); + jl_timing_show_location(file, line, inmodule, JL_TIMING_DEFAULT_BLOCK); + jl_expr_t *expr = jl_exprn(jl_empty_sym, 0); + JL_GC_PUSH1(&expr); + expr->args = fieldkinds; + jl_code_info_t *ci = (jl_code_info_t*)jl_call_scm_on_ast_and_loc("jl-default-inner-ctor-body", (jl_value_t*)expr, inmodule, file, line); + JL_GC_POP(); + assert(jl_is_code_info(ci)); + return ci; +} + //------------------------------------------------------------------------------ // Parsing API and utils for calling parser from runtime diff --git a/src/builtin_proto.h b/src/builtin_proto.h index 77463ae4884cb..a543aa895fb97 100644 --- a/src/builtin_proto.h +++ b/src/builtin_proto.h @@ -80,6 +80,7 @@ JL_CALLABLE(jl_f__structtype); JL_CALLABLE(jl_f__abstracttype); JL_CALLABLE(jl_f__primitivetype); JL_CALLABLE(jl_f__setsuper); +JL_CALLABLE(jl_f__defaultctors); JL_CALLABLE(jl_f__equiv_typedef); JL_CALLABLE(jl_f_get_binding_type); JL_CALLABLE(jl_f__compute_sparams); diff --git a/src/builtins.c b/src/builtins.c index f3d2dfad42819..063b191510bfd 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -2345,6 +2345,13 @@ JL_CALLABLE(jl_f__equiv_typedef) return equiv_type(args[0], args[1]) ? jl_true : jl_false; } +JL_CALLABLE(jl_f__defaultctors) +{ + JL_NARGS(_defaultctors, 2, 2); + jl_ctor_def(args[0], args[1]); + return jl_nothing; +} + // IntrinsicFunctions --------------------------------------------------------- static void (*runtime_fp[num_intrinsics])(void); @@ -2541,6 +2548,7 @@ void jl_init_primitives(void) JL_GC_DISABLED add_builtin_func("_abstracttype", jl_f__abstracttype); add_builtin_func("_primitivetype", jl_f__primitivetype); add_builtin_func("_setsuper!", jl_f__setsuper); + add_builtin_func("_defaultctors", jl_f__defaultctors); jl_builtin__typebody = add_builtin_func("_typebody!", jl_f__typebody); add_builtin_func("_equiv_typedef", jl_f__equiv_typedef); jl_builtin_donotdelete = add_builtin_func("donotdelete", jl_f_donotdelete); diff --git a/src/jlfrontend.scm b/src/jlfrontend.scm index 9c69da199c0cd..c313a1e9b0db5 100644 --- a/src/jlfrontend.scm +++ b/src/jlfrontend.scm @@ -198,6 +198,12 @@ (error-wrap (lambda () (julia-expand-macroscope expr)))) +(define (jl-default-inner-ctor-body field-kinds file line) + (expand-to-thunk- (default-inner-ctor-body (cdr field-kinds) file line) file line)) + +(define (jl-default-outer-ctor-body args file line) + (expand-to-thunk- (default-outer-ctor-body (cadr args) (caddr args) (cadddr args) file line) file line)) + ; run whole frontend on a string. useful for testing. (define (fe str) (expand-toplevel-expr (julia-parse str) 'none 0)) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 00057498bbf9b..b6dc7bb9c8a12 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -183,6 +183,7 @@ (meta ret-type ,R) ,@(list-tail body (+ 1 (length meta)))))))))) + ;; convert x<:T<:y etc. exprs into (name lower-bound upper-bound) ;; a bound is #f if not specified (define (analyze-typevar e) @@ -753,64 +754,34 @@ (params bounds) (sparam-name-bounds params) (struct-def-expr- name params bounds super (flatten-blocks fields) mut))) -;; replace field names with gensyms if they conflict with field-types -(define (safe-field-names field-names field-types) - (if (any (lambda (v) (contains (lambda (e) (eq? e v)) field-types)) - field-names) - (map (lambda (x) (gensy)) field-names) - ;; use a different name for a field called `_` - (map (lambda (x) (if (eq? x '_) (gensy) x)) field-names))) - -(define (with-wheres call wheres) - (if (pair? wheres) - `(where ,call ,@wheres) - call)) - -(define (default-inner-ctors name field-names field-types params bounds locs) - (let* ((field-names (safe-field-names field-names field-types)) - (all-ctor (if (null? params) - ;; definition with exact types for all arguments - `(function (call ,name - ,@(map make-decl field-names field-types)) - (block - ,@locs - (new (globalref (thismodule) ,name) ,@field-names))) - #f)) - (any-ctor (if (or (not all-ctor) (any (lambda (t) (not (equal? t '(core Any)))) - field-types)) - ;; definition with Any for all arguments - ;; only if any field type is not Any, checked at runtime - `(function (call (|::| |#ctor-self#| - ,(with-wheres - `(curly (core Type) ,(if (pair? params) - `(curly ,name ,@params) - name)) - (map (lambda (b) (cons 'var-bounds b)) bounds))) - ,@field-names) - (block - ,@locs - (call new ,@field-names))) ; this will add convert calls later - #f))) - (if all-ctor - (if any-ctor - (list all-ctor - `(if ,(foldl (lambda (t u) - `(&& ,u (call (core ===) (core Any) ,t))) - `(call (core ===) (core Any) ,(car field-types)) - (cdr field-types)) - '(block) - ,any-ctor)) - (list all-ctor)) - (list any-ctor)))) - -(define (default-outer-ctor name field-names field-types params bounds locs) - (let ((field-names (safe-field-names field-names field-types))) - `(function ,(with-wheres - `(call ,name ,@(map make-decl field-names field-types)) - (map (lambda (b) (cons 'var-bounds b)) bounds)) - (block - ,@locs - (new (curly ,name ,@params) ,@field-names))))) +;; definition with Any for all arguments (except type, which is exact) +;; field-kinds: +;; -1 no convert (e.g. because it is Any) +;; 0 normal convert to fieldtype +;; 1+ static_parameter N +(define (default-inner-ctor-body field-kinds file line) + (let* ((name '|#ctor-self#|) + (field-names (map (lambda (idx) (symbol (string "_" (+ idx 1)))) (iota (length field-kinds)))) + (field-convert (lambda (fld fty val) + (cond ((eq? fty -1) val) + ((> fty 0) (convert-for-type-decl val `(static_parameter ,fty) #f #f)) + (else (convert-for-type-decl val `(call (core fieldtype) ,name ,(+ fld 1)) #f #f))))) + (field-vals (map field-convert (iota (length field-names)) field-kinds field-names)) + (body `(block + (line ,line ,file) + (return (new ,name ,@field-vals))))) + `(lambda ,(cons name field-names) () (scope-block ,body)))) + +;; definition with exact types for all arguments (except type, which is not parameterized) +(define (default-outer-ctor-body thistype field-count sparam-count file line) + (let* ((name '|#ctor-self#|) + (field-names (map (lambda (idx) (symbol (string "_" (+ idx 1)))) (iota field-count))) + (sparams (map (lambda (idx) `(static_parameter ,(+ idx 1))) (iota sparam-count))) + (type (if (null? sparams) name `(curly ,thistype ,@sparams))) + (body `(block + (line ,line ,file) + (return (new ,type ,@field-names))))) + `(lambda ,(cons name field-names) () (scope-block ,body)))) (define (num-non-varargs args) (count (lambda (a) (not (vararg? a))) args)) @@ -993,14 +964,11 @@ fields))) (attrs (reverse attrs)) (defs (filter (lambda (x) (not (or (effect-free? x) (eq? (car x) 'string)))) defs)) - (locs (if (and (pair? fields0) (linenum? (car fields0))) - (list (car fields0)) - '())) + (loc (if (and (pair? fields0) (linenum? (car fields0))) + (car fields0) + '(line 0 ||))) (field-names (map decl-var fields)) (field-types (map decl-type fields)) - (defs2 (if (null? defs) - (default-inner-ctors name field-names field-types params bounds locs) - defs)) (min-initialized (min (ctors-min-initialized defs) (length fields))) (hasprev (make-ssavalue)) (prev (make-ssavalue)) @@ -1042,34 +1010,21 @@ (const (globalref (thismodule) ,name) ,newdef) (latestworld) (null))) - ;; "inner" constructors - (scope-block - (block - (hardscope) - (global ,name) - ,@(map (lambda (c) - (rewrite-ctor c name params field-names field-types)) - defs2))) - ;; "outer" constructors - ,@(if (and (null? defs) - (not (null? params)) - ;; To generate an outer constructor, each parameter must occur in a field - ;; type, or in the bounds of a subsequent parameter. - ;; Otherwise the constructor would not work, since the parameter values - ;; would never be specified. - (let loop ((root-types field-types) - (sp (reverse bounds))) - (or (null? sp) - (let ((p (car sp))) - (and (expr-contains-eq (car p) (cons 'list root-types)) - (loop (append (cdr p) root-types) - (cdr sp))))))) - `((scope-block - (block - (global ,name) - ,(default-outer-ctor name field-names field-types - params bounds locs)))) - '()) + ;; Always define ctors even if we didn't change the definition. + ;; If newdef===prev, then this is a bit suspect, since we don't know what might be + ;; changing about the old ctor definitions (we don't even track whether we're + ;; replacing defaultctors with identical ones). But it seems better to have the ctors + ;; added alongside (replacing) the old ones, than to not have them and need them. + ;; Commonly Revise.jl should be used to figure out actually which methods should + ;; actually be deleted or added anew. + ,(if (null? defs) + `(call (core _defaultctors) ,newdef (inert ,loc)) + `(scope-block + (block + (hardscope) + (global ,name) + ,@(map (lambda (c) (rewrite-ctor c name params field-names field-types)) defs)))) + (latestworld) (null))))) (define (abstract-type-def-expr name params super) @@ -4646,7 +4601,7 @@ f(x) = yt(x) ;; from the current function. (define (compile e break-labels value tail) (if (or (not (pair? e)) (memq (car e) '(null true false ssavalue quote inert top core copyast the_exception $ - globalref thismodule cdecl stdcall fastcall thiscall llvmcall))) + globalref thismodule cdecl stdcall fastcall thiscall llvmcall static_parameter))) (let ((e1 (if (and arg-map (symbol? e)) (get arg-map e e) e))) @@ -4657,7 +4612,7 @@ f(x) = yt(x) (cond (tail (emit-return tail e1)) (value e1) ((symbol? e1) (emit e1) #f) ;; keep symbols for undefined-var checking - ((and (pair? e1) (eq? (car e1) 'globalref)) (emit e1) #f) ;; keep globals for undefined-var checking + ((and (pair? e1) (memq (car e1) '(globalref static_parameter))) (emit e1) #f) ;; keep for undefined-var checking (else #f))) (case (car e) ((call new splatnew foreigncall cfunction new_opaque_closure) diff --git a/src/julia.h b/src/julia.h index bf049c909d833..3e730a44453ce 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1612,6 +1612,7 @@ static inline int jl_field_isconst(jl_datatype_t *st, int i) JL_NOTSAFEPOINT #define jl_is_quotenode(v) jl_typetagis(v,jl_quotenode_type) #define jl_is_newvarnode(v) jl_typetagis(v,jl_newvarnode_type) #define jl_is_linenode(v) jl_typetagis(v,jl_linenumbernode_type) +#define jl_is_linenumbernode(v) jl_typetagis(v,jl_linenumbernode_type) #define jl_is_method_instance(v) jl_typetagis(v,jl_method_instance_type) #define jl_is_code_instance(v) jl_typetagis(v,jl_code_instance_type) #define jl_is_code_info(v) jl_typetagis(v,jl_code_info_type) diff --git a/src/julia_internal.h b/src/julia_internal.h index 0f52f82ac8230..7fff59806f62f 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -1214,6 +1214,9 @@ JL_DLLEXPORT int jl_has_meta(jl_array_t *body, jl_sym_t *sym) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_parse(const char *text, size_t text_len, jl_value_t *filename, size_t lineno, size_t offset, jl_value_t *options); +jl_code_info_t *jl_inner_ctor_body(jl_array_t *fieldkinds, jl_module_t *inmodule, const char *file, int line); +jl_code_info_t *jl_outer_ctor_body(jl_value_t *thistype, size_t nfields, size_t nsparams, jl_module_t *inmodule, const char *file, int line); +void jl_ctor_def(jl_value_t *ty, jl_value_t *functionloc); //-------------------------------------------------- // Backtraces diff --git a/src/method.c b/src/method.c index 0fc0e0ca1f87d..31544ef77fa3e 100644 --- a/src/method.c +++ b/src/method.c @@ -1266,6 +1266,135 @@ JL_DLLEXPORT jl_method_t* jl_method_def(jl_svec_t *argdata, return m; } +void jl_ctor_def(jl_value_t *ty, jl_value_t *functionloc) +{ + jl_datatype_t *dt = (jl_datatype_t*)jl_unwrap_unionall(ty); + JL_TYPECHK(ctor_def, datatype, (jl_value_t*)dt); + JL_TYPECHK(ctor_def, linenumbernode, functionloc); + jl_svec_t *fieldtypes = jl_get_fieldtypes(dt); + size_t nfields = jl_svec_len(fieldtypes); + size_t nparams = jl_subtype_env_size(ty); + jl_module_t *inmodule = dt->name->module; + jl_sym_t *file = (jl_sym_t*)jl_linenode_file(functionloc); + if (!jl_is_symbol(file)) + file = jl_empty_sym; + int32_t line = jl_linenode_line(functionloc); + + // argdata is svec(svec(types...), svec(typevars...), functionloc) + jl_svec_t *argdata = jl_alloc_svec(3); + jl_array_t *fieldkinds = NULL; + jl_code_info_t *body = NULL; + JL_GC_PUSH3(&argdata, &fieldkinds, &body); + jl_svecset(argdata, 2, functionloc); + jl_svec_t *tvars = jl_alloc_svec(nparams); + jl_svecset(argdata, 1, tvars); + jl_unionall_t *ua = (jl_unionall_t*)ty; + for (size_t i = 0; i < nparams; i++) { + assert(jl_is_unionall(ua)); + jl_svecset(tvars, i, ua->var); + ua = (jl_unionall_t*)ua->body; + } + jl_svec_t *names = dt->name->names; + + // define outer constructor (if all typevars are present (thus not definitely unconstrained) by the fields or other typevars which themselves are constrained) + int constrains_all_tvars = 1; + for (size_t i = nparams; i > 0; i--) { + jl_tvar_t *tv = (jl_tvar_t*)jl_svecref(tvars, i - 1); + int constrains_tvar = 0; + for (size_t i = 0; i < nfields; i++) { + jl_value_t *ft = jl_svecref(fieldtypes, i); + if (jl_has_typevar(ft, tv)) { + constrains_tvar = 1; + break; + } + } + for (size_t j = i; j < nparams; j++) { + jl_tvar_t *tv2 = (jl_tvar_t*)jl_svecref(tvars, j); + if (jl_has_typevar(tv2->ub, tv)) { // lb doesn't constrain, but jl_has_typevar doesn't have a way to specify that we care about may-constrain and not merely containment + constrains_tvar = 1; + break; + } + if (tv2 == tv) { + constrains_tvar = 0; + break; + } + } + if (!constrains_tvar) { + constrains_all_tvars = 0; + break; + } + } + if (constrains_all_tvars) { + jl_svec_t *atypes = jl_alloc_svec(nfields + 1); + jl_svecset(argdata, 0, atypes); + jl_svecset(atypes, 0, jl_wrap_Type(ty)); + for (size_t i = 0; i < nfields; i++) { + jl_value_t *ft = jl_svecref(fieldtypes, i); + jl_svecset(atypes, i + 1, ft); + } + body = jl_outer_ctor_body(ty, nfields, nparams, inmodule, jl_symbol_name(file), line); + if (names) { + jl_array_t *slotnames = body->slotnames; + for (size_t i = 0; i < nfields; i++) { + jl_array_ptr_set(slotnames, i + 1, jl_svecref(names, i)); + } + } + jl_method_def(argdata, NULL, body, inmodule); + if (nparams == 0) { + int all_Any = 1; // check if all fields are Any and the type is not parameterized, since inner constructor would be the same signature and code + for (size_t i = 0; i < nfields; i++) { + jl_value_t *ft = jl_svecref(fieldtypes, i); + if (ft != (jl_value_t*)jl_any_type) { + all_Any = 0; + break; + } + } + if (all_Any) { + JL_GC_POP(); + return; + } + } + } + + // define inner constructor + jl_svec_t *atypes = jl_svec_fill(nfields + 1, (jl_value_t*)jl_any_type); + jl_svecset(argdata, 0, atypes); + jl_value_t *typedt = (jl_value_t*)jl_wrap_Type((jl_value_t*)dt); + jl_svecset(atypes, 0, typedt); + fieldkinds = jl_alloc_vec_any(nfields); + for (size_t i = 0; i < nfields; i++) { + jl_value_t *ft = jl_svecref(fieldtypes, i); + int kind = ft == (jl_value_t*)jl_any_type ? -1 : 0; + // TODO: if more efficient to do so, we could reference the sparam instead of fieldtype + //if (jl_is_typevar(ft)) { + // for (size_t i = 0; i < nparams; i++) { + // if (jl_svecref(tvars, i) == ft) { + // kind = i + 1; + // break; // if repeated, must consider only the innermost + // } + // } + //} + jl_array_ptr_set(fieldkinds, i, jl_box_long(kind)); + } + // rewrap_unionall(Type{dt}, ty) + for (size_t i = nparams; i > 0; i--) { + jl_value_t *tv = jl_svecref(tvars, i - 1); + typedt = jl_new_struct(jl_unionall_type, tv, typedt); + jl_svecset(atypes, 0, typedt); + } + tvars = jl_emptysvec; + jl_svecset(argdata, 1, tvars); + body = jl_inner_ctor_body(fieldkinds, inmodule, jl_symbol_name(file), line); + if (names) { + jl_array_t *slotnames = body->slotnames; + for (size_t i = 0; i < nfields; i++) { + jl_array_ptr_set(slotnames, i + 1, jl_svecref(names, i)); + } + } + jl_method_def(argdata, NULL, body, inmodule); + JL_GC_POP(); +} + // root blocks // This section handles method roots. Roots are GC-preserved items needed to diff --git a/src/staticdata.c b/src/staticdata.c index c29448c491eb7..ef6140166adc1 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -515,8 +515,8 @@ static const jl_fptr_args_t id_to_fptrs[] = { &jl_f_memoryrefset, &jl_f_memoryrefswap, &jl_f_memoryrefmodify, &jl_f_memoryrefreplace, &jl_f_memoryrefsetonce, &jl_f_applicable, &jl_f_invoke, &jl_f_sizeof, &jl_f__expr, &jl_f__typevar, &jl_f_ifelse, &jl_f__structtype, &jl_f__abstracttype, &jl_f__primitivetype, - &jl_f__typebody, &jl_f__setsuper, &jl_f__equiv_typedef, &jl_f_get_binding_type, - &jl_f_opaque_closure_call, &jl_f_donotdelete, &jl_f_compilerbarrier, + &jl_f__typebody, &jl_f__setsuper, &jl_f__equiv_typedef, &jl_f__defaultctors, + &jl_f_opaque_closure_call, &jl_f_donotdelete, &jl_f_compilerbarrier, &jl_f_get_binding_type, &jl_f_getglobal, &jl_f_setglobal, &jl_f_swapglobal, &jl_f_modifyglobal, &jl_f_replaceglobal, &jl_f_setglobalonce, &jl_f_finalizer, &jl_f__compute_sparams, &jl_f__svec_ref, &jl_f_current_scope, diff --git a/src/toplevel.c b/src/toplevel.c index 9bb82a3451848..5b5db28f113e8 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -433,7 +433,7 @@ static void expr_attributes(jl_value_t *v, jl_array_t *body, int *has_ccall, int if (jl_is_intrinsic(called) && jl_unbox_int32(called) == (int)llvmcall) { *has_ccall = 1; } - if (called == jl_builtin__typebody) { + if (called == jl_builtin__typebody) { // TODO: rely on latestworld instead of function callee detection here (or add it to jl_is_toplevel_only_expr) *has_defs = 1; } } From d0e80250f2f99d8a9f4c62f511cf958e7bb8dde0 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 11 Feb 2025 18:39:13 +0000 Subject: [PATCH 335/342] fix ismutationfree bits for types This was breaking effects tests. --- src/jltypes.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/jltypes.c b/src/jltypes.c index e21d8ac184302..52026c4d71c9b 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3876,7 +3876,10 @@ void jl_init_types(void) JL_GC_DISABLED jl_string_type->ismutationfree = jl_string_type->isidentityfree = 1; jl_symbol_type->ismutationfree = jl_symbol_type->isidentityfree = 1; jl_simplevector_type->ismutationfree = jl_simplevector_type->isidentityfree = 1; + jl_typename_type->ismutationfree = 1; jl_datatype_type->ismutationfree = 1; + jl_uniontype_type->ismutationfree = 1; + jl_unionall_type->ismutationfree = 1; assert(((jl_datatype_t*)jl_array_any_type)->ismutationfree == 0); assert(((jl_datatype_t*)jl_array_uint8_type)->ismutationfree == 0); From 864d2bfa102e02a8bee76e9a337ff122a913c054 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Thu, 13 Feb 2025 22:51:01 -0500 Subject: [PATCH 336/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?Pkg=20stdlib=20from=207aeec766c=20to=20c54ee594d=20(#57401)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/md5 | 1 - .../Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/sha512 | 1 - .../Pkg-c54ee594d1c16270d4f67e09788839d9618faf18.tar.gz/md5 | 1 + .../Pkg-c54ee594d1c16270d4f67e09788839d9618faf18.tar.gz/sha512 | 1 + stdlib/Pkg.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/md5 delete mode 100644 deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/sha512 create mode 100644 deps/checksums/Pkg-c54ee594d1c16270d4f67e09788839d9618faf18.tar.gz/md5 create mode 100644 deps/checksums/Pkg-c54ee594d1c16270d4f67e09788839d9618faf18.tar.gz/sha512 diff --git a/deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/md5 b/deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/md5 deleted file mode 100644 index 2574fca7dbe2b..0000000000000 --- a/deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -d3e705f029ba3d81bd0725c2cb0b2e46 diff --git a/deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/sha512 b/deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/sha512 deleted file mode 100644 index 54276d232add9..0000000000000 --- a/deps/checksums/Pkg-7aeec766cf637e2bc2af161eba8abd3a4b68d025.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -ef8c37b056fb6dfc3c8b1b542d65d6ffdfdc1f41a08da5307ad1c3e7ce9fe0030ac4132c9d30af0e850964842d9b330e2f950bb49dd6dd0fd5b30592f8173477 diff --git a/deps/checksums/Pkg-c54ee594d1c16270d4f67e09788839d9618faf18.tar.gz/md5 b/deps/checksums/Pkg-c54ee594d1c16270d4f67e09788839d9618faf18.tar.gz/md5 new file mode 100644 index 0000000000000..b447f41a4ea7c --- /dev/null +++ b/deps/checksums/Pkg-c54ee594d1c16270d4f67e09788839d9618faf18.tar.gz/md5 @@ -0,0 +1 @@ +331e68c7e647051d55352054ad58f2ee diff --git a/deps/checksums/Pkg-c54ee594d1c16270d4f67e09788839d9618faf18.tar.gz/sha512 b/deps/checksums/Pkg-c54ee594d1c16270d4f67e09788839d9618faf18.tar.gz/sha512 new file mode 100644 index 0000000000000..bf572806ec843 --- /dev/null +++ b/deps/checksums/Pkg-c54ee594d1c16270d4f67e09788839d9618faf18.tar.gz/sha512 @@ -0,0 +1 @@ +087848451bd13e05d11d0ff7321c89d14161cb74a51b545cc266f7f7edddf12f28f02fa73c7bb46aa353fae6607cf3ae05cebdfe9fb9310304b898f6b1506a54 diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 63845886099aa..6aff7efd20790 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = master -PKG_SHA1 = 7aeec766cf637e2bc2af161eba8abd3a4b68d025 +PKG_SHA1 = c54ee594d1c16270d4f67e09788839d9618faf18 PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 From 75dba048f49ddb4281c625ed4d12ffbab3e3c426 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 13 Feb 2025 23:02:09 -0500 Subject: [PATCH 337/342] [LateLowerGCFrame] fix PlaceGCFrameReset for returns_twice (#57392) Using the right variable here should help quite a bit with the random GC segfaults we have seen. We already have the tests for this, but it is quite hard to make them just complex enough to trigger reliably. Fixes #57333 --- src/codegen.cpp | 5 ++--- src/llvm-late-gc-lowering.cpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 26f34d63e578f..b99a9eff473fd 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3232,7 +3232,6 @@ static bool slot_eq(jl_value_t *e, int sl) // --- find volatile variables --- // assigned in a try block and used outside that try block - static bool local_var_occurs(jl_value_t *e, int sl) { if (slot_eq(e, sl)) { @@ -3272,13 +3271,13 @@ static bool have_try_block(jl_array_t *stmts) return 0; } -// conservative marking of all variables potentially used after a catch block that were assigned before it +// conservative marking of all variables potentially used after a catch block that were assigned after the try static void mark_volatile_vars(jl_array_t *stmts, SmallVectorImpl &slots, const std::set &bbstarts) { if (!have_try_block(stmts)) return; size_t slength = jl_array_dim0(stmts); - BitVector assigned_in_block(slots.size()); // conservatively only ignore slots assigned in the same basic block + BitVector assigned_in_block(slots.size()); // since we don't have domtree access, conservatively only ignore slots assigned in the same basic block for (int j = 0; j < (int)slength; j++) { if (bbstarts.count(j + 1)) assigned_in_block.reset(); diff --git a/src/llvm-late-gc-lowering.cpp b/src/llvm-late-gc-lowering.cpp index 7d6fba65a79e7..2b9b918c4bd53 100644 --- a/src/llvm-late-gc-lowering.cpp +++ b/src/llvm-late-gc-lowering.cpp @@ -2291,7 +2291,7 @@ void LateLowerGCFrame::PlaceGCFrameStores(State &S, unsigned MinColorRoot, const LargeSparseBitVector &NowLive = S.LiveSets[*rit]; // reset slots which are no longer alive for (int Idx : *LastLive) { - if (Idx >= PreAssignedColors && !HasBitSet(NowLive, Idx)) { + if (Colors[Idx] >= PreAssignedColors && !HasBitSet(NowLive, Idx)) { PlaceGCFrameReset(S, Idx, MinColorRoot, Colors, GCFrame, S.ReverseSafepointNumbering[*rit]); } From b3198c9962c5893c53b7c0571422b9c38ec1e52e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Fri, 14 Feb 2025 12:22:38 +0100 Subject: [PATCH 338/342] Bump JuliaSyntax to v1.0.2 (#57388) Resolves https://github.com/JuliaLang/julia/issues/56950. This should get backported to julia-1.12. --- deps/JuliaSyntax.version | 2 +- .../md5 | 1 + .../sha512 | 1 + .../md5 | 1 - .../sha512 | 1 - 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/JuliaSyntax-46723f071d5b2efcb21ca6757788028afb91cc13.tar.gz/md5 create mode 100644 deps/checksums/JuliaSyntax-46723f071d5b2efcb21ca6757788028afb91cc13.tar.gz/sha512 delete mode 100644 deps/checksums/JuliaSyntax-86bc4331eaa08e08bf2af1ba7b50bbbf4af70cdb.tar.gz/md5 delete mode 100644 deps/checksums/JuliaSyntax-86bc4331eaa08e08bf2af1ba7b50bbbf4af70cdb.tar.gz/sha512 diff --git a/deps/JuliaSyntax.version b/deps/JuliaSyntax.version index 70dac3231f626..9487754d8a617 100644 --- a/deps/JuliaSyntax.version +++ b/deps/JuliaSyntax.version @@ -1,4 +1,4 @@ JULIASYNTAX_BRANCH = main -JULIASYNTAX_SHA1 = 86bc4331eaa08e08bf2af1ba7b50bbbf4af70cdb +JULIASYNTAX_SHA1 = 46723f071d5b2efcb21ca6757788028afb91cc13 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 new file mode 100644 index 0000000000000..ff40f520dfe85 --- /dev/null +++ b/deps/checksums/JuliaSyntax-46723f071d5b2efcb21ca6757788028afb91cc13.tar.gz/md5 @@ -0,0 +1 @@ +2a0921e59edfab54554aa173f091c5b7 diff --git a/deps/checksums/JuliaSyntax-46723f071d5b2efcb21ca6757788028afb91cc13.tar.gz/sha512 b/deps/checksums/JuliaSyntax-46723f071d5b2efcb21ca6757788028afb91cc13.tar.gz/sha512 new file mode 100644 index 0000000000000..64e90d0edaba0 --- /dev/null +++ b/deps/checksums/JuliaSyntax-46723f071d5b2efcb21ca6757788028afb91cc13.tar.gz/sha512 @@ -0,0 +1 @@ +17050e23216335f6599f009f71e9614a11b6686e455554b1efd287cd8526a7ebece06dc473e34cd50f61bf52085ff72bb4279144a9fdb3a234d3d589a10fddaf diff --git a/deps/checksums/JuliaSyntax-86bc4331eaa08e08bf2af1ba7b50bbbf4af70cdb.tar.gz/md5 b/deps/checksums/JuliaSyntax-86bc4331eaa08e08bf2af1ba7b50bbbf4af70cdb.tar.gz/md5 deleted file mode 100644 index c5d3c249ca1e0..0000000000000 --- a/deps/checksums/JuliaSyntax-86bc4331eaa08e08bf2af1ba7b50bbbf4af70cdb.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -a514fe65096a489bd4d3c06b675573c7 diff --git a/deps/checksums/JuliaSyntax-86bc4331eaa08e08bf2af1ba7b50bbbf4af70cdb.tar.gz/sha512 b/deps/checksums/JuliaSyntax-86bc4331eaa08e08bf2af1ba7b50bbbf4af70cdb.tar.gz/sha512 deleted file mode 100644 index bdb48e7ef87eb..0000000000000 --- a/deps/checksums/JuliaSyntax-86bc4331eaa08e08bf2af1ba7b50bbbf4af70cdb.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -95d45a27e427f2553da4d4e821edaee6896121977ce6572212c4234013c6f85bc69fc78d237b4dae5d4ed3451f3ba9e1a7172668025ef7bf8aad024293aa2865 From 504cbc36648640eb09898f1ee0ea4fc36f38a18e Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Fri, 14 Feb 2025 06:23:28 -0500 Subject: [PATCH 339/342] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20?= =?UTF-8?q?Statistics=20stdlib=20from=20d49c2bf=20to=2077bd570=20(#57266)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: Statistics URL: https://github.com/JuliaStats/Statistics.jl.git Stdlib branch: master Julia branch: master Old commit: d49c2bf New commit: 77bd570 Julia version: 1.13.0-DEV Statistics version: 1.11.2(Does not match) Bump invoked by: @nalimilan Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaStats/Statistics.jl/compare/d49c2bf4f81e1efb4980a35fe39c815ef8396297...77bd5707f143eb624721a7df28ddef470e70ecef ``` $ git log --oneline d49c2bf..77bd570 77bd570 Fix `quantile` doctest (#188) bfa5c6b Merge pull request #184 from JuliaStats/an/quantilemuladd 6bd1531 Update src/Statistics.jl 44d51c7 Use muladd in aleph calculation in _quantile to avoid some rounding errors. 793733e Bump codecov/codecov-action from 4 to 5 (#181) ``` Co-authored-by: nalimilan <1120448+nalimilan@users.noreply.github.com> --- .../md5 | 1 + .../sha512 | 1 + .../md5 | 1 - .../sha512 | 1 - stdlib/Statistics.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/Statistics-77bd5707f143eb624721a7df28ddef470e70ecef.tar.gz/md5 create mode 100644 deps/checksums/Statistics-77bd5707f143eb624721a7df28ddef470e70ecef.tar.gz/sha512 delete mode 100644 deps/checksums/Statistics-d49c2bf4f81e1efb4980a35fe39c815ef8396297.tar.gz/md5 delete mode 100644 deps/checksums/Statistics-d49c2bf4f81e1efb4980a35fe39c815ef8396297.tar.gz/sha512 diff --git a/deps/checksums/Statistics-77bd5707f143eb624721a7df28ddef470e70ecef.tar.gz/md5 b/deps/checksums/Statistics-77bd5707f143eb624721a7df28ddef470e70ecef.tar.gz/md5 new file mode 100644 index 0000000000000..600c561d0cf14 --- /dev/null +++ b/deps/checksums/Statistics-77bd5707f143eb624721a7df28ddef470e70ecef.tar.gz/md5 @@ -0,0 +1 @@ +5235ac479da042d5dc3c572c473b7219 diff --git a/deps/checksums/Statistics-77bd5707f143eb624721a7df28ddef470e70ecef.tar.gz/sha512 b/deps/checksums/Statistics-77bd5707f143eb624721a7df28ddef470e70ecef.tar.gz/sha512 new file mode 100644 index 0000000000000..2f663a3d7c44d --- /dev/null +++ b/deps/checksums/Statistics-77bd5707f143eb624721a7df28ddef470e70ecef.tar.gz/sha512 @@ -0,0 +1 @@ +0c02ccf1b4988fc701209afb949f27e6f675f37a628385d3f28dc9ea333fed38ce1ca77b001e58fdbe15af833bbe98598cbf478cef21a98b37d54acfe52270b6 diff --git a/deps/checksums/Statistics-d49c2bf4f81e1efb4980a35fe39c815ef8396297.tar.gz/md5 b/deps/checksums/Statistics-d49c2bf4f81e1efb4980a35fe39c815ef8396297.tar.gz/md5 deleted file mode 100644 index 3956c67f7fd47..0000000000000 --- a/deps/checksums/Statistics-d49c2bf4f81e1efb4980a35fe39c815ef8396297.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -acf2bb0ea30132602e172e2f5f6274b4 diff --git a/deps/checksums/Statistics-d49c2bf4f81e1efb4980a35fe39c815ef8396297.tar.gz/sha512 b/deps/checksums/Statistics-d49c2bf4f81e1efb4980a35fe39c815ef8396297.tar.gz/sha512 deleted file mode 100644 index 051f2d0a862c3..0000000000000 --- a/deps/checksums/Statistics-d49c2bf4f81e1efb4980a35fe39c815ef8396297.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -5e879fe79bae19b62f81659a102602271c73a424faf4be069ab31fb50e30b536a8c7b3692127763000cc1dbab69c93ac3da7bace5f093d05dce2d652fb221d52 diff --git a/stdlib/Statistics.version b/stdlib/Statistics.version index 3df70d30ba7e6..e6f0a62b3cec5 100644 --- a/stdlib/Statistics.version +++ b/stdlib/Statistics.version @@ -1,4 +1,4 @@ STATISTICS_BRANCH = master -STATISTICS_SHA1 = d49c2bf4f81e1efb4980a35fe39c815ef8396297 +STATISTICS_SHA1 = 77bd5707f143eb624721a7df28ddef470e70ecef STATISTICS_GIT_URL := https://github.com/JuliaStats/Statistics.jl.git STATISTICS_TAR_URL = https://api.github.com/repos/JuliaStats/Statistics.jl/tarball/$1 From 57b7d2e0a88d2e4006ad74ec4bd1db5586e2d0bf Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 14 Feb 2025 10:43:22 -0500 Subject: [PATCH 340/342] lowering: fix has_fcall computation (#57395) Previously didn't handle ccall or cfunction that were assigned to a variable. Required for inlining correctness. Fixes #57023 --- src/method.c | 8 ++++++-- test/core.jl | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/method.c b/src/method.c index 31544ef77fa3e..48edd8071e53d 100644 --- a/src/method.c +++ b/src/method.c @@ -485,8 +485,12 @@ jl_code_info_t *jl_new_code_info_from_ir(jl_expr_t *ir) is_flag_stmt = 1; else if (jl_is_expr(st) && ((jl_expr_t*)st)->head == jl_return_sym) jl_array_ptr_set(body, j, jl_new_struct(jl_returnnode_type, jl_exprarg(st, 0))); - else if (jl_is_expr(st) && (((jl_expr_t*)st)->head == jl_foreigncall_sym || ((jl_expr_t*)st)->head == jl_cfunction_sym)) - li->has_fcall = 1; + else { + if (jl_is_expr(st) && ((jl_expr_t*)st)->head == jl_assign_sym) + st = jl_exprarg(st, 1); + if (jl_is_expr(st) && (((jl_expr_t*)st)->head == jl_foreigncall_sym || ((jl_expr_t*)st)->head == jl_cfunction_sym)) + li->has_fcall = 1; + } if (is_flag_stmt) jl_array_uint32_set(li->ssaflags, j, 0); else { diff --git a/test/core.jl b/test/core.jl index ee47eba0d2c7d..ef1d6784cac94 100644 --- a/test/core.jl +++ b/test/core.jl @@ -8443,3 +8443,8 @@ f_call_me() = invoke(f_invoke_me, f_invoke_me_ci) f_invalidate_me() = 2 @test_throws ErrorException invoke(f_invoke_me, f_invoke_me_ci) @test_throws ErrorException f_call_me() + +myfun57023a(::Type{T}) where {T} = (x = @ccall mycfun()::Ptr{T}; x) +@test only(code_lowered(myfun57023a)).has_fcall +myfun57023b(::Type{T}) where {T} = (x = @cfunction myfun57023a Ptr{T} (Ref{T},); x) +@test only(code_lowered(myfun57023b)).has_fcall From 41a4dfa34086df0c43ec933235dc2cf9cb6f66bb Mon Sep 17 00:00:00 2001 From: Lilith Orion Hafner Date: Fri, 14 Feb 2025 09:56:23 -0600 Subject: [PATCH 341/342] Clarify mathematical definition of `gcd` (#57204) See also: Triage request for this: https://github.com/JuliaLang/julia/pull/57067#issuecomment-2625399127 Similar PR for `lcm`: https://github.com/JuliaLang/julia/pull/56992 --- base/intfuncs.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index dc81f2bd3e489..bb0f454d9c574 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -8,6 +8,9 @@ Greatest common (positive) divisor (or zero if all arguments are zero). The arguments may be integer and rational numbers. +``a`` is a divisor of ``b`` if there exists an integer ``m`` such +that ``ma=b``. + !!! compat "Julia 1.4" Rational arguments require Julia 1.4 or later. From be574cd1b441afdbc62fb40bfcc0cbec10475ad6 Mon Sep 17 00:00:00 2001 From: Lilith Orion Hafner Date: Fri, 14 Feb 2025 10:05:01 -0600 Subject: [PATCH 342/342] Make `Pairs` public (#56794) This is the type of slurped keyword args and IMO was already public in 1.10. --- base/public.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/base/public.jl b/base/public.jl index 8777a454c920a..8d2a65f9a150c 100644 --- a/base/public.jl +++ b/base/public.jl @@ -20,6 +20,7 @@ public Generator, ImmutableDict, OneTo, + Pairs, LogRange, UUID,