diff --git a/.github/labeler.yml b/.github/labeler.yml
new file mode 100644
index 0000000000000..9359bd0ca70a6
--- /dev/null
+++ b/.github/labeler.yml
@@ -0,0 +1,3 @@
+# See https://github.com/actions/labeler
+port-to-master: '**'
+port-to-v1.10: '**'
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000000000..7ed825781c53b
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,14 @@
+
+## PR Description
+
+_What does this PR do?_
+
+## Checklist
+
+Requirements for merging:
+- [ ] I have opened an issue or PR upstream on JuliaLang/julia:
+- [ ] I have removed the `port-to-*` labels that don't apply.
+- [ ] I have opened a PR on raicode to test these changes:
diff --git a/.github/workflows/Typos.yml b/.github/workflows/Typos.yml
index 6c9eeacc21800..25cf9fea7cd0b 100644
--- a/.github/workflows/Typos.yml
+++ b/.github/workflows/Typos.yml
@@ -11,7 +11,7 @@ jobs:
timeout-minutes: 5
steps:
- name: Checkout the JuliaLang/julia repository
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Check spelling with typos
diff --git a/.github/workflows/Whitespace.yml b/.github/workflows/Whitespace.yml
index 37c9dbfd39a3c..9b800da77dc29 100644
--- a/.github/workflows/Whitespace.yml
+++ b/.github/workflows/Whitespace.yml
@@ -15,10 +15,10 @@ jobs:
timeout-minutes: 2
steps:
- name: Checkout the JuliaLang/julia repository
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- - uses: julia-actions/setup-julia@9b79636afcfb07ab02c256cede01fe2db6ba808c # v2.6.0
+ - uses: julia-actions/setup-julia@5c9647d97b78a5debe5164e9eec09d653d29bd71 # v2.6.1
with:
version: '1'
- name: Check whitespace
diff --git a/.github/workflows/cffconvert.yml b/.github/workflows/cffconvert.yml
index 4c9debb246f3f..45f19078a8af8 100644
--- a/.github/workflows/cffconvert.yml
+++ b/.github/workflows/cffconvert.yml
@@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out a copy of the repository
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml
new file mode 100644
index 0000000000000..2141a906e96cd
--- /dev/null
+++ b/.github/workflows/labeler.yml
@@ -0,0 +1,17 @@
+# See https://github.com/actions/labeler
+name: "Pull Request Labeler"
+on:
+ pull_request_target:
+ types:
+ - opened
+
+jobs:
+ triage:
+ permissions:
+ contents: read
+ pull-requests: write
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/labeler@v4
+ with:
+ dot: true
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
new file mode 100644
index 0000000000000..3df2093491753
--- /dev/null
+++ b/.github/workflows/stale.yml
@@ -0,0 +1,16 @@
+name: "Close stale PRs"
+on:
+ schedule:
+ - cron: "0 0 * * *" # every night at midnight
+
+jobs:
+ stale:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/stale@v8
+ with:
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+ stale-pr-message: 'This PR is stale because it has been open 30 days with no activity. Comment or remove stale label, or this PR will be closed in 5 days.'
+ days-before-stale: 30
+ days-before-close: 5
+ stale-pr-label: 'stale'
diff --git a/.github/workflows/update-upstream-branches.yml b/.github/workflows/update-upstream-branches.yml
new file mode 100644
index 0000000000000..247000bbd42cd
--- /dev/null
+++ b/.github/workflows/update-upstream-branches.yml
@@ -0,0 +1,28 @@
+name: "Update upstream branches"
+on:
+ schedule:
+ - cron: "0 0 * * *" # every night at midnight
+ workflow_dispatch:
+
+jobs:
+ PullUpstream:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false # run all jobs in the matrix even if one fails
+ matrix:
+ branch:
+ - "master"
+ - "backports-release-1.10"
+ steps:
+ - name: Checkout RAI/julia
+ uses: actions/checkout@v3
+ with:
+ ref: ${{ matrix.branch }}
+ - name: Update ${{ matrix.branch }}
+ run: |
+ git config --global user.email "julia-engineering@relational.ai"
+ git config --global user.name "RAI CI (GitHub Action Automation)"
+
+ git remote add upstream https://github.com/JuliaLang/julia
+ git pull upstream ${{ matrix.branch }}
+ git push origin ${{ matrix.branch }}
diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl
index b455f078d83eb..f27a68da44b90 100644
--- a/Compiler/src/abstractinterpretation.jl
+++ b/Compiler/src/abstractinterpretation.jl
@@ -2247,7 +2247,7 @@ function abstract_invoke(interp::AbstractInterpreter, arginfo::ArgInfo, si::Stmt
return Future(CallMeta(Bottom, ErrorException, EFFECTS_THROWS, NoCallInfo()))
end
# TODO: When we add curing, we may want to assume this is nothrow
- if (method_or_ci.owner === Nothing && method_ir_ci.def.def isa Method)
+ if (method_or_ci.owner === Nothing && method_or_ci.def.def isa Method)
exct = Union{exct, ErrorException}
end
update_valid_age!(sv, callee_valid_range)
diff --git a/Compiler/src/ssair/ir.jl b/Compiler/src/ssair/ir.jl
index d7f0dbedcbec5..431ee63f57788 100644
--- a/Compiler/src/ssair/ir.jl
+++ b/Compiler/src/ssair/ir.jl
@@ -1373,8 +1373,19 @@ function kill_edge!(ir::IRCode, from::Int, to::Int, callback=nothing)
kill_edge!(ir.cfg.blocks, from, to, callback)
end
-# N.B.: from and to are non-renamed indices
-function kill_edge!(compact::IncrementalCompact, active_bb::Int, from::Int, to::Int)
+@inline function compacted_stmt_range(compact::IncrementalCompact, bb::BasicBlock, active_bb::Int, to::Int)
+ to == active_bb && return StmtRange(first(bb.stmts), compact.result_idx - 1)
+ return bb.stmts
+end
+
+"""
+ kill_edge_terminator!(compact::IncrementalCompact, active_bb::Int, from::Int, to::Int)
+
+Kill a CFG edge while compacting a terminator in `active_bb`. Assumes all PhiNode
+block statements in `to` have already been processed, so the active BB may only
+scan the compacted prefix when `to == active_bb`. `from` and `to` are non-renamed indices.
+"""
+function kill_edge_terminator!(compact::IncrementalCompact, active_bb::Int, from::Int, to::Int)
# Note: We recursively kill as many edges as are obviously dead.
(; bb_rename_pred, bb_rename_succ, result_bbs, domtree) = compact.cfg_transform
preds = result_bbs[bb_rename_succ[to]].preds
@@ -1390,7 +1401,7 @@ function kill_edge!(compact::IncrementalCompact, active_bb::Int, from::Int, to::
for succ in copy(to_succs)
new_succ = findfirst(x::Int->x==succ, bb_rename_pred)
new_succ === nothing && continue
- kill_edge!(compact, active_bb, to, new_succ)
+ kill_edge_terminator!(compact, active_bb, to, new_succ)
end
empty!(preds)
empty!(to_succs)
@@ -1412,8 +1423,9 @@ function kill_edge!(compact::IncrementalCompact, active_bb::Int, from::Int, to::
# Remove this edge from all phi nodes in `to` block
# NOTE: It is possible for `to` to contain only `nothing` statements,
# so we must be careful to stop at its last statement
- if to < active_bb
- stmts = result_bbs[bb_rename_succ[to]].stmts
+ if to <= active_bb
+ bb = result_bbs[bb_rename_succ[to]]
+ stmts = compacted_stmt_range(compact, bb, active_bb, to)
idx = first(stmts)
while idx <= last(stmts)
stmt = compact.result[idx][:stmt]
@@ -1493,14 +1505,14 @@ function process_node!(compact::IncrementalCompact, result_idx::Int, inst::Instr
if cond
ssa_rename[idx] = nothing
result[result_idx][:stmt] = nothing
- kill_edge!(compact, active_bb, active_bb, stmt.dest)
+ kill_edge_terminator!(compact, active_bb, active_bb, stmt.dest)
# Don't increment result_idx => Drop this statement
else
label = bb_rename_succ[stmt.dest]
@assert label > 0
ssa_rename[idx] = SSAValue(result_idx)
result[result_idx][:stmt] = GotoNode(label)
- kill_edge!(compact, active_bb, active_bb, active_bb+1)
+ kill_edge_terminator!(compact, active_bb, active_bb, active_bb+1)
result_idx += 1
end
else
@@ -1675,7 +1687,10 @@ function process_node!(compact::IncrementalCompact, result_idx::Int, inst::Instr
stmt = ssa_rename[stmt.id]
end
elseif isa(stmt, NewSSAValue)
- stmt = SSAValue(stmt.id)
+ if stmt.id > 0
+ # Negative ids reference new_new_nodes and must remain NewSSAValue.
+ stmt = SSAValue(stmt.id)
+ end
else
# Constant assign, replace uses of this ssa value with its result
end
diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl
index 746b32c22506c..060072e834f2c 100644
--- a/Compiler/src/typeinfer.jl
+++ b/Compiler/src/typeinfer.jl
@@ -1052,6 +1052,8 @@ function codeinfo_for_const(interp::AbstractInterpreter, mi::MethodInstance, @no
tree.ssaflags = [IR_FLAG_NULL]
tree.rettype = Core.Typeof(val)
tree.edges = Core.svec()
+ tree.nargs = UInt(nargs)
+ tree.isva = method.isva
set_inlineable!(tree, true)
tree.parent = mi
return tree
diff --git a/Compiler/src/typeutils.jl b/Compiler/src/typeutils.jl
index 50b3dc6b0c6f5..5abae32cdb7d6 100644
--- a/Compiler/src/typeutils.jl
+++ b/Compiler/src/typeutils.jl
@@ -277,8 +277,9 @@ function _switchtupleunion(𝕃::AbstractLattice, t::Vector{Any}, i::Int, tunion
_switchtupleunion(𝕃, t, i - 1, tunion, origt)
end
t[i] = origti
- elseif has_extended_unionsplit(𝕃) && !isa(ti, Const) && !isvarargtype(ti) && isa(widenconst(ti), Union)
- for ty in uniontypes(ti)
+ elseif (has_extended_unionsplit(𝕃) && !isa(ti, Const) && !isvarargtype(ti) &&
+ (wty = widenconst(ti); isa(wty, Union)))
+ for ty in uniontypes(wty)
t[i] = ty
_switchtupleunion(𝕃, t, i - 1, tunion, origt)
end
diff --git a/Compiler/test/inference.jl b/Compiler/test/inference.jl
index 6b1b964805149..a4bb3773366a3 100644
--- a/Compiler/test/inference.jl
+++ b/Compiler/test/inference.jl
@@ -2591,6 +2591,15 @@ end == Integer
Val(isdefined(xxx.value, :x))
end == Val{true}
+# Test union splitting for MustAlias
+struct GetSomethingA; x::Union{Nothing,Int}; end
+struct GetSomethingB; x::Int; end
+getsomethingx(a::GetSomethingA) = something(a.x, 0)
+getsomethingx(b::GetSomethingB) = b.x
+@test Base.infer_return_type((Union{GetSomethingA,GetSomethingB},); interp=MustAliasInterpreter()) do x
+ getsomethingx(x)
+end == Int
+
@testset "issue #56913: `BoundsError` in type inference" begin
R = UnitRange{Int}
@test Type{AbstractVector} == Base.infer_return_type(Base.promote_typeof, Tuple{R, R, Vector{Any}, Vararg{R}})
diff --git a/Compiler/test/irpasses.jl b/Compiler/test/irpasses.jl
index 77a66ec6435fa..6e087f048beae 100644
--- a/Compiler/test/irpasses.jl
+++ b/Compiler/test/irpasses.jl
@@ -2059,3 +2059,19 @@ let src = code_typed1((Vector{Any},)) do xs
end
@test count(iscall((src, Core.svec)), src.code) == 1
end
+
+# Negative NewSSAValue ids must be preserved during compaction
+function f_57827(op, init, x)
+ v = op(init, x)
+ i = 0
+ while i < 1
+ v = op(v, x)
+ i += 1
+ end
+ return v
+end
+let rf = (acc, x) -> ifelse(x > acc[1], (x,), (acc[1],))
+ @test f_57827(rf, (0.0,), 1) === (1,)
+ ir = first(only(Base.code_ircode(f_57827, (typeof(rf), Tuple{Float64}, Int64); optimize_until="CC: SROA")))
+ @test ir isa Compiler.IRCode
+end
diff --git a/Compiler/test/ssair.jl b/Compiler/test/ssair.jl
index 80faac97d83a4..c9228b30d9e17 100644
--- a/Compiler/test/ssair.jl
+++ b/Compiler/test/ssair.jl
@@ -108,6 +108,21 @@ let cfg = CFG(BasicBlock[
@test length(compact.cfg_transform.result_bbs) == 4 && 0 in compact.cfg_transform.result_bbs[3].preds
end
+# Test that removing a self-edge during compaction only scans compacted phi statements.
+let code = Any[
+ # Block 1
+ Compiler.GotoNode(2),
+ # Block 2
+ Core.PhiNode(Int32[1, 3], Any[1, 2]),
+ Compiler.GotoIfNot(true, 2),
+ # Block 3
+ Compiler.ReturnNode(0),
+ ]
+ ir = make_ircode(code)
+ ir = Compiler.compact!(ir, true)
+ @test Compiler.verify_ir(ir) === nothing
+end
+
# Issue #32579 - Optimizer bug involving type constraints
function f32579(x::Int, b::Bool)
if b
@@ -838,3 +853,31 @@ end
let ir = Base.code_ircode(_worker_task57153, (), optimize_until="CC: COMPACT_2")[1].first
@test findfirst(x->x==0, ir.cfg.blocks[1].preds) !== nothing
end
+
+# codeinfo_for_const should set nargs and isva
+let
+ _const_return_func(@nospecialize(x)) = 42
+ mi = Compiler.specialize_method(only(methods(_const_return_func)), Tuple{typeof(_const_return_func), Int}, Core.svec())
+ ci = Compiler.codeinfo_for_const(Compiler.NativeInterpreter(), mi, 42)
+ @test ci.nargs == 2
+ @test ci.isva == false
+ # inflate_ir! should succeed now that nargs/isva are set
+ ir = Compiler.inflate_ir!(ci, mi)
+ @test ir isa Compiler.IRCode
+end
+
+# Tests that CFG edge cleanup during compaction doesn't corrupt iteration codegen.
+Trips_60660 = let
+ Ts = (Float64, Float32)
+ [(Ta, Tb, Tc) for Ta in Ts for Tb in Ts for Tc in Ts]
+end
+@test Trips_60660 == [
+ (Float64, Float64, Float64),
+ (Float64, Float64, Float32),
+ (Float64, Float32, Float64),
+ (Float64, Float32, Float32),
+ (Float32, Float64, Float64),
+ (Float32, Float64, Float32),
+ (Float32, Float32, Float64),
+ (Float32, Float32, Float32),
+]
diff --git a/Make.inc b/Make.inc
index c2ccf6757e3c9..a145980e0264c 100644
--- a/Make.inc
+++ b/Make.inc
@@ -381,7 +381,7 @@ $(foreach D,build_libdir build_private_libdir,$(eval $(call cache_rel_path,$(D),
# Save a special one: reverse_private_libdir_rel: usually just `../`, but good to be general:
reverse_private_libdir_rel_eval = $(call rel_path,$(private_libdir),$(libdir))
reverse_private_libdir_rel = $(call hit_cache,reverse_private_libdir_rel_eval)
-reverse_private_libexecdir_rel_eval = $(call rel_path,$(private_libexecdir),$(libdir))
+reverse_private_libexecdir_rel_eval = $(call rel_path,$(private_libexecdir),$(private_libdir))
reverse_private_libexecdir_rel = $(call hit_cache,reverse_private_libexecdir_rel_eval)
reverse_build_private_libexecdir_rel_eval = $(call rel_path,$(build_private_libexecdir),$(build_libdir))
reverse_build_private_libexecdir_rel = $(call hit_cache,reverse_build_private_libexecdir_rel_eval)
diff --git a/Makefile b/Makefile
index bae449b255a10..fd84ad0e7b033 100644
--- a/Makefile
+++ b/Makefile
@@ -26,7 +26,7 @@ default: $(JULIA_BUILD_MODE) # contains either "debug" or "release"
all: debug release
# sort is used to remove potential duplicates
-DIRS := $(sort $(build_bindir) $(build_depsbindir) $(build_libdir) $(build_private_libdir) $(build_libexecdir) $(build_includedir) $(build_includedir)/julia $(build_sysconfdir)/julia $(build_datarootdir)/julia $(build_datarootdir)/julia/stdlib $(build_man1dir))
+DIRS := $(sort $(build_bindir) $(build_depsbindir) $(build_libdir) $(build_private_libdir) $(build_private_libexecdir) $(build_libexecdir) $(build_includedir) $(build_includedir)/julia $(build_sysconfdir)/julia $(build_datarootdir)/julia $(build_datarootdir)/julia/stdlib $(build_man1dir))
ifneq ($(BUILDROOT),$(JULIAHOME))
BUILDDIRS := $(BUILDROOT) $(addprefix $(BUILDROOT)/,base src src/flisp src/support src/clangsa cli doc deps stdlib test test/clangsa test/embedding test/gcext test/llvmpasses)
BUILDDIRMAKE := $(addsuffix /Makefile,$(BUILDDIRS)) $(BUILDROOT)/sysimage.mk $(BUILDROOT)/pkgimage.mk
@@ -325,8 +325,7 @@ else ifeq ($(JULIA_BUILD_MODE),debug)
-$(INSTALL_M) $(build_libdir)/libjulia-debug.dll.a $(DESTDIR)$(libdir)/
-$(INSTALL_M) $(build_libdir)/libjulia-internal-debug.dll.a $(DESTDIR)$(libdir)/
endif
- -$(INSTALL_M) $(wildcard $(build_private_libdir)/*.a) $(DESTDIR)$(private_libdir)/
- -rm -f $(DESTDIR)$(private_libdir)/sys-o.a
+ -$(INSTALL_M) $(filter-out %-bc.a %-o.a,$(wildcard $(build_private_libdir)/lib*.a)) $(DESTDIR)$(private_libdir)/
-$(INSTALL_M) $(build_bindir)/libopenlibm.dll.a $(DESTDIR)$(libdir)/
-$(INSTALL_M) $(build_libdir)/libssp.dll.a $(DESTDIR)$(libdir)/
@@ -485,6 +484,37 @@ else ifeq ($(JULIA_BUILD_MODE),debug)
$(PATCHELF) $(PATCHELF_SET_RPATH_ARG) '$$ORIGIN:$$ORIGIN/$(reverse_private_libdir_rel)' $(DESTDIR)$(private_libdir)/libjulia-internal-debug.$(SHLIB_EXT)
$(PATCHELF) $(PATCHELF_SET_RPATH_ARG) '$$ORIGIN:$$ORIGIN/$(reverse_private_libdir_rel)' $(DESTDIR)$(private_libdir)/libjulia-codegen-debug.$(SHLIB_EXT)
endif
+endif
+
+ifeq ($(OS), Darwin)
+ifneq ($(DARWIN_FRAMEWORK),1)
+ for j in $(JL_PRIVATE_TOOLS) ; do \
+ [ -L $(DESTDIR)$(private_libexecdir)/$$j ] && continue; \
+ install_name_tool -rpath @loader_path/$(build_libdir_rel) @executable_path/$(reverse_private_libexecdir_rel) $(DESTDIR)$(private_libexecdir)/$$j || exit 1; \
+ done
+endif
+else ifneq (,$(findstring $(OS),Linux FreeBSD))
+ for j in $(JL_PRIVATE_TOOLS) ; do \
+ [ -L $(DESTDIR)$(private_libexecdir)/$$j ] && continue; \
+ $(PATCHELF) $(PATCHELF_SET_RPATH_ARG) '$$ORIGIN/$(reverse_private_libexecdir_rel)' $(DESTDIR)$(private_libexecdir)/$$j || exit 1; \
+ done
+endif
+
+ifneq ($(reverse_private_libexecdir_rel),$(reverse_build_private_libexecdir_rel))
+ifeq ($(OS), Darwin)
+ifneq ($(DARWIN_FRAMEWORK),1)
+ for j in $(JL_PRIVATE_EXES) ; do \
+ [ $$j = 7z ] && continue; \
+ [ -L $(DESTDIR)$(private_libexecdir)/$$j ] && continue; \
+ install_name_tool -rpath @executable_path/$(reverse_build_private_libexecdir_rel) @executable_path/$(reverse_private_libexecdir_rel) $(DESTDIR)$(private_libexecdir)/$$j || exit 1; \
+ done
+endif
+else ifneq (,$(findstring $(OS),Linux FreeBSD))
+ for j in $(JL_PRIVATE_EXES) ; do \
+ [ -L $(DESTDIR)$(private_libexecdir)/$$j ] && continue; \
+ $(PATCHELF) $(PATCHELF_SET_RPATH_ARG) '$$ORIGIN/$(reverse_private_libexecdir_rel)' $(DESTDIR)$(private_libexecdir)/$$j || exit 1; \
+ done
+endif
endif
# Fix rpaths for dependencies. This should be fixed in BinaryBuilder later.
diff --git a/NEWS.md b/NEWS.md
index f5f68e508bdd9..17dd8ced3d56c 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -8,7 +8,7 @@ New language features
entry points. Entry points can be marked using `Base.Experimental.entrypoint` ([#55047]). Not all
code is expected to work with this option, and since it is experimental you may encounter problems.
* Redefinition of constants is now well defined and follows world age semantics ([#57253]). Additional redefinitions
- (e.g. of types) are now allowed. See [the new manual chapter on world age](https://docs.julialang.org/en/v1.13-dev/manual/worldage/).
+ (e.g. of types) are now allowed. See [the new manual chapter on world age](https://docs.julialang.org/en/v1/manual/worldage/).
* A new keyword argument `usings::Bool` has been added to `names`, returning all names visible
via `using` ([#54609]).
* The `@atomic` macro family now supports reference assignment syntax, e.g. `@atomic :monotonic v[3] += 4`,
diff --git a/VERSION b/VERSION
index 6b89d58f861a7..3c27091f99178 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.12.2
+1.12.5+RAI
diff --git a/base/Makefile b/base/Makefile
index eb36d6d0a4319..0f7767e0aef37 100644
--- a/base/Makefile
+++ b/base/Makefile
@@ -183,14 +183,14 @@ endif
endef
# libexec executables
-symlink_p7zip: $(build_bindir)/7z$(EXE)
+symlink_p7zip: $(build_private_libexecdir)/7z$(EXE)
ifneq ($(USE_SYSTEM_P7ZIP),0)
SYMLINK_SYSTEM_LIBRARIES += symlink_p7zip
7Z_PATH := $(shell which 7z$(EXE))
endif
-$(build_bindir)/7z$(EXE):
+$(build_private_libexecdir)/7z$(EXE):
[ -e "$(7Z_PATH)" ] && \
rm -f "$@" && \
ln -sf "$(7Z_PATH)" "$@"
diff --git a/base/array.jl b/base/array.jl
index 665934b8a3a11..9674bc170ad6e 100644
--- a/base/array.jl
+++ b/base/array.jl
@@ -641,7 +641,7 @@ julia> collect(Float64, 1:2:5)
collect(::Type{T}, itr) where {T} = _collect(T, itr, IteratorSize(itr))
_collect(::Type{T}, itr, isz::Union{HasLength,HasShape}) where {T} =
- copyto!(_array_for(T, isz, _similar_shape(itr, isz)), itr)
+ copyto!(_array_for_inner(T, isz, _similar_shape(itr, isz)), itr)
function _collect(::Type{T}, itr, isz::SizeUnknown) where T
a = Vector{T}()
for x in itr
@@ -665,12 +665,12 @@ _similar_for(c::AbstractArray, ::Type{T}, itr, ::HasShape, axs) where {T} =
similar(c, T, axs)
# make a collection appropriate for collecting `itr::Generator`
-_array_for(::Type{T}, ::SizeUnknown, ::Nothing) where {T} = Vector{T}(undef, 0)
-_array_for(::Type{T}, ::HasLength, len::Integer) where {T} = Vector{T}(undef, Int(len))
-_array_for(::Type{T}, ::HasShape{N}, axs) where {T,N} = similar(Array{T,N}, axs)
+_array_for_inner(::Type{T}, ::SizeUnknown, ::Nothing) where {T} = Vector{T}(undef, 0)
+_array_for_inner(::Type{T}, ::HasLength, len::Integer) where {T} = Vector{T}(undef, Int(len))
+_array_for_inner(::Type{T}, ::HasShape{N}, axs) where {T,N} = similar(Array{T,N}, axs)
# used by syntax lowering for simple typed comprehensions
-_array_for(::Type{T}, itr, isz) where {T} = _array_for(T, isz, _similar_shape(itr, isz))
+_array_for(::Type{T}, itr, isz) where {T} = _array_for_inner(T, isz, _similar_shape(itr, isz))
"""
@@ -789,10 +789,10 @@ function collect(itr::Generator)
shp = _similar_shape(itr, isz)
y = iterate(itr)
if y === nothing
- return _array_for(et, isz, shp)
+ return _array_for_inner(et, isz, shp)
end
v1, st = y
- dest = _array_for(typeof(v1), isz, shp)
+ dest = _array_for_inner(typeof(v1), isz, shp)
# The typeassert gives inference a helping hand on the element type and dimensionality
# (work-around for #28382)
et′ = et <: Type ? Type : et
diff --git a/base/bitarray.jl b/base/bitarray.jl
index 93fa48c56e379..2b73b1ea8a710 100644
--- a/base/bitarray.jl
+++ b/base/bitarray.jl
@@ -151,16 +151,14 @@ function copy_chunks!(dest::Vector{UInt64}, pos_d::Int, src::Vector{UInt64}, pos
delta_ks = ks1 - ks0
u = _msk64
+ msk_d0 = ~(u << ld0)
+ msk_d1 = (u << (ld1+1))
if delta_kd == 0
- msk_d0 = ~(u << ld0) | (u << (ld1+1))
- else
- msk_d0 = ~(u << ld0)
- msk_d1 = (u << (ld1+1))
+ msk_d0 |= msk_d1
end
+ msk_s0 = (u << ls0)
if delta_ks == 0
- msk_s0 = (u << ls0) & ~(u << (ls1+1))
- else
- msk_s0 = (u << ls0)
+ msk_s0 &= ~(u << (ls1+1))
end
chunk_s0 = glue_src_bitchunks(src, ks0, ks1, msk_s0, ls0)
@@ -211,16 +209,14 @@ function copy_chunks_rtol!(chunks::Vector{UInt64}, pos_d::Int, pos_s::Int, numbi
delta_kd = kd1 - kd0
delta_ks = ks1 - ks0
+ msk_d0 = ~(u << ld0)
+ msk_d1 = (u << (ld1+1))
if delta_kd == 0
- msk_d0 = ~(u << ld0) | (u << (ld1+1))
- else
- msk_d0 = ~(u << ld0)
- msk_d1 = (u << (ld1+1))
+ msk_d0 |= msk_d1
end
+ msk_s0 = (u << ls0)
if delta_ks == 0
- msk_s0 = (u << ls0) & ~(u << (ls1+1))
- else
- msk_s0 = (u << ls0)
+ msk_s0 &= ~(u << (ls1+1))
end
chunk_s0 = glue_src_bitchunks(chunks, ks0, ks1, msk_s0, ls0) & ~(u << s)
@@ -246,11 +242,10 @@ function fill_chunks!(Bc::Array{UInt64}, x::Bool, pos::Int, numbits::Int)
k1, l1 = get_chunks_id(pos+numbits-1)
u = _msk64
+ msk0 = (u << l0)
+ msk1 = ~(u << (l1+1))
if k1 == k0
- msk0 = (u << l0) & ~(u << (l1+1))
- else
- msk0 = (u << l0)
- msk1 = ~(u << (l1+1))
+ msk0 &= msk1
end
@inbounds if x
Bc[k0] |= msk0
diff --git a/base/fastmath.jl b/base/fastmath.jl
index ed686fb92bf34..afae504a8830f 100644
--- a/base/fastmath.jl
+++ b/base/fastmath.jl
@@ -297,12 +297,13 @@ exp10_fast(x::Union{Float32,Float64}) = Base.Math.exp10_fast(x)
# builtins
-@inline function pow_fast(x::Float64, y::Integer)
+@inline function pow_fast(x::Union{Float32, Float64}, y::Integer)
z = y % Int32
z == y ? pow_fast(x, z) : x^y
end
-pow_fast(x::Float32, y::Integer) = x^y
-pow_fast(x::Float64, y::Int32) = ccall("llvm.powi.f64.i32", llvmcall, Float64, (Float64, Int32), x, y)
+@inline pow_fast(x::Float16, y::Integer) = Float16(pow_fast(Float32(x), y))
+pow_fast(x::Float64, y::Int32) = ccall("llvm.powi", llvmcall, Float64, (Float64, Int32), x, y)
+pow_fast(x::Float32, y::Int32) = ccall("llvm.powi", llvmcall, Float32, (Float32, Int32), x, y)
pow_fast(x::FloatTypes, ::Val{p}) where {p} = pow_fast(x, p) # inlines already via llvm.powi
@inline pow_fast(x, v::Val) = Base.literal_pow(^, x, v)
diff --git a/base/file.jl b/base/file.jl
index ce9bc76256fd3..cece850ea265b 100644
--- a/base/file.jl
+++ b/base/file.jl
@@ -1059,7 +1059,7 @@ struct DirEntry
end
function Base.getproperty(obj::DirEntry, p::Symbol)
if p === :path
- return joinpath(obj.dir, obj.name)
+ return joinpath(getfield(obj, :dir), getfield(obj, :name))
else
return getfield(obj, p)
end
@@ -1267,22 +1267,19 @@ function rename(oldpath::AbstractString, newpath::AbstractString)
end
function sendfile(src::AbstractString, dst::AbstractString)
- src_open = false
- dst_open = false
- local src_file, dst_file
+ src_file = nothing
+ dst_file = nothing
try
src_file = open(src, JL_O_RDONLY)
- src_open = true
dst_file = open(dst, JL_O_CREAT | JL_O_TRUNC | JL_O_WRONLY, filemode(src_file))
- dst_open = true
bytes = filesize(stat(src_file))
sendfile(dst_file, src_file, Int64(0), Int(bytes))
finally
- if src_open && isopen(src_file)
+ if src_file !== nothing && isopen(src_file)
close(src_file)
end
- if dst_open && isopen(dst_file)
+ if dst_file !== nothing && isopen(dst_file)
close(dst_file)
end
end
diff --git a/base/loading.jl b/base/loading.jl
index 40db7df679b60..a804cc5f54706 100644
--- a/base/loading.jl
+++ b/base/loading.jl
@@ -4211,6 +4211,20 @@ function expand_compiler_path(tup)
end
compiler_chi(tup::Tuple) = CacheHeaderIncludes(expand_compiler_path(tup))
+"""
+ isprecompilable(f, argtypes::Tuple{Vararg{Any}})
+
+Check, as far as is possible without actually compiling, if the given
+function `f` can be compiled for the argument tuple (of types) `argtypes`.
+"""
+function isprecompilable(@nospecialize(f), @nospecialize(argtypes::Tuple))
+ isprecompilable(Tuple{Core.Typeof(f), argtypes...})
+end
+
+function isprecompilable(@nospecialize(argt::Type))
+ ccall(:jl_is_compilable, Int32, (Any,), argt) != 0
+end
+
"""
precompile(f, argtypes::Tuple{Vararg{Any}})
diff --git a/base/lock.jl b/base/lock.jl
index e74da826900a6..1feea348e5ac4 100644
--- a/base/lock.jl
+++ b/base/lock.jl
@@ -366,7 +366,7 @@ This is similar to using [`lock`](@ref) with a `do` block, but avoids creating a
and thus can improve the performance.
!!! compat
- `@lock` was added in Julia 1.3, and exported in Julia 1.10.
+ `@lock` was added in Julia 1.3, and exported in Julia 1.7.
"""
macro lock(l, expr)
quote
diff --git a/base/logging/logging.jl b/base/logging/logging.jl
index c44e74ffa627b..bb24a0e47b05b 100644
--- a/base/logging/logging.jl
+++ b/base/logging/logging.jl
@@ -129,6 +129,8 @@ end
LogLevel(level::LogLevel) = level
isless(a::LogLevel, b::LogLevel) = isless(a.level, b.level)
+isless(a::LogLevel, b::Integer) = isless(a.level, b)
+isless(a::Integer, b::LogLevel) = isless(a, b.level)
+(level::LogLevel, inc::Integer) = LogLevel(level.level+inc)
-(level::LogLevel, inc::Integer) = LogLevel(level.level-inc)
convert(::Type{LogLevel}, level::Integer) = LogLevel(level)
diff --git a/base/meta.jl b/base/meta.jl
index 4807b910c494a..79497f6e6d068 100644
--- a/base/meta.jl
+++ b/base/meta.jl
@@ -409,7 +409,7 @@ function _partially_inline!(@nospecialize(x), slot_replacements::Vector{Any},
end
return x
elseif head === :cfunction
- @assert !isa(type_signature, UnionAll) || !isempty(spvals)
+ @assert !isa(type_signature, UnionAll) || !isempty(static_param_values)
if !isa(x.args[2], QuoteNode) # very common no-op
x.args[2] = _partially_inline!(x.args[2], slot_replacements, type_signature,
static_param_values, slot_offset,
diff --git a/base/options.jl b/base/options.jl
index 1692c765443f3..b5730994492aa 100644
--- a/base/options.jl
+++ b/base/options.jl
@@ -64,6 +64,7 @@ struct JLOptions
trim::Int8
task_metrics::Int8
timeout_for_safepoint_straggler_s::Int16
+ safe_crash_log_file::Ptr{UInt8}
end
# This runs early in the sysimage != is not defined yet
diff --git a/base/partr.jl b/base/partr.jl
index d488330f0c87e..671c88fd6e786 100644
--- a/base/partr.jl
+++ b/base/partr.jl
@@ -97,7 +97,7 @@ function multiq_sift_down(heap::taskheap, idx::Int32)
child = Int(child)
child > length(heap.tasks) && break
if isassigned(heap.tasks, child) &&
- heap.tasks[child].priority < heap.tasks[idx].priority
+ heap.tasks[child].priority <= heap.tasks[idx].priority
t = heap.tasks[idx]
heap.tasks[idx] = heap.tasks[child]
heap.tasks[child] = t
diff --git a/base/precompilation.jl b/base/precompilation.jl
index 45634d877115f..27c380a3d14af 100644
--- a/base/precompilation.jl
+++ b/base/precompilation.jl
@@ -845,7 +845,7 @@ function _precompilepkgs(pkgs::Union{Vector{String}, Vector{PkgId}},
write(get!(IOBuffer, std_outputs, pkg_config), str)
if !in(pkg_config, taskwaiting) && occursin("waiting for IO to finish", str)
!fancyprint && @lock print_lock begin
- println(io, pkg.name, color_string(" Waiting for background task / IO / timer.", Base.warn_color()))
+ println(io, full_name(ext_to_parent, pkg), color_string(" Waiting for background task / IO / timer.", Base.warn_color()))
end
push!(taskwaiting, pkg_config)
end
@@ -1015,7 +1015,8 @@ function _precompilepkgs(pkgs::Union{Vector{String}, Vector{PkgId}},
try
# allows processes to wait if another process is precompiling a given package to
# a functionally identical package cache (except for preferences, which may differ)
- t = @elapsed ret = precompile_pkgs_maybe_cachefile_lock(io, print_lock, fancyprint, pkg_config, pkgspidlocked, hascolor, parallel_limiter, ignore_loaded) do
+ fullname = full_name(ext_to_parent, pkg)
+ t = @elapsed ret = precompile_pkgs_maybe_cachefile_lock(io, print_lock, fancyprint, pkg_config, pkgspidlocked, hascolor, parallel_limiter, ignore_loaded, fullname) do
Base.with_logger(Base.NullLogger()) do
# whether to respect already loaded dependency versions
keep_loaded_modules = !ignore_loaded
@@ -1094,7 +1095,7 @@ function _precompilepkgs(pkgs::Union{Vector{String}, Vector{PkgId}},
str = sprint(context=io) do iostr
if !quick_exit
if fancyprint # replace the progress bar
- what = isempty(requested_pkgids) ? "packages finished." : "$(join((p.name for p in requested_pkgids), ", ", " and ")) finished."
+ what = isempty(requested_pkgids) ? "packages finished." : "$(join((full_name(ext_to_parent, p) for p in requested_pkgids), ", ", " and ")) finished."
printpkgstyle(iostr, :Precompiling, what)
end
plural = length(configs) > 1 ? "dependency configurations" : ndeps == 1 ? "dependency" : "dependencies"
@@ -1157,7 +1158,7 @@ function _precompilepkgs(pkgs::Union{Vector{String}, Vector{PkgId}},
for (pkg_config, err) in failed_deps
dep, config = pkg_config
if strict || (dep in project_deps)
- print(err_str, "\n", dep.name, " ")
+ print(err_str, "\n", full_name(ext_to_parent, dep), " ")
for cfg in config[1]
print(err_str, cfg, " ")
end
@@ -1205,7 +1206,7 @@ function _color_string(cstr::String, col::Union{Int64, Symbol}, hascolor)
end
# Can be merged with `maybe_cachefile_lock` in loading?
-function precompile_pkgs_maybe_cachefile_lock(f, io::IO, print_lock::ReentrantLock, fancyprint::Bool, pkg_config, pkgspidlocked, hascolor, parallel_limiter::Base.Semaphore, ignore_loaded::Bool)
+function precompile_pkgs_maybe_cachefile_lock(f, io::IO, print_lock::ReentrantLock, fancyprint::Bool, pkg_config, pkgspidlocked, hascolor, parallel_limiter::Base.Semaphore, ignore_loaded::Bool, fullname)
if !(isdefined(Base, :mkpidlock_hook) && isdefined(Base, :trymkpidlock_hook) && Base.isdefined(Base, :parse_pidfile_hook))
return f()
end
@@ -1226,7 +1227,7 @@ function precompile_pkgs_maybe_cachefile_lock(f, io::IO, print_lock::ReentrantLo
"another machine (hostname: $hostname, pid: $pid, pidfile: $pidfile)"
end
!fancyprint && @lock print_lock begin
- println(io, " ", pkg.name, _color_string(" Being precompiled by $(pkgspidlocked[pkg_config])", Base.info_color(), hascolor))
+ println(io, " ", fullname, _color_string(" Being precompiled by $(pkgspidlocked[pkg_config])", Base.info_color(), hascolor))
end
Base.release(parallel_limiter) # release so other work can be done while waiting
try
diff --git a/base/process.jl b/base/process.jl
index fbc4acfd83e80..1a2324cb5d86e 100644
--- a/base/process.jl
+++ b/base/process.jl
@@ -131,15 +131,14 @@ end
if err == 0
pp = Process(cmd, handle, syncd)
associate_julia_struct(handle, pp)
+ iolock_end()
+ return pp
else
ccall(:jl_forceclose_uv, Cvoid, (Ptr{Cvoid},), handle) # will call free on handle eventually
+ iolock_end()
+ throw(_UVError("could not spawn " * repr(cmd), err))
end
- iolock_end()
end
- if err != 0
- throw(_UVError("could not spawn " * repr(cmd), err))
- end
- return pp
end
_spawn(cmds::AbstractCmd) = _spawn(cmds, SpawnIOs())
diff --git a/base/stacktraces.jl b/base/stacktraces.jl
index 34af576737b33..3c1d5892e138c 100644
--- a/base/stacktraces.jl
+++ b/base/stacktraces.jl
@@ -273,9 +273,10 @@ function show_spec_linfo(io::IO, frame::StackFrame)
if linfo isa Union{MethodInstance, CodeInstance}
def = frame_method_or_module(frame)
if def isa Module
- Base.show_mi(io, linfo, #=from_stackframe=#true)
+ Base.show_mi(io, linfo::MethodInstance, #=from_stackframe=#true)
else
- show_spec_sig(io, def, frame_mi(frame).specTypes)
+ mi = frame_mi(frame)::MethodInstance
+ show_spec_sig(io, def::Method, mi.specTypes)
end
else
m = linfo::Method
diff --git a/base/sysinfo.jl b/base/sysinfo.jl
index 56a3681ae35f7..f6c4ed58f5daa 100644
--- a/base/sysinfo.jl
+++ b/base/sysinfo.jl
@@ -107,8 +107,6 @@ const WORD_SIZE = Core.sizeof(Int) * 8
The number of system "clock ticks" per second, corresponding to `sysconf(_SC_CLK_TCK)` on
POSIX systems, or `0` if it is unknown.
-
-CPU times, e.g. as returned by `Sys.cpu_info()`, are in units of ticks, i.e. units of `1 / Sys.SC_CLK_TCK` seconds if `Sys.SC_CLK_TCK > 0`.
"""
global SC_CLK_TCK::Clong
@@ -202,8 +200,7 @@ The `CPUinfo` type is a mutable struct with the following fields:
- `cpu_times!idle::UInt64`: Time spent in idle mode. CPU state shows the CPU time that's not actively being used.
- `cpu_times!irq::UInt64`: Time spent handling interrupts. CPU state shows the amount of time the CPU has been servicing hardware interrupts.
-The times are in units of `1/Sys.SC_CLK_TCK` seconds if `Sys.SC_CLK_TCK > 0`; otherwise they are in
-unknown units.
+The times are in units of milliseconds.
Note: Included in the detailed system information via `versioninfo(verbose=true)`.
"""
@@ -224,7 +221,6 @@ CPUinfo(info::UV_cpu_info_t) = CPUinfo(unsafe_string(info.model), info.speed,
public CPUinfo
function _show_cpuinfo(io::IO, info::Sys.CPUinfo, header::Bool=true, prefix::AbstractString=" ")
- tck = SC_CLK_TCK
if header
println(io, info.model, ": ")
print(io, " "^length(prefix))
@@ -232,16 +228,13 @@ function _show_cpuinfo(io::IO, info::Sys.CPUinfo, header::Bool=true, prefix::Abs
lpad("sys", 9), " ", lpad("idle", 9), " ", lpad("irq", 9))
end
print(io, prefix)
- unit = tck > 0 ? " s " : " "
- tc = max(tck, 1)
+ ms_per_s = 1000
+ unit = " s "
d(i, unit=unit) = lpad(string(round(Int64,i)), 9) * unit
print(io,
lpad(string(info.speed), 5), " MHz ",
- d(info.cpu_times!user / tc), d(info.cpu_times!nice / tc), d(info.cpu_times!sys / tc),
- d(info.cpu_times!idle / tc), d(info.cpu_times!irq / tc, tck > 0 ? " s" : " "))
- if tck <= 0
- print(io, "ticks")
- end
+ d(info.cpu_times!user / ms_per_s), d(info.cpu_times!nice / ms_per_s), d(info.cpu_times!sys / ms_per_s),
+ d(info.cpu_times!idle / ms_per_s), d(info.cpu_times!irq / ms_per_s))
end
show(io::IO, ::MIME"text/plain", info::CPUinfo) = _show_cpuinfo(io, info, true, " ")
diff --git a/base/timing.jl b/base/timing.jl
index e937d396a52a2..98f4f06cbcd47 100644
--- a/base/timing.jl
+++ b/base/timing.jl
@@ -113,7 +113,7 @@ end
@static if Base.USING_STOCK_GC
# must be kept in sync with `src/gc-stock.h``
const FULL_SWEEP_REASONS = [:FULL_SWEEP_REASON_SWEEP_ALWAYS_FULL, :FULL_SWEEP_REASON_FORCED_FULL_SWEEP,
- :FULL_SWEEP_REASON_USER_MAX_EXCEEDED, :FULL_SWEEP_REASON_LARGE_PROMOTION_RATE]
+ :FULL_SWEEP_REASON_USER_MAX_EXCEEDED, :FULL_SWEEP_REASON_LARGE_PROMOTION_RATE, :FULL_SWEEP_REASON_LARGE_HEAP_GROWTH]
end
"""
@@ -498,6 +498,14 @@ function is_simply_call(@nospecialize ex)
Meta.isexpr(a, :..., 1) && is_simple_atom(a.args[1]) && continue
return false
end
+ # Ensure Expr(:call, .+, ...) get wrapped
+ if ex.args[1] isa Symbol
+ sa = String(ex.args[1]::Symbol)
+ startswith(sa, ".") &&
+ !endswith(sa, ".") &&
+ isoperator(Symbol(sa[2:end])) &&
+ return false
+ end
return true
end
diff --git a/base/toml_parser.jl b/base/toml_parser.jl
index 378322e8cba95..46208eeff4195 100644
--- a/base/toml_parser.jl
+++ b/base/toml_parser.jl
@@ -716,8 +716,8 @@ function parse_array(l::Parser{Dates})::Err{Vector} where Dates
copyto_typed!(new, array)
elseif T === Union{}
new = Any[]
- elseif (T === TOMLDict) || (T == BigInt) || (T === UInt128) || (T === Int128) || (T <: Vector) ||
- (T === Dates.Date) || (T === Dates.Time) || (T === Dates.DateTime)
+ elseif (T === TOMLDict) || (T === BigInt) || (T === UInt128) || (T === Int128) || (T <: Vector) ||
+ (Dates !== nothing && ((T === Dates.Date) || (T === Dates.Time) || (T === Dates.DateTime)))
# do nothing, leave as Vector{Any}
new = array
else @assert false end
diff --git a/contrib/mac/app/Makefile b/contrib/mac/app/Makefile
index 70436a857c265..81b7e47cdf2cf 100644
--- a/contrib/mac/app/Makefile
+++ b/contrib/mac/app/Makefile
@@ -47,8 +47,8 @@ dmg/$(APP_NAME): startup.applescript julia.icns
plutil -insert CFBundleVersion -string "$(JULIA_VERSION_OPT_COMMIT)" $@/Contents/Info.plist
plutil -insert NSHumanReadableCopyright -string "$(APP_COPYRIGHT)" $@/Contents/Info.plist
-mkdir -p $@/Contents/Resources/julia
- $(MAKE) -C $(JULIAHOME) binary-dist
- $(TAR) -xzf $(JULIAHOME)/$(JULIA_BINARYDIST_FILENAME).tar.gz -C $@/Contents/Resources/julia --strip-components 1
+ make -C $(JULIAHOME) binary-dist
+ tar zxf $(JULIAHOME)/$(JULIA_BINARYDIST_FILENAME).tar.gz -C $@/Contents/Resources/julia --strip-components 1
find $@/Contents/Resources/julia -type f -exec chmod -w {} \;
# Even though the tarball may already be signed, we re-sign here to make it easier to add
# unsigned executables (like the app launcher) and whatnot, without needing to maintain lists
diff --git a/deps/JuliaSyntax.version b/deps/JuliaSyntax.version
index 9487754d8a617..4372237a6824f 100644
--- a/deps/JuliaSyntax.version
+++ b/deps/JuliaSyntax.version
@@ -1,4 +1,4 @@
-JULIASYNTAX_BRANCH = main
-JULIASYNTAX_SHA1 = 46723f071d5b2efcb21ca6757788028afb91cc13
+JULIASYNTAX_BRANCH = backports-julialang-1.12
+JULIASYNTAX_SHA1 = de4d1cd21cf13501c65b91c68c2fd5c9aa704e97
JULIASYNTAX_GIT_URL := https://github.com/JuliaLang/JuliaSyntax.jl.git
JULIASYNTAX_TAR_URL = https://api.github.com/repos/JuliaLang/JuliaSyntax.jl/tarball/$1
diff --git a/deps/checksums/JuliaSyntax-46723f071d5b2efcb21ca6757788028afb91cc13.tar.gz/md5 b/deps/checksums/JuliaSyntax-46723f071d5b2efcb21ca6757788028afb91cc13.tar.gz/md5
deleted file mode 100644
index ff40f520dfe85..0000000000000
--- a/deps/checksums/JuliaSyntax-46723f071d5b2efcb21ca6757788028afb91cc13.tar.gz/md5
+++ /dev/null
@@ -1 +0,0 @@
-2a0921e59edfab54554aa173f091c5b7
diff --git a/deps/checksums/JuliaSyntax-46723f071d5b2efcb21ca6757788028afb91cc13.tar.gz/sha512 b/deps/checksums/JuliaSyntax-46723f071d5b2efcb21ca6757788028afb91cc13.tar.gz/sha512
deleted file mode 100644
index 64e90d0edaba0..0000000000000
--- a/deps/checksums/JuliaSyntax-46723f071d5b2efcb21ca6757788028afb91cc13.tar.gz/sha512
+++ /dev/null
@@ -1 +0,0 @@
-17050e23216335f6599f009f71e9614a11b6686e455554b1efd287cd8526a7ebece06dc473e34cd50f61bf52085ff72bb4279144a9fdb3a234d3d589a10fddaf
diff --git a/deps/checksums/JuliaSyntax-de4d1cd21cf13501c65b91c68c2fd5c9aa704e97.tar.gz/md5 b/deps/checksums/JuliaSyntax-de4d1cd21cf13501c65b91c68c2fd5c9aa704e97.tar.gz/md5
new file mode 100644
index 0000000000000..5daa6f8f8538f
--- /dev/null
+++ b/deps/checksums/JuliaSyntax-de4d1cd21cf13501c65b91c68c2fd5c9aa704e97.tar.gz/md5
@@ -0,0 +1 @@
+420f41ff75161d7ee4e3a564228de206
diff --git a/deps/checksums/JuliaSyntax-de4d1cd21cf13501c65b91c68c2fd5c9aa704e97.tar.gz/sha512 b/deps/checksums/JuliaSyntax-de4d1cd21cf13501c65b91c68c2fd5c9aa704e97.tar.gz/sha512
new file mode 100644
index 0000000000000..2fa1d2693fd44
--- /dev/null
+++ b/deps/checksums/JuliaSyntax-de4d1cd21cf13501c65b91c68c2fd5c9aa704e97.tar.gz/sha512
@@ -0,0 +1 @@
+fbc2cc1b2dd1903c15e33d86a4f1f84807cd7988cd169c62fea58a71af06694deb5d3882a772ab9599ee878bdaa51e069e5a399e565f03b0eb2c99c2b5ec4759
diff --git a/deps/checksums/LinearAlgebra-7249e662d66b53da6c9335ea748eac2750c2924f.tar.gz/md5 b/deps/checksums/LinearAlgebra-7249e662d66b53da6c9335ea748eac2750c2924f.tar.gz/md5
new file mode 100644
index 0000000000000..cbd119f9a07e5
--- /dev/null
+++ b/deps/checksums/LinearAlgebra-7249e662d66b53da6c9335ea748eac2750c2924f.tar.gz/md5
@@ -0,0 +1 @@
+c8fea09ab0a67dcd9bacc413a008056b
diff --git a/deps/checksums/LinearAlgebra-7249e662d66b53da6c9335ea748eac2750c2924f.tar.gz/sha512 b/deps/checksums/LinearAlgebra-7249e662d66b53da6c9335ea748eac2750c2924f.tar.gz/sha512
new file mode 100644
index 0000000000000..01c026a488114
--- /dev/null
+++ b/deps/checksums/LinearAlgebra-7249e662d66b53da6c9335ea748eac2750c2924f.tar.gz/sha512
@@ -0,0 +1 @@
+f44e5518d45d568a56116fcef058c006adefff6752b7bfecd29afffa7fc797739271bde2d3a6d0813d89973c862341d5ee47347a933146a43108ea716b133672
diff --git a/deps/checksums/LinearAlgebra-997c4b7e7664f30645ef8bd51d8a4203e49c4631.tar.gz/md5 b/deps/checksums/LinearAlgebra-997c4b7e7664f30645ef8bd51d8a4203e49c4631.tar.gz/md5
deleted file mode 100644
index 0981743e0907a..0000000000000
--- a/deps/checksums/LinearAlgebra-997c4b7e7664f30645ef8bd51d8a4203e49c4631.tar.gz/md5
+++ /dev/null
@@ -1 +0,0 @@
-1cf83c7ea8935ac0804e07ebe8ce7506
diff --git a/deps/checksums/LinearAlgebra-997c4b7e7664f30645ef8bd51d8a4203e49c4631.tar.gz/sha512 b/deps/checksums/LinearAlgebra-997c4b7e7664f30645ef8bd51d8a4203e49c4631.tar.gz/sha512
deleted file mode 100644
index 971b146eecf64..0000000000000
--- a/deps/checksums/LinearAlgebra-997c4b7e7664f30645ef8bd51d8a4203e49c4631.tar.gz/sha512
+++ /dev/null
@@ -1 +0,0 @@
-ec3edd7208e25fb1af0b9cb2324abbfb66e556442b75df619ffdf428f1d59f851055117db896fd3514352a32c34c4c42cf50e1386deca4ebd051de98369d5a3e
diff --git a/deps/checksums/NetworkOptions-532992fcc0f1d02df48374969cbae37e34c01360.tar.gz/md5 b/deps/checksums/NetworkOptions-532992fcc0f1d02df48374969cbae37e34c01360.tar.gz/md5
deleted file mode 100644
index fbb7d5b86627f..0000000000000
--- a/deps/checksums/NetworkOptions-532992fcc0f1d02df48374969cbae37e34c01360.tar.gz/md5
+++ /dev/null
@@ -1 +0,0 @@
-afab093d162a62d5a488894f33d3b396
diff --git a/deps/checksums/NetworkOptions-532992fcc0f1d02df48374969cbae37e34c01360.tar.gz/sha512 b/deps/checksums/NetworkOptions-532992fcc0f1d02df48374969cbae37e34c01360.tar.gz/sha512
deleted file mode 100644
index 146d3a3d1bad8..0000000000000
--- a/deps/checksums/NetworkOptions-532992fcc0f1d02df48374969cbae37e34c01360.tar.gz/sha512
+++ /dev/null
@@ -1 +0,0 @@
-14b41cc9c93e2f9eeaa9499d65b8c42ee80691cbd533ef6cafabdb6e94c7cf31eee00fb603ca70dfe86930c871419cf17a8f05c0a76bd379a8bbf705b875dfe2
diff --git a/deps/checksums/NetworkOptions-7034c55dbf52ee959cabd63bcbe656df658f5bda.tar.gz/md5 b/deps/checksums/NetworkOptions-7034c55dbf52ee959cabd63bcbe656df658f5bda.tar.gz/md5
new file mode 100644
index 0000000000000..8f918b40b2ffb
--- /dev/null
+++ b/deps/checksums/NetworkOptions-7034c55dbf52ee959cabd63bcbe656df658f5bda.tar.gz/md5
@@ -0,0 +1 @@
+1fbf59e3052ec0d40a195d935b3d4a96
diff --git a/deps/checksums/NetworkOptions-7034c55dbf52ee959cabd63bcbe656df658f5bda.tar.gz/sha512 b/deps/checksums/NetworkOptions-7034c55dbf52ee959cabd63bcbe656df658f5bda.tar.gz/sha512
new file mode 100644
index 0000000000000..feeb688dcb7e2
--- /dev/null
+++ b/deps/checksums/NetworkOptions-7034c55dbf52ee959cabd63bcbe656df658f5bda.tar.gz/sha512
@@ -0,0 +1 @@
+4ec9724062d97a9d400bfb4a672ed5ce52999738ddbc01d2892d97df3fd256fe03bb5ea69f2ebbbbdbfef91edc24d82e54df48f997781eba2c6cd8e1c36d046c
diff --git a/deps/checksums/Pkg-1c1c173d35be3eb478054fb0229b0b1b6aa040cf.tar.gz/md5 b/deps/checksums/Pkg-1c1c173d35be3eb478054fb0229b0b1b6aa040cf.tar.gz/md5
new file mode 100644
index 0000000000000..21bc73b46a108
--- /dev/null
+++ b/deps/checksums/Pkg-1c1c173d35be3eb478054fb0229b0b1b6aa040cf.tar.gz/md5
@@ -0,0 +1 @@
+8893f471072bfa55bf25077d3759e951
diff --git a/deps/checksums/Pkg-1c1c173d35be3eb478054fb0229b0b1b6aa040cf.tar.gz/sha512 b/deps/checksums/Pkg-1c1c173d35be3eb478054fb0229b0b1b6aa040cf.tar.gz/sha512
new file mode 100644
index 0000000000000..b9d18c5a172ed
--- /dev/null
+++ b/deps/checksums/Pkg-1c1c173d35be3eb478054fb0229b0b1b6aa040cf.tar.gz/sha512
@@ -0,0 +1 @@
+6df46485c91f099501a27cb8f28688df94afa7ad877b8d1ddf9b3d210cbd5ed6c8386cb92f2f2ff6a13b855de4755f9159e0d3b9699d638b5eaf4f16513c58d1
diff --git a/deps/checksums/Pkg-53b2b5da91c27515ce129635fe184e8bd9afb09f.tar.gz/md5 b/deps/checksums/Pkg-53b2b5da91c27515ce129635fe184e8bd9afb09f.tar.gz/md5
deleted file mode 100644
index 48b17f7ee32d2..0000000000000
--- a/deps/checksums/Pkg-53b2b5da91c27515ce129635fe184e8bd9afb09f.tar.gz/md5
+++ /dev/null
@@ -1 +0,0 @@
-5c898e09839cfa16f80940b08bdebe9f
diff --git a/deps/checksums/Pkg-53b2b5da91c27515ce129635fe184e8bd9afb09f.tar.gz/sha512 b/deps/checksums/Pkg-53b2b5da91c27515ce129635fe184e8bd9afb09f.tar.gz/sha512
deleted file mode 100644
index 7236505c4e9f1..0000000000000
--- a/deps/checksums/Pkg-53b2b5da91c27515ce129635fe184e8bd9afb09f.tar.gz/sha512
+++ /dev/null
@@ -1 +0,0 @@
-5202b09eaf172291260bc69a28944986c80a4362a9ef521b05c8ce95c69c9909439b5b2f3a52326ab820f1eff2e1ba2a8ddaa90080d9e29fd2f6e226856bda3e
diff --git a/deps/checksums/SparseArrays-2376bf8734754c5dd4264186299ae6839ab7783f.tar.gz/md5 b/deps/checksums/SparseArrays-2376bf8734754c5dd4264186299ae6839ab7783f.tar.gz/md5
new file mode 100644
index 0000000000000..233004ebc84fe
--- /dev/null
+++ b/deps/checksums/SparseArrays-2376bf8734754c5dd4264186299ae6839ab7783f.tar.gz/md5
@@ -0,0 +1 @@
+059aef1395d4160561236167379af7ae
diff --git a/deps/checksums/SparseArrays-2376bf8734754c5dd4264186299ae6839ab7783f.tar.gz/sha512 b/deps/checksums/SparseArrays-2376bf8734754c5dd4264186299ae6839ab7783f.tar.gz/sha512
new file mode 100644
index 0000000000000..ea773676bed87
--- /dev/null
+++ b/deps/checksums/SparseArrays-2376bf8734754c5dd4264186299ae6839ab7783f.tar.gz/sha512
@@ -0,0 +1 @@
+69015dbc54d0d374b89eea2464eafd0aae461ad819965ad5745fc5ce50cf9519eb4d4024209184a90f2704873a96a0fd3586bf354a036c4c44452141d5535f43
diff --git a/deps/checksums/SparseArrays-5d674dc7bd90156cf8ecea4e143b69b5a5b7640d.tar.gz/md5 b/deps/checksums/SparseArrays-5d674dc7bd90156cf8ecea4e143b69b5a5b7640d.tar.gz/md5
deleted file mode 100644
index ab3e4ebfe9f25..0000000000000
--- a/deps/checksums/SparseArrays-5d674dc7bd90156cf8ecea4e143b69b5a5b7640d.tar.gz/md5
+++ /dev/null
@@ -1 +0,0 @@
-eadaa92895c8d4d33eb601165ef765d5
diff --git a/deps/checksums/SparseArrays-5d674dc7bd90156cf8ecea4e143b69b5a5b7640d.tar.gz/sha512 b/deps/checksums/SparseArrays-5d674dc7bd90156cf8ecea4e143b69b5a5b7640d.tar.gz/sha512
deleted file mode 100644
index 7a250e67b00d3..0000000000000
--- a/deps/checksums/SparseArrays-5d674dc7bd90156cf8ecea4e143b69b5a5b7640d.tar.gz/sha512
+++ /dev/null
@@ -1 +0,0 @@
-bb37377b360eca1a32c78b1d11b83c7e918a8ddb9df79388694b6f415dc5d5cf6182df7437869b3970011e5dcda4a3f821b58498bfa6fd7df697fcd51383ca12
diff --git a/deps/checksums/cacert-2025-11-04.pem/md5 b/deps/checksums/cacert-2025-11-04.pem/md5
new file mode 100644
index 0000000000000..641a98aecef02
--- /dev/null
+++ b/deps/checksums/cacert-2025-11-04.pem/md5
@@ -0,0 +1 @@
+4ca8e1c3e8fc44c3ecd7a1fb9d3a6d03
diff --git a/deps/checksums/cacert-2025-11-04.pem/sha512 b/deps/checksums/cacert-2025-11-04.pem/sha512
new file mode 100644
index 0000000000000..bbd48b9475d7f
--- /dev/null
+++ b/deps/checksums/cacert-2025-11-04.pem/sha512
@@ -0,0 +1 @@
+9d9f7ecc829bafc222501d8a66852d96a51f522b04a82963e4166c87b85d6a5e5eedb50ced2ef3026cd7cb06fcb4b7dca59c4157813a067cb7b185e32f2957ec
diff --git a/deps/libgit2.mk b/deps/libgit2.mk
index dd0d883c2e736..8b17ae6d70424 100644
--- a/deps/libgit2.mk
+++ b/deps/libgit2.mk
@@ -4,7 +4,6 @@ ifneq ($(USE_BINARYBUILDER_LIBGIT2),1)
LIBGIT2_GIT_URL := https://github.com/libgit2/libgit2.git
LIBGIT2_TAR_URL = https://api.github.com/repos/libgit2/libgit2/tarball/$1
$(eval $(call git-external,libgit2,LIBGIT2,CMakeLists.txt,,$(SRCCACHE)))
-$(SRCCACHE)/$(LIBGIT2_SRC_DIR)/source-extracted: $(MSYS_NONEXISTENT_SYMLINK_TARGET_FIX)
ifeq ($(USE_SYSTEM_LIBSSH2), 0)
$(BUILDDIR)/$(LIBGIT2_SRC_DIR)/build-configured: | $(build_prefix)/manifest/libssh2
@@ -14,15 +13,7 @@ ifeq ($(USE_SYSTEM_OPENSSL), 0)
$(BUILDDIR)/$(LIBGIT2_SRC_DIR)/build-configured: | $(build_prefix)/manifest/openssl
endif
-ifeq ($(USE_SYSTEM_PCRE), 0)
-$(BUILDDIR)/$(LIBGIT2_SRC_DIR)/build-configured: | $(build_prefix)/manifest/pcre
-endif
-
-ifeq ($(USE_SYSTEM_ZLIB), 0)
-$(BUILDDIR)/$(LIBGIT2_SRC_DIR)/build-configured: | $(build_prefix)/manifest/zlib
-endif
-
-LIBGIT2_OPTS := $(CMAKE_COMMON) -DCMAKE_BUILD_TYPE=Release -DUSE_THREADS=ON -DUSE_BUNDLED_ZLIB=OFF -DUSE_SSH=ON -DREGEX_BACKEND=pcre2 -DBUILD_CLI=OFF -DBUILD_TESTS=OFF
+LIBGIT2_OPTS := $(CMAKE_COMMON) -DCMAKE_BUILD_TYPE=Release -DUSE_THREADS=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON -DBUILD_CLI=OFF
ifeq ($(OS),WINNT)
LIBGIT2_OPTS += -DWIN32=ON -DMINGW=ON
ifeq ($(USE_SYSTEM_LIBSSH2), 0)
diff --git a/deps/libgit2.version b/deps/libgit2.version
index ffba640e3b24e..5a7fb591098bb 100644
--- a/deps/libgit2.version
+++ b/deps/libgit2.version
@@ -11,4 +11,4 @@ LIBGIT2_SHA1=338e6fb681369ff0537719095e22ce9dc602dbf0
# The versions of cacert.pem are identified by the date (YYYY-MM-DD) of their changes.
# See https://curl.haxx.se/docs/caextract.html for more details.
# Keep in sync with `stdlib/MozillaCACerts_jll/Project.toml`.
-MOZILLA_CACERT_VERSION := 2025-05-20
+MOZILLA_CACERT_VERSION := 2025-11-04
diff --git a/deps/libssh2.mk b/deps/libssh2.mk
index 05cc12b6e159b..661e26516c828 100644
--- a/deps/libssh2.mk
+++ b/deps/libssh2.mk
@@ -17,6 +17,9 @@ endif
ifeq ($(OS),WINNT)
LIBSSH2_OPTS += -DCRYPTO_BACKEND=WinCNG -DENABLE_ZLIB_COMPRESSION=OFF
+ifeq ($(BUILD_OS),WINNT)
+LIBSSH2_OPTS += -G"MSYS Makefiles"
+endif
else
LIBSSH2_OPTS += -DCRYPTO_BACKEND=OpenSSL -DENABLE_ZLIB_COMPRESSION=OFF
LIBSSH2_OPTS += -DOPENSSL_ROOT_DIR=$(build_prefix)
@@ -35,7 +38,7 @@ LIBSSH2_SRC_PATH := $(SRCCACHE)/$(LIBSSH2_SRC_DIR)
$(BUILDDIR)/$(LIBSSH2_SRC_DIR)/build-configured: $(LIBSSH2_SRC_PATH)/source-extracted
mkdir -p $(dir $@)
cd $(dir $@) && \
- $(CMAKE) $(CMAKE_GENERATOR_COMMAND) $(dir $<) $(LIBSSH2_OPTS)
+ $(CMAKE) $(dir $<) $(LIBSSH2_OPTS)
echo 1 > $@
$(BUILDDIR)/$(LIBSSH2_SRC_DIR)/build-compiled: $(BUILDDIR)/$(LIBSSH2_SRC_DIR)/build-configured
diff --git a/deps/libuv.mk b/deps/libuv.mk
index 993aa4fc144da..eacabac55e34f 100644
--- a/deps/libuv.mk
+++ b/deps/libuv.mk
@@ -4,7 +4,7 @@ LIBUV_GIT_URL:=https://github.com/JuliaLang/libuv.git
LIBUV_TAR_URL=https://api.github.com/repos/JuliaLang/libuv/tarball/$1
$(eval $(call git-external,libuv,LIBUV,configure,,$(SRCCACHE)))
-UV_CFLAGS := -O2 -DBUILDING_UV_SHARED=1
+UV_CFLAGS := -O2
UV_FLAGS := LDFLAGS="$(LDFLAGS) $(CLDFLAGS) -v"
UV_FLAGS += CFLAGS="$(CFLAGS) $(UV_CFLAGS) $(SANITIZE_OPTS)"
diff --git a/deps/llvm.mk b/deps/llvm.mk
index 8b823b8664bf2..09dd4f187d611 100644
--- a/deps/llvm.mk
+++ b/deps/llvm.mk
@@ -7,14 +7,6 @@ ifneq ($(USE_BINARYBUILDER_LLVM), 1)
LLVM_GIT_URL:=https://github.com/JuliaLang/llvm-project.git
LLVM_TAR_URL=https://api.github.com/repos/JuliaLang/llvm-project/tarball/$1
$(eval $(call git-external,llvm,LLVM,CMakeLists.txt,,$(SRCCACHE)))
-# LLVM's tarball contains symlinks to non-existent targets. This breaks the
-# the default msys strategy `deepcopy` symlink strategy. To workaround this,
-# switch to `native` which tries native windows symlinks (possible if the
-# machine is in developer mode) - or if not, falls back to cygwin-style
-# symlinks. We don't particularly care either way - we just need to symlinks
-# to succeed. We could guard this by a uname check, but it's harmless elsewhere,
-# so let's not incur the additional overhead.
-$(SRCCACHE)/$(LLVM_SRC_DIR)/source-extracted: $(MSYS_NONEXISTENT_SYMLINK_TARGET_FIX)
LLVM_BUILDDIR := $(BUILDDIR)/$(LLVM_SRC_DIR)
LLVM_BUILDDIR_withtype := $(LLVM_BUILDDIR)/build_$(LLVM_BUILDTYPE)
diff --git a/deps/openblas.mk b/deps/openblas.mk
index e5a988ba84df2..80881a6a13c4e 100644
--- a/deps/openblas.mk
+++ b/deps/openblas.mk
@@ -44,7 +44,7 @@ OPENBLAS_CFLAGS := -O2
# Decide whether to build for 32-bit or 64-bit arch
ifneq ($(XC_HOST),)
-OPENBLAS_BUILD_OPTS += OSNAME=$(OS) CROSS=1 HOSTCC=$(HOSTCC) CROSS_SUFFIX=$(CROSS_COMPILE)
+OPENBLAS_BUILD_OPTS += OSNAME=$(OS) CROSS=1 HOSTCC="$(HOSTCC)" CROSS_SUFFIX=$(CROSS_COMPILE)
endif
ifeq ($(OS),WINNT)
ifneq ($(ARCH),x86_64)
diff --git a/deps/openssl.mk b/deps/openssl.mk
index 734ddb3274e78..705303432c2c6 100644
--- a/deps/openssl.mk
+++ b/deps/openssl.mk
@@ -59,7 +59,7 @@ $(BUILDDIR)/openssl-$(OPENSSL_VER)/build-configured: $(SRCCACHE)/openssl-$(OPENS
mkdir -p $(dir $@)
cd $(dir $@) && \
CC="$(CC) $(SANITIZE_OPTS)" CXX="$(CXX) $(SANITIZE_OPTS)" LDFLAGS="$(LDFLAGS) $(RPATH_ESCAPED_ORIGIN) $(SANITIZE_LDFLAGS)" \
- $(dir $<)/Configure shared --prefix=$(abspath $(build_prefix)) --libdir=$(abspath $(build_libdir)) $(OPENSSL_TARGET)
+ $(dir $<)/Configure shared --prefix=$(abspath $(build_prefix)) $(OPENSSL_TARGET)
echo 1 > $@
$(BUILDDIR)/openssl-$(OPENSSL_VER)/build-compiled: $(BUILDDIR)/openssl-$(OPENSSL_VER)/build-configured
@@ -75,16 +75,18 @@ endif
# Override bindir and only install runtime libraries, otherwise they'll go into build_depsbindir.
OPENSSL_INSTALL = \
mkdir -p $2$$(build_shlibdir) && \
- $$(MAKE) -C $1 install_runtime_libs $$(MAKE_COMMON) bindir=$$(build_shlibdir) $3 DESTDIR="$2"
+ $$(MAKE) -C $1 install_dev $$(MAKE_COMMON) bindir=$$(build_shlibdir) $3 DESTDIR="$2"
+
+OPENSSL_POST_INSTALL := \
+ $(WIN_MAKE_HARD_LINK) $(build_bindir)/libcrypto-*.dll $(build_bindir)/libcrypto.dll && \
+ $(WIN_MAKE_HARD_LINK) $(build_bindir)/libssl-*.dll $(build_bindir)/libssl.dll && \
+ $(INSTALL_NAME_CMD)libcrypto.$(SHLIB_EXT) $(build_shlibdir)/libcrypto.$(SHLIB_EXT) && \
+ $(INSTALL_NAME_CMD)libssl.$(SHLIB_EXT) $(build_shlibdir)/libssl.$(SHLIB_EXT) && \
+ $(INSTALL_NAME_CHANGE_CMD) $(build_shlibdir)/libcrypto.3.dylib @rpath/libcrypto.$(SHLIB_EXT) $(build_shlibdir)/libssl.$(SHLIB_EXT)
$(eval $(call staged-install, \
openssl,openssl-$(OPENSSL_VER), \
- OPENSSL_INSTALL,,, \
- $$(WIN_MAKE_HARD_LINK) $(build_bindir)/libcrypto-*.dll $(build_bindir)/libcrypto.dll && \
- $$(WIN_MAKE_HARD_LINK) $(build_bindir)/libssl-*.dll $(build_bindir)/libssl.dll && \
- $$(INSTALL_NAME_CMD)libcrypto.$$(SHLIB_EXT) $$(build_shlibdir)/libcrypto.$$(SHLIB_EXT) && \
- $$(INSTALL_NAME_CMD)libssl.$$(SHLIB_EXT) $$(build_shlibdir)/libssl.$$(SHLIB_EXT) && \
- $$(INSTALL_NAME_CHANGE_CMD) $$(build_shlibdir)/libcrypto.3.dylib @rpath/libcrypto.$$(SHLIB_EXT) $$(build_shlibdir)/libssl.$$(SHLIB_EXT)))
+ OPENSSL_INSTALL,,,$(OPENSSL_POST_INSTALL)))
clean-openssl:
-rm -f $(BUILDDIR)/-openssl-$(OPENSSL_VER)/build-configured $(BUILDDIR)/-openssl-$(OPENSSL_VER)/build-compiled
diff --git a/deps/tools/common.mk b/deps/tools/common.mk
index 212b576fb63f9..01b57316f9d1a 100644
--- a/deps/tools/common.mk
+++ b/deps/tools/common.mk
@@ -59,6 +59,7 @@ CMAKE_COMMON += -DCMAKE_SYSTEM_NAME=Windows
CMAKE_COMMON += -DCMAKE_RC_COMPILER="$$(which $(CROSS_COMPILE)windres)"
endif
+# For now this is LLVM specific, but I expect it won't be in the future
ifeq ($(CMAKE_GENERATOR),Ninja)
CMAKE_GENERATOR_COMMAND := -G Ninja
else ifeq ($(CMAKE_GENERATOR),make)
@@ -67,27 +68,6 @@ else
$(error Unknown CMake generator '$(CMAKE_GENERATOR)'. Options are 'Ninja' and 'make')
endif
-ifneq (,$(findstring MINGW,$(RAW_BUILD_OS)))
-ifneq (,$(shell ldd $(shell which cmake) | grep msys-2.0.dll))
-# Detect MSYS2 with cygwin CMake rather than MinGW cmake - the former fails to
-# properly drive MinGW tools
-override CMAKE := echo "ERROR: CMake is Cygwin CMake, not MinGW CMake. Build will fail. Use 'pacman -S mingw-w64-{i686,x86_64}-cmake'."; exit 1; $(CMAKE)
-endif
-# In our setup, CMAKE_INSTALL_PREFIX is a relative path inside usr-staging.
-# We do not want this converted to a windows path, because our make system
-# assumes it to be relative to msys `/`.
-override CMAKE := MSYS2_ARG_CONV_EXCL="-DCMAKE_INSTALL_PREFIX" $(CMAKE)
-endif
-
-# Some dependencies' tarballs contains symlinks to non-existent targets. This breaks the
-# the default msys strategy `deepcopy` symlink strategy. To workaround this,
-# switch to `native` which tries native windows symlinks (possible if the
-# machine is in developer mode) - or if not, falls back to cygwin-style
-# symlinks. We don't particularly care either way - we just need to symlinks
-# to succeed. We could guard this by a uname check, but it's harmless elsewhere,
-# so let's not incur the additional overhead.
-MSYS_NONEXISTENT_SYMLINK_TARGET_FIX := export MSYS=winsymlinks:native
-
# If the top-level Makefile is called with environment variables,
# they will override the values passed above to ./configure
MAKE_COMMON := DESTDIR="" prefix=$(build_prefix) bindir=$(build_depsbindir) libdir=$(build_libdir) shlibdir=$(build_shlibdir) libexecdir=$(build_libexecdir) datarootdir=$(build_datarootdir) includedir=$(build_includedir) sysconfdir=$(build_sysconfdir) O=
@@ -164,7 +144,7 @@ upper = $(shell echo $1 | tr a-z A-Z)
# this rule ensures that make install is more nearly atomic
# so it's harder to get half-installed (or half-reinstalled) dependencies
# # and enables sharing deps compiles, uninstall, and fast reinstall
-MAKE_INSTALL = MSYS2_ARG_CONV_EXCL="prefix=" $$(MAKE) -C $1 install $$(MAKE_COMMON) $3 DESTDIR="$2"
+MAKE_INSTALL = +$$(MAKE) -C $1 install $$(MAKE_COMMON) $3 DESTDIR="$2"
define SHLIBFILE_INSTALL
mkdir -p $2/$$(build_shlibdir)
diff --git a/doc/src/manual/installation.md b/doc/src/manual/installation.md
index f45aba2c37a28..5107d30c7286f 100644
--- a/doc/src/manual/installation.md
+++ b/doc/src/manual/installation.md
@@ -75,7 +75,12 @@ If the Windows Store is blocked on a system, we have an alternative
[MSIX App Installer](https://learn.microsoft.com/en-us/windows/msix/app-installer/app-installer-file-overview)
based setup. To use the App Installer version, download
[this](https://install.julialang.org/Julia.appinstaller) file and open it by
-double clicking on it.
+double clicking on it. One can also install exactly the same version by executing
+the PowerShell command
+
+```
+Add-AppxPackage -AppInstallerFile https://install.julialang.org/Julia.appinstaller
+```
### MSI Installer (Windows)
diff --git a/pkgimage.mk b/pkgimage.mk
index 78b2618be549f..e90e0e9618808 100644
--- a/pkgimage.mk
+++ b/pkgimage.mk
@@ -26,7 +26,7 @@ print-depot-path:
$(BUILDDIR)/stdlib/%.image: $(JULIAHOME)/stdlib/Project.toml $(JULIAHOME)/stdlib/Manifest.toml $(INDEPENDENT_STDLIBS_SRCS) $(JULIA_DEPOT_PATH)/compiled
@$(call PRINT_JULIA, JULIA_CPU_TARGET="$(JULIA_CPU_TARGET)" $(call spawn,$(JULIA_EXECUTABLE)) --startup-file=no -e \
- 'Base.Precompilation.precompilepkgs(configs=[``=>Base.CacheFlags(debug_level=2, opt_level=3), ``=>Base.CacheFlags(check_bounds=1, debug_level=2, opt_level=3)])')
+ 'Base.Precompilation.precompilepkgs(configs=[``=>Base.CacheFlags(debug_level=2, opt_level=3), ``=>Base.CacheFlags(check_bounds=1, debug_level=2, opt_level=3)]; strict=true)')
touch $@
$(BUILDDIR)/stdlib/release.image: $(build_private_libdir)/sys.$(SHLIB_EXT)
diff --git a/src/Makefile b/src/Makefile
index 6245139592db1..e859acc765354 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -75,7 +75,7 @@ GC_CODEGEN_SRCS += llvm-late-gc-lowering-stock
endif
CODEGEN_SRCS := codegen jitlayers aotcompile debuginfo disasm llvm-simdloop \
llvm-pass-helpers llvm-ptls \
- llvm-lower-handlers llvm-propagate-addrspaces \
+ llvm-lower-handlers llvm-propagate-addrspaces null_sysimage \
llvm-multiversioning llvm-alloc-opt llvm-alloc-helpers cgmemmgr llvm-remove-addrspaces \
llvm-remove-ni llvm-julia-licm llvm-demote-float16 llvm-cpufeatures pipeline llvm_api \
$(GC_CODEGEN_SRCS)
@@ -192,9 +192,7 @@ endif
COMMON_LIBPATHS := -L$(build_libdir) -L$(build_shlibdir)
RT_LIBS := $(WHOLE_ARCHIVE) $(LIBUV) $(WHOLE_ARCHIVE) $(LIBUTF8PROC) $(NO_WHOLE_ARCHIVE) $(LIBUNWIND) $(RT_LLVMLINK) $(OSLIBS) $(LIBTRACYCLIENT) $(LIBITTAPI) $(MMTK_LIB)
-# NB: CG needs uv_mutex_* symbols, but we expect to export them from libjulia-internal
CG_LIBS := $(LIBUNWIND) $(CG_LLVMLINK) $(OSLIBS) $(LIBTRACYCLIENT) $(LIBITTAPI) $(MMTK_LIB)
-
RT_DEBUG_LIBS := $(COMMON_LIBPATHS) $(WHOLE_ARCHIVE) $(BUILDDIR)/flisp/libflisp-debug.a $(WHOLE_ARCHIVE) $(BUILDDIR)/support/libsupport-debug.a -ljulia-debug $(RT_LIBS)
CG_DEBUG_LIBS := $(COMMON_LIBPATHS) $(CG_LIBS) -ljulia-debug -ljulia-internal-debug
RT_RELEASE_LIBS := $(COMMON_LIBPATHS) $(WHOLE_ARCHIVE) $(BUILDDIR)/flisp/libflisp.a $(WHOLE_ARCHIVE) $(BUILDDIR)/support/libsupport.a -ljulia $(RT_LIBS)
@@ -471,10 +469,10 @@ libjulia-codegen-debug: $(build_shlibdir)/libjulia-codegen-debug.$(JL_MAJOR_MINO
libjulia-codegen-debug libjulia-codegen-release: $(PUBLIC_HEADER_TARGETS)
# set the exports for the source files based on where they are getting linked
-$(OBJS): SHIPFLAGS += -DJL_LIBRARY_EXPORTS_INTERNAL -DBUILDING_UV_SHARED
-$(DOBJS): DEBUGFLAGS += -DJL_LIBRARY_EXPORTS_INTERNAL -DBUILDING_UV_SHARED
-$(CODEGEN_OBJS): SHIPFLAGS += -DJL_LIBRARY_EXPORTS_CODEGEN -DUSING_UV_SHARED
-$(CODEGEN_DOBJS): DEBUGFLAGS += -DJL_LIBRARY_EXPORTS_CODEGEN -DUSING_UV_SHARED
+$(OBJS): SHIPFLAGS += -DJL_LIBRARY_EXPORTS_INTERNAL
+$(DOBJS): DEBUGFLAGS += -DJL_LIBRARY_EXPORTS_INTERNAL
+$(CODEGEN_OBJS): SHIPFLAGS += -DJL_LIBRARY_EXPORTS_CODEGEN
+$(CODEGEN_DOBJS): DEBUGFLAGS += -DJL_LIBRARY_EXPORTS_CODEGEN
clean:
-rm -fr $(build_shlibdir)/libjulia-internal* $(build_shlibdir)/libjulia-codegen* $(build_shlibdir)/libccalltest* $(build_shlibdir)/libllvmcalltest*
diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp
index 6009bd435534c..9a1157afda3e4 100644
--- a/src/aotcompile.cpp
+++ b/src/aotcompile.cpp
@@ -108,6 +108,24 @@ jl_get_llvm_mis_impl(void *native_code, size_t *num_elements, jl_method_instance
}
}
+extern "C" JL_DLLEXPORT_CODEGEN void
+jl_get_llvm_cis_impl(void *native_code, size_t *num_elements, jl_code_instance_t **data)
+{
+ jl_native_code_desc_t *desc = (jl_native_code_desc_t *)native_code;
+ auto &map = desc->jl_fvar_map;
+
+ if (data == NULL) {
+ *num_elements = map.size();
+ return;
+ }
+
+ assert(*num_elements == map.size());
+ size_t i = 0;
+ for (auto &ci : map) {
+ data[i++] = ci.first;
+ }
+}
+
extern "C" JL_DLLEXPORT_CODEGEN void jl_get_llvm_gvs_impl(void *native_code,
size_t *num_elements, void **data)
{
@@ -124,6 +142,22 @@ extern "C" JL_DLLEXPORT_CODEGEN void jl_get_llvm_gvs_impl(void *native_code,
memcpy(data, value_map.data(), *num_elements * sizeof(void *));
}
+extern "C" JL_DLLEXPORT_CODEGEN void jl_get_llvm_gvs_globals_impl(void *native_code,
+ size_t *num_elements, void **data)
+{
+ // map a memory location (jl_value_t or jl_binding_t) to a GlobalVariable
+ jl_native_code_desc_t *desc = (jl_native_code_desc_t *)native_code;
+ auto &value_map = desc->jl_sysimg_gvars;
+
+ if (data == NULL) {
+ *num_elements = value_map.size();
+ return;
+ }
+
+ assert(*num_elements == value_map.size());
+ memcpy(data, value_map.data(), *num_elements * sizeof(void *));
+}
+
extern "C" JL_DLLEXPORT_CODEGEN void jl_get_llvm_external_fns_impl(void *native_code,
size_t *num_elements,
jl_code_instance_t *data)
diff --git a/src/cgutils.cpp b/src/cgutils.cpp
index 65a01c1355f76..cc8ea597516a3 100644
--- a/src/cgutils.cpp
+++ b/src/cgutils.cpp
@@ -628,13 +628,13 @@ static unsigned convert_struct_offset(jl_codectx_t &ctx, Type *lty, unsigned byt
static Type *_julia_struct_to_llvm(jl_codegen_params_t *ctx, LLVMContext &ctxt, jl_value_t *jt, bool *isboxed, bool llvmcall=false);
-static Type *_julia_type_to_llvm(jl_codegen_params_t *ctx, LLVMContext &ctxt, jl_value_t *jt, bool *isboxed)
+static Type *_julia_type_to_llvm(jl_codegen_params_t *ctx, LLVMContext &ctxt, jl_value_t *jt, bool *isboxed, bool no_boxing)
{
// this function converts a Julia Type into the equivalent LLVM type
if (isboxed) *isboxed = false;
if (jt == (jl_value_t*)jl_bottom_type || jt == (jl_value_t*)jl_typeofbottom_type || jt == (jl_value_t*)jl_typeofbottom_type->super)
return getVoidTy(ctxt);
- if (jl_is_concrete_immutable(jt)) {
+ if (jl_is_concrete_immutable(jt) || no_boxing) {
if (jl_datatype_nbits(jt) == 0)
return getVoidTy(ctxt);
Type *t = _julia_struct_to_llvm(ctx, ctxt, jt, isboxed);
@@ -647,13 +647,20 @@ static Type *_julia_type_to_llvm(jl_codegen_params_t *ctx, LLVMContext &ctxt, jl
static Type *julia_type_to_llvm(jl_codectx_t &ctx, jl_value_t *jt, bool *isboxed)
{
- return _julia_type_to_llvm(&ctx.emission_context, ctx.builder.getContext(), jt, isboxed);
+ return _julia_type_to_llvm(&ctx.emission_context, ctx.builder.getContext(), jt, isboxed, false);
}
extern "C" JL_DLLEXPORT_CODEGEN
Type *jl_type_to_llvm_impl(jl_value_t *jt, LLVMContextRef ctxt, bool *isboxed)
{
- return _julia_type_to_llvm(NULL, *unwrap(ctxt), jt, isboxed);
+ return _julia_type_to_llvm(NULL, *unwrap(ctxt), jt, isboxed, false);
+}
+
+
+extern "C" JL_DLLEXPORT_CODEGEN
+Type *jl_struct_to_llvm_impl(jl_value_t *jt, LLVMContextRef ctxt, bool *isboxed)
+{
+ return _julia_type_to_llvm(NULL, *unwrap(ctxt), jt, isboxed, true);
}
diff --git a/src/codegen-stubs.c b/src/codegen-stubs.c
index 04f38fb9091be..c77c449fa1b3d 100644
--- a/src/codegen-stubs.c
+++ b/src/codegen-stubs.c
@@ -14,9 +14,10 @@ JL_DLLEXPORT void jl_dump_native_fallback(void *native_code,
const char *bc_fname, const char *unopt_bc_fname, const char *obj_fname, const char *asm_fname,
ios_t *z, ios_t *s) UNAVAILABLE
JL_DLLEXPORT void jl_get_llvm_gvs_fallback(void *native_code, arraylist_t *gvs) UNAVAILABLE
+JL_DLLEXPORT void jl_get_llvm_gvs_globals_fallback(void *native_code, arraylist_t *gvs) UNAVAILABLE
JL_DLLEXPORT void jl_get_llvm_external_fns_fallback(void *native_code, arraylist_t *gvs) UNAVAILABLE
-JL_DLLEXPORT void jl_get_llvm_mis_fallback(void *native_code, arraylist_t* MIs) UNAVAILABLE
-
+JL_DLLEXPORT void jl_get_llvm_mis_fallback(void *native_code, size_t *num_elements, jl_method_instance_t **data) UNAVAILABLE
+JL_DLLEXPORT void jl_get_llvm_cis_fallback(void *native_code, size_t *num_elements, jl_code_instance_t **data) UNAVAILABLE
JL_DLLEXPORT jl_value_t *jl_dump_method_asm_fallback(jl_method_instance_t *linfo, size_t world,
char emit_mc, char getwrapper, const char* asm_variant, const char *debuginfo, char binary) UNAVAILABLE
JL_DLLEXPORT jl_value_t *jl_dump_function_ir_fallback(jl_llvmf_dump_t *dump, char strip_ir_metadata, char dump_module, const char *debuginfo) UNAVAILABLE
@@ -116,6 +117,8 @@ JL_DLLEXPORT LLVMOrcThreadSafeModuleRef jl_get_llvm_module_fallback(void *native
JL_DLLEXPORT void *jl_type_to_llvm_fallback(jl_value_t *jt, LLVMContextRef llvmctxt, bool_t *isboxed) UNAVAILABLE
+JL_DLLEXPORT void *jl_struct_to_llvm_fallback(jl_value_t *jt, LLVMContextRef llvmctxt, bool_t *isboxed) UNAVAILABLE
+
JL_DLLEXPORT jl_value_t *jl_get_libllvm_fallback(void) JL_NOTSAFEPOINT
{
return jl_nothing;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 8f0644c0cff7f..816a4d24583a8 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -2163,9 +2163,11 @@ static AllocaInst *emit_static_alloca(jl_codectx_t &ctx, unsigned nb, Align alig
// if it cannot find something better to do, which is terrible for performance.
// However, if we emit this with an element size equal to the alignment, it will instead split it into aligned chunks
// which is great for performance and vectorization.
- if (alignTo(nb, align) == align.value()) // don't bother with making an array of length 1
- return emit_static_alloca(ctx, ctx.builder.getIntNTy(align.value() * 8), align);
- return emit_static_alloca(ctx, ArrayType::get(ctx.builder.getIntNTy(align.value() * 8), alignTo(nb, align) / align.value()), align);
+ // Cap element size at 64 bits since not all backends support larger integers.
+ unsigned elsize = std::min(align.value(), (uint64_t)8);
+ if (alignTo(nb, elsize) == elsize) // don't bother with making an array of length 1
+ return emit_static_alloca(ctx, ctx.builder.getIntNTy(elsize * 8), align);
+ return emit_static_alloca(ctx, ArrayType::get(ctx.builder.getIntNTy(elsize * 8), alignTo(nb, elsize) / elsize), align);
}
static AllocaInst *emit_static_roots(jl_codectx_t &ctx, unsigned nroots)
@@ -2305,6 +2307,19 @@ static inline jl_cgval_t value_to_pointer(jl_codectx_t &ctx, const jl_cgval_t &v
Align align(julia_alignment(v.typ));
Type *ty = julia_type_to_llvm(ctx, v.typ);
AllocaInst *loc = emit_static_alloca(ctx, ty, align);
+ jl_datatype_t *dt = (jl_datatype_t *)v.typ;
+ size_t npointers = dt->layout->first_ptr >= 0 ? dt->layout->npointers : 0;
+ if (npointers > 0) {
+ auto InsertPoint = ctx.builder.saveIP();
+ ctx.builder.SetInsertPoint(ctx.topalloca->getParent(), ++ctx.topalloca->getIterator());
+ for (size_t i = 0; i < npointers; i++) {
+ // make sure these are nullptr early from LLVM's perspective, in case it decides to SROA it
+ Value *ptr_field = emit_ptrgep(ctx, loc, jl_ptr_offset(dt, i) * sizeof(void *));
+ ctx.builder.CreateAlignedStore(
+ Constant::getNullValue(ctx.types().T_prjlvalue), ptr_field, Align(sizeof(void *)));
+ }
+ ctx.builder.restoreIP(InsertPoint);
+ }
auto tbaa = v.V == nullptr ? ctx.tbaa().tbaa_gcframe : ctx.tbaa().tbaa_stack;
auto stack_ai = jl_aliasinfo_t::fromTBAA(ctx, tbaa);
recombine_value(ctx, v, loc, stack_ai, align, false);
@@ -5007,7 +5022,11 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_clos
AllocaInst *result = nullptr;
if (returninfo.cc == jl_returninfo_t::SRet || returninfo.cc == jl_returninfo_t::Union) {
- result = emit_static_alloca(ctx, returninfo.union_bytes, Align(returninfo.union_align));
+ if (returninfo.all_roots) {
+ result = emit_static_roots(ctx, returninfo.union_bytes / sizeof(void *));
+ } else {
+ result = emit_static_alloca(ctx, returninfo.union_bytes, Align(returninfo.union_align));
+ }
setName(ctx.emission_context, result, "sret_box");
argvals[idx] = result;
idx++;
@@ -6159,6 +6178,7 @@ static void emit_stmtpos(jl_codectx_t &ctx, jl_value_t *expr, int ssaval_result)
Value *scope_ptr = get_scope_field(ctx);
jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe).decorateInst(
ctx.builder.CreateAlignedStore(scope_to_restore, scope_ptr, ctx.types().alignof_ptr));
+ // NOTE: wb not needed here, due to store to current_task (see jl_gc_wb_current_task)
}
}
else if (head == jl_pop_exception_sym) {
@@ -7855,7 +7875,7 @@ static jl_returninfo_t get_specsig_function(jl_codegen_params_t ¶ms, Module
}
else if (!deserves_retbox(jlrettype)) {
bool retboxed;
- rt = _julia_type_to_llvm(¶ms, M->getContext(), jlrettype, &retboxed);
+ rt = _julia_type_to_llvm(¶ms, M->getContext(), jlrettype, &retboxed, /*noboxing*/false);
assert(!retboxed);
if (rt != getVoidTy(M->getContext()) && deserves_sret(jlrettype, rt)) {
auto tracked = CountTrackedPointers(rt, true);
@@ -7867,6 +7887,7 @@ static jl_returninfo_t get_specsig_function(jl_codegen_params_t ¶ms, Module
props.cc = jl_returninfo_t::SRet;
props.union_bytes = jl_datatype_size(jlrettype);
props.union_align = props.union_minalign = julia_alignment(jlrettype);
+ props.all_roots = tracked.all;
// sret is always passed from alloca
assert(M);
fsig.push_back(rt->getPointerTo(M->getDataLayout().getAllocaAddrSpace()));
@@ -7931,7 +7952,7 @@ static jl_returninfo_t get_specsig_function(jl_codegen_params_t ¶ms, Module
if (is_uniquerep_Type(jt))
continue;
isboxed = deserves_argbox(jt);
- et = isboxed ? T_prjlvalue : _julia_type_to_llvm(¶ms, M->getContext(), jt, nullptr);
+ et = isboxed ? T_prjlvalue : _julia_type_to_llvm(¶ms, M->getContext(), jt, nullptr, /*noboxing*/false);
if (type_is_ghost(et))
continue;
}
@@ -9334,12 +9355,12 @@ static jl_llvm_functions_t
Value *scope_ptr = get_scope_field(ctx);
LoadInst *current_scope = ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, scope_ptr, ctx.types().alignof_ptr);
StoreInst *scope_store = ctx.builder.CreateAlignedStore(scope_boxed, scope_ptr, ctx.types().alignof_ptr);
+ // NOTE: wb not needed here, due to store to current_task (see jl_gc_wb_current_task)
jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe).decorateInst(current_scope);
jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe).decorateInst(scope_store);
- // GC preserve the scope, since it is not rooted in the `jl_handler_t *`
- // and may be removed from jl_current_task by any nested block and then
- // replaced later
- Value *scope_token = ctx.builder.CreateCall(prepare_call(gc_preserve_begin_func), {scope_boxed});
+ // GC preserve the current_scope, since it is not rooted in the `jl_handler_t *`,
+ // the newly entered scope is preserved through the current_task.
+ Value *scope_token = ctx.builder.CreateCall(prepare_call(gc_preserve_begin_func), {current_scope});
ctx.scope_restore[cursor] = std::make_pair(scope_token, current_scope);
}
}
diff --git a/src/datatype.c b/src/datatype.c
index 4cf2c6d780bbd..447586135cdc7 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -1040,10 +1040,14 @@ JL_DLLEXPORT int jl_reinit_foreign_type(jl_datatype_t *dt,
const jl_datatype_layout_t *layout = dt->layout;
jl_fielddescdyn_t * desc =
(jl_fielddescdyn_t *) ((char *)layout + sizeof(*layout));
- assert(!desc->markfunc);
- assert(!desc->sweepfunc);
- desc->markfunc = markfunc;
- desc->sweepfunc = sweepfunc;
+ if (desc->markfunc != markfunc) {
+ assert(!desc->markfunc);
+ desc->markfunc = markfunc;
+ }
+ if (desc->sweepfunc != sweepfunc) {
+ assert(!desc->sweepfunc);
+ desc->sweepfunc = sweepfunc;
+ }
return 1;
}
diff --git a/src/flisp/Makefile b/src/flisp/Makefile
index 2e902a31dbeed..eca1de86e588a 100644
--- a/src/flisp/Makefile
+++ b/src/flisp/Makefile
@@ -117,7 +117,7 @@ $(BUILDDIR)/host/Makefile:
@printf "%s\n" 'include $(SRCDIR)/Makefile' >> $@
$(BUILDDIR)/host/$(EXENAME): $(BUILDDIR)/host/Makefile | ${BUILDDIR}/host/flisp.boot
- $(MAKE) -C $(BUILDDIR)/host $(EXENAME)
+ make -C $(BUILDDIR)/host $(EXENAME)
$(BUILDDIR)/host/flisp.boot: $(SRCDIR)/flisp.boot | $(BUILDDIR)/host/Makefile
diff --git a/src/gc-interface.h b/src/gc-interface.h
index 826e91355b17a..9c59e274d1261 100644
--- a/src/gc-interface.h
+++ b/src/gc-interface.h
@@ -240,7 +240,14 @@ STATIC_INLINE void jl_gc_wb(const void *parent, const void *ptr) JL_NOTSAFEPOINT
// so write barriers can be omitted until the next allocation. This function is a no-op that
// can be used to annotate that a write barrier would be required were it not for this property
// (as opposed to somebody just having forgotten to think about write barriers).
-STATIC_INLINE void jl_gc_wb_fresh(const void *parent, const void *ptr) JL_NOTSAFEPOINT {}
+STATIC_INLINE void jl_gc_wb_fresh(const void *parent JL_UNUSED, const void *ptr JL_UNUSED) JL_NOTSAFEPOINT {}
+// As an optimization, the current_task is explicitly added to the remset while it is running.
+// Upon deschedule, we conservatively move the write barrier into the young generation.
+// This allows the omission of write barriers for all GC roots on the current task stack (JL_GC_PUSH_*),
+// as well as the Task's explicit fields (but only for the current task).
+// This function is a no-op that can be used to annotate that a write barrier would be required were
+// it not for this property (as opposed to somebody just having forgotten to think about write barriers).
+STATIC_INLINE void jl_gc_wb_current_task(const void *parent JL_UNUSED, const void *ptr JL_UNUSED) JL_NOTSAFEPOINT {}
// Used to annotate that a write barrier would be required, but may be omitted because `ptr`
// is known to be an old object.
STATIC_INLINE void jl_gc_wb_knownold(const void *parent, const void *ptr) JL_NOTSAFEPOINT {}
diff --git a/src/gc-pages.c b/src/gc-pages.c
index 71d59de29166f..79dd8993a8861 100644
--- a/src/gc-pages.c
+++ b/src/gc-pages.c
@@ -28,6 +28,28 @@ JL_DLLEXPORT uint64_t jl_get_pg_size(void)
static int block_pg_cnt = DEFAULT_BLOCK_PG_ALLOC;
+// Julia allocates large blocks (64M) with mmap. These are never
+// unmapped but the underlying physical memory may be released
+// with calls to madvise(MADV_DONTNEED).
+static uint64_t poolmem_blocks_allocated_total = 0;
+
+JL_DLLEXPORT uint64_t jl_poolmem_blocks_allocated_total(void)
+{
+ return poolmem_blocks_allocated_total;
+}
+
+JL_DLLEXPORT uint64_t jl_poolmem_bytes_allocated(void)
+{
+ return jl_atomic_load_relaxed(&gc_heap_stats.bytes_resident);
+}
+
+JL_DLLEXPORT uint64_t jl_current_pg_count(void)
+{
+ assert(jl_page_size == GC_PAGE_SZ && "RAI fork of Julia should be running on platforms for which jl_page_size == GC_PAGE_SZ");
+ size_t nb = jl_atomic_load_relaxed(&gc_heap_stats.bytes_resident);
+ return nb / GC_PAGE_SZ; // exact division
+}
+
void jl_gc_init_page(void)
{
if (GC_PAGE_SZ * block_pg_cnt < jl_page_size)
@@ -55,6 +77,11 @@ char *jl_gc_try_alloc_pages_(int pg_cnt) JL_NOTSAFEPOINT
MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (mem == MAP_FAILED)
return NULL;
+
+#ifdef MADV_NOHUGEPAGE
+ madvise(mem, pages_sz, MADV_NOHUGEPAGE);
+#endif
+
#endif
if (GC_PAGE_SZ > jl_page_size)
// round data pointer up to the nearest gc_page_data-aligned
@@ -62,6 +89,7 @@ char *jl_gc_try_alloc_pages_(int pg_cnt) JL_NOTSAFEPOINT
mem = (char*)gc_page_data(mem + GC_PAGE_SZ - 1);
jl_atomic_fetch_add_relaxed(&gc_heap_stats.bytes_mapped, pages_sz);
jl_atomic_fetch_add_relaxed(&gc_heap_stats.bytes_resident, pages_sz);
+ poolmem_blocks_allocated_total++; // RAI-specific
return mem;
}
@@ -184,7 +212,7 @@ void jl_gc_free_page(jl_gc_pagemeta_t *pg) JL_NOTSAFEPOINT
}
#ifdef _OS_WINDOWS_
VirtualFree(p, decommit_size, MEM_DECOMMIT);
-#elif defined(MADV_FREE)
+#elif 0
static int supports_madv_free = 1;
if (supports_madv_free) {
if (madvise(p, decommit_size, MADV_FREE) == -1) {
diff --git a/src/gc-stacks.c b/src/gc-stacks.c
index 9387c7fb065ec..55c4a470dd33e 100644
--- a/src/gc-stacks.c
+++ b/src/gc-stacks.c
@@ -72,8 +72,10 @@ static void *malloc_stack(size_t bufsz) JL_NOTSAFEPOINT
munmap(stk, bufsz);
return MAP_FAILED;
}
-# endif
-
+#ifdef MADV_NOHUGEPAGE
+ madvise(stk, bufsz, MADV_NOHUGEPAGE);
+#endif
+#endif
jl_atomic_fetch_add_relaxed(&num_stack_mappings, 1);
return stk;
}
diff --git a/src/gc-stock.c b/src/gc-stock.c
index 55f31b26679ff..a56e61cdec37f 100644
--- a/src/gc-stock.c
+++ b/src/gc-stock.c
@@ -197,6 +197,7 @@ static int mark_reset_age = 0;
static int64_t scanned_bytes; // young bytes scanned while marking
static int64_t perm_scanned_bytes; // old bytes scanned while marking
+static int64_t heap_size_after_last_full_gc = 0;
int prev_sweep_full = 1;
int current_sweep_full = 0;
int next_sweep_full = 0;
@@ -629,7 +630,7 @@ void jl_gc_reset_alloc_count(void) JL_NOTSAFEPOINT
static void jl_gc_free_memory(jl_genericmemory_t *m, int isaligned) JL_NOTSAFEPOINT
{
assert(jl_is_genericmemory(m));
- assert(jl_genericmemory_how(m) == 1 || jl_genericmemory_how(m) == 2);
+ assert(jl_genericmemory_how(m) == 1);
char *d = (char*)m->ptr;
size_t freed_bytes = memory_block_usable_size(d, isaligned);
assert(freed_bytes != 0);
@@ -2232,13 +2233,13 @@ JL_DLLEXPORT void jl_gc_mark_queue_objarray(jl_ptls_t ptls, jl_value_t *parent,
// `_new_obj` has its lowest bit tagged if it's in the remset (in which case we shouldn't update page metadata)
FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_new_obj)
{
- int meta_updated = (uintptr_t)_new_obj & GC_REMSET_PTR_TAG;
+ int remset_object = (uintptr_t)_new_obj & GC_REMSET_PTR_TAG;
jl_value_t *new_obj = (jl_value_t *)((uintptr_t)_new_obj & ~(uintptr_t)GC_REMSET_PTR_TAG);
mark_obj: {
jl_taggedvalue_t *o = jl_astaggedvalue(new_obj);
uintptr_t vtag = o->header & ~(uintptr_t)0xf;
uint8_t bits = (gc_old(o->header) && !mark_reset_age) ? GC_OLD_MARKED : GC_MARKED;
- int update_meta = __likely(!meta_updated && !gc_verifying);
+ int update_meta = __likely(!remset_object && !gc_verifying);
int foreign_alloc = 0;
if (update_meta && o->bits.in_image) {
foreign_alloc = 1;
@@ -2338,7 +2339,7 @@ FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_
uintptr_t nptr = (npointers << 2) | 1 | bits;
new_obj = gc_mark_obj8(ptls, obj8_parent, obj8_begin, obj8_end, nptr);
if (new_obj != NULL) {
- if (!meta_updated)
+ if (!remset_object)
goto mark_obj;
else
gc_ptr_queue_push(mq, new_obj);
@@ -2460,7 +2461,7 @@ FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_
assert(obj8_begin < obj8_end);
new_obj = gc_mark_obj8(ptls, obj8_parent, obj8_begin, obj8_end, nptr);
if (new_obj != NULL) {
- if (!meta_updated)
+ if (!remset_object)
goto mark_obj;
else
gc_ptr_queue_push(mq, new_obj);
@@ -2473,7 +2474,7 @@ FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_
assert(obj16_begin < obj16_end);
new_obj = gc_mark_obj16(ptls, obj16_parent, obj16_begin, obj16_end, nptr);
if (new_obj != NULL) {
- if (!meta_updated)
+ if (!remset_object)
goto mark_obj;
else
gc_ptr_queue_push(mq, new_obj);
@@ -2488,7 +2489,7 @@ FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_
assert(obj32_begin < obj32_end);
new_obj = gc_mark_obj32(ptls, obj32_parent, obj32_begin, obj32_end, nptr);
if (new_obj != NULL) {
- if (!meta_updated)
+ if (!remset_object)
goto mark_obj;
else
gc_ptr_queue_push(mq, new_obj);
@@ -3036,7 +3037,6 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
uint64_t gc_start_time = jl_hrtime();
uint64_t mutator_time = gc_end_time == 0 ? old_mut_time : gc_start_time - gc_end_time;
uint64_t before_free_heap_size = jl_atomic_load_relaxed(&gc_heap_stats.heap_size);
- int64_t last_perm_scanned_bytes = perm_scanned_bytes;
uint64_t start_mark_time = jl_hrtime();
JL_PROBE_GC_MARK_BEGIN();
{
@@ -3130,8 +3130,9 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
gc_stats_all_pool();
gc_stats_big_obj();
gc_num.total_allocd += gc_num.allocd;
- if (!prev_sweep_full)
- promoted_bytes += perm_scanned_bytes - last_perm_scanned_bytes;
+ // promoted_bytes are all the new bytes scanned that got promoted to old but that have never seen a full GC as old
+ promoted_bytes += scanned_bytes;
+ scanned_bytes = 0;
// 4. next collection decision
int remset_nptr = 0;
int sweep_full = next_sweep_full;
@@ -3157,13 +3158,6 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
recollect = 1;
gc_count_full_sweep_reason(FULL_SWEEP_REASON_FORCED_FULL_SWEEP);
}
- if (sweep_full) {
- // these are the difference between the number of gc-perm bytes scanned
- // on the first collection after sweep_full, and the current scan
- perm_scanned_bytes = 0;
- promoted_bytes = 0;
- }
- scanned_bytes = 0;
// 5. start sweeping
uint64_t start_sweep_time = jl_hrtime();
JL_PROBE_GC_SWEEP_BEGIN(sweep_full);
@@ -3295,7 +3289,19 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
target_heap = jl_atomic_load_relaxed(&gc_heap_stats.heap_target);
}
+ if (sweep_full) {
+ // these are the difference between the number of gc-perm bytes scanned
+ // on the first collection after sweep_full, and the current scan
+ perm_scanned_bytes = 0;
+ promoted_bytes = 0;
+ heap_size_after_last_full_gc = jl_atomic_load_relaxed(&gc_heap_stats.heap_size);
+ }
+ // We want to trigger full GCs either if the heap size has grown a lot since the last full GC.
+ // For this we use the overallocation function to see what a reasonable rate of growth is,
+ // or if there is too much memory that has not seen a full GC after being promoted to old.
double old_ratio = (double)promoted_bytes/(double)heap_size;
+ double expected_heap_size = overallocation(heap_size_after_last_full_gc, 0, UINT64_MAX) + heap_size_after_last_full_gc;
+ double last_full_gc_heap_ratio = (double)heap_size/expected_heap_size;
if (heap_size > user_max) {
next_sweep_full = 1;
gc_count_full_sweep_reason(FULL_SWEEP_REASON_USER_MAX_EXCEEDED);
@@ -3304,6 +3310,10 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
next_sweep_full = 1;
gc_count_full_sweep_reason(FULL_SWEEP_REASON_LARGE_PROMOTION_RATE);
}
+ else if (last_full_gc_heap_ratio > 1) {
+ next_sweep_full = 1;
+ gc_count_full_sweep_reason(FULL_SWEEP_REASON_LARGE_HEAP_GROWTH);
+ }
else {
next_sweep_full = 0;
}
@@ -3397,6 +3407,9 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
return recollect;
}
+extern int jl_heartbeat_pause(void);
+extern int jl_heartbeat_resume(void);
+
JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection)
{
JL_PROBE_GC_BEGIN(collection);
@@ -3439,6 +3452,7 @@ JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection)
// existence of the thread in the jl_n_threads count.
//
// TODO: concurrently queue objects
+ jl_heartbeat_pause();
jl_fence();
gc_n_threads = jl_atomic_load_acquire(&jl_n_threads);
gc_all_tls_states = jl_atomic_load_relaxed(&jl_all_tls_states);
@@ -3470,6 +3484,7 @@ JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection)
gc_n_threads = 0;
gc_all_tls_states = NULL;
+ jl_heartbeat_resume();
jl_safepoint_end_gc();
jl_gc_state_set(ptls, old_state, JL_GC_STATE_WAITING);
JL_PROBE_GC_END();
@@ -3906,6 +3921,9 @@ void *jl_gc_perm_alloc_nolock(size_t sz, int zero, unsigned align, unsigned offs
errno = last_errno;
if (__unlikely(pool == MAP_FAILED))
return NULL;
+#ifdef MADV_NOHUGEPAGE
+ madvise(pool, GC_PERM_POOL_SIZE, MADV_NOHUGEPAGE);
+#endif
#endif
gc_perm_pool = (uintptr_t)pool;
gc_perm_end = gc_perm_pool + GC_PERM_POOL_SIZE;
diff --git a/src/gc-stock.h b/src/gc-stock.h
index d478ee1366da0..fb55a2e8fa9bd 100644
--- a/src/gc-stock.h
+++ b/src/gc-stock.h
@@ -483,7 +483,8 @@ FORCE_INLINE void gc_big_object_link(bigval_t *sentinel_node, bigval_t *node) JL
#define FULL_SWEEP_REASON_FORCED_FULL_SWEEP (1)
#define FULL_SWEEP_REASON_USER_MAX_EXCEEDED (2)
#define FULL_SWEEP_REASON_LARGE_PROMOTION_RATE (3)
-#define FULL_SWEEP_NUM_REASONS (4)
+#define FULL_SWEEP_REASON_LARGE_HEAP_GROWTH (4)
+#define FULL_SWEEP_NUM_REASONS (5)
extern JL_DLLEXPORT uint64_t jl_full_sweep_reasons[FULL_SWEEP_NUM_REASONS];
STATIC_INLINE void gc_count_full_sweep_reason(int reason) JL_NOTSAFEPOINT
@@ -499,6 +500,9 @@ extern uv_sem_t gc_sweep_assists_needed;
extern _Atomic(int) gc_n_threads_marking;
extern _Atomic(int) gc_n_threads_sweeping_pools;
extern _Atomic(int) n_threads_running;
+extern _Atomic(int) gc_n_threads_sweeping_stacks;
+extern _Atomic(int) gc_ptls_sweep_idx;
+extern _Atomic(int) gc_stack_free_idx;
extern uv_barrier_t thread_init_done;
void gc_mark_queue_all_roots(jl_ptls_t ptls, jl_gc_markqueue_t *mq);
void gc_mark_finlist_(jl_gc_markqueue_t *mq, jl_value_t *fl_parent, jl_value_t **fl_begin, jl_value_t **fl_end) JL_NOTSAFEPOINT;
diff --git a/src/genericmemory.c b/src/genericmemory.c
index 32adc1add3d06..fbdccca2174fa 100644
--- a/src/genericmemory.c
+++ b/src/genericmemory.c
@@ -200,7 +200,6 @@ JL_DLLEXPORT jl_value_t *jl_genericmemory_to_string(jl_genericmemory_t *m, size_
m->length = 0;
if (how != 0) {
jl_value_t *o = jl_genericmemory_data_owner_field(m);
- jl_genericmemory_data_owner_field(m) = NULL;
if (how == 3 && // implies jl_is_string(o)
((mlength + sizeof(void*) + 1 <= GC_MAX_SZCLASS) == (len + sizeof(void*) + 1 <= GC_MAX_SZCLASS))) {
if (jl_string_data(o)[len] != '\0')
diff --git a/src/gf.c b/src/gf.c
index 47db5474701ac..53415ba4716fd 100644
--- a/src/gf.c
+++ b/src/gf.c
@@ -399,6 +399,8 @@ static jl_code_instance_t *jl_method_inferred_with_abi(jl_method_instance_t *mi
return NULL;
}
+jl_mutex_t jl_typeinf_lock;
+
// run type inference on lambda "mi" for given argument types.
// returns the inferred source, and may cache the result in mi
// if successful, also updates the mi argument to describe the validity of this src
@@ -427,6 +429,7 @@ jl_code_instance_t *jl_type_infer(jl_method_instance_t *mi, size_t world, uint8_
return NULL;
JL_TIMING(INFERENCE, INFERENCE);
jl_value_t **fargs;
+ JL_GC_PUSH1(&ci);
JL_GC_PUSHARGS(fargs, 5);
fargs[0] = (jl_value_t*)jl_typeinf_func;
fargs[1] = (jl_value_t*)mi;
@@ -458,6 +461,7 @@ jl_code_instance_t *jl_type_infer(jl_method_instance_t *mi, size_t world, uint8_
// increase that limit, we'll need to
// allocate another bit for the counter.
ct->reentrant_timing += 0b10;
+ JL_LOCK(&jl_typeinf_lock);
JL_TRY {
ci = (jl_code_instance_t*)jl_apply(fargs, 5);
}
@@ -481,6 +485,7 @@ jl_code_instance_t *jl_type_infer(jl_method_instance_t *mi, size_t world, uint8_
abort();
#endif
}
+ JL_UNLOCK(&jl_typeinf_lock);
ct->world_age = last_age;
ct->reentrant_timing -= 0b10;
ct->ptls->in_pure_callback = last_pure;
@@ -495,12 +500,11 @@ jl_code_instance_t *jl_type_infer(jl_method_instance_t *mi, size_t world, uint8_
// Record inference entrance backtrace if enabled
if (ci) {
- JL_GC_PUSH1(&ci);
jl_push_inference_entrance_backtraces((jl_value_t*)ci);
- JL_GC_POP();
}
JL_GC_POP();
+ JL_GC_POP();
#endif
return ci;
@@ -1841,7 +1845,7 @@ JL_DLLEXPORT jl_typemap_entry_t *jl_mt_find_cache_entry(jl_methcache_t *mc JL_PR
return entry;
}
-static jl_method_instance_t *jl_mt_assoc_by_type(jl_methcache_t *mc JL_PROPAGATES_ROOT, jl_datatype_t *tt JL_MAYBE_UNROOTED, size_t world)
+static jl_method_instance_t *jl_mt_assoc_by_type(jl_methtable_t *mt, jl_methcache_t *mc JL_PROPAGATES_ROOT, jl_datatype_t *tt JL_MAYBE_UNROOTED, size_t world)
{
jl_typemap_entry_t *entry = jl_mt_find_cache_entry(mc, tt, world);
if (entry)
@@ -1858,11 +1862,11 @@ static jl_method_instance_t *jl_mt_assoc_by_type(jl_methcache_t *mc JL_PROPAGATE
if (!mi) {
size_t min_valid = 0;
size_t max_valid = ~(size_t)0;
- matc = _gf_invoke_lookup((jl_value_t*)tt, jl_method_table, world, 0, &min_valid, &max_valid);
+ matc = _gf_invoke_lookup((jl_value_t*)tt, mt, world, 0, &min_valid, &max_valid);
if (matc) {
jl_method_t *m = matc->method;
jl_svec_t *env = matc->sparams;
- mi = cache_method(jl_method_table, mc, &mc->cache, (jl_value_t*)mc, tt, m, world, min_valid, max_valid, env);
+ mi = cache_method(mt, mc, &mc->cache, (jl_value_t*)mc, tt, m, world, min_valid, max_valid, env);
JL_GC_POP();
return mi;
}
@@ -3079,7 +3083,7 @@ JL_DLLEXPORT jl_value_t *jl_method_lookup_by_tt(jl_tupletype_t *tt, size_t world
mt = (jl_methtable_t*) _mt;
}
jl_methcache_t *mc = mt->cache;
- jl_method_instance_t *mi = jl_mt_assoc_by_type(mc, tt, world);
+ jl_method_instance_t *mi = jl_mt_assoc_by_type(mt, mc, tt, world);
if (!mi)
return jl_nothing;
return (jl_value_t*) mi;
@@ -3094,7 +3098,7 @@ JL_DLLEXPORT jl_method_instance_t *jl_method_lookup(jl_value_t **args, size_t na
if (entry)
return entry->func.linfo;
jl_tupletype_t *tt = arg_type_tuple(args[0], &args[1], nargs);
- return jl_mt_assoc_by_type(mc, tt, world);
+ return jl_mt_assoc_by_type(jl_method_table, mc, tt, world);
}
// return a Vector{Any} of svecs, each describing a method match:
@@ -3890,6 +3894,15 @@ JL_DLLEXPORT void jl_compile_method_sig(jl_method_t *m, jl_value_t *types, jl_sv
jl_compile_method_instance(mi, NULL, world);
}
+JL_DLLEXPORT int jl_is_compilable(jl_tupletype_t *types)
+{
+ size_t world = jl_atomic_load_acquire(&jl_world_counter);
+ size_t min_valid = 0;
+ size_t max_valid = ~(size_t)0;
+ jl_method_instance_t *mi = jl_get_compile_hint_specialization(types, world, &min_valid, &max_valid, 1);
+ return mi == NULL ? 0 : 1;
+}
+
JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types)
{
size_t world = jl_atomic_load_acquire(&jl_world_counter);
@@ -4169,7 +4182,7 @@ STATIC_INLINE jl_method_instance_t *jl_lookup_generic_(jl_value_t *F, jl_value_t
assert(tt);
// cache miss case
jl_methcache_t *mc = jl_method_table->cache;
- mfunc = jl_mt_assoc_by_type(mc, tt, world);
+ mfunc = jl_mt_assoc_by_type(jl_method_table, mc, tt, world);
if (jl_options.malloc_log)
jl_gc_sync_total_bytes(last_alloc); // discard allocation count from compilation
if (mfunc == NULL) {
diff --git a/src/init.c b/src/init.c
index e11b360b5d378..f9c5409a0fe99 100644
--- a/src/init.c
+++ b/src/init.c
@@ -552,6 +552,9 @@ extern jl_mutex_t precomp_statement_out_lock;
extern jl_mutex_t newly_inferred_mutex;
extern jl_mutex_t global_roots_lock;
extern jl_mutex_t profile_show_peek_cond_lock;
+extern jl_mutex_t jl_typeinf_lock;
+
+extern void jl_init_heartbeat(void);
static void restore_fp_env(void)
{
@@ -612,6 +615,11 @@ static NOINLINE void _finish_jl_init_(jl_image_buf_t sysimage, jl_ptls_t ptls, j
jl_start_gc_threads();
uv_barrier_wait(&thread_init_done);
+ if (jl_base_module != NULL) {
+ // requires code in Base
+ jl_init_heartbeat();
+ }
+
jl_gc_enable(1);
if ((sysimage.kind != JL_IMAGE_KIND_NONE) &&
@@ -661,6 +669,7 @@ static void init_global_mutexes(void) {
JL_MUTEX_INIT(&global_roots_lock, "global_roots_lock");
JL_MUTEX_INIT(&typecache_lock, "typecache_lock");
JL_MUTEX_INIT(&profile_show_peek_cond_lock, "profile_show_peek_cond_lock");
+ JL_MUTEX_INIT(&jl_typeinf_lock, "jl_typeinf_lock");
}
JL_DLLEXPORT void jl_init_(jl_image_buf_t sysimage)
@@ -750,6 +759,15 @@ JL_DLLEXPORT void jl_init_(jl_image_buf_t sysimage)
if (jl_options.handle_signals == JL_OPTIONS_HANDLE_SIGNALS_ON)
jl_install_default_signal_handlers();
+#if (defined(_OS_LINUX_) && defined(_CPU_X86_64_)) || (defined(_OS_DARWIN_) && defined(_CPU_AARCH64_))
+ if (jl_options.safe_crash_log_file != NULL) {
+ jl_sig_fd = open(jl_options.safe_crash_log_file, O_WRONLY | O_CREAT | O_APPEND, 0600);
+ if (jl_sig_fd == -1) {
+ jl_error("fatal error: could not open safe crash log file for writing");
+ }
+ }
+#endif
+
jl_gc_init();
arraylist_new(&jl_linkage_blobs, 0);
diff --git a/src/interpreter.c b/src/interpreter.c
index a692cadaf9be1..55f8ec9188b19 100644
--- a/src/interpreter.c
+++ b/src/interpreter.c
@@ -539,12 +539,12 @@ static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, size_t ip,
}
s->locals[jl_source_nslots(s->src) + ip] = jl_box_ulong(jl_excstack_state(ct));
if (jl_enternode_scope(stmt)) {
- jl_value_t *scope = eval_value(jl_enternode_scope(stmt), s);
- // GC preserve the scope, since it is not rooted in the `jl_handler_t *`
- // and may be removed from jl_current_task by any nested block and then
- // replaced later
- JL_GC_PUSH1(&scope);
- ct->scope = scope;
+ jl_value_t *old_scope = ct->scope; // Identical to __eh.scope
+ // GC preserve the old_scope, since it is not rooted in the `jl_handler_t *`,
+ // the newly entered scope is preserved through the current_task.
+ JL_GC_PUSH1(&old_scope);
+ ct->scope = eval_value(jl_enternode_scope(stmt), s);
+ jl_gc_wb_current_task(ct, ct->scope);
if (!jl_setjmp(__eh.eh_ctx, 0)) {
ct->eh = &__eh;
eval_body(stmts, s, next_ip, toplevel);
diff --git a/src/jitlayers.h b/src/jitlayers.h
index 070bf576ffd35..7975d4c4163a7 100644
--- a/src/jitlayers.h
+++ b/src/jitlayers.h
@@ -203,6 +203,7 @@ struct jl_returninfo_t {
size_t union_align;
size_t union_minalign;
unsigned return_roots;
+ bool all_roots;
};
struct jl_codegen_call_target_t {
diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc
index 61420c7306de9..aee7f0974359f 100644
--- a/src/jl_exported_funcs.inc
+++ b/src/jl_exported_funcs.inc
@@ -271,6 +271,7 @@
XX(jl_istopmod) \
XX(jl_is_binding_deprecated) \
XX(jl_is_char_signed) \
+ XX(jl_is_compilable) \
XX(jl_is_const) \
XX(jl_is_assertsbuild) \
XX(jl_is_debugbuild) \
@@ -523,8 +524,10 @@
YY(jl_get_LLVM_VERSION) \
YY(jl_dump_native) \
YY(jl_get_llvm_gvs) \
+ YY(jl_get_llvm_gvs_globals) \
YY(jl_get_llvm_external_fns) \
YY(jl_get_llvm_mis) \
+ YY(jl_get_llvm_cis) \
YY(jl_dump_function_asm) \
YY(jl_LLVMCreateDisasm) \
YY(jl_LLVMDisasmInstruction) \
@@ -542,6 +545,7 @@
YY(jl_dump_fptr_asm) \
YY(jl_emit_native) \
YY(jl_get_function_id) \
+ YY(jl_struct_to_llvm) \
YY(jl_type_to_llvm) \
YY(jl_getUnwindInfo) \
YY(jl_get_libllvm) \
diff --git a/src/jl_uv.c b/src/jl_uv.c
index a21b05433b8c6..5d8ba54c06c4e 100644
--- a/src/jl_uv.c
+++ b/src/jl_uv.c
@@ -15,6 +15,7 @@
#include "errno.h"
#include
#include
+#include
#endif
#include "julia.h"
@@ -813,6 +814,83 @@ JL_DLLEXPORT int jl_printf(uv_stream_t *s, const char *format, ...)
return c;
}
+STATIC_INLINE int copystp(char *dest, const char *src)
+{
+ char *d = stpcpy(dest, src);
+ return (int)(d - dest);
+}
+
+// RAI-specific
+STATIC_INLINE void write_to_safe_crash_log(char *buf) JL_NOTSAFEPOINT
+{
+ int buflen = strlen(buf);
+ // Our telemetry on SPCS expects a JSON object per line.
+ // We ignore write failures because there is nothing we can do.
+ // We'll use a 2K byte buffer: 69 bytes for JSON message decorations,
+ // 1 byte for the terminating NUL character, and 3 bytes for an
+ // ellipsis if we have to truncate the message leaves `max_b` bytes
+ // for the message.
+ const int wbuflen = 2048;
+ const int max_b = wbuflen - 70 - 3;
+ char wbuf[wbuflen];
+ bzero(wbuf, wbuflen);
+ int wlen = 0;
+
+ // JSON preamble (32 bytes)
+ wlen += copystp(&wbuf[wlen], "\n{\"level\":\"Error\", \"timestamp\":\"");
+
+ // Timestamp (19 bytes)
+ struct timeval tv;
+ struct tm* tm_info;
+ gettimeofday(&tv, NULL);
+ tm_info = gmtime(&tv.tv_sec);
+ wlen += strftime(&wbuf[wlen], 42, "%Y-%m-%dT%H:%M:%S", tm_info);
+ sprintf(&wbuf[wlen], ".%03ld", (long)tv.tv_usec / 1000);
+ wlen += 4;
+
+ // JSON preamble to message (15 bytes)
+ wlen += copystp(&wbuf[wlen], "\", \"message\": \"");
+
+ // Message
+ // Each iteration will advance wlen by 1 or 2
+ for (size_t i = 0; i < buflen; i++) {
+ // Truncate the message if the write buffer is full
+ if (wlen == max_b || wlen == max_b - 1) {
+ wlen += copystp(&wbuf[wlen], "...");
+ break;
+ }
+ switch (buf[i]) {
+ case '"':
+ wlen += copystp(&wbuf[wlen], "\\\"");
+ break;
+ case '\b':
+ wlen += copystp(&wbuf[wlen], "\\b");
+ break;
+ case '\n':
+ wlen += copystp(&wbuf[wlen], "\\n");
+ break;
+ case '\r':
+ wlen += copystp(&wbuf[wlen], "\\r");
+ break;
+ case '\t':
+ wlen += copystp(&wbuf[wlen], "\\t");
+ break;
+ case '\\':
+ wlen += copystp(&wbuf[wlen], "\\\\");
+ break;
+ default:
+ wbuf[wlen++] = buf[i];
+ break;
+ }
+ }
+ // JSON completion (3 bytes)
+ wlen += copystp(&wbuf[wlen], "\"}\n");
+ write(jl_sig_fd, wbuf, wlen);
+ fdatasync(jl_sig_fd);
+}
+
+extern int jl_inside_heartbeat_thread(void);
+
JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...)
{
static char buf[1000];
@@ -829,6 +907,12 @@ JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...)
va_end(args);
buf[999] = '\0';
+ // order is important here: we want to ensure that the threading infra
+ // has been initialized before we start trying to print to the
+ // safe crash log file
+ if (jl_sig_fd != 0 && (jl_inside_signal_handler() || jl_inside_heartbeat_thread())) {
+ write_to_safe_crash_log(buf);
+ }
if (write(STDERR_FILENO, buf, strlen(buf)) < 0) {
// nothing we can do; ignore the failure
}
diff --git a/src/jloptions.c b/src/jloptions.c
index 96cce1c8d29a3..e128045b5b5af 100644
--- a/src/jloptions.c
+++ b/src/jloptions.c
@@ -155,6 +155,7 @@ JL_DLLEXPORT void jl_init_options(void)
JL_TRIM_NO, // trim
0, // task_metrics
-1, // timeout_for_safepoint_straggler_s
+ NULL, // safe_crash_log_file
};
jl_options_initialized = 1;
}
@@ -384,6 +385,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
opt_permalloc_pkgimg,
opt_trim,
opt_experimental_features,
+ opt_safe_crash_log_file,
};
static const char* const shortopts = "+vhqH:e:E:L:J:C:it:p:O:g:m:";
static const struct option longopts[] = {
@@ -452,6 +454,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
{ "permalloc-pkgimg",required_argument, 0, opt_permalloc_pkgimg },
{ "heap-size-hint", required_argument, 0, opt_heap_size_hint },
{ "trim", optional_argument, 0, opt_trim },
+ { "safe-crash-log-file", required_argument, 0, opt_safe_crash_log_file },
{ 0, 0, 0, 0 }
};
@@ -668,9 +671,11 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
}
jl_options.nthreads = nthreads + nthreadsi;
}
+ assert(jl_options.nthreadpools == 1 || jl_options.nthreadpools == 2);
int16_t *ntpp = (int16_t *)malloc_s(jl_options.nthreadpools * sizeof(int16_t));
ntpp[0] = (int16_t)nthreads;
- ntpp[1] = (int16_t)nthreadsi;
+ if (jl_options.nthreadpools == 2)
+ ntpp[1] = (int16_t)nthreadsi;
jl_options.nthreads_per_pool = ntpp;
break;
case 'p': // procs
@@ -1011,6 +1016,10 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
jl_options.task_metrics = JL_OPTIONS_TASK_METRICS_ON;
else
jl_errorf("julia: invalid argument to --task-metrics={yes|no} (%s)", optarg);
+ case opt_safe_crash_log_file:
+ jl_options.safe_crash_log_file = strdup(optarg);
+ if (jl_options.safe_crash_log_file == NULL)
+ jl_error("julia: failed to allocate memory for --safe-crash-log-file");
break;
default:
jl_errorf("julia: unhandled option -- %c\n"
diff --git a/src/jloptions.h b/src/jloptions.h
index 06e00e9309dba..f5c8f72a2cb6c 100644
--- a/src/jloptions.h
+++ b/src/jloptions.h
@@ -68,6 +68,7 @@ typedef struct {
int8_t trim;
int8_t task_metrics;
int16_t timeout_for_safepoint_straggler_s;
+ const char *safe_crash_log_file;
} jl_options_t;
#endif
diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm
index aad8105b34308..07668878a20e1 100644
--- a/src/julia-syntax.scm
+++ b/src/julia-syntax.scm
@@ -1790,11 +1790,13 @@
(cons e '())
(let ((a '()))
(define (arg-to-temp x)
- (cond ((effect-free? x) x)
- ((or (eq? (car x) '...) (eq? (car x) '&))
- `(,(car x) ,(arg-to-temp (cadr x))))
+ (cond ((effect-free? x) x)
+ ((eq? (car x) '...)
+ `(... ,(arg-to-temp (cadr x))))
((eq? (car x) 'kw)
- `(,(car x) ,(cadr x) ,(arg-to-temp (caddr x))))
+ `(kw ,(cadr x) ,(arg-to-temp (caddr x))))
+ ((eq? (car x) 'parameters)
+ `(parameters ,@(map arg-to-temp (cdr x))))
(else
(let ((g (make-ssavalue)))
(begin (set! a (cons `(= ,g ,x) a))
diff --git a/src/julia_internal.h b/src/julia_internal.h
index c9e1b0e204df6..a8172c3e8c1c1 100644
--- a/src/julia_internal.h
+++ b/src/julia_internal.h
@@ -230,6 +230,7 @@ extern volatile size_t profile_bt_size_max;
extern volatile size_t profile_bt_size_cur;
extern volatile int profile_running;
extern volatile int profile_all_tasks;
+extern int heartbeat_tid; // Mostly used to ensure we skip this thread in the CPU profiler. XXX: not implemented on Windows
// Ensures that we can safely read the `live_tasks`field of every TLS when profiling.
// We want to avoid the case that a GC gets interleaved with `jl_profile_task` and shrinks
// the `live_tasks` array while we are reading it or frees tasks that are being profiled.
@@ -245,6 +246,7 @@ extern uv_mutex_t bt_data_prof_lock;
#define PROFILE_STATE_THREAD_NOT_SLEEPING (1)
#define PROFILE_STATE_THREAD_SLEEPING (2)
#define PROFILE_STATE_WALL_TIME_PROFILING (3)
+extern _Atomic(int) n_threads_running;
void jl_profile_task(void);
// number of cycles since power-on
@@ -780,6 +782,32 @@ JL_CALLABLE(jl_f_tuple);
void jl_install_default_signal_handlers(void);
void restore_signals(void);
void jl_install_thread_signal_handler(jl_ptls_t ptls);
+extern const size_t sig_stack_size;
+STATIC_INLINE int is_addr_on_sigstack(jl_ptls_t ptls, void *ptr)
+{
+ // One guard page for signal_stack.
+ return !((char*)ptr < (char*)ptls->signal_stack - jl_page_size ||
+ (char*)ptr > (char*)ptls->signal_stack + sig_stack_size);
+}
+STATIC_INLINE int jl_inside_signal_handler(void)
+{
+#if (defined(_OS_LINUX_) && defined(_CPU_X86_64_)) || (defined(_OS_DARWIN_) && defined(_CPU_AARCH64_))
+ // Read the stack pointer
+ size_t sp;
+#if defined(_OS_LINUX_) && defined(_CPU_X86_64_)
+ __asm__ __volatile__("movq %%rsp, %0" : "=r"(sp));
+#elif defined(_OS_DARWIN_) && defined(_CPU_AARCH64_)
+ __asm__ __volatile__("mov %0, sp" : "=r"(sp));
+#endif
+ // Check if the stack pointer is within the signal stack
+ jl_ptls_t ptls = jl_current_task->ptls;
+ return is_addr_on_sigstack(ptls, (void*)sp);
+#else
+ return 0;
+#endif
+}
+// File-descriptor for safe logging on signal handling
+extern int jl_sig_fd;
extern uv_loop_t *jl_io_loop;
JL_DLLEXPORT void jl_uv_flush(uv_stream_t *stream);
@@ -1499,9 +1527,9 @@ JL_DLLEXPORT jl_value_t *jl_backtrace_from_here(int returnsp, int skip);
void jl_critical_error(int sig, int si_code, bt_context_t *context, jl_task_t *ct);
JL_DLLEXPORT void jl_raise_debugger(void) JL_NOTSAFEPOINT;
JL_DLLEXPORT void jl_gdblookup(void* ip) JL_NOTSAFEPOINT;
-void jl_print_native_codeloc(uintptr_t ip) JL_NOTSAFEPOINT;
-void jl_print_bt_entry_codeloc(jl_bt_element_t *bt_data) JL_NOTSAFEPOINT;
-JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT;
+void jl_print_native_codeloc(char *pre_str, uintptr_t ip) JL_NOTSAFEPOINT;
+void jl_print_bt_entry_codeloc(int sig, jl_bt_element_t *bt_data) JL_NOTSAFEPOINT;
+JL_DLLEXPORT void jl_print_task_backtraces(int show_done)JL_NOTSAFEPOINT ;
#ifdef _OS_WINDOWS_
JL_DLLEXPORT void jl_refresh_dbg_module_list(void);
#endif
@@ -2057,6 +2085,7 @@ JL_DLLIMPORT void jl_dump_native(void *native_code,
const char *bc_fname, const char *unopt_bc_fname, const char *obj_fname, const char *asm_fname,
ios_t *z, ios_t *s, jl_emission_params_t *params);
JL_DLLIMPORT void jl_get_llvm_gvs(void *native_code, size_t *num_els, void **gvs);
+JL_DLLIMPORT void jl_get_llvm_gvs_globals(void *native_code, size_t *num_els, void **gvs);
JL_DLLIMPORT void jl_get_llvm_external_fns(void *native_code, size_t *num_els,
jl_code_instance_t *gvs);
JL_DLLIMPORT void jl_get_function_id(void *native_code, jl_code_instance_t *ncode,
@@ -2064,7 +2093,8 @@ JL_DLLIMPORT void jl_get_function_id(void *native_code, jl_code_instance_t *ncod
JL_DLLIMPORT void jl_register_fptrs(uint64_t image_base, const struct _jl_image_fptrs_t *fptrs,
jl_method_instance_t **linfos, size_t n);
JL_DLLIMPORT void jl_get_llvm_mis(void *native_code, size_t *num_els,
- jl_method_instance_t *MIs);
+ jl_method_instance_t **MIs);
+JL_DLLIMPORT void jl_get_llvm_cis(void *native_code, size_t *num_els, jl_code_instance_t **data);
JL_DLLIMPORT void jl_init_codegen(void);
JL_DLLIMPORT void jl_teardown_codegen(void) JL_NOTSAFEPOINT;
JL_DLLIMPORT int jl_getFunctionInfo(jl_frame_t **frames, uintptr_t pointer, int skipC, int noInline) JL_NOTSAFEPOINT;
diff --git a/src/llvm-alloc-opt.cpp b/src/llvm-alloc-opt.cpp
index ce1d22f42d0ae..97e881296d1be 100644
--- a/src/llvm-alloc-opt.cpp
+++ b/src/llvm-alloc-opt.cpp
@@ -662,11 +662,8 @@ void Optimizer::moveToStack(CallInst *orig_inst, size_t sz, bool has_ref, AllocF
// The allocation does not escape or get used in a phi node so none of the derived
// SSA from it are live when we run the allocation again.
// It is now safe to promote the allocation to an entry block alloca.
- size_t align = 1;
- // TODO: This is overly conservative. May want to instead pass this as a
- // parameter to the allocation function directly.
- if (sz > 1)
- align = MinAlign(JL_SMALL_BYTE_ALIGNMENT, NextPowerOf2(sz));
+ // Inherit alignment from the original allocation, with GC alignment as minimum.
+ Align align(std::max((unsigned)orig_inst->getRetAlign().valueOrOne().value(), (unsigned)JL_SMALL_BYTE_ALIGNMENT));
// No debug info for prolog instructions
IRBuilder<> prolog_builder(&F.getEntryBlock().front());
AllocaInst *buff;
@@ -682,17 +679,21 @@ void Optimizer::moveToStack(CallInst *orig_inst, size_t sz, bool has_ref, AllocF
const DataLayout &DL = F.getParent()->getDataLayout();
auto asize = ConstantInt::get(Type::getInt64Ty(prolog_builder.getContext()), sz / DL.getTypeAllocSize(pass.T_prjlvalue));
buff = prolog_builder.CreateAlloca(pass.T_prjlvalue, asize);
- buff->setAlignment(Align(align));
+ buff->setAlignment(align);
ptr = cast(buff);
}
else {
+ // Use alignment-sized chunks so SROA splits the alloca into aligned pieces
+ // which is better for performance and vectorization (see emit_static_alloca).
+ // Cap element size at 64 bits since not all backends support larger integers.
Type *buffty;
- if (pass.DL->isLegalInteger(sz * 8))
- buffty = Type::getIntNTy(pass.getLLVMContext(), sz * 8);
+ unsigned elsize = std::min(align.value(), (uint64_t)8);
+ if (alignTo(sz, elsize) == elsize)
+ buffty = Type::getIntNTy(pass.getLLVMContext(), elsize * 8);
else
- buffty = ArrayType::get(Type::getInt8Ty(pass.getLLVMContext()), sz);
+ buffty = ArrayType::get(Type::getIntNTy(pass.getLLVMContext(), elsize * 8), alignTo(sz, elsize) / elsize);
buff = prolog_builder.CreateAlloca(buffty);
- buff->setAlignment(Align(align));
+ buff->setAlignment(align);
ptr = cast(buff);
}
insertLifetime(ptr, ConstantInt::get(Type::getInt64Ty(prolog_builder.getContext()), sz), orig_inst);
@@ -701,6 +702,7 @@ void Optimizer::moveToStack(CallInst *orig_inst, size_t sz, bool has_ref, AllocF
initializeAlloca(builder, buff, allockind);
}
Instruction *new_inst = cast(ptr);
+ new_inst->copyMetadata(*orig_inst);
new_inst->takeName(orig_inst);
auto simple_replace = [&] (Instruction *orig_i, Instruction *new_i) {
@@ -958,6 +960,8 @@ void Optimizer::splitOnStack(CallInst *orig_inst)
uint32_t size;
};
SmallVector slots;
+ // Inherit alignment from the original allocation, with GC alignment as minimum.
+ Align align(std::max((unsigned)orig_inst->getRetAlign().valueOrOne().value(), (unsigned)JL_SMALL_BYTE_ALIGNMENT));
for (auto memop: use_info.memops) {
auto offset = memop.first;
auto &field = memop.second;
@@ -973,12 +977,18 @@ void Optimizer::splitOnStack(CallInst *orig_inst)
else if (field.elty && !field.multiloc) {
allocty = field.elty;
}
- else if (pass.DL->isLegalInteger(field.size * 8)) {
- allocty = Type::getIntNTy(pass.getLLVMContext(), field.size * 8);
- } else {
- allocty = ArrayType::get(Type::getInt8Ty(pass.getLLVMContext()), field.size);
+ else {
+ // Use alignment-sized chunks so SROA splits the alloca into aligned pieces
+ // which is better for performance and vectorization (see emit_static_alloca).
+ // Cap element size at 64 bits since not all backends support larger integers.
+ unsigned elsize = std::min(align.value(), (uint64_t)8);
+ if (alignTo(field.size, elsize) == elsize)
+ allocty = Type::getIntNTy(pass.getLLVMContext(), elsize * 8);
+ else
+ allocty = ArrayType::get(Type::getIntNTy(pass.getLLVMContext(), elsize * 8), alignTo(field.size, elsize) / elsize);
}
slot.slot = prolog_builder.CreateAlloca(allocty);
+ slot.slot->setAlignment(align);
IRBuilder<> builder(orig_inst);
insertLifetime(slot.slot, ConstantInt::get(Type::getInt64Ty(prolog_builder.getContext()), field.size), orig_inst);
initializeAlloca(builder, slot.slot, use_info.allockind);
diff --git a/src/llvm-late-gc-lowering.cpp b/src/llvm-late-gc-lowering.cpp
index 1d262ff7968b0..b5ad4358626dc 100644
--- a/src/llvm-late-gc-lowering.cpp
+++ b/src/llvm-late-gc-lowering.cpp
@@ -1208,6 +1208,13 @@ State LateLowerGCFrame::LocalScan(Function &F) {
auto tracked = CountTrackedPointers(ElT, true);
if (tracked.count) {
AllocaInst *SRet = dyn_cast((CI->arg_begin()[0])->stripInBoundsOffsets());
+ if (!SRet) {
+ llvm::errs() << "LLVMLateGCLowering: Expected AllocaInst, found" << *(CI->arg_begin()[0])->stripInBoundsOffsets() << "\n";
+ llvm::errs() << " + CI: " << *CI << "\n";
+ llvm::errs() << " + scope: " << *CI->getFunction() << "\n";
+ llvm::errs() << " + callee: " << *CI->getCalledOperand() << "\n";
+ llvm_unreachable("LLVMLateGCLowering: Expected AllocaInst");
+ }
assert(SRet);
{
if (!(SRet->isStaticAlloca() && isa(ElT) && ElT->getPointerAddressSpace() == AddressSpace::Tracked)) {
diff --git a/src/module.c b/src/module.c
index 60d2652ddfaaa..546a8d3e60fb8 100644
--- a/src/module.c
+++ b/src/module.c
@@ -104,7 +104,6 @@ static void update_implicit_resolution(struct implicit_search_resolution *to_upd
return;
}
if (to_update->ultimate_kind == PARTITION_KIND_GUARD) {
- assert(resolution.binding_or_const);
to_update->ultimate_kind = resolution.ultimate_kind;
to_update->binding_or_const = resolution.binding_or_const;
to_update->debug_only_import_from = resolution.debug_only_import_from;
@@ -310,6 +309,10 @@ struct implicit_search_resolution jl_resolve_implicit_import(jl_binding_t *b, mo
imp_resolution.binding_or_const = tempbpart->restriction;
imp_resolution.debug_only_ultimate_binding = tempb;
imp_resolution.ultimate_kind = PARTITION_KIND_IMPLICIT_CONST;
+ } else if (kind == PARTITION_KIND_FAILED) {
+ imp_resolution.binding_or_const = NULL;
+ imp_resolution.debug_only_ultimate_binding = tempb;
+ imp_resolution.ultimate_kind = PARTITION_KIND_FAILED;
}
}
imp_resolution.debug_only_import_from = imp;
diff --git a/src/options.h b/src/options.h
index 0715069faab32..fb2797ffd0336 100644
--- a/src/options.h
+++ b/src/options.h
@@ -144,6 +144,9 @@
#define MACHINE_EXCLUSIVE_NAME "JULIA_EXCLUSIVE"
#define DEFAULT_MACHINE_EXCLUSIVE 0
+// heartbeats
+#define JL_HEARTBEAT_THREAD
+
// sanitizer defaults ---------------------------------------------------------
// Automatically enable MEMDEBUG and KEEP_BODIES for the sanitizers
diff --git a/src/rtutils.c b/src/rtutils.c
index 6d4a375017bf2..77ce3c0d4adb0 100644
--- a/src/rtutils.c
+++ b/src/rtutils.c
@@ -296,6 +296,7 @@ JL_DLLEXPORT void jl_eh_restore_state(jl_task_t *ct, jl_handler_t *eh)
ct->eh = eh->prev;
ct->gcstack = eh->gcstack;
ct->scope = eh->scope;
+ jl_gc_wb_current_task(ct, ct->scope);
small_arraylist_t *locks = &ptls->locks;
int unlocks = locks->len > eh->locks_len;
if (unlocks) {
@@ -335,6 +336,7 @@ JL_DLLEXPORT void jl_eh_restore_state_noexcept(jl_task_t *ct, jl_handler_t *eh)
{
assert(ct->gcstack == eh->gcstack && "Incorrect GC usage under try catch");
ct->scope = eh->scope;
+ jl_gc_wb_current_task(ct, ct->scope);
ct->eh = eh->prev;
ct->ptls->defer_signal = eh->defer_signal; // optional, but certain try-finally (in stream.jl) may be slightly harder to write without this
}
diff --git a/src/safepoint.c b/src/safepoint.c
index 970c48875d790..96da3c1a05eb1 100644
--- a/src/safepoint.c
+++ b/src/safepoint.c
@@ -172,7 +172,7 @@ void jl_gc_wait_for_the_world(jl_ptls_t* gc_all_tls_states, int gc_n_threads)
size_t bt_size = jl_try_record_thread_backtrace(ptls2, ptls->bt_data, JL_MAX_BT_SIZE);
// Print the backtrace of the straggler
for (size_t i = 0; i < bt_size; i += jl_bt_entry_size(ptls->bt_data + i)) {
- jl_print_bt_entry_codeloc(ptls->bt_data + i);
+ jl_print_bt_entry_codeloc(-1, ptls->bt_data + i);
}
}
}
diff --git a/src/signal-handling.c b/src/signal-handling.c
index b03f0c1a430cd..269885bb5c14c 100644
--- a/src/signal-handling.c
+++ b/src/signal-handling.c
@@ -30,6 +30,8 @@ static const uint64_t GIGA = 1000000000ULL;
// Timers to take samples at intervals
JL_DLLEXPORT void jl_profile_stop_timer(void);
JL_DLLEXPORT int jl_profile_start_timer(uint8_t);
+// File-descriptor for safe logging on signal handling
+int jl_sig_fd;
///////////////////////
// Utility functions //
@@ -647,7 +649,7 @@ void jl_critical_error(int sig, int si_code, bt_context_t *context, jl_task_t *c
*bt_size = n = rec_backtrace_ctx(bt_data, JL_MAX_BT_SIZE, context, NULL);
}
for (i = 0; i < n; i += jl_bt_entry_size(bt_data + i)) {
- jl_print_bt_entry_codeloc(bt_data + i);
+ jl_print_bt_entry_codeloc(sig, bt_data + i);
}
jl_gc_debug_print_status();
jl_gc_debug_critical_error();
diff --git a/src/signals-mach.c b/src/signals-mach.c
index 4a670547bdfcd..12d545ee81ce6 100644
--- a/src/signals-mach.c
+++ b/src/signals-mach.c
@@ -824,6 +824,10 @@ void *mach_profile_listener(void *arg)
for (int idx = nthreads; idx-- > 0; ) {
// Stop the threads in random order.
int i = randperm[idx];
+ // skip heartbeat thread
+ if (i == heartbeat_tid) {
+ continue;
+ }
jl_profile_thread_mach(i);
}
}
diff --git a/src/signals-unix.c b/src/signals-unix.c
index 2db397050420e..ed186d5b357cd 100644
--- a/src/signals-unix.c
+++ b/src/signals-unix.c
@@ -42,7 +42,7 @@
#endif
// 8M signal stack, same as default stack size (though we barely use this)
-static const size_t sig_stack_size = 8 * 1024 * 1024;
+const size_t sig_stack_size = 8 * 1024 * 1024;
#include "julia_assert.h"
@@ -102,14 +102,6 @@ static inline uintptr_t jl_get_rsp_from_ctx(const void *_ctx)
#endif
}
-static int is_addr_on_sigstack(jl_ptls_t ptls, void *ptr) JL_NOTSAFEPOINT
-{
- // One guard page for signal_stack.
- return ptls->signal_stack == NULL ||
- ((char*)ptr >= (char*)ptls->signal_stack - jl_page_size &&
- (char*)ptr <= (char*)ptls->signal_stack + (ptls->signal_stack_size ? ptls->signal_stack_size : sig_stack_size));
-}
-
// Modify signal context `_ctx` so that `fptr` will execute when the signal returns
// The function `fptr` itself must not return.
JL_NO_ASAN static void jl_call_in_ctx(jl_ptls_t ptls, void (*fptr)(void), int sig, void *_ctx)
@@ -873,6 +865,10 @@ static void do_profile(void *ctx)
for (int idx = nthreads; idx-- > 0; ) {
// Stop the threads in the random order.
int tid = randperm[idx];
+ // skip heartbeat thread
+ if (tid == heartbeat_tid) {
+ return;
+ }
// do backtrace for profiler
if (!profile_running)
return;
@@ -1111,7 +1107,7 @@ static void *signal_listener(void *arg)
jl_safe_printf("\nsignal (%d): %s\n", sig, strsignal(sig));
size_t i;
for (i = 0; i < signal_bt_size; i += jl_bt_entry_size(signal_bt_data + i)) {
- jl_print_bt_entry_codeloc(signal_bt_data + i);
+ jl_print_bt_entry_codeloc(sig, signal_bt_data + i);
}
}
}
diff --git a/src/signals-win.c b/src/signals-win.c
index c8ae74f52dba4..d9c7ffd5ae769 100644
--- a/src/signals-win.c
+++ b/src/signals-win.c
@@ -4,7 +4,7 @@
// Note that this file is `#include`d by "signal-handling.c"
#include // hidden by LEAN_AND_MEAN
-static const size_t sig_stack_size = 131072; // 128k reserved for backtrace_fiber for stack overflow handling
+const size_t sig_stack_size = 131072; // 128k reserved for backtrace_fiber for stack overflow handling
// Copied from MINGW_FLOAT_H which may not be found due to a collision with the builtin gcc float.h
// eventually we can probably integrate this into OpenLibm.
@@ -333,7 +333,7 @@ LONG WINAPI jl_exception_handler(struct _EXCEPTION_POINTERS *ExceptionInfo)
jl_safe_printf("UNKNOWN"); break;
}
jl_safe_printf(" at 0x%zx -- ", (size_t)ExceptionInfo->ExceptionRecord->ExceptionAddress);
- jl_print_native_codeloc((uintptr_t)ExceptionInfo->ExceptionRecord->ExceptionAddress);
+ jl_print_native_codeloc("", (uintptr_t)ExceptionInfo->ExceptionRecord->ExceptionAddress);
jl_critical_error(0, 0, ExceptionInfo->ContextRecord, ct);
static int recursion = 0;
diff --git a/src/stackwalk.c b/src/stackwalk.c
index 50566b46ff45a..b04142f7cf845 100644
--- a/src/stackwalk.c
+++ b/src/stackwalk.c
@@ -637,22 +637,25 @@ JL_DLLEXPORT jl_value_t *jl_lookup_code_address(void *ip, int skipC)
return rs;
}
-static void jl_safe_print_codeloc(const char* func_name, const char* file_name,
+static void jl_safe_print_codeloc(const char *pre_str,
+ const char* func_name, const char* file_name,
int line, int inlined) JL_NOTSAFEPOINT
{
const char *inlined_str = inlined ? " [inlined]" : "";
if (line != -1) {
- jl_safe_printf("%s at %s:%d%s\n", func_name, file_name, line, inlined_str);
+ jl_safe_printf("%s%s at %s:%d%s\n",
+ pre_str, func_name, file_name, line, inlined_str);
}
else {
- jl_safe_printf("%s at %s (unknown line)%s\n", func_name, file_name, inlined_str);
+ jl_safe_printf("%s%s at %s (unknown line)%s\n",
+ pre_str, func_name, file_name, inlined_str);
}
}
// Print function, file and line containing native instruction pointer `ip` by
// looking up debug info. Prints multiple such frames when `ip` points to
// inlined code.
-void jl_print_native_codeloc(uintptr_t ip) JL_NOTSAFEPOINT
+void jl_print_native_codeloc(char *pre_str, uintptr_t ip) JL_NOTSAFEPOINT
{
// This function is not allowed to reference any TLS variables since
// it can be called from an unmanaged thread on OSX.
@@ -664,10 +667,11 @@ void jl_print_native_codeloc(uintptr_t ip) JL_NOTSAFEPOINT
for (i = 0; i < n; i++) {
jl_frame_t frame = frames[i];
if (!frame.func_name) {
- jl_safe_printf("unknown function (ip: %p) at %s\n", (void*)ip, frame.file_name ? frame.file_name : "(unknown file)");
+ jl_safe_printf("%sunknown function (ip: %p) at %s\n", pre_str, (void*)ip, frame.file_name ? frame.file_name : "(unknown file)");
}
else {
- jl_safe_print_codeloc(frame.func_name, frame.file_name, frame.line, frame.inlined);
+ jl_safe_print_codeloc(pre_str, frame.func_name,
+ frame.file_name, frame.line, frame.inlined);
free(frame.func_name);
}
free(frame.file_name);
@@ -725,7 +729,7 @@ const char *jl_debuginfo_name(jl_value_t *func)
// func == module : top-level
// func == NULL : macro expansion
-static void jl_print_debugloc(jl_debuginfo_t *debuginfo, jl_value_t *func, size_t ip, int inlined) JL_NOTSAFEPOINT
+static void jl_print_debugloc(const char *pre_str, jl_debuginfo_t *debuginfo, jl_value_t *func, size_t ip, int inlined) JL_NOTSAFEPOINT
{
if (!jl_is_symbol(debuginfo->def)) // this is a path or
func = debuginfo->def; // this is inlined code
@@ -734,26 +738,36 @@ static void jl_print_debugloc(jl_debuginfo_t *debuginfo, jl_value_t *func, size_
if (edges_idx) {
jl_debuginfo_t *edge = (jl_debuginfo_t*)jl_svecref(debuginfo->edges, edges_idx - 1);
assert(jl_typetagis(edge, jl_debuginfo_type));
- jl_print_debugloc(edge, NULL, stmt.pc, 1);
+ jl_print_debugloc(pre_str, edge, NULL, stmt.pc, 1);
}
intptr_t ip2 = stmt.line;
if (ip2 >= 0 && ip > 0 && (jl_value_t*)debuginfo->linetable != jl_nothing) {
- jl_print_debugloc(debuginfo->linetable, func, ip2, 0);
+ jl_print_debugloc(pre_str, debuginfo->linetable, func, ip2, 0);
}
else {
if (ip2 < 0) // set broken debug info to ignored
ip2 = 0;
const char *func_name = jl_debuginfo_name(func);
const char *file = jl_debuginfo_file(debuginfo);
- jl_safe_print_codeloc(func_name, file, ip2, inlined);
+ jl_safe_print_codeloc(pre_str, func_name, file, ip2, inlined);
}
}
// Print code location for backtrace buffer entry at *bt_entry
-void jl_print_bt_entry_codeloc(jl_bt_element_t *bt_entry) JL_NOTSAFEPOINT
+void jl_print_bt_entry_codeloc(int sig, jl_bt_element_t *bt_entry) JL_NOTSAFEPOINT
{
+ char sig_str[32], pre_str[64];
+ sig_str[0] = pre_str[0] = '\0';
+ if (sig != -1) {
+ snprintf(sig_str, 32, "signal (%d) ", sig);
+ }
+ // do not call jl_threadid if there's no current task
+ if (jl_get_current_task()) {
+ snprintf(pre_str, 64, "%sthread (%d) ", sig_str, jl_threadid() + 1);
+ }
+
if (jl_bt_is_native(bt_entry)) {
- jl_print_native_codeloc(bt_entry[0].uintptr);
+ jl_print_native_codeloc(pre_str, bt_entry[0].uintptr);
}
else if (jl_bt_entry_tag(bt_entry) == JL_BT_INTERP_FRAME_TAG) {
size_t ip = jl_bt_entry_header(bt_entry); // zero-indexed
@@ -772,7 +786,7 @@ void jl_print_bt_entry_codeloc(jl_bt_element_t *bt_entry) JL_NOTSAFEPOINT
if (jl_is_code_info(code)) {
jl_code_info_t *src = (jl_code_info_t*)code;
// See also the debug info handling in codegen.cpp.
- jl_print_debugloc(src->debuginfo, def, ip + 1, 0);
+ jl_print_debugloc(pre_str, src->debuginfo, def, ip + 1, 0);
}
else {
// If we're using this function something bad has already happened;
@@ -1361,7 +1375,13 @@ JL_DLLEXPORT jl_record_backtrace_result_t jl_record_backtrace(jl_task_t *t, jl_b
JL_DLLEXPORT void jl_gdblookup(void* ip)
{
- jl_print_native_codeloc((uintptr_t)ip);
+ char pre_str[64];
+ pre_str[0] = '\0';
+ // do not call jl_threadid if there's no current task
+ if (jl_get_current_task()) {
+ snprintf(pre_str, 64, "thread (%d) ", jl_threadid() + 1);
+ }
+ jl_print_native_codeloc(pre_str, (uintptr_t)ip);
}
// Print backtrace for current exception in catch block
@@ -1376,7 +1396,7 @@ JL_DLLEXPORT void jlbacktrace(void) JL_NOTSAFEPOINT
size_t i, bt_size = jl_excstack_bt_size(s, s->top);
jl_bt_element_t *bt_data = jl_excstack_bt_data(s, s->top);
for (i = 0; i < bt_size; i += jl_bt_entry_size(bt_data + i)) {
- jl_print_bt_entry_codeloc(bt_data + i);
+ jl_print_bt_entry_codeloc(-1, bt_data + i);
}
}
@@ -1399,7 +1419,7 @@ JL_DLLEXPORT void jlbacktracet(jl_task_t *t) JL_NOTSAFEPOINT
size_t bt_size = r.bt_size;
size_t i;
for (i = 0; i < bt_size; i += jl_bt_entry_size(bt_data + i)) {
- jl_print_bt_entry_codeloc(bt_data + i);
+ jl_print_bt_entry_codeloc(-1, bt_data + i);
}
if (bt_size == 0)
jl_safe_printf(" no backtrace recorded\n");
@@ -1410,11 +1430,30 @@ JL_DLLEXPORT void jl_print_backtrace(void) JL_NOTSAFEPOINT
jlbacktrace();
}
-// Print backtraces for all live tasks, for all threads, to jl_safe_printf stderr
+extern int jl_inside_heartbeat_thread(void);
+extern int jl_heartbeat_pause(void);
+extern int jl_heartbeat_resume(void);
+
+// Print backtraces for all live tasks, for all threads, to jl_safe_printf
+// stderr. This can take a _long_ time!
JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT
{
+ // disable heartbeats to prevent heartbeat loss while running this,
+ // unless this is called from the heartbeat thread itself; in that
+ // situation, the thread is busy running this and it will not be
+ // updating the missed heartbeats counter
+ if (!jl_inside_heartbeat_thread()) {
+ jl_heartbeat_pause();
+ }
+
size_t nthreads = jl_atomic_load_acquire(&jl_n_threads);
jl_ptls_t *allstates = jl_atomic_load_relaxed(&jl_all_tls_states);
+ int ctid = -1;
+ // do not call jl_threadid if there's no current task
+ if (jl_get_current_task()) {
+ ctid = jl_threadid() + 1;
+ }
+ jl_safe_printf("thread (%d) ++++ Task backtraces\n", ctid);
for (size_t i = 0; i < nthreads; i++) {
jl_ptls_t ptls2 = allstates[i];
if (gc_is_collector_thread(i)) {
@@ -1430,17 +1469,22 @@ JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT
jl_task_t *t = ptls2->root_task;
if (t != NULL)
t_state = jl_atomic_load_relaxed(&t->_state);
- jl_safe_printf("==== Thread %d created %zu live tasks\n",
- ptls2->tid + 1, n + (t_state != JL_TASK_STATE_DONE));
+ jl_safe_printf("thread (%d) ==== Thread %d created %zu live tasks\n",
+ ctid, ptls2->tid + 1, n + (t_state != JL_TASK_STATE_DONE));
if (show_done || t_state != JL_TASK_STATE_DONE) {
- jl_safe_printf(" ---- Root task (%p)\n", ptls2->root_task);
+ jl_safe_printf("thread (%d) ---- Root task (%p)\n", ctid, ptls2->root_task);
if (t != NULL) {
- jl_safe_printf(" (sticky: %d, started: %d, state: %d, tid: %d)\n",
- t->sticky, t->ctx.started, t_state,
+ jl_safe_printf("thread (%d) (sticky: %d, started: %d, state: %d, tid: %d)\n",
+ ctid, t->sticky, t->ctx.started, t_state,
jl_atomic_load_relaxed(&t->tid) + 1);
- jlbacktracet(t);
+ if (t->ctx.stkbuf != NULL) {
+ jlbacktracet(t);
+ }
+ else {
+ jl_safe_printf("thread (%d) no stack\n", ctid);
+ }
}
- jl_safe_printf(" ---- End root task\n");
+ jl_safe_printf("thread (%d) ---- End root task\n", ctid);
}
for (size_t j = 0; j < n; j++) {
@@ -1450,17 +1494,24 @@ JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT
int t_state = jl_atomic_load_relaxed(&t->_state);
if (!show_done && t_state == JL_TASK_STATE_DONE)
continue;
- jl_safe_printf(" ---- Task %zu (%p)\n", j + 1, t);
+ jl_safe_printf("thread (%d) ---- Task %zu (%p)\n", ctid, j + 1, t);
// n.b. this information might not be consistent with the stack printing after it, since it could start running or change tid, etc.
- jl_safe_printf(" (sticky: %d, started: %d, state: %d, tid: %d)\n",
- t->sticky, t->ctx.started, t_state,
+ jl_safe_printf("thread (%d) (sticky: %d, started: %d, state: %d, tid: %d)\n",
+ ctid, t->sticky, t->ctx.started, t_state,
jl_atomic_load_relaxed(&t->tid) + 1);
- jlbacktracet(t);
- jl_safe_printf(" ---- End task %zu\n", j + 1);
+ if (t->ctx.stkbuf != NULL)
+ jlbacktracet(t);
+ else
+ jl_safe_printf("thread (%d) no stack\n", ctid);
+ jl_safe_printf("thread (%d) ---- End task %zu\n", ctid, j + 1);
}
- jl_safe_printf("==== End thread %d\n", ptls2->tid + 1);
+ jl_safe_printf("thread (%d) ==== End thread %d\n", ctid, ptls2->tid + 1);
+ }
+ jl_safe_printf("thread (%d) ++++ Done\n", ctid);
+
+ if (!jl_inside_heartbeat_thread()) {
+ jl_heartbeat_resume();
}
- jl_safe_printf("==== Done\n");
}
#ifdef __cplusplus
diff --git a/src/staticdata.c b/src/staticdata.c
index 466bb349fa4e1..20a265550b612 100644
--- a/src/staticdata.c
+++ b/src/staticdata.c
@@ -3108,7 +3108,7 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array,
size_t num_mis;
jl_get_llvm_mis(native_functions, &num_mis, NULL);
arraylist_grow(&MIs, num_mis);
- jl_get_llvm_mis(native_functions, &num_mis, (jl_method_instance_t*)MIs.items);
+ jl_get_llvm_mis(native_functions, &num_mis, (jl_method_instance_t**)MIs.items);
}
}
if (jl_options.trim) {
diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c
index 1d8ed0e19b04b..0dc64d27a57a9 100644
--- a/src/staticdata_utils.c
+++ b/src/staticdata_utils.c
@@ -314,7 +314,7 @@ static jl_array_t *queue_external_cis(jl_array_t *list, jl_query_cache *query_ca
assert(jl_is_code_instance(ci));
jl_method_instance_t *mi = jl_get_ci_mi(ci);
jl_method_t *m = mi->def.method;
- if (ci->owner == jl_nothing && jl_atomic_load_relaxed(&ci->inferred) && jl_is_method(m) && jl_object_in_image((jl_value_t*)m->module)) {
+ if (jl_atomic_load_relaxed(&ci->inferred) && jl_is_method(m) && jl_object_in_image((jl_value_t*)m->module)) {
int found = has_backedge_to_worklist(mi, &visited, &stack, query_cache);
assert(found == 0 || found == 1 || found == 2);
assert(stack.len == 0);
diff --git a/src/task.c b/src/task.c
index 019a301b1f062..bb86bce48101a 100644
--- a/src/task.c
+++ b/src/task.c
@@ -203,10 +203,6 @@ static void NOINLINE save_stack(jl_ptls_t ptls, jl_task_t *lastt, jl_task_t **pt
lastt->ctx.copy_stack = nb;
lastt->sticky = 1;
memcpy_stack_a16((uint64_t*)buf, (uint64_t*)frame_addr, nb);
- // this task's stack could have been modified after
- // it was marked by an incremental collection
- // move the barrier back instead of walking it again here
- jl_gc_wb_back(lastt);
}
JL_NO_ASAN static void NOINLINE JL_NORETURN restore_stack(jl_ucontext_t *t, jl_ptls_t ptls, char *p)
@@ -504,6 +500,12 @@ JL_NO_ASAN static void ctx_switch(jl_task_t *lastt)
lastt->ctx.ctx = &lasttstate.ctx;
}
}
+ // this task's stack or scope field could have been modified after
+ // it was marked by an incremental collection
+ // move the barrier back instead of walking the shadow stack again here to check if that is required
+ // even if killed (dropping the stack) and just the scope field matters,
+ // let the gc figure that out next time it does a quick mark
+ jl_gc_wb_back(lastt);
// set up global state for new task and clear global state for old task
t->ptls = ptls;
@@ -1108,6 +1110,7 @@ JL_DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, jl_value_t *completion
jl_atomic_store_relaxed(&t->_isexception, 0);
// Inherit scope from parent task
t->scope = ct->scope;
+ jl_gc_wb_fresh(t, t->scope);
// Fork task-local random state from parent
jl_rng_split(t->rngState, ct->rngState);
// there is no active exception handler available on this stack yet
@@ -1573,6 +1576,7 @@ jl_task_t *jl_init_root_task(jl_ptls_t ptls, void *stack_lo, void *stack_hi)
ct->donenotify = jl_nothing;
jl_atomic_store_relaxed(&ct->_isexception, 0);
ct->scope = jl_nothing;
+ jl_gc_wb_knownold(ct, ct->scope);
ct->eh = NULL;
ct->gcstack = NULL;
ct->excstack = NULL;
diff --git a/src/threading.c b/src/threading.c
index 9f5c18fe53555..e56aba2de51a1 100644
--- a/src/threading.c
+++ b/src/threading.c
@@ -1111,6 +1111,289 @@ JL_DLLEXPORT int jl_setaffinity(int16_t tid, char *mask, int cpumasksize) {
return 0; // success
}
+// Heartbeat mechanism for Julia's task scheduler
+// ---
+// Start a thread that does not participate in running Julia's tasks. This
+// thread simply sleeps until the heartbeat mechanism is enabled. When
+// enabled, the heartbeat thread enters a loop in which it blocks waiting
+// for the specified heartbeat interval. If, within that interval,
+// `jl_heartbeat()` is *not* called at least once, then the thread calls
+// `jl_print_task_backtraces(0)`.
+
+#ifdef JL_HEARTBEAT_THREAD
+
+#include
+
+volatile int heartbeat_enabled;
+int heartbeat_tid; // Mostly used to ensure we skip this thread in the CPU profiler. XXX: not implemented on Windows
+uv_thread_t heartbeat_uvtid;
+uv_sem_t heartbeat_on_sem, // jl_heartbeat_enable -> thread
+ heartbeat_off_sem; // thread -> jl_heartbeat_enable
+int heartbeat_interval_s,
+ tasks_after_n,
+ reset_tasks_after_n;
+int tasks_showed, n_hbs_missed, n_hbs_recvd;
+_Atomic(int) heartbeats;
+
+JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT;
+void jl_heartbeat_threadfun(void *arg);
+
+// start the heartbeat thread with heartbeats disabled
+void jl_init_heartbeat(void)
+{
+ heartbeat_enabled = 0;
+ uv_sem_init(&heartbeat_on_sem, 0);
+ uv_sem_init(&heartbeat_off_sem, 0);
+ uv_thread_create(&heartbeat_uvtid, jl_heartbeat_threadfun, NULL);
+ uv_thread_detach(&heartbeat_uvtid);
+}
+
+int jl_inside_heartbeat_thread(void)
+{
+ uv_thread_t curr_uvtid = uv_thread_self();
+ return curr_uvtid == heartbeat_uvtid;
+}
+
+// enable/disable heartbeats
+// heartbeat_s: interval within which jl_heartbeat() must be called
+// show_tasks_after_n: number of heartbeats missed before printing task backtraces
+// reset_after_n: number of heartbeats after which to reset
+//
+// When disabling heartbeats, the heartbeat thread must wake up,
+// find out that heartbeats are now disabled, and reset. For now, we
+// handle this by preventing re-enabling of heartbeats until this
+// completes.
+JL_DLLEXPORT int jl_heartbeat_enable(int heartbeat_s, int show_tasks_after_n,
+ int reset_after_n)
+{
+ if (heartbeat_s <= 0) {
+ heartbeat_enabled = 0;
+ heartbeat_interval_s = tasks_after_n = reset_tasks_after_n = 0;
+ }
+ else {
+ // must disable before enabling
+ if (heartbeat_enabled) {
+ return -1;
+ }
+ // heartbeat thread must be ready
+ if (uv_sem_trywait(&heartbeat_off_sem) != 0) {
+ return -1;
+ }
+
+ jl_atomic_store_relaxed(&heartbeats, 0);
+ heartbeat_interval_s = heartbeat_s;
+ tasks_after_n = show_tasks_after_n;
+ reset_tasks_after_n = reset_after_n;
+ tasks_showed = 0;
+ n_hbs_missed = 0;
+ n_hbs_recvd = 0;
+ heartbeat_enabled = 1;
+ uv_sem_post(&heartbeat_on_sem); // wake the heartbeat thread
+ }
+ return 0;
+}
+
+// temporarily pause the heartbeat thread
+JL_DLLEXPORT int jl_heartbeat_pause(void)
+{
+ if (!heartbeat_enabled) {
+ return -1;
+ }
+ heartbeat_enabled = 0;
+ return 0;
+}
+
+// resume the paused heartbeat thread
+JL_DLLEXPORT int jl_heartbeat_resume(void)
+{
+ // cannot resume if the heartbeat thread is already running
+ if (heartbeat_enabled) {
+ return -1;
+ }
+
+ // cannot resume if we weren't paused (disabled != paused)
+ if (heartbeat_interval_s == 0) {
+ return -1;
+ }
+
+ // heartbeat thread must be ready
+ if (uv_sem_trywait(&heartbeat_off_sem) != 0) {
+ return -1;
+ }
+
+ // reset state as we've been paused
+ n_hbs_missed = 0;
+ n_hbs_recvd = 0;
+ tasks_showed = 0;
+
+ // resume
+ heartbeat_enabled = 1;
+ uv_sem_post(&heartbeat_on_sem); // wake the heartbeat thread
+ return 0;
+}
+
+// heartbeat
+JL_DLLEXPORT void jl_heartbeat(void)
+{
+ jl_atomic_fetch_add(&heartbeats, 1);
+}
+
+// sleep the thread for the specified interval
+void sleep_for(int secs, int nsecs)
+{
+ struct timespec rqtp, rmtp;
+ rqtp.tv_sec = secs;
+ rqtp.tv_nsec = nsecs;
+ rmtp.tv_sec = 0;
+ rmtp.tv_nsec = 0;
+ for (; ;) {
+ // this suspends the thread so we aren't using CPU
+ if (nanosleep(&rqtp, &rmtp) == 0) {
+ return;
+ }
+ // TODO: else if (errno == EINTR)
+ // this could be SIGTERM and we should shutdown but how to find out?
+ rqtp = rmtp;
+ }
+}
+
+// check for heartbeats and maybe report loss
+uint8_t check_heartbeats(uint8_t gc_state)
+{
+ int hb = jl_atomic_exchange(&heartbeats, 0);
+
+ if (hb <= 0) {
+ // we didn't get a heartbeat
+ n_hbs_recvd = 0;
+ n_hbs_missed++;
+
+ // if we've printed task backtraces already, do nothing
+ if (!tasks_showed) {
+ // otherwise, at least show this message
+ jl_safe_printf("==== heartbeat loss (%ds) ====\n",
+ n_hbs_missed * heartbeat_interval_s);
+ // if we've missed enough heartbeats, print task backtraces
+ if (n_hbs_missed >= tasks_after_n) {
+ jl_task_t *ct = jl_current_task;
+ jl_ptls_t ptls = ct->ptls;
+
+ // exit GC-safe region to report then re-enter
+ jl_gc_safe_leave(ptls, gc_state);
+ jl_print_task_backtraces(0);
+ gc_state = jl_gc_safe_enter(ptls);
+
+ // we printed task backtraces
+ tasks_showed = 1;
+ }
+ }
+ }
+ else {
+ // got a heartbeat
+ n_hbs_recvd++;
+ // if we'd printed task backtraces, check for reset
+ if (tasks_showed && n_hbs_recvd >= reset_tasks_after_n) {
+ tasks_showed = 0;
+ jl_safe_printf("==== heartbeats recovered (lost for %ds) ====\n",
+ n_hbs_missed * heartbeat_interval_s);
+ }
+ n_hbs_missed = 0;
+ }
+
+ return gc_state;
+}
+
+// heartbeat thread function
+void jl_heartbeat_threadfun(void *arg)
+{
+ int s = 59, ns = 1e9 - 1, rs;
+ uint64_t t0, tchb;
+
+ // We need a TLS because backtraces are accumulated into ptls->bt_size
+ // and ptls->bt_data, so we need to call jl_adopt_thread().
+ jl_adopt_thread();
+ (void)jl_atomic_fetch_add_relaxed(&n_threads_running, -1);
+ jl_task_t *ct = jl_current_task;
+ jl_ptls_t ptls = ct->ptls;
+ heartbeat_tid = ptls->tid;
+
+ // Don't hold up GC, this thread doesn't participate.
+ uint8_t gc_state = jl_gc_safe_enter(ptls);
+
+ for (;;) {
+ if (!heartbeat_enabled) {
+ // post the off semaphore to indicate we're ready to enable
+ uv_sem_post(&heartbeat_off_sem);
+
+ // sleep the thread here; this semaphore is posted in
+ // jl_heartbeat_enable() or jl_heartbeat_resume()
+ uv_sem_wait(&heartbeat_on_sem);
+
+ // Set the sleep duration.
+ s = heartbeat_interval_s - 1;
+ ns = 1e9 - 1;
+ continue;
+ }
+
+ // heartbeat is enabled; sleep, waiting for the desired interval
+ sleep_for(s, ns);
+
+ // if heartbeats were turned off/paused while we were sleeping, reset
+ if (!heartbeat_enabled) {
+ continue;
+ }
+
+ // check if any heartbeats have happened, report as appropriate
+ t0 = jl_hrtime();
+ gc_state = check_heartbeats(gc_state);
+ tchb = jl_hrtime() - t0;
+
+ // adjust the next sleep duration based on how long the heartbeat
+ // check took, but if it took too long then use the normal duration
+ rs = 1;
+ while (tchb > 1e9) {
+ rs++;
+ tchb -= 1e9;
+ }
+ if (rs < heartbeat_interval_s) {
+ s = heartbeat_interval_s - rs;
+ }
+ ns = 1e9 - tchb;
+ }
+}
+
+#else // !JL_HEARTBEAT_THREAD
+
+void jl_init_heartbeat(void)
+{
+}
+
+int jl_inside_heartbeat_thread(void)
+{
+ return 0;
+}
+
+JL_DLLEXPORT int jl_heartbeat_enable(int heartbeat_s, int show_tasks_after_n,
+ int reset_after_n)
+{
+ return -1;
+}
+
+JL_DLLEXPORT int jl_heartbeat_pause(void)
+{
+ return -1;
+}
+
+JL_DLLEXPORT int jl_heartbeat_resume(void)
+{
+ return -1;
+}
+
+JL_DLLEXPORT void jl_heartbeat(void)
+{
+}
+
+#endif // JL_HEARTBEAT_THREAD
+
#ifdef __cplusplus
}
#endif
diff --git a/stdlib/Artifacts/src/Artifacts.jl b/stdlib/Artifacts/src/Artifacts.jl
index 4af706606d326..79cb05e86e354 100644
--- a/stdlib/Artifacts/src/Artifacts.jl
+++ b/stdlib/Artifacts/src/Artifacts.jl
@@ -16,6 +16,13 @@ using Base.TOML: TOML
export artifact_exists, artifact_path, artifact_meta, artifact_hash,
select_downloadable_artifacts, find_artifacts_toml, @artifact_str
+const _artifacts_world_age = Ref{UInt}(typemax(UInt))
+
+function __init__()
+ _artifacts_world_age[] = Base.get_world_counter()
+ nothing
+end
+
"""
parse_toml(path::String)
@@ -403,7 +410,7 @@ function artifact_meta(name::String, artifact_dict::Dict, artifacts_toml::String
dl_dict = Dict{Platform,Dict{String,Any}}()
for x in meta
x = x::Dict{String, Any}
- dl_dict[unpack_platform(x, name, artifacts_toml)] = x
+ dl_dict[unpack_platform(x, name, artifacts_toml)::Platform] = x
end
meta = select_platform(dl_dict, platform)
# If it's NOT a dict, complain
@@ -543,7 +550,7 @@ function jointail(dir, tail)
end
function _artifact_str(__module__, artifacts_toml, name, path_tail, artifact_dict, hash, platform, ::Val{LazyArtifacts}) where LazyArtifacts
- world = Base._require_world_age[]
+ world = _artifacts_world_age[]
if world == typemax(UInt)
world = Base.get_world_counter()
end
diff --git a/stdlib/LinearAlgebra.version b/stdlib/LinearAlgebra.version
index 3b1f7cc5847d9..6caafbaf313ac 100644
--- a/stdlib/LinearAlgebra.version
+++ b/stdlib/LinearAlgebra.version
@@ -1,4 +1,4 @@
LINEARALGEBRA_BRANCH = release-1.12
-LINEARALGEBRA_SHA1 = 997c4b7e7664f30645ef8bd51d8a4203e49c4631
+LINEARALGEBRA_SHA1 = 7249e662d66b53da6c9335ea748eac2750c2924f
LINEARALGEBRA_GIT_URL := https://github.com/JuliaLang/LinearAlgebra.jl.git
LINEARALGEBRA_TAR_URL = https://api.github.com/repos/JuliaLang/LinearAlgebra.jl/tarball/$1
diff --git a/stdlib/Logging/test/runtests.jl b/stdlib/Logging/test/runtests.jl
index 3e92b7d9e2697..a0ba9f7c43b1e 100644
--- a/stdlib/Logging/test/runtests.jl
+++ b/stdlib/Logging/test/runtests.jl
@@ -19,6 +19,13 @@ macro customlog(exs...) Base.CoreLogging.logmsg_code((Base.CoreLogging.@_sourcei
@test :handle_message in names(Logging, all=true) # non-exported public function
end
+@testset "LogLevel compatibility with integers" begin
+ @test Logging.Debug + 1000 == Logging.Info
+ @test Logging.Warn - 1000 == Logging.Info
+ @test Logging.Info < 500
+ @test 500 < Logging.Warn
+end
+
@testset "ConsoleLogger" begin
# First pass log limiting
@test min_enabled_level(ConsoleLogger(devnull, Logging.Debug)) == Logging.Debug
diff --git a/stdlib/Manifest.toml b/stdlib/Manifest.toml
index 3db51cf75328d..14482fd3001b6 100644
--- a/stdlib/Manifest.toml
+++ b/stdlib/Manifest.toml
@@ -240,6 +240,11 @@ weakdeps = ["SparseArrays"]
uuid = "f489334b-da3d-4c2e-b8f0-e476e12c162b"
version = "1.11.0"
+[[deps.SuiteSparse]]
+deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"]
+uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9"
+version = "1.12.0"
+
[[deps.SuiteSparse_jll]]
deps = ["Artifacts", "Libdl", "libblastrampoline_jll"]
uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c"
diff --git a/stdlib/MozillaCACerts_jll/Project.toml b/stdlib/MozillaCACerts_jll/Project.toml
index 57c5526a6f1f2..d63251d59d58f 100644
--- a/stdlib/MozillaCACerts_jll/Project.toml
+++ b/stdlib/MozillaCACerts_jll/Project.toml
@@ -1,7 +1,7 @@
name = "MozillaCACerts_jll"
uuid = "14a3606d-f60d-562e-9121-12d972cd8159"
# Keep in sync with `deps/libgit2.version`.
-version = "2025.05.20"
+version = "2025.11.04"
[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
diff --git a/stdlib/NetworkOptions.version b/stdlib/NetworkOptions.version
index f7cb50a74d106..7a3c0ccd27d3f 100644
--- a/stdlib/NetworkOptions.version
+++ b/stdlib/NetworkOptions.version
@@ -1,4 +1,4 @@
NETWORKOPTIONS_BRANCH = master
-NETWORKOPTIONS_SHA1 = 532992fcc0f1d02df48374969cbae37e34c01360
+NETWORKOPTIONS_SHA1 = 7034c55dbf52ee959cabd63bcbe656df658f5bda
NETWORKOPTIONS_GIT_URL := https://github.com/JuliaLang/NetworkOptions.jl.git
NETWORKOPTIONS_TAR_URL = https://api.github.com/repos/JuliaLang/NetworkOptions.jl/tarball/$1
diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version
index 6feeb870e2f20..56f673f582df6 100644
--- a/stdlib/Pkg.version
+++ b/stdlib/Pkg.version
@@ -1,4 +1,4 @@
PKG_BRANCH = release-1.12
-PKG_SHA1 = 53b2b5da91c27515ce129635fe184e8bd9afb09f
+PKG_SHA1 = 1c1c173d35be3eb478054fb0229b0b1b6aa040cf
PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git
PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1
diff --git a/stdlib/Project.toml b/stdlib/Project.toml
index 1e03a0f474490..8a3e0f4d78e69 100644
--- a/stdlib/Project.toml
+++ b/stdlib/Project.toml
@@ -48,6 +48,7 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
StyledStrings = "f489334b-da3d-4c2e-b8f0-e476e12c162b"
SuiteSparse_jll = "bea87d4a-7f5b-5778-9afe-8cc45184846c"
+SuiteSparse = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9"
TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
Tar = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl
index cd13f0880d7c4..0a5975179e3a3 100644
--- a/stdlib/REPL/src/REPLCompletions.jl
+++ b/stdlib/REPL/src/REPLCompletions.jl
@@ -1025,8 +1025,8 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif
if obj !== nothing
# Skip leading whitespace inside brackets.
i = @something findnext(!isspace, string, first(key)) nextind(string, last(key))
- key = i:last(key)
- s = string[intersect(key, 1:pos)]
+ key = intersect(i:last(key), 1:pos)
+ s = string[key]
matches = find_dict_matches(obj, s)
length(matches) == 1 && !closed && (matches[1] *= ']')
if length(matches) > 0
@@ -1051,7 +1051,8 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif
# "~/example.txt TAB => "/home/user/example.txt"
r, closed = find_str(cur)
if r !== nothing
- s = do_string_unescape(string[intersect(r, 1:pos)])
+ r = intersect(r, 1:pos)
+ s = do_string_unescape(string[r])
ret, success = complete_path_string(s, hint; string_escape=true,
dirsep=Sys.iswindows() ? '\\' : '/')
if length(ret) == 1 && !closed && close_path_completion(ret[1].path)
@@ -1094,8 +1095,8 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif
# Keyword argument completion:
# foo(ar TAB => keyword arguments like `arg1=`
elseif kind(cur) == K"Identifier"
- r = char_range(cur)
- s = string[intersect(r, 1:pos)]
+ r = intersect(char_range(cur), 1:pos)
+ s = string[r]
# Return without adding more suggestions if kwargs only
complete_keyword_argument!(suggestions, e, s, context_module, arg_pos; shift) &&
return sort_suggestions(), r, true
diff --git a/stdlib/REPL/src/precompile.jl b/stdlib/REPL/src/precompile.jl
index a4d289db8cd40..21ca166b94a71 100644
--- a/stdlib/REPL/src/precompile.jl
+++ b/stdlib/REPL/src/precompile.jl
@@ -61,7 +61,7 @@ function repl_workload()
display("a string")
foo(x) = 1
@time @eval foo(1)
- ; pwd
+ ;
$CTRL_C
$CTRL_R$CTRL_C#
? reinterpret
diff --git a/stdlib/REPL/test/replcompletions.jl b/stdlib/REPL/test/replcompletions.jl
index de723cf83d0e7..428a13dd59e79 100644
--- a/stdlib/REPL/test/replcompletions.jl
+++ b/stdlib/REPL/test/replcompletions.jl
@@ -1492,6 +1492,23 @@ mktempdir() do path
@test "$(path_expected)$(sep)foo_dir$(sep)" in c
@test "$(path_expected)$(sep)foo_file.txt" in c
end
+
+ # Issue #60444: path completion should not delete text after the string (e.g. indexing)
+ let (c, r, res) = test_complete_pos("f(\"$(path)$(sep)foo|\")")
+ @test res
+ @test length(c) == 2
+ @test "$(path_expected)$(sep)foo_dir$(sep)" in c
+ @test "$(path_expected)$(sep)foo_file.txt" in c
+ end
+ let (c, r, res) = test_complete_pos("f(\"$(path)$(sep)foo|\")[1]")
+ @test res
+ @test length(c) == 2
+ @test "$(path_expected)$(sep)foo_dir$(sep)" in c
+ @test "$(path_expected)$(sep)foo_file.txt" in c
+ # Range should end at cursor position, not overwrite ")[1]"
+ pos = findfirst('|', "f(\"$(path)$(sep)foo|\")[1]") - 1
+ @test last(r) == pos
+ end
end
if Sys.iswindows()
@@ -1643,6 +1660,14 @@ test_dict_completion("test_repl_comp_customdict")
let s = "test_dict_no_length["
@test REPLCompletions.completions(s, sizeof(s), Main.CompletionFoo) isa Tuple
end
+
+ # Issue #60444: completing dict keys should not overwrite input after cursor
+ let s = "test_dict[\"ab|c\"]"
+ c, r = test_complete_context_pos(s, Main.CompletionFoo)
+ @test "\"abc\"" in c
+ @test "\"abcd\"" in c
+ @test r == 11:13 # range ends at cursor, not at end of key
+ end
end
@testset "completion of string/cmd macros (#22577)" begin
@@ -1789,6 +1814,13 @@ end
@test hasnokwsuggestions("CompletionFoo.kwtest5('a', 3, 5, unknownsplat...; xy")
@test hasnokwsuggestions("CompletionFoo.kwtest5(3; somek")
=#
+
+ # Issue #60444: completing keyword arguments should not overwrite input after cursor
+ let s = "CompletionFoo.kwtest3(a; foob|true)"
+ c, r = test_complete_pos(s)
+ @test c == ["foobar="]
+ @test r == 26:29
+ end
end
# Test completion in context
diff --git a/stdlib/SparseArrays.version b/stdlib/SparseArrays.version
index b6d9a820d9a06..0e282a70c0acb 100644
--- a/stdlib/SparseArrays.version
+++ b/stdlib/SparseArrays.version
@@ -1,4 +1,4 @@
SPARSEARRAYS_BRANCH = release-1.12
-SPARSEARRAYS_SHA1 = 5d674dc7bd90156cf8ecea4e143b69b5a5b7640d
+SPARSEARRAYS_SHA1 = 2376bf8734754c5dd4264186299ae6839ab7783f
SPARSEARRAYS_GIT_URL := https://github.com/JuliaSparse/SparseArrays.jl.git
SPARSEARRAYS_TAR_URL = https://api.github.com/repos/JuliaSparse/SparseArrays.jl/tarball/$1
diff --git a/stdlib/stdlib.mk b/stdlib/stdlib.mk
index 006b7a276a3b3..1c418a7e1a8f4 100644
--- a/stdlib/stdlib.mk
+++ b/stdlib/stdlib.mk
@@ -6,8 +6,8 @@ INDEPENDENT_STDLIBS := \
ArgTools Base64 CRC32c Dates DelimitedFiles Distributed Downloads Future \
InteractiveUtils JuliaSyntaxHighlighting LazyArtifacts LibGit2 LibCURL Logging \
Markdown Mmap NetworkOptions Profile Printf Pkg REPL Serialization SharedArrays \
- SparseArrays Statistics StyledStrings SuiteSparse_jll Tar Test TOML Unicode UUIDs \
- dSFMT_jll GMP_jll libLLVM_jll LLD_jll LLVMLibUnwind_jll LibUnwind_jll LibUV_jll \
+ SparseArrays Statistics StyledStrings SuiteSparse_jll SuiteSparse Tar Test TOML \
+ Unicode UUIDs dSFMT_jll GMP_jll libLLVM_jll LLD_jll LLVMLibUnwind_jll LibUnwind_jll LibUV_jll \
LibCURL_jll LibSSH2_jll LibGit2_jll nghttp2_jll MozillaCACerts_jll \
MPFR_jll OpenLibm_jll OpenSSL_jll PCRE2_jll p7zip_jll Zlib_jll
diff --git a/test/core.jl b/test/core.jl
index d18f7fe8136b6..dd2dfd86b9619 100644
--- a/test/core.jl
+++ b/test/core.jl
@@ -8422,6 +8422,32 @@ let ms = Base._methods_by_ftype(Tuple{typeof(sin), Int}, OverlayModule.mt, 1, Ba
@test isempty(ms)
end
+# fresh module to ensure uncached methods
+module OverlayMTTest
+ using Base.Experimental: @MethodTable, @overlay
+ @MethodTable(mt)
+
+ function overlay_only end
+ @overlay mt overlay_only(x::Int) = x * 2
+end
+
+# #60702 & #60716: Overlay methods must be found without prior cache population
+let world = Base.get_world_counter()
+ mi = Base.method_instance(OverlayMTTest.overlay_only, Tuple{Int};
+ world, method_table=OverlayMTTest.mt)
+ @test mi isa Core.MethodInstance
+ @test mi.def.module === OverlayMTTest
+end
+
+# #60712: Global-only methods must NOT be found via custom MT
+let
+ @eval global_only_func(x::Int) = x + 1
+ world = Base.get_world_counter()
+ mi = Base.method_instance(global_only_func, Tuple{Int};
+ world, method_table=OverlayMTTest.mt)
+ @test mi === nothing
+end
+
# precompilation
let load_path = mktempdir()
depot_path = mkdepottempdir()
@@ -8605,3 +8631,17 @@ primitive type ByteString58434 (18 * 8) end
@test Base.datatype_isbitsegal(Tuple{ByteString58434}) == false
@test Base.datatype_haspadding(Tuple{ByteString58434}) == (length(Base.padding(Tuple{ByteString58434})) > 0)
+
+# #60659 - Behavior of using'd ambiguous bindings
+module AmbiguousUsing60659
+ using Test
+ module A
+ export X
+ module B; struct X; end; export X; end
+ module C; struct X; end; export X; end
+ using .B, .C
+ end
+ module D; struct X; end; export X; end
+ using .D, .A
+ @test_throws UndefVarError X
+end
diff --git a/test/download_exec.jl b/test/download_exec.jl
index 777fb6773c463..93af540dd70a1 100644
--- a/test/download_exec.jl
+++ b/test/download_exec.jl
@@ -5,22 +5,31 @@ module TestDownload
using Test
mktempdir() do temp_dir
+ url = try
+ download("https://httpbingo.julialang.org")
+ "https://httpbingo.julialang.org"
+ catch ex
+ bt = catch_backtrace()
+ @info "Looks like there is a problem with a JuliaLang mirror of httpbingo"
+ @info "Trying httpbin" exception=(ex,bt)
+ "https://httpbin.julialang.org/"
+ end
# Download a file
file = joinpath(temp_dir, "ip")
- @test download("https://httpbin.julialang.org/ip", file) == file
+ @test download("$url/ip", file) == file
@test isfile(file)
@test !isempty(read(file))
ip = read(file, String)
# Download an empty file
empty_file = joinpath(temp_dir, "empty")
- @test download("https://httpbin.julialang.org/status/200", empty_file) == empty_file
+ @test download("$url/status/200", empty_file) == empty_file
@test isfile(empty_file)
@test isempty(read(empty_file))
# Make sure that failed downloads do not leave files around
missing_file = joinpath(temp_dir, "missing")
- @test_throws Exception download("https://httpbin.julialang.org/status/404", missing_file)
+ @test_throws Exception download("$url/status/404", missing_file)
@test !isfile(missing_file)
# Use a TEST-NET (192.0.2.0/24) address which shouldn't be bound
diff --git a/test/llvmpasses/alloc-opt-gcframe-addrspaces.ll b/test/llvmpasses/alloc-opt-gcframe-addrspaces.ll
index b96c9385e38eb..c66cb815ea8b9 100644
--- a/test/llvmpasses/alloc-opt-gcframe-addrspaces.ll
+++ b/test/llvmpasses/alloc-opt-gcframe-addrspaces.ll
@@ -16,7 +16,7 @@ declare {}* @julia.pointer_from_objref({} addrspace(11)*)
; CHECK-LABEL: @non_zero_addrspace
-; OPAQUE: %var1 = alloca i32, align 8, addrspace(5)
+; OPAQUE: %var1 = alloca i64, align 16, addrspace(5)
; OPAQUE: %1 = addrspacecast ptr addrspace(5) %var1 to ptr
; OPAQUE: call void @llvm.lifetime.start.p5(i64 4, ptr addrspace(5) %var1)
diff --git a/test/llvmpasses/alloc-opt-gcframe.ll b/test/llvmpasses/alloc-opt-gcframe.ll
index f53a4d5c01df7..44714b702d7bc 100644
--- a/test/llvmpasses/alloc-opt-gcframe.ll
+++ b/test/llvmpasses/alloc-opt-gcframe.ll
@@ -25,7 +25,8 @@ define {} addrspace(10)* @return_obj() {
; CHECK-LABEL: }{{$}}
; CHECK-LABEL: @return_load
-; CHECK: alloca i64
+; When the element type is known (i64), splitOnStack preserves it
+; CHECK: alloca i64, align 16
; CHECK-NOT: @julia.gc_alloc_obj
; CHECK-NOT: @jl_gc_small_alloc
; OPAQUE: call void @llvm.lifetime.start{{.*}}(i64 8, ptr
@@ -62,7 +63,7 @@ define void @ccall_obj(i8* %fptr) {
; CHECK-LABEL: }{{$}}
; CHECK-LABEL: @ccall_ptr
-; CHECK: alloca i64
+; CHECK: alloca i64, align 16
; OPAQUE: call ptr @julia.get_pgcstack()
; CHECK-NOT: @julia.gc_alloc_obj
; CHECK-NOT: @jl_gc_small_alloc
@@ -105,7 +106,7 @@ define void @ccall_unknown_bundle(i8* %fptr) {
; CHECK-LABEL: }{{$}}
; CHECK-LABEL: @lifetime_branches
-; CHECK: alloca i64
+; CHECK: alloca i64, align 16
; OPAQUE: call ptr @julia.get_pgcstack()
; CHECK: L1:
; CHECK-NEXT: call void @llvm.lifetime.start{{.*}}(i64 8,
@@ -166,7 +167,7 @@ define void @object_field({} addrspace(10)* %field) {
; CHECK-LABEL: }{{$}}
; CHECK-LABEL: @memcpy_opt
-; CHECK: alloca [16 x i8], align 16
+; CHECK: alloca [2 x i64], align 16
; OPAQUE: call ptr @julia.get_pgcstack()
; CHECK-NOT: @julia.gc_alloc_obj
; CHECK-NOT: @jl_gc_small_alloc
diff --git a/test/llvmpasses/alloc-opt-pass.ll b/test/llvmpasses/alloc-opt-pass.ll
index 83f2118412cc1..ad79baafd19dd 100644
--- a/test/llvmpasses/alloc-opt-pass.ll
+++ b/test/llvmpasses/alloc-opt-pass.ll
@@ -79,8 +79,9 @@ declare ptr addrspace(10) @external_function2()
; CHECK-LABEL: @legal_int_types
-; CHECK: alloca [12 x i8]
-; CHECK-NOT: alloca i96
+; Test that allocations use i64 chunks (capped at 64 bits for backend compatibility)
+; A 12-byte allocation rounds up to 16 bytes, giving [2 x i64]
+; CHECK: alloca [2 x i64], align 16
; CHECK: call void @llvm.memset.p0.i64(ptr align 16 %var1,
; CHECK: ret void
define void @legal_int_types() {
@@ -151,11 +152,10 @@ define void @lifetime_no_preserve_end(ptr noalias nocapture noundef nonnull sret
; CHECK-LABEL: @initializers
-; CHECK: alloca [1 x i8]
-; CHECK-DAG: alloca [2 x i8]
-; CHECK-DAG: alloca [3 x i8]
-; CHECK-DAG: call void @llvm.memset.p0.i64(ptr align 1 %var1,
-; CHECK-DAG: call void @llvm.memset.p0.i64(ptr align 4 %var7,
+; Small allocations (1, 2, 3 bytes) all round up to 8 bytes, giving i64
+; CHECK-DAG: alloca i64, align 16
+; CHECK-DAG: call void @llvm.memset.p0.i64(ptr align 16 %var1,
+; CHECK-DAG: call void @llvm.memset.p0.i64(ptr align 16 %var7,
; CHECK: ret void
define void @initializers() {
%pgcstack = call ptr @julia.get_pgcstack()
@@ -268,6 +268,37 @@ define swiftcc i64 @"atomicrmw"(ptr nonnull swiftself %0) #0 {
ret i64 %19
}
+; Test that higher alignment from the original allocation is inherited
+; 8 bytes with 32-byte alignment uses i64 (element size capped at 64 bits)
+; CHECK-LABEL: @align_inherit
+; CHECK: alloca i64, align 32
+; CHECK: ret void
+define void @align_inherit() {
+ %pgcstack = call ptr @julia.get_pgcstack()
+ %ptls = call ptr @julia.ptls_states()
+ %ptls_i8 = bitcast ptr %ptls to ptr
+ %var1 = call align 32 ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 8, ptr addrspace(10) @tag)
+ %var2 = addrspacecast ptr addrspace(10) %var1 to ptr addrspace(11)
+ %var3 = call ptr @julia.pointer_from_objref(ptr addrspace(11) %var2)
+ ret void
+}
+; CHECK-LABEL: }{{$}}
+
+; Test that 8-byte allocation uses i64 with GC alignment
+; CHECK-LABEL: @legal_int_i64
+; CHECK: alloca i64, align 16
+; CHECK: ret void
+define void @legal_int_i64() {
+ %pgcstack = call ptr @julia.get_pgcstack()
+ %ptls = call ptr @julia.ptls_states()
+ %ptls_i8 = bitcast ptr %ptls to ptr
+ %var1 = call ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 8, ptr addrspace(10) @tag)
+ %var2 = addrspacecast ptr addrspace(10) %var1 to ptr addrspace(11)
+ %var3 = call ptr @julia.pointer_from_objref(ptr addrspace(11) %var2)
+ ret void
+}
+; CHECK-LABEL: }{{$}}
+
declare ptr @julia.ptls_states()
declare ptr @julia.pointer_from_objref(ptr addrspace(11))
diff --git a/test/misc.jl b/test/misc.jl
index 8d6ee39715303..f830913d21098 100644
--- a/test/misc.jl
+++ b/test/misc.jl
@@ -1542,6 +1542,9 @@ end
@allocated _x = 1+2
@test _x === 3
+ # test `@allocated` works for dotted operations
+ @test (@allocated 1 .+ 1) == 0
+
n, m = 10, 20
X = rand(n, m)
treshape59278(X, n, m)
diff --git a/test/precompile_absint1.jl b/test/precompile_absint1.jl
index 98078ebf41098..000ba116bae95 100644
--- a/test/precompile_absint1.jl
+++ b/test/precompile_absint1.jl
@@ -43,43 +43,35 @@ precompile_test_harness() do load_path
let m = only(methods(TestAbsIntPrecompile1.basic_callee))
mi = only(Base.specializations(m))
ci = mi.cache
- @test_broken isdefined(ci, :next)
+ ci = check_presence(mi, nothing)
+ @test ci !== nothing
@test ci.owner === nothing
@test ci.max_world == typemax(UInt)
@test Base.module_build_id(TestAbsIntPrecompile1) ==
Base.object_build_id(ci)
- @test_skip begin
- ci = ci.next
- @test !isdefined(ci, :next)
+ ci = check_presence(mi, cache_owner)
+ @test ci !== nothing
@test ci.owner === cache_owner
@test ci.max_world == typemax(UInt)
@test Base.module_build_id(TestAbsIntPrecompile1) ==
Base.object_build_id(ci)
- end
end
let m = only(methods(sum, (Vector{Float64},)))
- found = false
for mi in Base.specializations(m)
if mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(sum),Vector{Float64}}
- ci = mi.cache
- @test_broken isdefined(ci, :next)
- @test_broken ci.owner === cache_owner
- @test_skip begin
- @test ci.max_world == typemax(UInt)
- @test Base.module_build_id(TestAbsIntPrecompile1) ==
- Base.object_build_id(ci)
- ci = ci.next
- end
- @test !isdefined(ci, :next)
+ ci = check_presence(mi, nothing)
+ @test ci !== nothing
@test ci.owner === nothing
@test ci.max_world == typemax(UInt)
+ @test Base.module_build_id(TestAbsIntPrecompile1) == Base.object_build_id(ci)
+ ci = check_presence(mi, cache_owner)
+ @test ci !== nothing
+ @test ci.owner === cache_owner
+ @test ci.max_world == typemax(UInt)
@test Base.module_build_id(TestAbsIntPrecompile1) ==
Base.object_build_id(ci)
- found = true
- break
end
end
- @test found
end
end
end
diff --git a/test/precompile_absint2.jl b/test/precompile_absint2.jl
index 4aa84e0992f7c..5b0ba32a8df82 100644
--- a/test/precompile_absint2.jl
+++ b/test/precompile_absint2.jl
@@ -62,44 +62,33 @@ precompile_test_harness() do load_path
TestAbsIntPrecompile2.Custom.PrecompileInterpreter())
let m = only(methods(TestAbsIntPrecompile2.basic_callee))
mi = only(Base.specializations(m))
- ci = mi.cache
- @test_broken isdefined(ci, :next)
+ ci = check_presence(mi, nothing)
+ @test ci !== nothing
@test ci.owner === nothing
@test ci.max_world == typemax(UInt)
@test Base.module_build_id(TestAbsIntPrecompile2) ==
Base.object_build_id(ci)
- @test_skip begin
- ci = ci.next
- @test !isdefined(ci, :next)
+ ci = check_presence(mi, cache_owner)
+ @test ci !== nothing
@test ci.owner === cache_owner
@test ci.max_world == typemax(UInt)
- @test Base.module_build_id(TestAbsIntPrecompile2) ==
- Base.object_build_id(ci)
- end
+ @test Base.module_build_id(TestAbsIntPrecompile2) == Base.object_build_id(ci)
end
let m = only(methods(sum, (Vector{Float64},)))
- found = false
for mi = Base.specializations(m)
if mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(sum),Vector{Float64}}
- ci = mi.cache
- @test_broken isdefined(ci, :next)
- @test_broken ci.owner === cache_owner
- @test_skip begin
- @test ci.max_world == typemax(UInt)
- @test Base.module_build_id(TestAbsIntPrecompile2) ==
- Base.object_build_id(ci)
- ci = ci.next
- end
- @test !isdefined(ci, :next)
+ ci = check_presence(mi, nothing)
+ @test ci !== nothing
@test ci.owner === nothing
@test ci.max_world == typemax(UInt)
- @test Base.module_build_id(TestAbsIntPrecompile2) ==
- Base.object_build_id(ci)
- found = true
- break
+ @test Base.module_build_id(TestAbsIntPrecompile2) == Base.object_build_id(ci)
+ ci = check_presence(mi, cache_owner)
+ @test ci !== nothing
+ @test ci.owner === cache_owner
+ @test ci.max_world == typemax(UInt)
+ @test Base.module_build_id(TestAbsIntPrecompile2) == Base.object_build_id(ci)
end
end
- @test found
end
end
end
diff --git a/test/precompile_utils.jl b/test/precompile_utils.jl
index c9a7c98d262e0..685161e98840f 100644
--- a/test/precompile_utils.jl
+++ b/test/precompile_utils.jl
@@ -29,3 +29,14 @@ let original_depot_path = copy(Base.DEPOT_PATH)
append!(Base.LOAD_PATH, original_load_path)
end
end
+
+function check_presence(mi, token)
+ ci = isdefined(mi, :cache) ? mi.cache : nothing
+ while ci !== nothing
+ if ci.owner === token && ci.max_world == typemax(UInt)
+ return ci
+ end
+ ci = isdefined(ci, :next) ? ci.next : nothing
+ end
+ return nothing
+end
diff --git a/test/scopedvalues.jl b/test/scopedvalues.jl
index e9b36d80fc2c4..500b9647f8da6 100644
--- a/test/scopedvalues.jl
+++ b/test/scopedvalues.jl
@@ -195,3 +195,74 @@ nothrow_scope()
push!(ts, 2)
end
end
+
+# LazyScopedValue
+global lsv_ncalled = 0
+const lsv = LazyScopedValue{Int}(OncePerProcess(() -> (global lsv_ncalled; lsv_ncalled += 1; 1)))
+@testset "LazyScopedValue" begin
+ @test (@with lsv=>2 lsv[]) == 2
+ @test lsv_ncalled == 0
+ @test lsv[] == 1
+ @test lsv_ncalled == 1
+ @test lsv[] == 1
+ @test lsv_ncalled == 1
+end
+
+@testset "ScopedThunk" begin
+ function check_svals()
+ @test sval[] == 8
+ @test sval_float[] == 8.0
+ end
+ sf = nothing
+ @with sval=>8 sval_float=>8.0 begin
+ sf = ScopedThunk(check_svals)
+ end
+ sf()
+ @with sval=>8 sval_float=>8.0 begin
+ sf2 = ScopedThunk{Function}(check_svals)
+ end
+ sf2()
+end
+
+using Base.ScopedValues: ScopedValue, with
+@noinline function test_59483()
+ sv = ScopedValue([])
+ ch = Channel{Bool}()
+
+ # Spawn a child task, which inherits the parent's Scope
+ @noinline function inner_function()
+ # Block until the parent task has left the scope.
+ take!(ch)
+ # Now, per issue 59483, this task's scope is not rooted, except by the task itself.
+
+ # Now switch to an inner scope, leaving the current scope possibly unrooted.
+ val = with(sv=>Any[2]) do
+ # Inside this new scope, when we perform GC, the parent scope can be freed.
+ # The fix for this issue made sure that the first scope in this task remains
+ # rooted.
+ GC.gc()
+ GC.gc()
+ sv[]
+ end
+ @test val == Any[2]
+ # Finally, we've returned to the original scope, but that could be a dangling
+ # pointer if the scope itself was freed by the above GCs. So these GCs could crash:
+ GC.gc()
+ GC.gc()
+ end
+ @noinline function spawn_inner()
+ # Set a new Scope in the parent task - this is the scope that could be freed.
+ with(sv=>Any[1]) do
+ return @async inner_function()
+ end
+ end
+
+ # RUN THE TEST:
+ t = spawn_inner()
+ # Exit the scope, and let the child task proceed
+ put!(ch, true)
+ wait(t)
+end
+@testset "issue 59483" begin
+ test_59483()
+end
diff --git a/test/syntax.jl b/test/syntax.jl
index 70640e6c93d67..b2d7ebfa96f98 100644
--- a/test/syntax.jl
+++ b/test/syntax.jl
@@ -3659,7 +3659,7 @@ end
@test p("public() = 6") == Expr(:(=), Expr(:call, :public), Expr(:block, 6))
end
-@testset "removing argument sideeffects" begin
+@testset "removing argument side effects" begin
# Allow let blocks in broadcasted LHSes, but only evaluate them once:
execs = 0
array = [1]
@@ -3675,6 +3675,15 @@ end
let; execs += 1; array; end::Vector{Int} .= 7
@test array == [7]
@test execs == 4
+
+ # remove argument side effects on lhs kwcall
+ pa_execs = 0
+ kw_execs = 0
+ f60152(v, pa; kw) = copy(v)
+ @test (f60152([1, 2, 3], 0; kw=0) .*= 2) == [2,4,6]
+ @test (f60152([1, 2, 3], (pa_execs+=1); kw=(kw_execs+=1)) .*= 2) == [2,4,6]
+ @test pa_execs === 1
+ @test kw_execs === 1
end
# Allow GlobalRefs in macro definition
diff --git a/test/sysinfo.jl b/test/sysinfo.jl
index f02d8ffe36091..a2af4cd0f5260 100644
--- a/test/sysinfo.jl
+++ b/test/sysinfo.jl
@@ -65,9 +65,7 @@ end
Base.Sys.CPUinfo("Apple M1 Pro", 2400, 0x00000000026784da, 0x0000000000000000, 0x0000000000fda30e, 0x0000000046a731ea, 0x0000000000000000)
Base.Sys.CPUinfo("Apple M1 Pro", 2400, 0x00000000017726c0, 0x0000000000000000, 0x00000000009491de, 0x0000000048134f1e, 0x0000000000000000)]
- Sys.SC_CLK_TCK, save_SC_CLK_TCK = 100, Sys.SC_CLK_TCK # use platform-independent tick units
@test repr(example_cpus[1]) == "Base.Sys.CPUinfo(\"Apple M1 Pro\", 2400, 0x000000000d913b08, 0x0000000000000000, 0x0000000005f4243c, 0x00000000352a550a, 0x0000000000000000)"
- @test repr("text/plain", example_cpus[1]) == "Apple M1 Pro: \n speed user nice sys idle irq\n 2400 MHz 2276216 s 0 s 998861 s 8919667 s 0 s"
- @test sprint(Sys.cpu_summary, example_cpus) == "Apple M1 Pro: \n speed user nice sys idle irq\n#1 2400 MHz 2276216 s 0 s 998861 s 8919667 s 0 s\n#2 2400 MHz 2275576 s 0 s 978101 s 8962204 s 0 s\n#3 2400 MHz 403386 s 0 s 166224 s 11853624 s 0 s\n#4 2400 MHz 245859 s 0 s 97367 s 12092250 s 0 s\n"
- Sys.SC_CLK_TCK = save_SC_CLK_TCK
+ @test repr("text/plain", example_cpus[1]) == "Apple M1 Pro: \n speed user nice sys idle irq\n 2400 MHz 227622 s 0 s 99886 s 891967 s 0 s "
+ @test sprint(Sys.cpu_summary, example_cpus) == "Apple M1 Pro: \n speed user nice sys idle irq\n#1 2400 MHz 227622 s 0 s 99886 s 891967 s 0 s \n#2 2400 MHz 227558 s 0 s 97810 s 896220 s 0 s \n#3 2400 MHz 40339 s 0 s 16622 s 1185362 s 0 s \n#4 2400 MHz 24586 s 0 s 9737 s 1209225 s 0 s \n"
end