Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e20b41b
add array element mutex offset in print and gc (#58997)
vtjnash Jul 26, 2025
a602e1a
update libblastrampoline_jll to fix julia compat
IanButterworth Jul 29, 2025
19f000f
REPL: improve type inference for `maybe_spawn_cache_PATH` (#59144)
aviatesk Jul 30, 2025
56be12b
iterator: improve type inference for `Filter` (#59142)
aviatesk Jul 30, 2025
962ca50
inference: avoid `LimitedAccuracy` within slot wrappers (#59182)
aviatesk Aug 1, 2025
3d15583
Revert "remove hand-coded methods for (U)Int128 on 32 bit systems (#5…
topolarity Aug 5, 2025
dcdbcfb
Add builtin function name to add methods error (#59112)
IanButterworth Jul 28, 2025
a966982
Fix memory order typo in "src/julia_atomics.h" (#59120)
omus Jul 29, 2025
50f37a5
fix serializer compat with CodeInfos from v1.11 (#58650)
JeffBezanson Jul 29, 2025
59e17ed
misc: Don't get confused by GC running during compilation (#59163)
Keno Jul 31, 2025
3cab711
Clarify and enhance confusing precompile test (#59170)
IanButterworth Jul 31, 2025
e5faf18
Fix desugaring of `const x::T = y` for complex `y` (#59155)
mlechu Aug 1, 2025
4723ce5
rename `GlobalMethods` to `methodtable` :bike: :house: (#59158)
JeffBezanson Aug 1, 2025
c638304
Export jl_declare_constant_val (#59192)
Taaitaaiger Aug 2, 2025
41aa62e
model ccall binding access in inference (#58872)
JeffBezanson Aug 4, 2025
4d38189
move threading news to threading section. Add reminder about threadid
IanButterworth Aug 11, 2025
7f40cfe
fix runtime cglobal builtin function implementation (#59210)
vtjnash Aug 6, 2025
7216482
Fix compile time regression for null ptr comparisons (#59259)
gbaraldi Aug 12, 2025
7cd4fff
make compile go faster with native caches (#57500)
vtjnash Feb 24, 2025
f41f678
fix #59252, make `args` in juliac like it is elsewhere (#59279)
JeffBezanson Aug 15, 2025
97ead58
Use Zlib instead of zstd
gbaraldi Aug 18, 2025
975aa9e
juliac: apply `buildscript` modifications after user code (#59297)
topolarity Aug 18, 2025
a2b0e15
Add `_assert_to_string` indirection for `Expr`-evaluated `@assert` (#…
topolarity Aug 18, 2025
7831da6
Fix printing of errors in juliac + searchsorted functions for LinearA…
gbaraldi Aug 18, 2025
54ccaad
Make `Base.disable_library_threading_hooks` ephemeral to the process …
topolarity Aug 18, 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
58 changes: 55 additions & 3 deletions Compiler/src/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ function find_union_split_method_matches(interp::AbstractInterpreter, argtypes::
end
valid_worlds = intersect(valid_worlds, thismatches.valid_worlds)
thisfullmatch = any(match::MethodMatch->match.fully_covers, thismatches)
mt = Core.GlobalMethods
mt = Core.methodtable
thisinfo = MethodMatchInfo(thismatches, mt, sig_n, thisfullmatch)
push!(infos, thisinfo)
for idx = 1:length(thismatches)
Expand All @@ -390,7 +390,7 @@ function find_simple_method_matches(interp::AbstractInterpreter, @nospecialize(a
return FailedMethodMatch("Too many methods matched")
end
fullmatch = any(match::MethodMatch->match.fully_covers, matches)
mt = Core.GlobalMethods
mt = Core.methodtable
info = MethodMatchInfo(matches, mt, atype, fullmatch)
applicable = MethodMatchTarget[MethodMatchTarget(matches[idx], info.edges, idx) for idx = 1:length(matches)]
return MethodMatches(applicable, info, matches.valid_worlds)
Expand Down Expand Up @@ -3214,7 +3214,7 @@ function abstract_eval_copyast(interp::AbstractInterpreter, e::Expr, sstate::Sta
return RTEffects(rt, Any, effects)
end

function abstract_eval_isdefined_expr(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
function abstract_eval_isdefined_expr(::AbstractInterpreter, e::Expr, sstate::StatementState,
sv::AbsIntState)
sym = e.args[1]
if isa(sym, SlotNumber) && sstate.vtypes !== nothing
Expand Down Expand Up @@ -3444,7 +3444,59 @@ function refine_partial_type(@nospecialize t)
return t
end

abstract_eval_nonlinearized_foreigncall_name(interp::AbstractInterpreter, e, sstate::StatementState, sv::IRInterpretationState) = nothing

function abstract_eval_nonlinearized_foreigncall_name(interp::AbstractInterpreter, e, sstate::StatementState, sv::AbsIntState)
if isexpr(e, :call)
n = length(e.args)
argtypes = Vector{Any}(undef, n)
callresult = Future{CallMeta}()
i::Int = 1
nextstate::UInt8 = 0x0
local ai, res
function evalargs(interp, sv)
if nextstate === 0x1
@goto state1
elseif nextstate === 0x2
@goto state2
end
while i <= n
ai = abstract_eval_nonlinearized_foreigncall_name(interp, e.args[i], sstate, sv)
if !isready(ai)
nextstate = 0x1
return false
@label state1
end
argtypes[i] = ai[].rt
i += 1
end
res = abstract_call(interp, ArgInfo(e.args, argtypes), sstate, sv)
if !isready(res)
nextstate = 0x2
return false
@label state2
end
callresult[] = res[]
return true
end
evalargs(interp, sv) || push!(sv.tasks, evalargs)
return callresult
else
return Future(abstract_eval_basic_statement(interp, e, sstate, sv))
end
end

function abstract_eval_foreigncall(interp::AbstractInterpreter, e::Expr, sstate::StatementState, sv::AbsIntState)
callee = e.args[1]
if isexpr(callee, :call) && length(callee.args) > 1 && callee.args[1] == GlobalRef(Core, :tuple)
# NOTE these expressions are not properly linearized
abstract_eval_nonlinearized_foreigncall_name(interp, callee.args[2], sstate, sv)
if length(callee.args) > 2
abstract_eval_nonlinearized_foreigncall_name(interp, callee.args[3], sstate, sv)
end
else
abstract_eval_value(interp, callee, sstate, sv)
end
mi = frame_instance(sv)
t = sp_type_rewrap(e.args[2], mi, true)
for i = 3:length(e.args)
Expand Down
4 changes: 2 additions & 2 deletions Compiler/src/stmtinfo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ function _add_edges_impl(edges::Vector{Any}, info::MethodMatchInfo, mi_edge::Boo
if !fully_covering(info)
exists = false
for i in 2:length(edges)
if edges[i] === Core.GlobalMethods && edges[i-1] == info.atype
if edges[i] === Core.methodtable && edges[i-1] == info.atype
exists = true
break
end
end
if !exists
push!(edges, info.atype)
push!(edges, Core.GlobalMethods)
push!(edges, Core.methodtable)
end
end
nmatches = length(info.results)
Expand Down
2 changes: 1 addition & 1 deletion Compiler/src/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3170,7 +3170,7 @@ function _hasmethod_tfunc(interp::AbstractInterpreter, argtypes::Vector{Any}, sv
if match === nothing
rt = Const(false)
vresults = MethodLookupResult(Any[], valid_worlds, true)
mt = Core.GlobalMethods
mt = Core.methodtable
vinfo = MethodMatchInfo(vresults, mt, types, false) # XXX: this should actually be an info with invoke-type edge
else
rt = Const(true)
Expand Down
9 changes: 9 additions & 0 deletions Compiler/src/typelattice.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ struct Conditional
isdefined::Bool=false)
assert_nested_slotwrapper(thentype)
assert_nested_slotwrapper(elsetype)
if thentype isa LimitedAccuracy || elsetype isa LimitedAccuracy
return Bool
end
return new(slot, thentype, elsetype, isdefined)
end
end
Expand Down Expand Up @@ -83,6 +86,9 @@ struct MustAlias
assert_nested_slotwrapper(fldtyp)
# @assert !isalreadyconst(vartyp) "vartyp is already const"
# @assert !isalreadyconst(fldtyp) "fldtyp is already const"
if vartyp isa LimitedAccuracy || fldtyp isa LimitedAccuracy
return fldtyp
end
return new(slot, vartyp, fldidx, fldtyp)
end
end
Expand All @@ -104,6 +110,9 @@ struct InterMustAlias
assert_nested_slotwrapper(fldtyp)
# @assert !isalreadyconst(vartyp) "vartyp is already const"
# @assert !isalreadyconst(fldtyp) "fldtyp is already const"
if vartyp isa LimitedAccuracy || fldtyp isa LimitedAccuracy
return fldtyp
end
return new(slot, vartyp, fldidx, fldtyp)
end
end
Expand Down
15 changes: 8 additions & 7 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,6 @@ New language features
Language changes
----------------

* Julia now defaults to 1 "interactive" thread, in addition to the 1 default "worker" thread. i.e. `-t1,1`.
This means in default configuration the main task and repl (when in interactive mode), which both run on
thread 1, now run within the `interactive` threadpool. The libuv IO loop also runs on thread 1,
helping efficient utilization of the worker threadpool used by `Threads.@spawn`. Asking for specifically 1 thread
(`-t1`/`JULIA_NUM_THREADS=1`) or passing `0` will disable the interactive thread i.e. `-t1,0` or `JULIA_NUM_THREADS=1,0`
, or `-tauto,0` etc. Asking for more than 1 thread will enable the interactive thread so
`-t2` will set the equivalent of `-t2,1` ([#57087]).
* When a method is replaced with an exactly equivalent one, the old method is not deleted. Instead, the
new method takes priority and becomes more specific than the old method. Thus if the new method is deleted
later, the old method will resume operating. This can be useful in mocking frameworks (as in SparseArrays,
Expand Down Expand Up @@ -88,6 +81,14 @@ Command-line option changes
Multi-threading changes
-----------------------

* Julia now defaults to 1 "interactive" thread, in addition to the 1 default "worker" thread. i.e. `-t1,1`.
This means in default configuration the main task and repl (when in interactive mode), which both run on
thread 1, now run within the `interactive` threadpool. The libuv IO loop also runs on thread 1,
helping efficient utilization of the worker threadpool used by `Threads.@spawn`. Asking for specifically 1 thread
(`-t1`/`JULIA_NUM_THREADS=1`) or `0` interactive threads will disable the interactive thread i.e. `-t1,0` or `JULIA_NUM_THREADS=1,0`
, or `-tauto,0` etc. Asking for more than 1 thread will enable the interactive thread so
`-t2` will set the equivalent of `-t2,1`. As a reminder, buffers
[should not be managed based on `threadid()`](https://docs.julialang.org/en/v1/manual/multi-threading/#Using-@threads-without-data-races) ([#57087]).
* New types are defined to handle the pattern of code that must run once per process, called
a `OncePerProcess{T}` type, which allows defining a function that should be run exactly once
the first time it is called, and then always return the same result value of type `T`
Expand Down
6 changes: 2 additions & 4 deletions base/error.jl
Original file line number Diff line number Diff line change
Expand Up @@ -233,14 +233,12 @@ macro assert(ex, msgs...)
msg = msg # pass-through
elseif !isempty(msgs) && (isa(msg, Expr) || isa(msg, Symbol))
# message is an expression needing evaluating
# N.B. To reduce the risk of invalidation caused by the complex callstack involved
# with `string`, use `inferencebarrier` here to hide this `string` from the compiler.
msg = :(Main.Base.inferencebarrier(Main.Base.string)($(esc(msg))))
msg = :($_assert_tostring($(esc(msg))))
elseif isdefined(Main, :Base) && isdefined(Main.Base, :string) && applicable(Main.Base.string, msg)
msg = Main.Base.string(msg)
else
# string() might not be defined during bootstrap
msg = :(_assert_tostring($(Expr(:quote,msg))))
msg = :($_assert_tostring($(Expr(:quote,msg))))
end
return :($(esc(ex)) ? $(nothing) : throw(AssertionError($msg)))
end
Expand Down
11 changes: 7 additions & 4 deletions base/initdefs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -494,10 +494,13 @@ end
## hook for disabling threaded libraries ##

library_threading_enabled::Bool = true
const disable_library_threading_hooks = []

# Base.OncePerProcess ensures that any registered hooks do not outlive the session.
# (even if they are registered during the sysimage build process by top-level code)
const disable_library_threading_hooks = Base.OncePerProcess(Vector{Any})

function at_disable_library_threading(f)
push!(disable_library_threading_hooks, f)
push!(disable_library_threading_hooks(), f)
if !library_threading_enabled
disable_library_threading()
end
Expand All @@ -506,8 +509,8 @@ end

function disable_library_threading()
global library_threading_enabled = false
while !isempty(disable_library_threading_hooks)
f = pop!(disable_library_threading_hooks)
while !isempty(disable_library_threading_hooks())
f = pop!(disable_library_threading_hooks())
try
f()
catch err
Expand Down
164 changes: 158 additions & 6 deletions base/int.jl
Original file line number Diff line number Diff line change
Expand Up @@ -845,14 +845,166 @@ widemul(x::Bool,y::Number) = x * y
widemul(x::Number,y::Bool) = x * y


# Int128 multiply and divide
*(x::T, y::T) where {T<:Union{Int128,UInt128}} = mul_int(x, y)
## wide multiplication, Int128 multiply and divide ##

if Core.sizeof(Int) == 4
function widemul(u::Int64, v::Int64)
local u0::UInt64, v0::UInt64, w0::UInt64
local u1::Int64, v1::Int64, w1::UInt64, w2::Int64, t::UInt64

u0 = u & 0xffffffff; u1 = u >> 32
v0 = v & 0xffffffff; v1 = v >> 32
w0 = u0 * v0
t = reinterpret(UInt64, u1) * v0 + (w0 >>> 32)
w2 = reinterpret(Int64, t) >> 32
w1 = u0 * reinterpret(UInt64, v1) + (t & 0xffffffff)
hi = u1 * v1 + w2 + (reinterpret(Int64, w1) >> 32)
lo = w0 & 0xffffffff + (w1 << 32)
return Int128(hi) << 64 + Int128(lo)
end

function widemul(u::UInt64, v::UInt64)
local u0::UInt64, v0::UInt64, w0::UInt64
local u1::UInt64, v1::UInt64, w1::UInt64, w2::UInt64, t::UInt64

u0 = u & 0xffffffff; u1 = u >>> 32
v0 = v & 0xffffffff; v1 = v >>> 32
w0 = u0 * v0
t = u1 * v0 + (w0 >>> 32)
w2 = t >>> 32
w1 = u0 * v1 + (t & 0xffffffff)
hi = u1 * v1 + w2 + (w1 >>> 32)
lo = w0 & 0xffffffff + (w1 << 32)
return UInt128(hi) << 64 + UInt128(lo)
end

function *(u::Int128, v::Int128)
u0 = u % UInt64; u1 = Int64(u >> 64)
v0 = v % UInt64; v1 = Int64(v >> 64)
lolo = widemul(u0, v0)
lohi = widemul(reinterpret(Int64, u0), v1)
hilo = widemul(u1, reinterpret(Int64, v0))
t = reinterpret(UInt128, hilo) + (lolo >>> 64)
w1 = reinterpret(UInt128, lohi) + (t & 0xffffffffffffffff)
return Int128(lolo & 0xffffffffffffffff) + reinterpret(Int128, w1) << 64
end

function *(u::UInt128, v::UInt128)
u0 = u % UInt64; u1 = UInt64(u>>>64)
v0 = v % UInt64; v1 = UInt64(v>>>64)
lolo = widemul(u0, v0)
lohi = widemul(u0, v1)
hilo = widemul(u1, v0)
t = hilo + (lolo >>> 64)
w1 = lohi + (t & 0xffffffffffffffff)
return (lolo & 0xffffffffffffffff) + UInt128(w1) << 64
end

function _setbit(x::UInt128, i)
# faster version of `return x | (UInt128(1) << i)`
j = i >> 5
y = UInt128(one(UInt32) << (i & 0x1f))
if j == 0
return x | y
elseif j == 1
return x | (y << 32)
elseif j == 2
return x | (y << 64)
elseif j == 3
return x | (y << 96)
end
return x
end

div(x::Int128, y::Int128) = checked_sdiv_int(x, y)
div(x::UInt128, y::UInt128) = checked_udiv_int(x, y)
function divrem(x::UInt128, y::UInt128)
iszero(y) && throw(DivideError())
if (x >> 64) % UInt64 == 0
if (y >> 64) % UInt64 == 0
# fast path: upper 64 bits are zero, so we can fallback to UInt64 division
q64, x64 = divrem(x % UInt64, y % UInt64)
return UInt128(q64), UInt128(x64)
else
# this implies y>x, so
return zero(UInt128), x
end
end
n = leading_zeros(y) - leading_zeros(x)
q = zero(UInt128)
ys = y << n
while n >= 0
# ys == y * 2^n
if ys <= x
x -= ys
q = _setbit(q, n)
if (x >> 64) % UInt64 == 0
# exit early, similar to above fast path
if (y >> 64) % UInt64 == 0
q64, x64 = divrem(x % UInt64, y % UInt64)
q |= q64
x = UInt128(x64)
end
return q, x
end
end
ys >>>= 1
n -= 1
end
return q, x
end

rem(x::Int128, y::Int128) = checked_srem_int(x, y)
rem(x::UInt128, y::UInt128) = checked_urem_int(x, y)
function div(x::Int128, y::Int128)
(x == typemin(Int128)) & (y == -1) && throw(DivideError())
return Int128(div(BigInt(x), BigInt(y)))::Int128
end
div(x::UInt128, y::UInt128) = divrem(x, y)[1]

function rem(x::Int128, y::Int128)
return Int128(rem(BigInt(x), BigInt(y)))::Int128
end

function rem(x::UInt128, y::UInt128)
iszero(y) && throw(DivideError())
if (x >> 64) % UInt64 == 0
if (y >> 64) % UInt64 == 0
# fast path: upper 64 bits are zero, so we can fallback to UInt64 division
return UInt128(rem(x % UInt64, y % UInt64))
else
# this implies y>x, so
return x
end
end
n = leading_zeros(y) - leading_zeros(x)
ys = y << n
while n >= 0
# ys == y * 2^n
if ys <= x
x -= ys
if (x >> 64) % UInt64 == 0
# exit early, similar to above fast path
if (y >> 64) % UInt64 == 0
x = UInt128(rem(x % UInt64, y % UInt64))
end
return x
end
end
ys >>>= 1
n -= 1
end
return x
end

function mod(x::Int128, y::Int128)
return Int128(mod(BigInt(x), BigInt(y)))::Int128
end
else
*(x::T, y::T) where {T<:Union{Int128,UInt128}} = mul_int(x, y)

div(x::Int128, y::Int128) = checked_sdiv_int(x, y)
div(x::UInt128, y::UInt128) = checked_udiv_int(x, y)

rem(x::Int128, y::Int128) = checked_srem_int(x, y)
rem(x::UInt128, y::UInt128) = checked_urem_int(x, y)
end

# issue #15489: since integer ops are unchecked, they shouldn't check promotion
for op in (:+, :-, :*, :&, :|, :xor)
Expand Down
Loading