Skip to content

Backports for 1.12.0-beta2 #58009

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 38 commits into from
Apr 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
2d27adc
`append_c_digits`: typeassert `Int` to improve inference (#57950)
nsajko Apr 1, 2025
6182de7
fix generated_body_to_codeinfo to avoid `string` (which is not always…
vtjnash Apr 4, 2025
787d934
fix `nextpow`, `prevpow` for types without `typemax` (#49669)
nsajko Apr 4, 2025
1e436b1
Backport #57423 to v1.12 (#58004)
Heptazhou Apr 5, 2025
fd213c3
🤖 [backports-release-1.12] Bump the LinearAlgebra stdlib from f0f7a46…
DilumAluthgeBot Apr 7, 2025
956422e
inference: re-enable inference overload for basic statements (#58027)
aviatesk Apr 8, 2025
af93514
Add matches for invoke invalidations (#57999)
timholy Apr 4, 2025
a210129
Logging: Improve threadsafety (#57591)
IanButterworth Apr 4, 2025
a7762c6
Add missing PARTITION_KIND_CONST_IMPORT case to print_partition (#58006)
xal-0 Apr 4, 2025
3582d8a
Avoid most boxes in precompilation code (#57986)
KristofferC Apr 7, 2025
4f6fbd6
inference: simplify `abstract_eval_globalref` (#58026)
aviatesk Apr 9, 2025
f9f5f6e
typeintersect: fix triangular vars handling outside constructor (#58018)
N5N3 Apr 6, 2025
fe36e65
deps: Update MPFR to v4.2.2 (#58039)
inkydragon Apr 10, 2025
ebdb9c0
Remove try-finally scope from `@time_imports` `@trace_compile` `@trac…
IanButterworth Apr 10, 2025
a7e9899
fix #58013, error for too few arguments in `invokelatest` (#58056)
JeffBezanson Apr 10, 2025
c4b6798
fix zero-dimensional `reverse!` (#58086)
nsajko Apr 13, 2025
2decc57
Fix `--project=@script` when outside script directory (#56351)
awadell1 Apr 15, 2025
65657d1
prevent allocation of Memory (layout and object) when not concrete (#…
vtjnash Apr 15, 2025
e0a1611
much faster code-coverage for packages (#57988)
vtjnash Apr 15, 2025
e207cf4
Fix `IOBuffer` `skip` regression (#57963)
nhz2 Apr 15, 2025
d3a569d
[DOC] Update installation docs: /downloads/ => /install/ (#58127)
StefanKarpinski Apr 15, 2025
9d454dc
Ensure completion of invalidation log (#58137)
timholy Apr 16, 2025
640c4e1
Scheduler: Use a "scheduler" task for thread sleep (#57544)
kpamnany Mar 27, 2025
a5bbb91
fix trimming for scheduler task (#57926)
JeffBezanson Mar 31, 2025
b3e1a0c
batch some binding changes (#57765)
vtjnash Apr 1, 2025
980347d
Merge adjacent implicit binding partitions (#57995)
Keno Apr 4, 2025
bba8a82
inference: minor refactoring on abstractinterpretation.jl (#58154)
aviatesk Apr 18, 2025
1515913
fix static show in some edge cases (#58128)
vtjnash Apr 16, 2025
bcb103a
Fix `jl_set_precompile_field_replace` for 0-size fields (#58155)
topolarity Apr 19, 2025
66a3cc9
Switch from segfault to `zip` behavior for mismatched indices in `map…
adienes Apr 19, 2025
f1517b4
subtype: save some union stack space for ∃ free cases. (#58159)
N5N3 Apr 20, 2025
ea25e2a
inference: allow specialization of `scan_specified_partitions` (#58165)
aviatesk Apr 20, 2025
43c784b
gf: make dispatch heuristic representation explicit (#58167)
vtjnash Apr 21, 2025
408e1da
fix performance regression introduced by #58027 (#58184)
aviatesk Apr 22, 2025
8d69739
add showing a string to REPL precompile workload (#58157)
KristofferC Apr 22, 2025
d9da421
JuliaSyntax parser-based REPL completions overhaul (#57767)
xal-0 Apr 22, 2025
44f35d9
Workaround StyledStrings type-piracy (#58112)
tecosaur Apr 22, 2025
debca00
staticdata: remove `reinit_ccallable`
aviatesk Jan 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
280 changes: 161 additions & 119 deletions Compiler/src/abstractinterpretation.jl

Large diffs are not rendered by default.

24 changes: 13 additions & 11 deletions Compiler/src/inferencestate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -575,21 +575,23 @@ function (::ComputeTryCatch{Handler})(code::Vector{Any}, bbs::Union{Vector{Basic
end

# check if coverage mode is enabled
function should_insert_coverage(mod::Module, debuginfo::DebugInfo)
coverage_enabled(mod) && return true
JLOptions().code_coverage == 3 || return false
should_insert_coverage(mod::Module, debuginfo::DebugInfo) = should_instrument(mod, debuginfo, true)

function should_instrument(mod::Module, debuginfo::DebugInfo, only_if_affects_optimizer::Bool=false)
instrumentation_enabled(mod, only_if_affects_optimizer) && return true
JLOptions().code_coverage == 3 || JLOptions().malloc_log == 3 || return false
# path-specific coverage mode: if any line falls in a tracked file enable coverage for all
return _should_insert_coverage(debuginfo)
return _should_instrument(debuginfo)
end

_should_insert_coverage(mod::Symbol) = is_file_tracked(mod)
_should_insert_coverage(mod::Method) = _should_insert_coverage(mod.file)
_should_insert_coverage(mod::MethodInstance) = _should_insert_coverage(mod.def)
_should_insert_coverage(mod::Module) = false
function _should_insert_coverage(info::DebugInfo)
_should_instrument(loc::Symbol) = is_file_tracked(loc)
_should_instrument(loc::Method) = _should_instrument(loc.file)
_should_instrument(loc::MethodInstance) = _should_instrument(loc.def)
_should_instrument(loc::Module) = false
function _should_instrument(info::DebugInfo)
linetable = info.linetable
linetable === nothing || (_should_insert_coverage(linetable) && return true)
_should_insert_coverage(info.def) && return true
linetable === nothing || (_should_instrument(linetable) && return true)
_should_instrument(info.def) && return true
return false
end

Expand Down
13 changes: 12 additions & 1 deletion Compiler/src/utilities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ end

inlining_enabled() = (JLOptions().can_inline == 1)

function coverage_enabled(m::Module)
function instrumentation_enabled(m::Module, only_if_affects_optimizer::Bool)
generating_output() && return false # don't alter caches
cov = JLOptions().code_coverage
if cov == 1 # user
Expand All @@ -340,6 +340,17 @@ function coverage_enabled(m::Module)
elseif cov == 2 # all
return true
end
if !only_if_affects_optimizer
log = JLOptions().malloc_log
if log == 1 # user
m = moduleroot(m)
m === Core && return false
isdefined(Main, :Base) && m === Main.Base && return false
return true
elseif log == 2 # all
return true
end
end
return false
end

Expand Down
22 changes: 18 additions & 4 deletions Compiler/test/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6160,14 +6160,28 @@ end === Int
swapglobal!(@__MODULE__, :swapglobal!_xxx, x)
end === Union{}

@newinterp AssumeBindingsStaticInterp
Compiler.InferenceParams(::AssumeBindingsStaticInterp) = Compiler.InferenceParams(; assume_bindings_static=true)

eval(Expr(:const, :swapglobal!_must_throw))
@newinterp SwapGlobalInterp
Compiler.InferenceParams(::SwapGlobalInterp) = Compiler.InferenceParams(; assume_bindings_static=true)
function func_swapglobal!_must_throw(x)
swapglobal!(@__MODULE__, :swapglobal!_must_throw, x)
end
@test Base.infer_return_type(func_swapglobal!_must_throw, (Int,); interp=SwapGlobalInterp()) === Union{}
@test !Compiler.is_effect_free(Base.infer_effects(func_swapglobal!_must_throw, (Int,); interp=SwapGlobalInterp()) )
@test Base.infer_return_type(func_swapglobal!_must_throw, (Int,); interp=AssumeBindingsStaticInterp()) === Union{}
@test !Compiler.is_effect_free(Base.infer_effects(func_swapglobal!_must_throw, (Int,); interp=AssumeBindingsStaticInterp()) )

global global_decl_defined
global_decl_defined = 42
@test Base.infer_effects(; interp=AssumeBindingsStaticInterp()) do
global global_decl_defined
return global_decl_defined
end |> Compiler.is_nothrow
global global_decl_defined2::Int
global_decl_defined2 = 42
@test Base.infer_effects(; interp=AssumeBindingsStaticInterp()) do
global global_decl_defined2
return global_decl_defined2
end |> Compiler.is_nothrow

@eval get_exception() = $(Expr(:the_exception))
@test Base.infer_return_type() do
Expand Down
2 changes: 1 addition & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ New library functions
* The new `isfull(c::Channel)` function can be used to check if `put!(c, some_value)` will block ([#53159]).
* `waitany(tasks; throw=false)` and `waitall(tasks; failfast=false, throw=false)` which wait for multiple tasks
at once ([#53341]).
* `uuid7()` creates an RFC 9652 compliant UUID with version 7 ([#54834]).
* `uuid7()` creates an RFC 9562 compliant UUID with version 7 ([#54834]).
* `insertdims(array; dims)` inserts singleton dimensions into an array --- the inverse operation of
`dropdims` ([#45793]).
* A new `Fix` type generalizes `Fix1/Fix2` for fixing a single argument ([#54653]).
Expand Down
29 changes: 17 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ and installing Julia, below.
## Resources

- **Homepage:** <https://julialang.org>
- **Binaries:** <https://julialang.org/downloads/>
- **Install:** <https://julialang.org/install/>
- **Source code:** <https://github.com/JuliaLang/julia>
- **Documentation:** <https://docs.julialang.org>
- **Packages:** <https://julialang.org/packages/>
Expand All @@ -63,17 +63,22 @@ helpful to start contributing to the Julia codebase.

## Binary Installation

If you would rather not compile the latest Julia from source,
platform-specific tarballs with pre-compiled binaries are also
[available for download](https://julialang.org/downloads/). The
downloads page also provides details on the
[different tiers of support](https://julialang.org/downloads/#supported_platforms)
for OS and platform combinations.

If everything works correctly, you will see a Julia banner and an
interactive prompt into which you can enter expressions for
evaluation. You can read about [getting
started](https://docs.julialang.org/en/v1/manual/getting-started/) in the manual.
The recommended way of installing Julia is to use `juliaup` which will install
the latest stable `julia` for you and help keep it up to date. It can also let
you install and run different Julia versions simultaneously. Instructions for
this can be find [here](https://julialang.org/install/). If you want to manually
download specific Julia binaries, you can find those on the [downloads
page](https://julialang.org/downloads/). The downloads page also provides
details on the [different tiers of
support](https://julialang.org/downloads/#supported_platforms) for OS and
platform combinations.

If everything works correctly, you will get a `julia` program and when you run
it in a terminal or command prompt, you will see a Julia banner and an
interactive prompt into which you can enter expressions for evaluation. You can
read about [getting
started](https://docs.julialang.org/en/v1/manual/getting-started/) in the
manual.

**Note**: Although some OS package managers provide Julia, such
installations are neither maintained nor endorsed by the Julia
Expand Down
51 changes: 28 additions & 23 deletions base/Base_compiler.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

baremodule Base
module Base

using Core
using Core.Intrinsics, Core.IR
using .Core.Intrinsics, .Core.IR

# to start, we're going to use a very simple definition of `include`
# that doesn't require any function (except what we can get from the `Core` top-module)
Expand Down Expand Up @@ -158,6 +157,31 @@ if false
println(io::IO, x...) = Core.println(io, x...)
end

## Load essential files and libraries
include("essentials.jl")

# Because lowering inserts direct references, it is mandatory for this binding
# to exist before we start inferring code.
function string end
import Core: String

# For OS specific stuff
# We need to strcat things here, before strings are really defined
function strcat(x::String, y::String)
out = ccall(:jl_alloc_string, Ref{String}, (Int,), Core.sizeof(x) + Core.sizeof(y))
gc_x = @_gc_preserve_begin(x)
gc_y = @_gc_preserve_begin(y)
gc_out = @_gc_preserve_begin(out)
out_ptr = unsafe_convert(Ptr{UInt8}, out)
unsafe_copyto!(out_ptr, unsafe_convert(Ptr{UInt8}, x), Core.sizeof(x))
unsafe_copyto!(out_ptr + Core.sizeof(x), unsafe_convert(Ptr{UInt8}, y), Core.sizeof(y))
@_gc_preserve_end(gc_x)
@_gc_preserve_end(gc_y)
@_gc_preserve_end(gc_out)
return out
end


"""
time_ns() -> UInt64

Expand All @@ -172,8 +196,6 @@ const _DOCS_ALIASING_WARNING = """
Behavior can be unexpected when any mutated argument shares memory with any other argument.
"""

## Load essential files and libraries
include("essentials.jl")
include("ctypes.jl")
include("gcutils.jl")
include("generator.jl")
Expand Down Expand Up @@ -284,7 +306,6 @@ include("rounding.jl")
include("float.jl")

# Lazy strings
import Core: String
include("strings/lazy.jl")

function cld end
Expand Down Expand Up @@ -321,22 +342,6 @@ using .Order
include("coreir.jl")
include("invalidation.jl")

# Because lowering inserts direct references, it is mandatory for this binding
# to exist before we start inferring code.
function string end

# For OS specific stuff
# We need to strcat things here, before strings are really defined
function strcat(x::String, y::String)
out = ccall(:jl_alloc_string, Ref{String}, (Csize_t,), Core.sizeof(x) + Core.sizeof(y))
GC.@preserve x y out begin
out_ptr = unsafe_convert(Ptr{UInt8}, out)
unsafe_copyto!(out_ptr, unsafe_convert(Ptr{UInt8}, x), Core.sizeof(x))
unsafe_copyto!(out_ptr + Core.sizeof(x), unsafe_convert(Ptr{UInt8}, y), Core.sizeof(y))
end
return out
end

BUILDROOT::String = ""
DATAROOT::String = ""
const DL_LOAD_PATH = String[]
Expand Down Expand Up @@ -375,5 +380,5 @@ Core._setparser!(fl_parse)

# Further definition of Base will happen in Base.jl if loaded.

end # baremodule Base
end # module Base
using .Base
19 changes: 13 additions & 6 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3412,12 +3412,19 @@ function ith_all(i, as)
end

function map_n!(f::F, dest::AbstractArray, As) where F
idxs1 = LinearIndices(As[1])
@boundscheck LinearIndices(dest) == idxs1 && all(x -> LinearIndices(x) == idxs1, As)
for i = idxs1
@inbounds I = ith_all(i, As)
val = f(I...)
@inbounds dest[i] = val
idxs = LinearIndices(dest)
if all(x -> LinearIndices(x) == idxs, As)
for i in idxs
@inbounds as = ith_all(i, As)
val = f(as...)
@inbounds dest[i] = val
end
else
for (i, Is...) in zip(eachindex(dest), map(eachindex, As)...)
as = ntuple(j->getindex(As[j], Is[j]), length(As))
val = f(as...)
dest[i] = val
end
end
return dest
end
Expand Down
2 changes: 1 addition & 1 deletion base/arraymath.jl
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,12 @@ _reverse!(A::AbstractArray{<:Any,N}, ::Colon) where {N} = _reverse!(A, ntuple(id
_reverse!(A, dim::Integer) = _reverse!(A, (Int(dim),))
_reverse!(A, dims::NTuple{M,Integer}) where {M} = _reverse!(A, Int.(dims))
function _reverse!(A::AbstractArray{<:Any,N}, dims::NTuple{M,Int}) where {N,M}
dims === () && return A # nothing to reverse
dimrev = ntuple(k -> k in dims, Val{N}()) # boolean tuple indicating reversed dims

if N < M || M != sum(dimrev)
throw(ArgumentError("invalid dimensions $dims in reverse!"))
end
M == 0 && return A # nothing to reverse

# swapping loop only needs to traverse ≈half of the array
halfsz = ntuple(k -> k == dims[1] ? size(A,k) ÷ 2 : size(A,k), Val{N}())
Expand Down
2 changes: 2 additions & 0 deletions base/essentials.jl
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,8 @@ cconvert(::Type{<:Ptr}, x) = x # but defer the conversion to Ptr to unsafe_conve
unsafe_convert(::Type{T}, x::T) where {T} = x # unsafe_convert (like convert) defaults to assuming the convert occurred
unsafe_convert(::Type{T}, x::T) where {T<:Ptr} = x # to resolve ambiguity with the next method
unsafe_convert(::Type{P}, x::Ptr) where {P<:Ptr} = convert(P, x)
unsafe_convert(::Type{Ptr{UInt8}}, s::String) = ccall(:jl_string_ptr, Ptr{UInt8}, (Any,), s)
unsafe_convert(::Type{Ptr{Int8}}, s::String) = ccall(:jl_string_ptr, Ptr{Int8}, (Any,), s)

"""
reinterpret(::Type{Out}, x::In)
Expand Down
3 changes: 2 additions & 1 deletion base/expr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1664,7 +1664,8 @@ function generated_body_to_codeinfo(ex::Expr, defmod::Module, isva::Bool)
ci = ccall(:jl_expand, Any, (Any, Any), ex, defmod)
if !isa(ci, CodeInfo)
if isa(ci, Expr) && ci.head === :error
error("syntax: $(ci.args[1])")
msg = ci.args[1]
error(msg isa String ? strcat("syntax: ", msg) : msg)
end
error("The function body AST defined by this @generated function is not pure. This likely means it contains a closure, a comprehension or a generator.")
end
Expand Down
24 changes: 8 additions & 16 deletions base/initdefs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -284,22 +284,14 @@ function load_path_expand(env::AbstractString)::Union{String, Nothing}
env == "@temp" && return mktempdir()
env == "@stdlib" && return Sys.STDLIB
if startswith(env, "@script")
if @isdefined(PROGRAM_FILE)
dir = dirname(PROGRAM_FILE)
else
cmds = unsafe_load_commands(JLOptions().commands)
if any(cmd::Pair{Char, String}->cmd_suppresses_program(first(cmd)), cmds)
# Usage error. The user did not pass a script.
return nothing
end
dir = dirname(ARGS[1])
end
if env == "@script" # complete match, not startswith, so search upwards
return current_project(dir)
else
# starts with, so assume relative path is after
return abspath(replace(env, "@script" => dir))
end
program_file = JLOptions().program_file
program_file = program_file != C_NULL ? unsafe_string(program_file) : nothing
isnothing(program_file) && return nothing # User did not pass a script

# Expand trailing relative path
dir = dirname(program_file)
dir = env != "@script" ? (dir * env[length("@script")+1:end]) : dir
return current_project(dir)
end
env = replace(env, '#' => VERSION.major, count=1)
env = replace(env, '#' => VERSION.minor, count=1)
Expand Down
10 changes: 6 additions & 4 deletions base/intfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,8 @@ function nextpow(a::Real, x::Real)
n = ceil(Integer,log(a, x))
# round-off error of log can go either direction, so need some checks
p = a^(n-1)
x > typemax(p) && throw(DomainError(x,"argument is beyond the range of type of the base"))
hastypemax(typeof(p)) && x > typemax(p) &&
throw(DomainError(x,"argument is beyond the range of type of the base"))
p >= x && return p
wp = a^n
wp > p || throw(OverflowError("result is beyond the range of type of the base"))
Expand Down Expand Up @@ -611,9 +612,10 @@ function prevpow(a::T, x::Real) where T <: Real
n = floor(Integer,log(a, x))
# round-off error of log can go either direction, so need some checks
p = a^n
x > typemax(p) && throw(DomainError(x,"argument is beyond the range of type of the base"))
hastypemax(typeof(p)) && x > typemax(p) &&
throw(DomainError(x,"argument is beyond the range of type of the base"))
if a isa Integer
wp, overflow = mul_with_overflow(a, p)
wp, overflow = mul_with_overflow(promote(a, p)...)
wp <= x && !overflow && return wp
else
wp = a^(n+1)
Expand Down Expand Up @@ -845,7 +847,7 @@ function append_c_digits(olength::Int, digits::Unsigned, buf, pos::Int)
while i >= 2
d, c = divrem(digits, 0x64)
digits = oftype(digits, d)
@inbounds d100 = _dec_d100[(c % Int) + 1]
@inbounds d100 = _dec_d100[(c % Int)::Int + 1]
@inbounds buf[pos + i - 2] = d100 % UInt8
@inbounds buf[pos + i - 1] = (d100 >> 0x8) % UInt8
i -= 2
Expand Down
6 changes: 3 additions & 3 deletions base/invalidation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,12 @@ function invalidate_code_for_globalref!(b::Core.Binding, invalidated_bpart::Core
(_, (ib, ibpart)) = Compiler.walk_binding_partition(b, invalidated_bpart, new_max_world)
(_, (nb, nbpart)) = Compiler.walk_binding_partition(b, new_bpart, new_max_world+1)

# abstract_eval_globalref_partition is the maximum amount of information that inference
# `abstract_eval_partition_load` is the maximum amount of information that inference
# reads from a binding partition. If this information does not change - we do not need to
# invalidate any code that inference created, because we know that the result will not change.
need_to_invalidate_code =
Compiler.abstract_eval_globalref_partition(nothing, ib, ibpart) !==
Compiler.abstract_eval_globalref_partition(nothing, nb, nbpart)
Compiler.abstract_eval_partition_load(nothing, ib, ibpart) !==
Compiler.abstract_eval_partition_load(nothing, nb, nbpart)

need_to_invalidate_export = export_affecting_partition_flags(invalidated_bpart) !==
export_affecting_partition_flags(new_bpart)
Expand Down
4 changes: 2 additions & 2 deletions base/iobuffer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -486,8 +486,8 @@ function skip(io::GenericIOBuffer, n::Int)
else
# Don't use seek in order to allow a non-seekable IO to still skip bytes.
# Handle overflow.
maxptr = io.size + 1
io.ptr = n > maxptr || io.ptr - n > maxptr ? maxptr : io.ptr + n
n_max = io.size + 1 - io.ptr
io.ptr += min(n, n_max)
io
end
end
Expand Down
Loading