Skip to content

Commit 18f42dc

Browse files
authored
Backports for 1.12.0-rc2 (#59110)
2 parents 6134d9a + 54ccaad commit 18f42dc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+585
-195
lines changed

Compiler/src/abstractinterpretation.jl

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ function find_union_split_method_matches(interp::AbstractInterpreter, argtypes::
369369
end
370370
valid_worlds = intersect(valid_worlds, thismatches.valid_worlds)
371371
thisfullmatch = any(match::MethodMatch->match.fully_covers, thismatches)
372-
mt = Core.GlobalMethods
372+
mt = Core.methodtable
373373
thisinfo = MethodMatchInfo(thismatches, mt, sig_n, thisfullmatch)
374374
push!(infos, thisinfo)
375375
for idx = 1:length(thismatches)
@@ -390,7 +390,7 @@ function find_simple_method_matches(interp::AbstractInterpreter, @nospecialize(a
390390
return FailedMethodMatch("Too many methods matched")
391391
end
392392
fullmatch = any(match::MethodMatch->match.fully_covers, matches)
393-
mt = Core.GlobalMethods
393+
mt = Core.methodtable
394394
info = MethodMatchInfo(matches, mt, atype, fullmatch)
395395
applicable = MethodMatchTarget[MethodMatchTarget(matches[idx], info.edges, idx) for idx = 1:length(matches)]
396396
return MethodMatches(applicable, info, matches.valid_worlds)
@@ -3214,7 +3214,7 @@ function abstract_eval_copyast(interp::AbstractInterpreter, e::Expr, sstate::Sta
32143214
return RTEffects(rt, Any, effects)
32153215
end
32163216

3217-
function abstract_eval_isdefined_expr(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
3217+
function abstract_eval_isdefined_expr(::AbstractInterpreter, e::Expr, sstate::StatementState,
32183218
sv::AbsIntState)
32193219
sym = e.args[1]
32203220
if isa(sym, SlotNumber) && sstate.vtypes !== nothing
@@ -3444,7 +3444,59 @@ function refine_partial_type(@nospecialize t)
34443444
return t
34453445
end
34463446

3447+
abstract_eval_nonlinearized_foreigncall_name(interp::AbstractInterpreter, e, sstate::StatementState, sv::IRInterpretationState) = nothing
3448+
3449+
function abstract_eval_nonlinearized_foreigncall_name(interp::AbstractInterpreter, e, sstate::StatementState, sv::AbsIntState)
3450+
if isexpr(e, :call)
3451+
n = length(e.args)
3452+
argtypes = Vector{Any}(undef, n)
3453+
callresult = Future{CallMeta}()
3454+
i::Int = 1
3455+
nextstate::UInt8 = 0x0
3456+
local ai, res
3457+
function evalargs(interp, sv)
3458+
if nextstate === 0x1
3459+
@goto state1
3460+
elseif nextstate === 0x2
3461+
@goto state2
3462+
end
3463+
while i <= n
3464+
ai = abstract_eval_nonlinearized_foreigncall_name(interp, e.args[i], sstate, sv)
3465+
if !isready(ai)
3466+
nextstate = 0x1
3467+
return false
3468+
@label state1
3469+
end
3470+
argtypes[i] = ai[].rt
3471+
i += 1
3472+
end
3473+
res = abstract_call(interp, ArgInfo(e.args, argtypes), sstate, sv)
3474+
if !isready(res)
3475+
nextstate = 0x2
3476+
return false
3477+
@label state2
3478+
end
3479+
callresult[] = res[]
3480+
return true
3481+
end
3482+
evalargs(interp, sv) || push!(sv.tasks, evalargs)
3483+
return callresult
3484+
else
3485+
return Future(abstract_eval_basic_statement(interp, e, sstate, sv))
3486+
end
3487+
end
3488+
34473489
function abstract_eval_foreigncall(interp::AbstractInterpreter, e::Expr, sstate::StatementState, sv::AbsIntState)
3490+
callee = e.args[1]
3491+
if isexpr(callee, :call) && length(callee.args) > 1 && callee.args[1] == GlobalRef(Core, :tuple)
3492+
# NOTE these expressions are not properly linearized
3493+
abstract_eval_nonlinearized_foreigncall_name(interp, callee.args[2], sstate, sv)
3494+
if length(callee.args) > 2
3495+
abstract_eval_nonlinearized_foreigncall_name(interp, callee.args[3], sstate, sv)
3496+
end
3497+
else
3498+
abstract_eval_value(interp, callee, sstate, sv)
3499+
end
34483500
mi = frame_instance(sv)
34493501
t = sp_type_rewrap(e.args[2], mi, true)
34503502
for i = 3:length(e.args)

Compiler/src/stmtinfo.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,14 @@ function _add_edges_impl(edges::Vector{Any}, info::MethodMatchInfo, mi_edge::Boo
4949
if !fully_covering(info)
5050
exists = false
5151
for i in 2:length(edges)
52-
if edges[i] === Core.GlobalMethods && edges[i-1] == info.atype
52+
if edges[i] === Core.methodtable && edges[i-1] == info.atype
5353
exists = true
5454
break
5555
end
5656
end
5757
if !exists
5858
push!(edges, info.atype)
59-
push!(edges, Core.GlobalMethods)
59+
push!(edges, Core.methodtable)
6060
end
6161
end
6262
nmatches = length(info.results)

Compiler/src/tfuncs.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3170,7 +3170,7 @@ function _hasmethod_tfunc(interp::AbstractInterpreter, argtypes::Vector{Any}, sv
31703170
if match === nothing
31713171
rt = Const(false)
31723172
vresults = MethodLookupResult(Any[], valid_worlds, true)
3173-
mt = Core.GlobalMethods
3173+
mt = Core.methodtable
31743174
vinfo = MethodMatchInfo(vresults, mt, types, false) # XXX: this should actually be an info with invoke-type edge
31753175
else
31763176
rt = Const(true)

Compiler/src/typelattice.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ struct Conditional
4040
isdefined::Bool=false)
4141
assert_nested_slotwrapper(thentype)
4242
assert_nested_slotwrapper(elsetype)
43+
if thentype isa LimitedAccuracy || elsetype isa LimitedAccuracy
44+
return Bool
45+
end
4346
return new(slot, thentype, elsetype, isdefined)
4447
end
4548
end
@@ -83,6 +86,9 @@ struct MustAlias
8386
assert_nested_slotwrapper(fldtyp)
8487
# @assert !isalreadyconst(vartyp) "vartyp is already const"
8588
# @assert !isalreadyconst(fldtyp) "fldtyp is already const"
89+
if vartyp isa LimitedAccuracy || fldtyp isa LimitedAccuracy
90+
return fldtyp
91+
end
8692
return new(slot, vartyp, fldidx, fldtyp)
8793
end
8894
end
@@ -104,6 +110,9 @@ struct InterMustAlias
104110
assert_nested_slotwrapper(fldtyp)
105111
# @assert !isalreadyconst(vartyp) "vartyp is already const"
106112
# @assert !isalreadyconst(fldtyp) "fldtyp is already const"
113+
if vartyp isa LimitedAccuracy || fldtyp isa LimitedAccuracy
114+
return fldtyp
115+
end
107116
return new(slot, vartyp, fldidx, fldtyp)
108117
end
109118
end

NEWS.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,6 @@ New language features
3333
Language changes
3434
----------------
3535

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

84+
* Julia now defaults to 1 "interactive" thread, in addition to the 1 default "worker" thread. i.e. `-t1,1`.
85+
This means in default configuration the main task and repl (when in interactive mode), which both run on
86+
thread 1, now run within the `interactive` threadpool. The libuv IO loop also runs on thread 1,
87+
helping efficient utilization of the worker threadpool used by `Threads.@spawn`. Asking for specifically 1 thread
88+
(`-t1`/`JULIA_NUM_THREADS=1`) or `0` interactive threads will disable the interactive thread i.e. `-t1,0` or `JULIA_NUM_THREADS=1,0`
89+
, or `-tauto,0` etc. Asking for more than 1 thread will enable the interactive thread so
90+
`-t2` will set the equivalent of `-t2,1`. As a reminder, buffers
91+
[should not be managed based on `threadid()`](https://docs.julialang.org/en/v1/manual/multi-threading/#Using-@threads-without-data-races) ([#57087]).
9192
* New types are defined to handle the pattern of code that must run once per process, called
9293
a `OncePerProcess{T}` type, which allows defining a function that should be run exactly once
9394
the first time it is called, and then always return the same result value of type `T`

base/error.jl

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -233,14 +233,12 @@ macro assert(ex, msgs...)
233233
msg = msg # pass-through
234234
elseif !isempty(msgs) && (isa(msg, Expr) || isa(msg, Symbol))
235235
# message is an expression needing evaluating
236-
# N.B. To reduce the risk of invalidation caused by the complex callstack involved
237-
# with `string`, use `inferencebarrier` here to hide this `string` from the compiler.
238-
msg = :(Main.Base.inferencebarrier(Main.Base.string)($(esc(msg))))
236+
msg = :($_assert_tostring($(esc(msg))))
239237
elseif isdefined(Main, :Base) && isdefined(Main.Base, :string) && applicable(Main.Base.string, msg)
240238
msg = Main.Base.string(msg)
241239
else
242240
# string() might not be defined during bootstrap
243-
msg = :(_assert_tostring($(Expr(:quote,msg))))
241+
msg = :($_assert_tostring($(Expr(:quote,msg))))
244242
end
245243
return :($(esc(ex)) ? $(nothing) : throw(AssertionError($msg)))
246244
end

base/initdefs.jl

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -494,10 +494,13 @@ end
494494
## hook for disabling threaded libraries ##
495495

496496
library_threading_enabled::Bool = true
497-
const disable_library_threading_hooks = []
497+
498+
# Base.OncePerProcess ensures that any registered hooks do not outlive the session.
499+
# (even if they are registered during the sysimage build process by top-level code)
500+
const disable_library_threading_hooks = Base.OncePerProcess(Vector{Any})
498501

499502
function at_disable_library_threading(f)
500-
push!(disable_library_threading_hooks, f)
503+
push!(disable_library_threading_hooks(), f)
501504
if !library_threading_enabled
502505
disable_library_threading()
503506
end
@@ -506,8 +509,8 @@ end
506509

507510
function disable_library_threading()
508511
global library_threading_enabled = false
509-
while !isempty(disable_library_threading_hooks)
510-
f = pop!(disable_library_threading_hooks)
512+
while !isempty(disable_library_threading_hooks())
513+
f = pop!(disable_library_threading_hooks())
511514
try
512515
f()
513516
catch err

base/int.jl

Lines changed: 158 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -845,14 +845,166 @@ widemul(x::Bool,y::Number) = x * y
845845
widemul(x::Number,y::Bool) = x * y
846846

847847

848-
# Int128 multiply and divide
849-
*(x::T, y::T) where {T<:Union{Int128,UInt128}} = mul_int(x, y)
848+
## wide multiplication, Int128 multiply and divide ##
849+
850+
if Core.sizeof(Int) == 4
851+
function widemul(u::Int64, v::Int64)
852+
local u0::UInt64, v0::UInt64, w0::UInt64
853+
local u1::Int64, v1::Int64, w1::UInt64, w2::Int64, t::UInt64
854+
855+
u0 = u & 0xffffffff; u1 = u >> 32
856+
v0 = v & 0xffffffff; v1 = v >> 32
857+
w0 = u0 * v0
858+
t = reinterpret(UInt64, u1) * v0 + (w0 >>> 32)
859+
w2 = reinterpret(Int64, t) >> 32
860+
w1 = u0 * reinterpret(UInt64, v1) + (t & 0xffffffff)
861+
hi = u1 * v1 + w2 + (reinterpret(Int64, w1) >> 32)
862+
lo = w0 & 0xffffffff + (w1 << 32)
863+
return Int128(hi) << 64 + Int128(lo)
864+
end
865+
866+
function widemul(u::UInt64, v::UInt64)
867+
local u0::UInt64, v0::UInt64, w0::UInt64
868+
local u1::UInt64, v1::UInt64, w1::UInt64, w2::UInt64, t::UInt64
869+
870+
u0 = u & 0xffffffff; u1 = u >>> 32
871+
v0 = v & 0xffffffff; v1 = v >>> 32
872+
w0 = u0 * v0
873+
t = u1 * v0 + (w0 >>> 32)
874+
w2 = t >>> 32
875+
w1 = u0 * v1 + (t & 0xffffffff)
876+
hi = u1 * v1 + w2 + (w1 >>> 32)
877+
lo = w0 & 0xffffffff + (w1 << 32)
878+
return UInt128(hi) << 64 + UInt128(lo)
879+
end
880+
881+
function *(u::Int128, v::Int128)
882+
u0 = u % UInt64; u1 = Int64(u >> 64)
883+
v0 = v % UInt64; v1 = Int64(v >> 64)
884+
lolo = widemul(u0, v0)
885+
lohi = widemul(reinterpret(Int64, u0), v1)
886+
hilo = widemul(u1, reinterpret(Int64, v0))
887+
t = reinterpret(UInt128, hilo) + (lolo >>> 64)
888+
w1 = reinterpret(UInt128, lohi) + (t & 0xffffffffffffffff)
889+
return Int128(lolo & 0xffffffffffffffff) + reinterpret(Int128, w1) << 64
890+
end
891+
892+
function *(u::UInt128, v::UInt128)
893+
u0 = u % UInt64; u1 = UInt64(u>>>64)
894+
v0 = v % UInt64; v1 = UInt64(v>>>64)
895+
lolo = widemul(u0, v0)
896+
lohi = widemul(u0, v1)
897+
hilo = widemul(u1, v0)
898+
t = hilo + (lolo >>> 64)
899+
w1 = lohi + (t & 0xffffffffffffffff)
900+
return (lolo & 0xffffffffffffffff) + UInt128(w1) << 64
901+
end
902+
903+
function _setbit(x::UInt128, i)
904+
# faster version of `return x | (UInt128(1) << i)`
905+
j = i >> 5
906+
y = UInt128(one(UInt32) << (i & 0x1f))
907+
if j == 0
908+
return x | y
909+
elseif j == 1
910+
return x | (y << 32)
911+
elseif j == 2
912+
return x | (y << 64)
913+
elseif j == 3
914+
return x | (y << 96)
915+
end
916+
return x
917+
end
850918

851-
div(x::Int128, y::Int128) = checked_sdiv_int(x, y)
852-
div(x::UInt128, y::UInt128) = checked_udiv_int(x, y)
919+
function divrem(x::UInt128, y::UInt128)
920+
iszero(y) && throw(DivideError())
921+
if (x >> 64) % UInt64 == 0
922+
if (y >> 64) % UInt64 == 0
923+
# fast path: upper 64 bits are zero, so we can fallback to UInt64 division
924+
q64, x64 = divrem(x % UInt64, y % UInt64)
925+
return UInt128(q64), UInt128(x64)
926+
else
927+
# this implies y>x, so
928+
return zero(UInt128), x
929+
end
930+
end
931+
n = leading_zeros(y) - leading_zeros(x)
932+
q = zero(UInt128)
933+
ys = y << n
934+
while n >= 0
935+
# ys == y * 2^n
936+
if ys <= x
937+
x -= ys
938+
q = _setbit(q, n)
939+
if (x >> 64) % UInt64 == 0
940+
# exit early, similar to above fast path
941+
if (y >> 64) % UInt64 == 0
942+
q64, x64 = divrem(x % UInt64, y % UInt64)
943+
q |= q64
944+
x = UInt128(x64)
945+
end
946+
return q, x
947+
end
948+
end
949+
ys >>>= 1
950+
n -= 1
951+
end
952+
return q, x
953+
end
853954

854-
rem(x::Int128, y::Int128) = checked_srem_int(x, y)
855-
rem(x::UInt128, y::UInt128) = checked_urem_int(x, y)
955+
function div(x::Int128, y::Int128)
956+
(x == typemin(Int128)) & (y == -1) && throw(DivideError())
957+
return Int128(div(BigInt(x), BigInt(y)))::Int128
958+
end
959+
div(x::UInt128, y::UInt128) = divrem(x, y)[1]
960+
961+
function rem(x::Int128, y::Int128)
962+
return Int128(rem(BigInt(x), BigInt(y)))::Int128
963+
end
964+
965+
function rem(x::UInt128, y::UInt128)
966+
iszero(y) && throw(DivideError())
967+
if (x >> 64) % UInt64 == 0
968+
if (y >> 64) % UInt64 == 0
969+
# fast path: upper 64 bits are zero, so we can fallback to UInt64 division
970+
return UInt128(rem(x % UInt64, y % UInt64))
971+
else
972+
# this implies y>x, so
973+
return x
974+
end
975+
end
976+
n = leading_zeros(y) - leading_zeros(x)
977+
ys = y << n
978+
while n >= 0
979+
# ys == y * 2^n
980+
if ys <= x
981+
x -= ys
982+
if (x >> 64) % UInt64 == 0
983+
# exit early, similar to above fast path
984+
if (y >> 64) % UInt64 == 0
985+
x = UInt128(rem(x % UInt64, y % UInt64))
986+
end
987+
return x
988+
end
989+
end
990+
ys >>>= 1
991+
n -= 1
992+
end
993+
return x
994+
end
995+
996+
function mod(x::Int128, y::Int128)
997+
return Int128(mod(BigInt(x), BigInt(y)))::Int128
998+
end
999+
else
1000+
*(x::T, y::T) where {T<:Union{Int128,UInt128}} = mul_int(x, y)
1001+
1002+
div(x::Int128, y::Int128) = checked_sdiv_int(x, y)
1003+
div(x::UInt128, y::UInt128) = checked_udiv_int(x, y)
1004+
1005+
rem(x::Int128, y::Int128) = checked_srem_int(x, y)
1006+
rem(x::UInt128, y::UInt128) = checked_urem_int(x, y)
1007+
end
8561008

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

0 commit comments

Comments
 (0)