Skip to content

Commit

Permalink
Backports for julia v1.10.0-beta2 (#50708)
Browse files Browse the repository at this point in the history
Backported PRs:
- [x] #50637 <!-- Remove SparseArrays legacy code -->
- [x] #50665 <!-- print `@time` msg into print buffer -->
- [x] #50523 <!-- Avoid generic call in most cases for getproperty -->
- [x] #50635 <!-- `versioninfo()`: include build info and unofficial
warning -->
- [x] #50670 <!-- Make reinterpret specialize fully. -->
- [x] #50666 <!-- include `--pkgimage=no` caches for stdlibs -->
- [x] #50765 
- [x] #50764
- [x] #50768
- [x] #50767
- [x] #50618 <!-- inference: continue const-prop' when concrete-eval
returns non-inlineable -->
- [x] #50689 <!-- Attach `tanpi` docstring to method -->
- [x] #50671 <!-- Fix rdiv of complex lhs by real factorizations -->
- [x] #50598 <!-- only limit types in stack traces in the REPL -->
- [x] #50766 <!-- Don't partition alwaysinline functions -->
- [x] #50771 <!-- re-allow non-string values in ENV `get!` -->
- [x] #50682 <!-- Add fallback if we have make a weird GC decision. -->
- [x] #50781 <!-- fix `bit_map!` with aliasing -->
- [x] #50172 <!-- print feature flags used for matching pkgimage -->
- [x] #50844 <!-- Bump OpenBLAS binaries to use the new GEMM
multithreading threshold -->
- [x] #50826 <!-- Update dependency builds -->
- [x] #50845 <!-- fix #50438, use default pool for at-threads -->
- [x] #50568 <!-- `Array(::AbstractRange)` should return an `Array` -->
- [x] #50655 <!-- fix hashing regression. -->
- [x] #50779 <!-- Minor refactor to image generation -->
- [x] #50791 <!-- Make symbols internal in jl_create_native, and only
externalize them when partitioning -->
- [x] #50724 <!-- Merge opaque closure modules with the rest of the
workqueue -->
- [x] #50738 <!-- Add alignment to constant globals -->
- [x] #50871 <!-- macOS: Don't inspect dead threadtls during exception
handling. -->

Need manual backport:

Contains multiple commits, manual intervention needed:

Non-merged PRs with backport label:
- [ ] #50850 <!-- Remove weird Rational dispatch and add pi functions to
list -->
- [ ] #50823 <!-- Make ranges more robust with unsigned indexes. -->
- [ ] #50809 <!-- Limit type-printing in MethodError -->
- [ ] #50663 <!-- Fix Expr(:loopinfo) codegen -->
- [ ] #50594 <!-- Disallow non-index Integer types in isassigned -->
- [ ] #50385 <!-- Precompile pidlocks: add to NEWS and docs -->
- [ ] #49805 <!-- Limit TimeType subtraction to AbstractDateTime -->
  • Loading branch information
KristofferC committed Aug 16, 2023
2 parents c11763f + 1fc06f2 commit 77e7e73
Show file tree
Hide file tree
Showing 113 changed files with 2,248 additions and 1,742 deletions.
2 changes: 1 addition & 1 deletion Make.inc
Original file line number Diff line number Diff line change
Expand Up @@ -1503,7 +1503,7 @@ endef
WINE ?= wine

ifeq ($(BINARY),32)
HEAPLIM := --heap-size-hint=500M
HEAPLIM := --heap-size-hint=1000M
else
HEAPLIM :=
endif
Expand Down
10 changes: 6 additions & 4 deletions base/bitarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1791,9 +1791,10 @@ function bit_map!(f::F, dest::BitArray, A::BitArray) where F
dest_last = destc[len_Ac]
_msk = _msk_end(A)
# first zero out the bits mask is going to change
destc[len_Ac] = (dest_last & (~_msk))
# then update bits by `or`ing with a masked RHS
destc[len_Ac] |= f(Ac[len_Ac]) & _msk
# DO NOT SEPARATE ONTO TO LINES.
# Otherwise there will be bugs when Ac aliases destc
destc[len_Ac] = (dest_last & (~_msk)) | f(Ac[len_Ac]) & _msk
dest
end
function bit_map!(f::F, dest::BitArray, A::BitArray, B::BitArray) where F
Expand All @@ -1812,9 +1813,10 @@ function bit_map!(f::F, dest::BitArray, A::BitArray, B::BitArray) where F
dest_last = destc[len_Ac]
_msk = _msk_end(min_bitlen)
# first zero out the bits mask is going to change
destc[len_Ac] = (dest_last & ~(_msk))
# then update bits by `or`ing with a masked RHS
destc[len_Ac] |= f(Ac[end], Bc[end]) & _msk
# DO NOT SEPARATE ONTO TO LINES.
# Otherwise there will be bugs when Ac or Bc aliases destc
destc[len_Ac] = (dest_last & ~(_msk)) | f(Ac[end], Bc[end]) & _msk
dest
end

Expand Down
50 changes: 35 additions & 15 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -773,11 +773,13 @@ struct ConstCallResults
const_result::ConstResult
effects::Effects
edge::MethodInstance
ConstCallResults(@nospecialize(rt),
const_result::ConstResult,
effects::Effects,
edge::MethodInstance) =
new(rt, const_result, effects, edge)
function ConstCallResults(
@nospecialize(rt),
const_result::ConstResult,
effects::Effects,
edge::MethodInstance)
return new(rt, const_result, effects, edge)
end
end

function abstract_call_method_with_const_args(interp::AbstractInterpreter,
Expand All @@ -791,24 +793,33 @@ function abstract_call_method_with_const_args(interp::AbstractInterpreter,
return nothing
end
eligibility = concrete_eval_eligible(interp, f, result, arginfo, sv)
concrete_eval_result = nothing
if eligibility === :concrete_eval
return concrete_eval_call(interp, f, result, arginfo, sv, invokecall)
concrete_eval_result = concrete_eval_call(interp, f, result, arginfo, sv, invokecall)
# if we don't inline the result of this concrete evaluation,
# give const-prop' a chance to inline a better method body
if !may_optimize(interp) || (
may_inline_concrete_result(concrete_eval_result.const_result::ConcreteResult) ||
concrete_eval_result.rt === Bottom) # unless this call deterministically throws and thus is non-inlineable
return concrete_eval_result
end
# TODO allow semi-concrete interp for this call?
end
mi = maybe_get_const_prop_profitable(interp, result, f, arginfo, si, match, sv)
mi === nothing && return nothing
mi === nothing && return concrete_eval_result
if is_constprop_recursed(result, mi, sv)
add_remark!(interp, sv, "[constprop] Edge cycle encountered")
return nothing
end
# try semi-concrete evaluation
if eligibility === :semi_concrete_eval
res = semi_concrete_eval_call(interp, mi, result, arginfo, sv)
if res !== nothing
return res
irinterp_result = semi_concrete_eval_call(interp, mi, result, arginfo, sv)
if irinterp_result !== nothing
return irinterp_result
end
end
# try constant prop'
return const_prop_call(interp, mi, result, arginfo, sv)
return const_prop_call(interp, mi, result, arginfo, sv, concrete_eval_result)
end

function const_prop_enabled(interp::AbstractInterpreter, sv::AbsIntState, match::MethodMatch)
Expand Down Expand Up @@ -900,7 +911,7 @@ function concrete_eval_call(interp::AbstractInterpreter,
Core._call_in_world_total(world, f, args...)
catch
# The evaluation threw. By :consistent-cy, we're guaranteed this would have happened at runtime
return ConstCallResults(Union{}, ConcreteResult(edge, result.effects), result.effects, edge)
return ConstCallResults(Bottom, ConcreteResult(edge, result.effects), result.effects, edge)
end
return ConstCallResults(Const(value), ConcreteResult(edge, EFFECTS_TOTAL, value), EFFECTS_TOTAL, edge)
end
Expand Down Expand Up @@ -1158,16 +1169,20 @@ function semi_concrete_eval_call(interp::AbstractInterpreter,
# that are newly resovled by irinterp
# state = InliningState(interp)
# ir = ssa_inlining_pass!(irsv.ir, state, propagate_inbounds(irsv))
new_effects = Effects(result.effects; nothrow)
return ConstCallResults(rt, SemiConcreteResult(mi, ir, new_effects), new_effects, mi)
effects = result.effects
if !is_nothrow(effects)
effects = Effects(effects; nothrow)
end
return ConstCallResults(rt, SemiConcreteResult(mi, ir, effects), effects, mi)
end
end
end
return nothing
end

function const_prop_call(interp::AbstractInterpreter,
mi::MethodInstance, result::MethodCallResult, arginfo::ArgInfo, sv::AbsIntState)
mi::MethodInstance, result::MethodCallResult, arginfo::ArgInfo, sv::AbsIntState,
concrete_eval_result::Union{Nothing,ConstCallResults}=nothing)
inf_cache = get_inference_cache(interp)
𝕃ᵢ = typeinf_lattice(interp)
inf_result = cache_lookup(𝕃ᵢ, mi, arginfo.argtypes, inf_cache)
Expand All @@ -1190,6 +1205,11 @@ function const_prop_call(interp::AbstractInterpreter,
return nothing
end
@assert inf_result.result !== nothing
if concrete_eval_result !== nothing
# override return type and effects with concrete evaluation result if available
inf_result.result = concrete_eval_result.rt
inf_result.ipo_effects = concrete_eval_result.effects
end
else
# found the cache for this constant prop'
if inf_result.result === nothing
Expand Down
12 changes: 9 additions & 3 deletions base/compiler/ssair/ir.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1338,7 +1338,12 @@ function process_node!(compact::IncrementalCompact, result_idx::Int, inst::Instr
return result_idx
end
end
ssa_rename[idx] = SSAValue(result_idx)
typ = inst[:type]
if isa(typ, Const) && is_inlineable_constant(typ.val)
ssa_rename[idx] = quoted(typ.val)
else
ssa_rename[idx] = SSAValue(result_idx)
end
result[result_idx][:inst] = stmt
result_idx += 1
elseif isa(stmt, PiNode)
Expand All @@ -1359,8 +1364,9 @@ function process_node!(compact::IncrementalCompact, result_idx::Int, inst::Instr
return result_idx
end
elseif !isa(pi_val, AnySSAValue) && !isa(pi_val, GlobalRef)
valtyp = isa(pi_val, QuoteNode) ? typeof(pi_val.value) : typeof(pi_val)
if valtyp === stmt.typ
pi_val′ = isa(pi_val, QuoteNode) ? pi_val.value : pi_val
stmttyp = stmt.typ
if isa(stmttyp, Const) ? pi_val′ === stmttyp.val : typeof(pi_val′) === stmttyp
ssa_rename[idx] = pi_val
return result_idx
end
Expand Down
21 changes: 10 additions & 11 deletions base/compiler/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2347,19 +2347,18 @@ function getfield_effects(𝕃::AbstractLattice, arginfo::ArgInfo, @nospecialize
end

function getglobal_effects(argtypes::Vector{Any}, @nospecialize(rt))
2 length(argtypes) 3 || return EFFECTS_THROWS
consistent = inaccessiblememonly = ALWAYS_FALSE
nothrow = false
if length(argtypes) 2
M, s = argtypes[1], argtypes[2]
if getglobal_nothrow(M, s)
nothrow = true
# typeasserts below are already checked in `getglobal_nothrow`
Mval, sval = (M::Const).val::Module, (s::Const).val::Symbol
if isconst(Mval, sval)
consistent = ALWAYS_TRUE
if is_mutation_free_argtype(rt)
inaccessiblememonly = ALWAYS_TRUE
end
M, s = argtypes[1], argtypes[2]
if (length(argtypes) == 3 ? getglobal_nothrow(M, s, argtypes[3]) : getglobal_nothrow(M, s))
nothrow = true
# typeasserts below are already checked in `getglobal_nothrow`
Mval, sval = (M::Const).val::Module, (s::Const).val::Symbol
if isconst(Mval, sval)
consistent = ALWAYS_TRUE
if is_mutation_free_argtype(rt)
inaccessiblememonly = ALWAYS_TRUE
end
end
end
Expand Down
4 changes: 4 additions & 0 deletions base/env.jl
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ end
getindex(::EnvDict, k::AbstractString) = access_env(k->throw(KeyError(k)), k)
get(::EnvDict, k::AbstractString, def) = access_env(Returns(def), k)
get(f::Callable, ::EnvDict, k::AbstractString) = access_env(k->f(), k)
function get!(default::Callable, ::EnvDict, k::AbstractString)
haskey(ENV, k) && return ENV[k]
ENV[k] = default()
end
in(k::AbstractString, ::KeySet{String, EnvDict}) = _hasenv(k)
pop!(::EnvDict, k::AbstractString) = (v = ENV[k]; _unsetenv(k); v)
pop!(::EnvDict, k::AbstractString, def) = haskey(ENV,k) ? pop!(ENV,k) : def
Expand Down
6 changes: 0 additions & 6 deletions base/errorshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -772,9 +772,6 @@ function show_backtrace(io::IO, t::Vector)
if haskey(io, :last_shown_line_infos)
empty!(io[:last_shown_line_infos])
end
# this will be set to true if types in the stacktrace are truncated
limitflag = Ref(false)
io = IOContext(io, :stacktrace_types_limited => limitflag)

# t is a pre-processed backtrace (ref #12856)
if t isa Vector{Any}
Expand All @@ -800,9 +797,6 @@ function show_backtrace(io::IO, t::Vector)
# process_backtrace returns a Vector{Tuple{Frame, Int}}
show_full_backtrace(io, filtered; print_linebreaks = stacktrace_linebreaks())
end
if limitflag[]
print(io, "\nSome type information was truncated. Use `show(err)` to see complete types.")
end
nothing
end

Expand Down
4 changes: 2 additions & 2 deletions base/essentials.jl
Original file line number Diff line number Diff line change
Expand Up @@ -571,8 +571,8 @@ julia> reinterpret(Tuple{UInt16, UInt8}, (0x01, 0x0203))
otherwise be prevented by the type's constructors and methods. Unexpected behavior
may result without additional validation.
"""
function reinterpret(Out::Type, x::In) where {In}
if isprimitivetype(Out) && isprimitivetype(In)
function reinterpret(::Type{Out}, x) where {Out}
if isprimitivetype(Out) && isprimitivetype(typeof(x))
return bitcast(Out, x)
end
# only available when Base is fully loaded.
Expand Down
16 changes: 9 additions & 7 deletions base/float.jl
Original file line number Diff line number Diff line change
Expand Up @@ -688,22 +688,24 @@ function hash(x::Real, h::UInt)
den_z = trailing_zeros(den)
den >>= den_z
pow += num_z - den_z

# handle values representable as Int64, UInt64, Float64
# If the real can be represented as an Int64, UInt64, or Float64, hash as those types.
# To be an Integer the denominator must be 1 and the power must be non-negative.
if den == 1
# left = ceil(log2(num*2^pow))
left = top_set_bit(abs(num)) + pow
right = pow + den_z
if -1074 <= right
if 0 <= right
# 2^-1074 is the minimum Float64 so if the power is smaller, not a Float64
if -1074 <= pow
if 0 <= pow # if pow is non-negative, it is an integer
left <= 63 && return hash(Int64(num) << Int(pow), h)
left <= 64 && !signbit(num) && return hash(UInt64(num) << Int(pow), h)
end # typemin(Int64) handled by Float64 case
left <= 1024 && left - right <= 53 && return hash(ldexp(Float64(num), pow), h)
# 2^1024 is the maximum Float64 so if the power is greater, not a Float64
# Float64s only have 53 mantisa bits (including implicit bit)
left <= 1024 && left - pow <= 53 && return hash(ldexp(Float64(num), pow), h)
end
else
h = hash_integer(den, h)
end

# handle generic rational values
h = hash_integer(pow, h)
h = hash_integer(num, h)
Expand Down
99 changes: 91 additions & 8 deletions base/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2841,11 +2841,9 @@ get_compiletime_preferences(m::Module) = get_compiletime_preferences(PkgId(m).uu
get_compiletime_preferences(::Nothing) = String[]

function check_clone_targets(clone_targets)
try
ccall(:jl_check_pkgimage_clones, Cvoid, (Ptr{Cchar},), clone_targets)
return true
catch
return false
rejection_reason = ccall(:jl_check_pkgimage_clones, Any, (Ptr{Cchar},), clone_targets)
if rejection_reason !== nothing
return rejection_reason
end
end

Expand Down Expand Up @@ -2877,6 +2875,88 @@ function show(io::IO, cf::CacheFlags)
print(io, ", opt_level = ", cf.opt_level)
end

struct ImageTarget
name::String
flags::Int32
ext_features::String
features_en::Vector{UInt8}
features_dis::Vector{UInt8}
end

function parse_image_target(io::IO)
flags = read(io, Int32)
nfeature = read(io, Int32)
feature_en = read(io, 4*nfeature)
feature_dis = read(io, 4*nfeature)
name_len = read(io, Int32)
name = String(read(io, name_len))
ext_features_len = read(io, Int32)
ext_features = String(read(io, ext_features_len))
ImageTarget(name, flags, ext_features, feature_en, feature_dis)
end

function parse_image_targets(targets::Vector{UInt8})
io = IOBuffer(targets)
ntargets = read(io, Int32)
targets = Vector{ImageTarget}(undef, ntargets)
for i in 1:ntargets
targets[i] = parse_image_target(io)
end
return targets
end

function current_image_targets()
targets = @ccall jl_reflect_clone_targets()::Vector{UInt8}
return parse_image_targets(targets)
end

struct FeatureName
name::Cstring
bit::UInt32 # bit index into a `uint32_t` array;
llvmver::UInt32 # 0 if it is available on the oldest LLVM version we support
end

function feature_names()
fnames = Ref{Ptr{FeatureName}}()
nf = Ref{Csize_t}()
@ccall jl_reflect_feature_names(fnames::Ptr{Ptr{FeatureName}}, nf::Ptr{Csize_t})::Cvoid
if fnames[] == C_NULL
@assert nf[] == 0
return Vector{FeatureName}(undef, 0)
end
Base.unsafe_wrap(Array, fnames[], nf[], own=false)
end

function test_feature(features::Vector{UInt8}, feat::FeatureName)
bitidx = feat.bit
u8idx = div(bitidx, 8) + 1
bit = bitidx % 8
return (features[u8idx] & (1 << bit)) != 0
end

function show(io::IO, it::ImageTarget)
print(io, it.name)
if !isempty(it.ext_features)
print(io, ",", it.ext_features)
end
print(io, "; flags=", it.flags)
print(io, "; features_en=(")
first = true
for feat in feature_names()
if test_feature(it.features_en, feat)
name = Base.unsafe_string(feat.name)
if first
first = false
print(io, name)
else
print(io, ", ", name)
end
end
end
print(io, ")")
# Is feature_dis useful?
end

# Set by FileWatching.__init__()
global mkpidlock_hook
global trymkpidlock_hook
Expand Down Expand Up @@ -2914,7 +2994,6 @@ function maybe_cachefile_lock(f, pkg::PkgId, srcpath::String; stale_age=300)
f()
end
end

# returns true if it "cachefile.ji" is stale relative to "modpath.jl" and build_id for modkey
# otherwise returns the list of dependencies to also check
@constprop :none function stale_cachefile(modpath::String, cachefile::String; ignore_loaded::Bool = false)
Expand Down Expand Up @@ -2948,8 +3027,12 @@ end
@debug "Rejecting cache file $cachefile for $modkey since it would require usage of pkgimage"
return true
end
if !check_clone_targets(clone_targets)
@debug "Rejecting cache file $cachefile for $modkey since pkgimage can't be loaded on this target"
rejection_reasons = check_clone_targets(clone_targets)
if !isnothing(rejection_reasons)
@debug("Rejecting cache file $cachefile for $modkey:",
Reasons=rejection_reasons,
var"Image Targets"=parse_image_targets(clone_targets),
var"Current Targets"=current_image_targets())
return true
end
if !isfile(ocachefile)
Expand Down

0 comments on commit 77e7e73

Please sign in to comment.