Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
30 changes: 15 additions & 15 deletions Compiler/src/ssair/passes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -872,14 +872,15 @@ function perform_lifting!(compact::IncrementalCompact,
return Pair{Any, PhiNest}(stmt_val, PhiNest(visited_philikes, lifted_philikes, lifted_leaves, reverse_mapping, walker_callback))
end

function lift_apply_args!(compact::IncrementalCompact, idx::Int, stmt::Expr, 𝕃ₒ::AbstractLattice)
# Handle _apply_iterate calls: convert arguments to use `Core.svec`. The behavior of Core.svec (with boxing) better matches the ABI of codegen.
# Handle _apply_iterate calls: convert arguments to use `Core.svec`.
# The behavior of `Core.svec` (with boxing) better matches the ABI of codegen.
function lift_apply_args!(compact::IncrementalCompact, idx::Int, stmt::Expr)
compact[idx] = nothing
for i in 4:length(stmt.args) # Skip iterate function, f, and first iterator
for i in 4:length(stmt.args) # Skip `_apply_iterate`, `iterate`, and the function
arg = stmt.args[i]
arg_type = argextype(arg, compact)
svec_args = nothing
arg_type = widenconst(argextype(arg, compact))
if isa(arg_type, DataType) && arg_type.name === Tuple.name
svec_args = nothing
if isa(arg, SSAValue)
arg_stmt = compact[arg][:stmt]
if is_known_call(arg_stmt, Core.tuple, compact)
Expand All @@ -900,15 +901,14 @@ function lift_apply_args!(compact::IncrementalCompact, idx::Int, stmt::Expr,
end
end
end
end
# Create Core.svec call if we have arguments
if svec_args !== nothing
svec_args[1] = GlobalRef(Core, :svec)
new_svec_call = Expr(:call)
new_svec_call.args = svec_args
inst = compact[SSAValue(idx)]
new_svec_ssa = insert_node!(compact, SSAValue(idx), NewInstruction(new_svec_call, SimpleVector, NoCallInfo(), inst[:line], inst[:flag]))
stmt.args[i] = new_svec_ssa
if svec_args !== nothing
svec_args[1] = GlobalRef(Core, :svec)
new_svec_call = Expr(:call)
new_svec_call.args = svec_args
inst = compact[SSAValue(idx)]
new_svec_ssa = insert_node!(compact, SSAValue(idx), NewInstruction(new_svec_call, SimpleVector, NoCallInfo(), inst[:line], inst[:flag]))
stmt.args[i] = new_svec_ssa
end
end
end
compact[idx] = stmt
Expand Down Expand Up @@ -1420,7 +1420,7 @@ function sroa_pass!(ir::IRCode, inlining::Union{Nothing,InliningState}=nothing)
refine_new_effects!(𝕃ₒ, compact, idx, stmt)
elseif is_known_call(stmt, Core._apply_iterate, compact)
length(stmt.args) >= 4 || continue
lift_apply_args!(compact, idx, stmt, 𝕃ₒ)
lift_apply_args!(compact, idx, stmt)
end
continue
end
Expand Down
14 changes: 14 additions & 0 deletions Compiler/test/irpasses.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2045,3 +2045,17 @@ let src = code_typed1(()) do
end
@test count(iscall((src, setfield!)), src.code) == 1
end

# JuliaLang/julia #59548
# Rewrite `Core._apply_iterate` to use `Core.svec` instead of `tuple` to better match
# the codegen ABI
let src = code_typed1((Vector{Any},)) do xs
println(stdout, xs...)
end
@test count(iscall((src, Core.svec)), src.code) == 1
end
let src = code_typed1((Vector{Any},)) do xs
println(stdout, 1, xs...) # convert tuples represented by `PartialStruct`
end
@test count(iscall((src, Core.svec)), src.code) == 1
end
4 changes: 0 additions & 4 deletions base/client.jl
Original file line number Diff line number Diff line change
Expand Up @@ -267,10 +267,6 @@ function exec_options(opts)
interactiveinput = (repl || is_interactive::Bool) && isa(stdin, TTY)
is_interactive::Bool |= interactiveinput

# load terminfo in for styled printing
term_env = get(ENV, "TERM", @static Sys.iswindows() ? "" : "dumb")
global current_terminfo = load_terminfo(term_env)

# load ~/.julia/config/startup.jl file
if startup
try
Expand Down
14 changes: 10 additions & 4 deletions base/lock.jl
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ end


# share a lock/condition, since we just need it briefly, so some contention is okay
const PerThreadLock = ThreadSynchronizer()
const PerThreadLock = Threads.SpinLock()
"""
OncePerThread{T}(init::Function)() -> T

Expand Down Expand Up @@ -871,7 +871,15 @@ OncePerThread(initializer) = OncePerThread{Base.promote_op(initializer), typeof(
state = @atomic :monotonic ss[tid]
while state == PerStateConcurrent
# lost race, wait for notification this is done running elsewhere
wait(PerThreadLock) # wait for initializer to finish without releasing this thread
# without releasing this thread
unlock(PerThreadLock)
while state == PerStateConcurrent
# spin loop until ready
ss = @atomic :acquire once.ss
state = @atomic :monotonic ss[tid]
GC.safepoint()
end
lock(PerThreadLock)
ss = @atomic :monotonic once.ss
state = @atomic :monotonic ss[tid]
end
Expand All @@ -885,7 +893,6 @@ OncePerThread(initializer) = OncePerThread{Base.promote_op(initializer), typeof(
lock(PerThreadLock)
ss = @atomic :monotonic once.ss
@atomic :release ss[tid] = PerStateErrored
notify(PerThreadLock)
rethrow()
end
# store result and notify waiters
Expand All @@ -894,7 +901,6 @@ OncePerThread(initializer) = OncePerThread{Base.promote_op(initializer), typeof(
@atomic :release xs[tid] = result
ss = @atomic :monotonic once.ss
@atomic :release ss[tid] = PerStateHasrun
notify(PerThreadLock)
elseif state == PerStateErrored
error("OncePerThread initializer failed previously")
elseif state != PerStateHasrun
Expand Down
4 changes: 2 additions & 2 deletions base/reduce.jl
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ Like [`mapreduce`](@ref), but with guaranteed right associativity, as in [`foldr
provided, the keyword argument `init` will be used exactly once. In general, it will be
necessary to provide `init` to work with empty collections.
"""
mapfoldr(f, op, itr; init=_InitialValue()) = mapfoldr_impl(f, op, init, itr)
mapfoldr(f::F, op::F2, itr; init=_InitialValue()) where {F,F2} = mapfoldr_impl(f, op, init, itr)


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

## reduce & mapreduce

Expand Down
10 changes: 10 additions & 0 deletions base/strings/annotated_io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ function _insert_annotations!(io::AnnotatedIOBuffer, annotations::Vector{RegionA
end
end

function printstyled end

# NOTE: This is an interim solution to the invalidations caused
# by the split styled display implementation. This should be
# replaced by a more robust solution (such as a consolidation of
Expand Down Expand Up @@ -250,6 +252,14 @@ Base.print(io::AnnotatedIOBuffer, s::Union{<:AnnotatedString, SubString{<:Annota
Base.print(io::AnnotatedIOBuffer, c::AnnotatedChar) =
(write(io, c); nothing)

styled_print(io::AnnotatedIOBuffer, msg::Any, kwargs::Any) = print(io, msg...)

styled_print_(io::AnnotatedIOBuffer, @nospecialize(msg), @nospecialize(kwargs)) =
invoke_in_world(tls_world_age(), styled_print, io, msg, kwargs)::Nothing

Base.printstyled(io::AnnotatedIOBuffer, msg...; kwargs...) =
styled_print_(io, msg, kwargs)

# Escape

Base.escape_string(io::IO, s::Union{<:AnnotatedString, SubString{<:AnnotatedString}},
Expand Down
24 changes: 16 additions & 8 deletions base/terminfo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -303,16 +303,24 @@ end
"""
The terminfo of the current terminal.
"""
current_terminfo::TermInfo = TermInfo()
const current_terminfo = OncePerProcess{TermInfo}() do
term_env = get(ENV, "TERM", @static Sys.iswindows() ? "" : "dumb")
terminfo = load_terminfo(term_env)
# Ensure setaf is set for xterm terminals
if !haskey(terminfo, :setaf) && startswith(term_env, "xterm")
# For xterm-like terminals without setaf, add a reasonable default
terminfo.strings[:setaf] = "\e[3%p1%dm"
end
return terminfo
end

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

if Sys.iswindows()
ttyhascolor(term_type = nothing) = true
ttyhascolor() = true
else
function ttyhascolor(term_type = get(ENV, "TERM", ""))
startswith(term_type, "xterm") ||
haskey(current_terminfo, :setaf)
function ttyhascolor()
haskey(current_terminfo(), :setaf)
end
end

Expand Down Expand Up @@ -352,9 +360,9 @@ Multiple conditions are taken as signifying truecolor support, specifically any
function ttyhastruecolor()
# Lasciate ogne speranza, voi ch'intrate
get(ENV, "COLORTERM", "") ∈ ("truecolor", "24bit") ||
get(current_terminfo, :RGB, false) || get(current_terminfo, :Tc, false) ||
(haskey(current_terminfo, :setrgbf) && haskey(current_terminfo, :setrgbb)) ||
@static if Sys.isunix() get(current_terminfo, :colors, 0) > 256 else false end ||
get(current_terminfo(), :RGB, false) || get(current_terminfo(), :Tc, false) ||
(haskey(current_terminfo(), :setrgbf) && haskey(current_terminfo(), :setrgbb)) ||
@static if Sys.isunix() get(current_terminfo(), :colors, 0) > 256 else false end ||
(Sys.iswindows() && Sys.windows_version() ≥ v"10.0.14931") || # See <https://devblogs.microsoft.com/commandline/24-bit-color-in-the-windows-console/>
something(tryparse(Int, get(ENV, "VTE_VERSION", "")), 0) >= 3600 || # Per GNOME bug #685759 <https://bugzilla.gnome.org/show_bug.cgi?id=685759>
haskey(ENV, "XTERM_VERSION") ||
Expand Down
78 changes: 61 additions & 17 deletions base/timing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -472,41 +472,93 @@ function gc_bytes()
b[]
end

function allocated(f, args::Vararg{Any,N}) where {N}
@constprop :none function allocated(f, args::Vararg{Any,N}) where {N}
b0 = Ref{Int64}(0)
b1 = Ref{Int64}(0)
Base.gc_bytes(b0)
f(args...)
@noinline f(args...)
Base.gc_bytes(b1)
return b1[] - b0[]
end
only(methods(allocated)).called = 0xff

function allocations(f, args::Vararg{Any,N}) where {N}
@constprop :none function allocations(f, args::Vararg{Any,N}) where {N}
stats = Base.gc_num()
f(args...)
@noinline f(args...)
diff = Base.GC_Diff(Base.gc_num(), stats)
return Base.gc_alloc_count(diff)
end
only(methods(allocations)).called = 0xff

function is_simply_call(@nospecialize ex)
is_simple_atom(a) = a isa QuoteNode || a isa Symbol || is_self_quoting(a)
Meta.isexpr(ex, :call) || return false
for a in ex.args
a isa QuoteNode && continue
a isa Symbol && continue
Base.is_self_quoting(a) && continue
is_simple_atom(a) && continue
Meta.isexpr(a, :..., 1) && is_simple_atom(a.args[1]) && continue
return false
end
return true
end

function _gen_allocation_measurer(ex, fname::Symbol)
if isexpr(ex, :call)
if !is_simply_call(ex)
ex = :((() -> $ex)())
end
pushfirst!(ex.args, GlobalRef(Base, fname))
return quote
Experimental.@force_compile
$(esc(ex))
end
elseif fname === :allocated
# v1.11-compatible implementation
return quote
Experimental.@force_compile
local b0 = Ref{Int64}(0)
local b1 = Ref{Int64}(0)
gc_bytes(b0)
$(esc(ex))
gc_bytes(b1)
b1[] - b0[]
end
else
@assert fname === :allocations
return quote
Experimental.@force_compile
# Note this value is unused, but without it `allocated` and `allocations`
# are sufficiently different that the compiler can remove allocations here
# that it cannot remove there, giving inconsistent numbers.
local b1 = Ref{Int64}(0)
local stats = Base.gc_num()
$(esc(ex))
local diff = Base.GC_Diff(Base.gc_num(), stats)
gc_bytes(b1)
Base.gc_alloc_count(diff)
end
end
end

"""
@allocated

A macro to evaluate an expression, discarding the resulting value, instead returning the
total number of bytes allocated during evaluation of the expression.

If the expression is a function call, an effort is made to measure only allocations from
the argument expressions and during the function, excluding any overhead from calling it
and not performing constant propagation with the provided argument values. If you want to
include those effects, i.e. measuring the call site as well, use the syntax
`@allocated (()->f(1))()`.

It is recommended to measure function calls with only simple argument expressions, e.g.
`x = []; @allocated f(x)` instead of `@allocated f([])` to clarify that only `f` is
being measured.

For more complex expressions, the code is simply run in place and therefore may see
allocations due to the surrounding context. For example it is possible for
`@allocated f(1)` and `@allocated x = f(1)` to give different results.

See also [`@allocations`](@ref), [`@time`](@ref), [`@timev`](@ref), [`@timed`](@ref),
and [`@elapsed`](@ref).

Expand All @@ -516,11 +568,7 @@ julia> @allocated rand(10^6)
```
"""
macro allocated(ex)
if !is_simply_call(ex)
ex = :((() -> $ex)())
end
pushfirst!(ex.args, GlobalRef(Base, :allocated))
return esc(ex)
_gen_allocation_measurer(ex, :allocated)
end

"""
Expand All @@ -541,11 +589,7 @@ julia> @allocations rand(10^6)
This macro was added in Julia 1.9.
"""
macro allocations(ex)
if !is_simply_call(ex)
ex = :((() -> $ex)())
end
pushfirst!(ex.args, GlobalRef(Base, :allocations))
return esc(ex)
_gen_allocation_measurer(ex, :allocations)
end


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
93162fc479ba1762028ef917176f45e0
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
d6c421048e52d5cf32848cf7a16db1ac269f2c553672b0f1126230a7f5954adb6f2883982efe747bd91fa8135071e1b2f717a12ceb1631c1c7effbf6cece8f4c

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
eadaa92895c8d4d33eb601165ef765d5
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bb37377b360eca1a32c78b1d11b83c7e918a8ddb9df79388694b6f415dc5d5cf6182df7437869b3970011e5dcda4a3f821b58498bfa6fd7df697fcd51383ca12

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ad2e6ba06c98990865f808b26b8f148c
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24e530c095f7838380adeb6f45349cf776df524a2fc721eb8b11411d25bc132a58c1048a89d630ba1ee66bf9a52cce9a0fbe2b4a76c33b11160c00ecb7a919a1
Loading