Skip to content

Commit d3df0d6

Browse files
authored
Backports for 1.12.0-rc3 (#59624)
2 parents a4940e7 + ad32b08 commit d3df0d6

File tree

29 files changed

+264
-78
lines changed

29 files changed

+264
-78
lines changed

Compiler/src/ssair/passes.jl

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -872,14 +872,15 @@ function perform_lifting!(compact::IncrementalCompact,
872872
return Pair{Any, PhiNest}(stmt_val, PhiNest(visited_philikes, lifted_philikes, lifted_leaves, reverse_mapping, walker_callback))
873873
end
874874

875-
function lift_apply_args!(compact::IncrementalCompact, idx::Int, stmt::Expr, 𝕃ₒ::AbstractLattice)
876-
# Handle _apply_iterate calls: convert arguments to use `Core.svec`. The behavior of Core.svec (with boxing) better matches the ABI of codegen.
875+
# Handle _apply_iterate calls: convert arguments to use `Core.svec`.
876+
# The behavior of `Core.svec` (with boxing) better matches the ABI of codegen.
877+
function lift_apply_args!(compact::IncrementalCompact, idx::Int, stmt::Expr)
877878
compact[idx] = nothing
878-
for i in 4:length(stmt.args) # Skip iterate function, f, and first iterator
879+
for i in 4:length(stmt.args) # Skip `_apply_iterate`, `iterate`, and the function
879880
arg = stmt.args[i]
880-
arg_type = argextype(arg, compact)
881-
svec_args = nothing
881+
arg_type = widenconst(argextype(arg, compact))
882882
if isa(arg_type, DataType) && arg_type.name === Tuple.name
883+
svec_args = nothing
883884
if isa(arg, SSAValue)
884885
arg_stmt = compact[arg][:stmt]
885886
if is_known_call(arg_stmt, Core.tuple, compact)
@@ -900,15 +901,14 @@ function lift_apply_args!(compact::IncrementalCompact, idx::Int, stmt::Expr,
900901
end
901902
end
902903
end
903-
end
904-
# Create Core.svec call if we have arguments
905-
if svec_args !== nothing
906-
svec_args[1] = GlobalRef(Core, :svec)
907-
new_svec_call = Expr(:call)
908-
new_svec_call.args = svec_args
909-
inst = compact[SSAValue(idx)]
910-
new_svec_ssa = insert_node!(compact, SSAValue(idx), NewInstruction(new_svec_call, SimpleVector, NoCallInfo(), inst[:line], inst[:flag]))
911-
stmt.args[i] = new_svec_ssa
904+
if svec_args !== nothing
905+
svec_args[1] = GlobalRef(Core, :svec)
906+
new_svec_call = Expr(:call)
907+
new_svec_call.args = svec_args
908+
inst = compact[SSAValue(idx)]
909+
new_svec_ssa = insert_node!(compact, SSAValue(idx), NewInstruction(new_svec_call, SimpleVector, NoCallInfo(), inst[:line], inst[:flag]))
910+
stmt.args[i] = new_svec_ssa
911+
end
912912
end
913913
end
914914
compact[idx] = stmt
@@ -1420,7 +1420,7 @@ function sroa_pass!(ir::IRCode, inlining::Union{Nothing,InliningState}=nothing)
14201420
refine_new_effects!(𝕃ₒ, compact, idx, stmt)
14211421
elseif is_known_call(stmt, Core._apply_iterate, compact)
14221422
length(stmt.args) >= 4 || continue
1423-
lift_apply_args!(compact, idx, stmt, 𝕃ₒ)
1423+
lift_apply_args!(compact, idx, stmt)
14241424
end
14251425
continue
14261426
end

Compiler/test/irpasses.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2045,3 +2045,17 @@ let src = code_typed1(()) do
20452045
end
20462046
@test count(iscall((src, setfield!)), src.code) == 1
20472047
end
2048+
2049+
# JuliaLang/julia #59548
2050+
# Rewrite `Core._apply_iterate` to use `Core.svec` instead of `tuple` to better match
2051+
# the codegen ABI
2052+
let src = code_typed1((Vector{Any},)) do xs
2053+
println(stdout, xs...)
2054+
end
2055+
@test count(iscall((src, Core.svec)), src.code) == 1
2056+
end
2057+
let src = code_typed1((Vector{Any},)) do xs
2058+
println(stdout, 1, xs...) # convert tuples represented by `PartialStruct`
2059+
end
2060+
@test count(iscall((src, Core.svec)), src.code) == 1
2061+
end

base/client.jl

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -267,10 +267,6 @@ function exec_options(opts)
267267
interactiveinput = (repl || is_interactive::Bool) && isa(stdin, TTY)
268268
is_interactive::Bool |= interactiveinput
269269

270-
# load terminfo in for styled printing
271-
term_env = get(ENV, "TERM", @static Sys.iswindows() ? "" : "dumb")
272-
global current_terminfo = load_terminfo(term_env)
273-
274270
# load ~/.julia/config/startup.jl file
275271
if startup
276272
try

base/lock.jl

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -767,7 +767,7 @@ end
767767

768768

769769
# share a lock/condition, since we just need it briefly, so some contention is okay
770-
const PerThreadLock = ThreadSynchronizer()
770+
const PerThreadLock = Threads.SpinLock()
771771
"""
772772
OncePerThread{T}(init::Function)() -> T
773773
@@ -871,7 +871,15 @@ OncePerThread(initializer) = OncePerThread{Base.promote_op(initializer), typeof(
871871
state = @atomic :monotonic ss[tid]
872872
while state == PerStateConcurrent
873873
# lost race, wait for notification this is done running elsewhere
874-
wait(PerThreadLock) # wait for initializer to finish without releasing this thread
874+
# without releasing this thread
875+
unlock(PerThreadLock)
876+
while state == PerStateConcurrent
877+
# spin loop until ready
878+
ss = @atomic :acquire once.ss
879+
state = @atomic :monotonic ss[tid]
880+
GC.safepoint()
881+
end
882+
lock(PerThreadLock)
875883
ss = @atomic :monotonic once.ss
876884
state = @atomic :monotonic ss[tid]
877885
end
@@ -885,7 +893,6 @@ OncePerThread(initializer) = OncePerThread{Base.promote_op(initializer), typeof(
885893
lock(PerThreadLock)
886894
ss = @atomic :monotonic once.ss
887895
@atomic :release ss[tid] = PerStateErrored
888-
notify(PerThreadLock)
889896
rethrow()
890897
end
891898
# store result and notify waiters
@@ -894,7 +901,6 @@ OncePerThread(initializer) = OncePerThread{Base.promote_op(initializer), typeof(
894901
@atomic :release xs[tid] = result
895902
ss = @atomic :monotonic once.ss
896903
@atomic :release ss[tid] = PerStateHasrun
897-
notify(PerThreadLock)
898904
elseif state == PerStateErrored
899905
error("OncePerThread initializer failed previously")
900906
elseif state != PerStateHasrun

base/reduce.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ Like [`mapreduce`](@ref), but with guaranteed right associativity, as in [`foldr
212212
provided, the keyword argument `init` will be used exactly once. In general, it will be
213213
necessary to provide `init` to work with empty collections.
214214
"""
215-
mapfoldr(f, op, itr; init=_InitialValue()) = mapfoldr_impl(f, op, init, itr)
215+
mapfoldr(f::F, op::F2, itr; init=_InitialValue()) where {F,F2} = mapfoldr_impl(f, op, init, itr)
216216

217217

218218
"""
@@ -231,7 +231,7 @@ julia> foldr(=>, 1:4; init=0)
231231
1 => (2 => (3 => (4 => 0)))
232232
```
233233
"""
234-
foldr(op, itr; kw...) = mapfoldr(identity, op, itr; kw...)
234+
foldr(op::F, itr; kw...) where {F} = mapfoldr(identity, op, itr; kw...)
235235

236236
## reduce & mapreduce
237237

base/strings/annotated_io.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ function _insert_annotations!(io::AnnotatedIOBuffer, annotations::Vector{RegionA
200200
end
201201
end
202202

203+
function printstyled end
204+
203205
# NOTE: This is an interim solution to the invalidations caused
204206
# by the split styled display implementation. This should be
205207
# replaced by a more robust solution (such as a consolidation of
@@ -250,6 +252,14 @@ Base.print(io::AnnotatedIOBuffer, s::Union{<:AnnotatedString, SubString{<:Annota
250252
Base.print(io::AnnotatedIOBuffer, c::AnnotatedChar) =
251253
(write(io, c); nothing)
252254

255+
styled_print(io::AnnotatedIOBuffer, msg::Any, kwargs::Any) = print(io, msg...)
256+
257+
styled_print_(io::AnnotatedIOBuffer, @nospecialize(msg), @nospecialize(kwargs)) =
258+
invoke_in_world(tls_world_age(), styled_print, io, msg, kwargs)::Nothing
259+
260+
Base.printstyled(io::AnnotatedIOBuffer, msg...; kwargs...) =
261+
styled_print_(io, msg, kwargs)
262+
253263
# Escape
254264

255265
Base.escape_string(io::IO, s::Union{<:AnnotatedString, SubString{<:AnnotatedString}},

base/terminfo.jl

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -303,16 +303,24 @@ end
303303
"""
304304
The terminfo of the current terminal.
305305
"""
306-
current_terminfo::TermInfo = TermInfo()
306+
const current_terminfo = OncePerProcess{TermInfo}() do
307+
term_env = get(ENV, "TERM", @static Sys.iswindows() ? "" : "dumb")
308+
terminfo = load_terminfo(term_env)
309+
# Ensure setaf is set for xterm terminals
310+
if !haskey(terminfo, :setaf) && startswith(term_env, "xterm")
311+
# For xterm-like terminals without setaf, add a reasonable default
312+
terminfo.strings[:setaf] = "\e[3%p1%dm"
313+
end
314+
return terminfo
315+
end
307316

308317
# Legacy/TTY methods and the `:color` parameter
309318

310319
if Sys.iswindows()
311-
ttyhascolor(term_type = nothing) = true
320+
ttyhascolor() = true
312321
else
313-
function ttyhascolor(term_type = get(ENV, "TERM", ""))
314-
startswith(term_type, "xterm") ||
315-
haskey(current_terminfo, :setaf)
322+
function ttyhascolor()
323+
haskey(current_terminfo(), :setaf)
316324
end
317325
end
318326

@@ -352,9 +360,9 @@ Multiple conditions are taken as signifying truecolor support, specifically any
352360
function ttyhastruecolor()
353361
# Lasciate ogne speranza, voi ch'intrate
354362
get(ENV, "COLORTERM", "") ("truecolor", "24bit") ||
355-
get(current_terminfo, :RGB, false) || get(current_terminfo, :Tc, false) ||
356-
(haskey(current_terminfo, :setrgbf) && haskey(current_terminfo, :setrgbb)) ||
357-
@static if Sys.isunix() get(current_terminfo, :colors, 0) > 256 else false end ||
363+
get(current_terminfo(), :RGB, false) || get(current_terminfo(), :Tc, false) ||
364+
(haskey(current_terminfo(), :setrgbf) && haskey(current_terminfo(), :setrgbb)) ||
365+
@static if Sys.isunix() get(current_terminfo(), :colors, 0) > 256 else false end ||
358366
(Sys.iswindows() && Sys.windows_version() v"10.0.14931") || # See <https://devblogs.microsoft.com/commandline/24-bit-color-in-the-windows-console/>
359367
something(tryparse(Int, get(ENV, "VTE_VERSION", "")), 0) >= 3600 || # Per GNOME bug #685759 <https://bugzilla.gnome.org/show_bug.cgi?id=685759>
360368
haskey(ENV, "XTERM_VERSION") ||

base/timing.jl

Lines changed: 61 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -472,41 +472,93 @@ function gc_bytes()
472472
b[]
473473
end
474474

475-
function allocated(f, args::Vararg{Any,N}) where {N}
475+
@constprop :none function allocated(f, args::Vararg{Any,N}) where {N}
476476
b0 = Ref{Int64}(0)
477477
b1 = Ref{Int64}(0)
478478
Base.gc_bytes(b0)
479-
f(args...)
479+
@noinline f(args...)
480480
Base.gc_bytes(b1)
481481
return b1[] - b0[]
482482
end
483483
only(methods(allocated)).called = 0xff
484484

485-
function allocations(f, args::Vararg{Any,N}) where {N}
485+
@constprop :none function allocations(f, args::Vararg{Any,N}) where {N}
486486
stats = Base.gc_num()
487-
f(args...)
487+
@noinline f(args...)
488488
diff = Base.GC_Diff(Base.gc_num(), stats)
489489
return Base.gc_alloc_count(diff)
490490
end
491491
only(methods(allocations)).called = 0xff
492492

493493
function is_simply_call(@nospecialize ex)
494+
is_simple_atom(a) = a isa QuoteNode || a isa Symbol || is_self_quoting(a)
494495
Meta.isexpr(ex, :call) || return false
495496
for a in ex.args
496-
a isa QuoteNode && continue
497-
a isa Symbol && continue
498-
Base.is_self_quoting(a) && continue
497+
is_simple_atom(a) && continue
498+
Meta.isexpr(a, :..., 1) && is_simple_atom(a.args[1]) && continue
499499
return false
500500
end
501501
return true
502502
end
503503

504+
function _gen_allocation_measurer(ex, fname::Symbol)
505+
if isexpr(ex, :call)
506+
if !is_simply_call(ex)
507+
ex = :((() -> $ex)())
508+
end
509+
pushfirst!(ex.args, GlobalRef(Base, fname))
510+
return quote
511+
Experimental.@force_compile
512+
$(esc(ex))
513+
end
514+
elseif fname === :allocated
515+
# v1.11-compatible implementation
516+
return quote
517+
Experimental.@force_compile
518+
local b0 = Ref{Int64}(0)
519+
local b1 = Ref{Int64}(0)
520+
gc_bytes(b0)
521+
$(esc(ex))
522+
gc_bytes(b1)
523+
b1[] - b0[]
524+
end
525+
else
526+
@assert fname === :allocations
527+
return quote
528+
Experimental.@force_compile
529+
# Note this value is unused, but without it `allocated` and `allocations`
530+
# are sufficiently different that the compiler can remove allocations here
531+
# that it cannot remove there, giving inconsistent numbers.
532+
local b1 = Ref{Int64}(0)
533+
local stats = Base.gc_num()
534+
$(esc(ex))
535+
local diff = Base.GC_Diff(Base.gc_num(), stats)
536+
gc_bytes(b1)
537+
Base.gc_alloc_count(diff)
538+
end
539+
end
540+
end
541+
504542
"""
505543
@allocated
506544
507545
A macro to evaluate an expression, discarding the resulting value, instead returning the
508546
total number of bytes allocated during evaluation of the expression.
509547
548+
If the expression is a function call, an effort is made to measure only allocations from
549+
the argument expressions and during the function, excluding any overhead from calling it
550+
and not performing constant propagation with the provided argument values. If you want to
551+
include those effects, i.e. measuring the call site as well, use the syntax
552+
`@allocated (()->f(1))()`.
553+
554+
It is recommended to measure function calls with only simple argument expressions, e.g.
555+
`x = []; @allocated f(x)` instead of `@allocated f([])` to clarify that only `f` is
556+
being measured.
557+
558+
For more complex expressions, the code is simply run in place and therefore may see
559+
allocations due to the surrounding context. For example it is possible for
560+
`@allocated f(1)` and `@allocated x = f(1)` to give different results.
561+
510562
See also [`@allocations`](@ref), [`@time`](@ref), [`@timev`](@ref), [`@timed`](@ref),
511563
and [`@elapsed`](@ref).
512564
@@ -516,11 +568,7 @@ julia> @allocated rand(10^6)
516568
```
517569
"""
518570
macro allocated(ex)
519-
if !is_simply_call(ex)
520-
ex = :((() -> $ex)())
521-
end
522-
pushfirst!(ex.args, GlobalRef(Base, :allocated))
523-
return esc(ex)
571+
_gen_allocation_measurer(ex, :allocated)
524572
end
525573

526574
"""
@@ -541,11 +589,7 @@ julia> @allocations rand(10^6)
541589
This macro was added in Julia 1.9.
542590
"""
543591
macro allocations(ex)
544-
if !is_simply_call(ex)
545-
ex = :((() -> $ex)())
546-
end
547-
pushfirst!(ex.args, GlobalRef(Base, :allocations))
548-
return esc(ex)
592+
_gen_allocation_measurer(ex, :allocations)
549593
end
550594

551595

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
93162fc479ba1762028ef917176f45e0
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
d6c421048e52d5cf32848cf7a16db1ac269f2c553672b0f1126230a7f5954adb6f2883982efe747bd91fa8135071e1b2f717a12ceb1631c1c7effbf6cece8f4c

0 commit comments

Comments
 (0)