Skip to content

Commit

Permalink
Merge pull request #46663 from JuliaLang/backports-release-1.8
Browse files Browse the repository at this point in the history
Backports for Julia 1.8.2
  • Loading branch information
KristofferC authored Sep 21, 2022
2 parents afb6c60 + 285b75c commit 4e8ce61
Show file tree
Hide file tree
Showing 60 changed files with 544 additions and 311 deletions.
1 change: 0 additions & 1 deletion .github/workflows/statuses.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ jobs:
- run: |
declare -a CONTEXT_LIST=(
"buildbot/tester_freebsd64"
"buildbot/tester_macos64"
"buildbot/tester_win32"
"buildbot/tester_win64"
)
Expand Down
2 changes: 1 addition & 1 deletion base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2308,7 +2308,7 @@ findall(testf::Function, A) = collect(first(p) for p in pairs(A) if testf(last(p

# Broadcasting is much faster for small testf, and computing
# integer indices from logical index using findall has a negligible cost
findall(testf::Function, A::AbstractArray) = findall(testf.(A))
findall(testf::F, A::AbstractArray) where {F<:Function} = findall(testf.(A))

"""
findall(A)
Expand Down
2 changes: 1 addition & 1 deletion base/binaryplatforms.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1027,7 +1027,7 @@ function platforms_match(a::AbstractPlatform, b::AbstractPlatform)

# Call the comparator, passing in which objects requested this comparison (one, the other, or both)
# For some comparators this doesn't matter, but for non-symmetrical comparisons, it does.
if !comparator(ak, bk, a_comp == comparator, b_comp == comparator)
if !(comparator(ak, bk, a_comp == comparator, b_comp == comparator)::Bool)
return false
end
end
Expand Down
72 changes: 46 additions & 26 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
result = abstract_call_method(interp, method, sig_n, svec(), multiple_matches, sv)
rt = result.rt
edge = result.edge
edge !== nothing && push!(edges, edge)
edge === nothing || push!(edges, edge)
this_argtypes = isa(matches, MethodMatches) ? argtypes : matches.applicable_argtypes[i]
this_arginfo = ArgInfo(fargs, this_argtypes)
const_call_result = abstract_call_method_with_const_args(interp, result,
Expand All @@ -136,25 +136,11 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
this_conditional = ignorelimited(this_rt)
this_rt = widenwrappedconditional(this_rt)
else
if infer_compilation_signature(interp)
# Also infer the compilation signature for this method, so it's available
# to the compiler in case it ends up needing it (which is likely).
csig = get_compileable_sig(method, sig, match.sparams)
if csig !== nothing && csig !== sig
# The result of this inference is not directly used, so temporarily empty
# the use set for the current SSA value.
saved_uses = sv.ssavalue_uses[sv.currpc]
sv.ssavalue_uses[sv.currpc] = empty_bitset
abstract_call_method(interp, method, csig, match.sparams, multiple_matches, sv)
sv.ssavalue_uses[sv.currpc] = saved_uses
end
end

result = abstract_call_method(interp, method, sig, match.sparams, multiple_matches, sv)
this_conditional = ignorelimited(result.rt)
this_rt = widenwrappedconditional(result.rt)
edge = result.edge
edge !== nothing && push!(edges, edge)
edge === nothing || push!(edges, edge)
# try constant propagation with argtypes for this match
# this is in preparation for inlining, or improving the return result
this_argtypes = isa(matches, MethodMatches) ? argtypes : matches.applicable_argtypes[i]
Expand Down Expand Up @@ -214,6 +200,26 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),

rettype = from_interprocedural!(rettype, sv, arginfo, conditionals)

# Also considering inferring the compilation signature for this method, so
# it is available to the compiler in case it ends up needing it.
if infer_compilation_signature(interp) && 1 == seen == napplicable && rettype !== Any && rettype !== Union{} && !is_removable_if_unused(all_effects)
match = applicable[1]::MethodMatch
method = match.method
sig = match.spec_types
mi = specialize_method(match; preexisting=true)
if mi !== nothing && !const_prop_methodinstance_heuristic(interp, match, mi::MethodInstance, arginfo, sv)
csig = get_compileable_sig(method, sig, match.sparams)
if csig !== nothing && csig !== sig
# The result of this inference is not directly used, so temporarily empty
# the use set for the current SSA value.
saved_uses = sv.ssavalue_uses[sv.currpc]
sv.ssavalue_uses[sv.currpc] = empty_bitset
abstract_call_method(interp, method, csig, match.sparams, multiple_matches, sv)
sv.ssavalue_uses[sv.currpc] = saved_uses
end
end
end

if call_result_unused(sv) && !(rettype === Bottom)
add_remark!(interp, sv, "Call result type was widened because the return value is unused")
# We're mainly only here because the optimizer might want this code,
Expand Down Expand Up @@ -765,13 +771,25 @@ function collect_const_args((; argtypes)::ArgInfo)
isa(a, Const) ? a.val :
isconstType(a) ? (a::DataType).parameters[1] :
(a::DataType).instance
end for i in 2:length(argtypes) ]
end for i = 2:length(argtypes) ]
end

struct InvokeCall
types # ::Type
lookupsig # ::Type
InvokeCall(@nospecialize(types), @nospecialize(lookupsig)) = new(types, lookupsig)
end

function concrete_eval_call(interp::AbstractInterpreter,
@nospecialize(f), result::MethodCallResult, arginfo::ArgInfo, sv::InferenceState)
@nospecialize(f), result::MethodCallResult, arginfo::ArgInfo, sv::InferenceState,
invokecall::Union{Nothing,InvokeCall}=nothing)
concrete_eval_eligible(interp, f, result, arginfo, sv) || return nothing
args = collect_const_args(arginfo)
if invokecall !== nothing
# this call should be `invoke`d, rewrite `args` back now
pushfirst!(args, f, invokecall.types)
f = invoke
end
world = get_world_counter(interp)
value = try
Core._call_in_world_total(world, f, args...)
Expand Down Expand Up @@ -811,13 +829,13 @@ struct ConstCallResults
new(rt, const_result, effects)
end

function abstract_call_method_with_const_args(interp::AbstractInterpreter, result::MethodCallResult,
@nospecialize(f), arginfo::ArgInfo, match::MethodMatch,
sv::InferenceState)
function abstract_call_method_with_const_args(interp::AbstractInterpreter,
result::MethodCallResult, @nospecialize(f), arginfo::ArgInfo, match::MethodMatch,
sv::InferenceState, invokecall::Union{Nothing,InvokeCall}=nothing)
if !const_prop_enabled(interp, sv, match)
return nothing
end
val = concrete_eval_call(interp, f, result, arginfo, sv)
val = concrete_eval_call(interp, f, result, arginfo, sv, invokecall)
if val !== nothing
add_backedge!(result.edge, sv)
return val
Expand Down Expand Up @@ -1547,10 +1565,10 @@ function abstract_invoke(interp::AbstractInterpreter, (; fargs, argtypes)::ArgIn
nargtype isa DataType || return CallMeta(Any, Effects(), false) # other cases are not implemented below
isdispatchelem(ft) || return CallMeta(Any, Effects(), false) # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below
ft = ft::DataType
types = rewrap_unionall(Tuple{ft, unwrap_unionall(types).parameters...}, types)::Type
lookupsig = rewrap_unionall(Tuple{ft, unwrap_unionall(types).parameters...}, types)::Type
nargtype = Tuple{ft, nargtype.parameters...}
argtype = Tuple{ft, argtype.parameters...}
match, valid_worlds, overlayed = findsup(types, method_table(interp))
match, valid_worlds, overlayed = findsup(lookupsig, method_table(interp))
match === nothing && return CallMeta(Any, Effects(), false)
update_valid_age!(sv, valid_worlds)
method = match.method
Expand All @@ -1569,8 +1587,10 @@ function abstract_invoke(interp::AbstractInterpreter, (; fargs, argtypes)::ArgIn
# t, a = ti.parameters[i], argtypes′[i]
# argtypes′[i] = t ⊑ a ? t : a
# end
const_call_result = abstract_call_method_with_const_args(interp, result,
overlayed ? nothing : singleton_type(ft′), arginfo, match, sv)
f = overlayed ? nothing : singleton_type(ft′)
invokecall = InvokeCall(types, lookupsig)
const_call_result = abstract_call_method_with_const_args(interp,
result, f, arginfo, match, sv, invokecall)
const_result = nothing
if const_call_result !== nothing
if const_call_result.rt rt
Expand Down
18 changes: 13 additions & 5 deletions base/compiler/methodtable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,23 @@ struct OverlayMethodTable <: MethodTableView
mt::Core.MethodTable
end

struct MethodMatchKey
sig # ::Type
limit::Int
MethodMatchKey(@nospecialize(sig), limit::Int) = new(sig, limit)
end

"""
struct CachedMethodTable <: MethodTableView
Overlays another method table view with an additional local fast path cache that
can respond to repeated, identical queries faster than the original method table.
"""
struct CachedMethodTable{T} <: MethodTableView
cache::IdDict{Any, Union{Missing, MethodMatchResult}}
cache::IdDict{MethodMatchKey, Union{Missing,MethodMatchResult}}
table::T
end
CachedMethodTable(table::T) where T = CachedMethodTable{T}(IdDict{Any, Union{Missing, MethodMatchResult}}(), table)
CachedMethodTable(table::T) where T = CachedMethodTable{T}(IdDict{MethodMatchKey, Union{Missing,MethodMatchResult}}(), table)

"""
findall(sig::Type, view::MethodTableView; limit::Int=typemax(Int)) ->
Expand Down Expand Up @@ -109,9 +115,11 @@ function findall(@nospecialize(sig::Type), table::CachedMethodTable; limit::Int=
# as for concrete types, we cache result at on the next level
return findall(sig, table.table; limit)
end
box = Core.Box(sig)
return get!(table.cache, sig) do
findall(box.contents, table.table; limit)
key = MethodMatchKey(sig, limit)
if haskey(table.cache, key)
return table.cache[key]
else
return table.cache[key] = findall(sig, table.table; limit)
end
end

Expand Down
5 changes: 5 additions & 0 deletions base/compiler/ssair/inlining.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1066,6 +1066,11 @@ function inline_invoke!(
return nothing
end

function invoke_signature(invokesig::Vector{Any})
ft, argtyps = widenconst(invokesig[2]), instanceof_tfunc(widenconst(invokesig[3]))[1]
return rewrap_unionall(Tuple{ft, unwrap_unionall(argtyps).parameters...}, argtyps)
end

function narrow_opaque_closure!(ir::IRCode, stmt::Expr, @nospecialize(info), state::InliningState)
if isa(info, OpaqueClosureCreateInfo)
lbt = argextype(stmt.args[2], ir)
Expand Down
8 changes: 6 additions & 2 deletions base/gmp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -667,8 +667,12 @@ function prod(arr::AbstractArray{BigInt})
# to account for the rounding to limbs in MPZ.mul!
# (BITS_PER_LIMB-1 would typically be enough, to which we add
# 1 for the initial multiplication by init=1 in foldl)
nbits = GC.@preserve arr sum(arr; init=BITS_PER_LIMB) do x
abs(x.size) * BITS_PER_LIMB - leading_zeros(unsafe_load(x.d))
nbits = BITS_PER_LIMB
for x in arr
iszero(x) && return zero(BigInt)
xsize = abs(x.size)
lz = GC.@preserve x leading_zeros(unsafe_load(x.d, xsize))
nbits += xsize * BITS_PER_LIMB - lz
end
init = BigInt(; nbits)
MPZ.set_si!(init, 1)
Expand Down
14 changes: 8 additions & 6 deletions base/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1587,12 +1587,14 @@ function create_expr_cache(pkg::PkgId, input::String, output::String, concrete_d
deps_eltype = sprint(show, eltype(concrete_deps); context = :module=>nothing)
deps = deps_eltype * "[" * join(deps_strs, ",") * "]"
trace = isassigned(PRECOMPILE_TRACE_COMPILE) ? `--trace-compile=$(PRECOMPILE_TRACE_COMPILE[])` : ``
io = open(pipeline(`$(julia_cmd()::Cmd) -O0
--output-ji $output --output-incremental=yes
--startup-file=no --history-file=no --warn-overwrite=yes
--color=$(have_color === nothing ? "auto" : have_color ? "yes" : "no")
$trace
-`, stderr = internal_stderr, stdout = internal_stdout),
io = open(pipeline(addenv(`$(julia_cmd()::Cmd) -O0
--output-ji $output --output-incremental=yes
--startup-file=no --history-file=no --warn-overwrite=yes
--color=$(have_color === nothing ? "auto" : have_color ? "yes" : "no")
$trace
-`,
"OPENBLAS_NUM_THREADS" => 1),
stderr = internal_stderr, stdout = internal_stdout),
"w", stdout)
# write data over stdin to avoid the (unlikely) case of exceeding max command line size
write(io.in, """
Expand Down
7 changes: 4 additions & 3 deletions base/namedtuple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ function NamedTuple{names}(nt::NamedTuple) where {names}
types = Tuple{(fieldtype(nt, idx[n]) for n in 1:length(idx))...}
Expr(:new, :(NamedTuple{names, $types}), Any[ :(getfield(nt, $(idx[n]))) for n in 1:length(idx) ]...)
else
types = Tuple{(fieldtype(typeof(nt), names[n]) for n in 1:length(names))...}
length_names = length(names)::Integer
types = Tuple{(fieldtype(typeof(nt), names[n]) for n in 1:length_names)...}
NamedTuple{names, types}(map(Fix1(getfield, nt), names))
end
end
Expand Down Expand Up @@ -318,8 +319,8 @@ values(nt::NamedTuple) = Tuple(nt)
haskey(nt::NamedTuple, key::Union{Integer, Symbol}) = isdefined(nt, key)
get(nt::NamedTuple, key::Union{Integer, Symbol}, default) = haskey(nt, key) ? getfield(nt, key) : default
get(f::Callable, nt::NamedTuple, key::Union{Integer, Symbol}) = haskey(nt, key) ? getfield(nt, key) : f()
tail(t::NamedTuple{names}) where names = NamedTuple{tail(names)}(t)
front(t::NamedTuple{names}) where names = NamedTuple{front(names)}(t)
tail(t::NamedTuple{names}) where names = NamedTuple{tail(names::Tuple)}(t)
front(t::NamedTuple{names}) where names = NamedTuple{front(names::Tuple)}(t)

@pure function diff_names(an::Tuple{Vararg{Symbol}}, bn::Tuple{Vararg{Symbol}})
@nospecialize an bn
Expand Down
2 changes: 1 addition & 1 deletion base/ordering.jl
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ lt(o::Lt, a, b) = o.lt(a,b)
@propagate_inbounds function lt(p::Perm, a::Integer, b::Integer)
da = p.data[a]
db = p.data[b]
lt(p.order, da, db) | (!lt(p.order, db, da) & (a < b))
(lt(p.order, da, db)::Bool) | (!(lt(p.order, db, da)::Bool) & (a < b))
end

_ord(lt::typeof(isless), by::typeof(identity), order::Ordering) = order
Expand Down
14 changes: 12 additions & 2 deletions base/permuteddimsarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -263,11 +263,21 @@ end
P
end

function Base._mapreduce_dim(f, op, init::Base._InitialValue, A::PermutedDimsArray, dims::Colon)
const CommutativeOps = Union{typeof(+),typeof(Base.add_sum),typeof(min),typeof(max),typeof(Base._extrema_rf),typeof(|),typeof(&)}

function Base._mapreduce_dim(f, op::CommutativeOps, init::Base._InitialValue, A::PermutedDimsArray, dims::Colon)
Base._mapreduce_dim(f, op, init, parent(A), dims)
end
function Base._mapreduce_dim(f::typeof(identity), op::Union{typeof(Base.mul_prod),typeof(*)}, init::Base._InitialValue, A::PermutedDimsArray{<:Union{Real,Complex}}, dims::Colon)
Base._mapreduce_dim(f, op, init, parent(A), dims)
end

function Base.mapreducedim!(f, op, B::AbstractArray{T,N}, A::PermutedDimsArray{T,N,perm,iperm}) where {T,N,perm,iperm}
function Base.mapreducedim!(f, op::CommutativeOps, B::AbstractArray{T,N}, A::PermutedDimsArray{S,N,perm,iperm}) where {T,S,N,perm,iperm}
C = PermutedDimsArray{T,N,iperm,perm,typeof(B)}(B) # make the inverse permutation for the output
Base.mapreducedim!(f, op, C, parent(A))
B
end
function Base.mapreducedim!(f::typeof(identity), op::Union{typeof(Base.mul_prod),typeof(*)}, B::AbstractArray{T,N}, A::PermutedDimsArray{<:Union{Real,Complex},N,perm,iperm}) where {T,N,perm,iperm}
C = PermutedDimsArray{T,N,iperm,perm,typeof(B)}(B) # make the inverse permutation for the output
Base.mapreducedim!(f, op, C, parent(A))
B
Expand Down
2 changes: 1 addition & 1 deletion base/process.jl
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ function open(f::Function, cmds::AbstractCmd, args...; kwargs...)
rethrow()
end
close(P.in)
if !eof(P.out)
if !(eof(P.out)::Bool)
waitkill(P)
throw(_UVError("open(do)", UV_EPIPE))
end
Expand Down
3 changes: 2 additions & 1 deletion base/sort.jl
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,8 @@ const SMALL_ALGORITHM = InsertionSort
const SMALL_THRESHOLD = 20

function sort!(v::AbstractVector, lo::Integer, hi::Integer, ::InsertionSortAlg, o::Ordering)
@inbounds for i = lo+1:hi
lo_plus_1 = (lo + 1)::Integer
@inbounds for i = lo_plus_1:hi
j = i
x = v[i]
while j > lo
Expand Down
2 changes: 1 addition & 1 deletion base/special/exp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ const J_TABLE = (0x0000000000000000, 0xaac00b1afa5abcbe, 0x9b60163da9fb3335, 0xa
# XXX we want to mark :consistent-cy here so that this function can be concrete-folded,
# because the effect analysis currently can't prove it in the presence of `@inbounds` or
# `:boundscheck`, but still the access to `J_TABLE` is really safe here
@noinline Base.@assume_effects :consistent @inline function table_unpack(ind::Int32)
Base.@assume_effects :consistent function table_unpack(ind::Int32)
ind = ind & 255 + 1 # 255 == length(J_TABLE) - 1
j = @inbounds J_TABLE[ind]
jU = reinterpret(Float64, JU_CONST | (j&JU_MASK))
Expand Down
11 changes: 7 additions & 4 deletions base/stream.jl
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ function wait_readnb(x::LibuvStream, nb::Int)
while bytesavailable(x.buffer) < nb
x.readerror === nothing || throw(x.readerror)
isopen(x) || break
x.status != StatusEOF || break
x.status == StatusEOF && break
x.throttle = max(nb, x.throttle)
start_reading(x) # ensure we are reading
iolock_end()
Expand Down Expand Up @@ -662,9 +662,11 @@ function uv_readcb(handle::Ptr{Cvoid}, nread::Cssize_t, buf::Ptr{Cvoid})
elseif nread == UV_EOF # libuv called uv_stop_reading already
if stream.status != StatusClosing
stream.status = StatusEOF
if stream isa TTY # TODO: || ccall(:uv_is_writable, Cint, (Ptr{Cvoid},), stream.handle) != 0
# stream can still be used either by reseteof # TODO: or write
notify(stream.cond)
notify(stream.cond)
if stream isa TTY
# stream can still be used by reseteof (or possibly write)
elseif !(stream isa PipeEndpoint) && ccall(:uv_is_writable, Cint, (Ptr{Cvoid},), stream.handle) != 0
# stream can still be used by write
else
# underlying stream is no longer useful: begin finalization
ccall(:jl_close_uv, Cvoid, (Ptr{Cvoid},), stream.handle)
Expand All @@ -673,6 +675,7 @@ function uv_readcb(handle::Ptr{Cvoid}, nread::Cssize_t, buf::Ptr{Cvoid})
end
else
stream.readerror = _UVError("read", nread)
notify(stream.cond)
# This is a fatal connection error
ccall(:jl_close_uv, Cvoid, (Ptr{Cvoid},), stream.handle)
stream.status = StatusClosing
Expand Down
Loading

0 comments on commit 4e8ce61

Please sign in to comment.