Skip to content

Commit

Permalink
Backports for 1.10.1 (#52755)
Browse files Browse the repository at this point in the history
Backported PRs:
- [x] #51095 <!-- Fix edge cases where inexact conversions to UInt don't
throw -->
- [x] #52583 <!-- Don't access parent of triangular matrix in powm -->
- [x] #52645 <!-- update --gcthreads section in command line options -->
- [x] #52423 <!-- update nthreads info in versioninfo -->
- [x] #52721 <!-- inference: Guard TypeVar special case against vararg
-->
- [x] #52637 <!-- fix finding bundled stdlibs even if they are e.g.
devved in an environment higher in the load path -->
- [x] #52752 <!-- staticdata: handle cycles in datatypes -->
- [x] #52758 <!-- use a Dict instead of an IdDict for caching of the
`cwstring` for Windows env variables -->
- [x] #51375 <!-- Insert hardcoded backlinks to stdlib doc pages -->
- [x] #52994 <!-- place work-stealing queue indices on different cache
lines to avoid false-sharing -->
- [x] #53015 <!-- Add type assertion in iterate for logicalindex -->
- [x] #53032 <!-- Fix a list in GC devdocs -->
- [x] #52748 
- [x] #52856 
- [x] #52878
- [x] #52754 
- [x] #52228
- [x] #52924
- [x] #52569 <!-- Fix GC rooting during rehashing of iddict -->
- [x] #52605 <!-- Default uplo in symmetric/hermitian -->
- [x] #52618 <!-- heap snapshot: add gc roots and gc finalist roots to
fix unrooted nodes -->
- [x] #52781 <!-- fix type-stability bugs in Ryu code -->
- [x] #53055 <!-- Profile: use full terminal cols to show function name
-->
- [x] #53096 
- [x] #53076 
- [x] #52841 <!-- Extensions: make loading of extensions independent of
what packages are in the sysimage -->
- [x] #52078 <!-- Replace `&hArr;` by `&harr;` in documentation -->
- [x] #53035 <!-- use proper cache-line size variable in work-stealing
queue -->
- [x] #53066 <!-- doc: replace harr HTML entity by unicode -->
- [x] #52996 <!-- Apple silicon has 128 byte alignment so fix our
defines to match -->
- [x] #53121 

Non-merged PRs with backport label:
- [ ] #52694 <!-- Reinstate similar for AbstractQ for backward
compatibility -->
- [ ] #51479 <!-- prevent code loading from lookin in the versioned
environment when building Julia -->
  • Loading branch information
KristofferC committed Feb 6, 2024
2 parents 7a96210 + 0627076 commit 1dfdf66
Show file tree
Hide file tree
Showing 95 changed files with 1,525 additions and 818 deletions.
2 changes: 1 addition & 1 deletion Make.inc
Original file line number Diff line number Diff line change
Expand Up @@ -1233,7 +1233,7 @@ LIBGFORTRAN_VERSION := $(subst libgfortran,,$(filter libgfortran%,$(subst -,$(SP
# shipped with CSL. Although we do not depend on any of the symbols, it is entirely
# possible that a user might choose to install a library which depends on symbols provided
# by a newer libstdc++. Without runtime detection, those libraries would break.
CSL_NEXT_GLIBCXX_VERSION=GLIBCXX_3\.4\.31|GLIBCXX_3\.5\.|GLIBCXX_4\.
CSL_NEXT_GLIBCXX_VERSION=GLIBCXX_3\.4\.33|GLIBCXX_3\.5\.|GLIBCXX_4\.


# This is the set of projects that BinaryBuilder dependencies are hooked up for.
Expand Down
9 changes: 3 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -281,16 +281,13 @@ else ifeq ($(JULIA_BUILD_MODE),debug)
-$(INSTALL_M) $(build_libdir)/libjulia-debug.dll.a $(DESTDIR)$(libdir)/
-$(INSTALL_M) $(build_libdir)/libjulia-internal-debug.dll.a $(DESTDIR)$(libdir)/
endif
-$(INSTALL_M) $(wildcard $(build_private_libdir)/*.a) $(DESTDIR)$(private_libdir)/

# We have a single exception; we want 7z.dll to live in private_libexecdir, not bindir, so that 7z.exe can find it.
# We have a single exception; we want 7z.dll to live in private_libexecdir,
# not bindir, so that 7z.exe can find it.
-mv $(DESTDIR)$(bindir)/7z.dll $(DESTDIR)$(private_libexecdir)/
-$(INSTALL_M) $(build_bindir)/libopenlibm.dll.a $(DESTDIR)$(libdir)/
-$(INSTALL_M) $(build_libdir)/libssp.dll.a $(DESTDIR)$(libdir)/
# The rest are compiler dependencies, as an example memcpy is exported by msvcrt
# These are files from mingw32 and required for creating shared libraries like our caches.
-$(INSTALL_M) $(build_libdir)/libgcc_s.a $(DESTDIR)$(libdir)/
-$(INSTALL_M) $(build_libdir)/libgcc.a $(DESTDIR)$(libdir)/
-$(INSTALL_M) $(build_libdir)/libmsvcrt.a $(DESTDIR)$(libdir)/
else

# Copy over .dSYM directories directly for Darwin
Expand Down
70 changes: 37 additions & 33 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -785,11 +785,7 @@ end
function abstract_call_method_with_const_args(interp::AbstractInterpreter,
result::MethodCallResult, @nospecialize(f), arginfo::ArgInfo, si::StmtInfo,
match::MethodMatch, sv::AbsIntState, invokecall::Union{Nothing,InvokeCall}=nothing)
if !const_prop_enabled(interp, sv, match)
return nothing
end
if bail_out_const_call(interp, result, si)
add_remark!(interp, sv, "[constprop] No more information to be gained")
if !const_prop_enabled(interp, match, sv) || bail_out_const_call(interp, result, si, sv)
return nothing
end
eligibility = concrete_eval_eligible(interp, f, result, arginfo, sv)
Expand Down Expand Up @@ -822,7 +818,7 @@ function abstract_call_method_with_const_args(interp::AbstractInterpreter,
return const_prop_call(interp, mi, result, arginfo, sv, concrete_eval_result)
end

function const_prop_enabled(interp::AbstractInterpreter, sv::AbsIntState, match::MethodMatch)
function const_prop_enabled(interp::AbstractInterpreter, match::MethodMatch, sv::AbsIntState)
if !InferenceParams(interp).ipo_constant_propagation
add_remark!(interp, sv, "[constprop] Disabled by parameter")
return false
Expand All @@ -834,9 +830,11 @@ function const_prop_enabled(interp::AbstractInterpreter, sv::AbsIntState, match:
return true
end

function bail_out_const_call(interp::AbstractInterpreter, result::MethodCallResult, si::StmtInfo)
function bail_out_const_call(interp::AbstractInterpreter, result::MethodCallResult,
si::StmtInfo, sv::AbsIntState)
if is_removable_if_unused(result.effects)
if isa(result.rt, Const) || call_result_unused(si)
add_remark!(interp, sv, "[constprop] No more information to be gained (const)")
return true
end
end
Expand Down Expand Up @@ -937,7 +935,10 @@ function maybe_get_const_prop_profitable(interp::AbstractInterpreter,
match::MethodMatch, sv::AbsIntState)
method = match.method
force = force_const_prop(interp, f, method)
force || const_prop_entry_heuristic(interp, result, si, sv) || return nothing
if !const_prop_entry_heuristic(interp, result, si, sv, force)
# N.B. remarks are emitted within `const_prop_entry_heuristic`
return nothing
end
nargs::Int = method.nargs
method.isva && (nargs -= 1)
length(arginfo.argtypes) < nargs && return nothing
Expand All @@ -964,8 +965,17 @@ function maybe_get_const_prop_profitable(interp::AbstractInterpreter,
return mi
end

function const_prop_entry_heuristic(interp::AbstractInterpreter, result::MethodCallResult, si::StmtInfo, sv::AbsIntState)
if call_result_unused(si) && result.edgecycle
function const_prop_entry_heuristic(interp::AbstractInterpreter, result::MethodCallResult,
si::StmtInfo, sv::AbsIntState, force::Bool)
if result.rt isa LimitedAccuracy
# optimizations like inlining are disabled for limited frames,
# thus there won't be much benefit in constant-prop' here
# N.B. don't allow forced constprop' for safety (xref #52763)
add_remark!(interp, sv, "[constprop] Disabled by entry heuristic (limited accuracy)")
return false
elseif force
return true
elseif call_result_unused(si) && result.edgecycle
add_remark!(interp, sv, "[constprop] Disabled by entry heuristic (edgecycle with unused result)")
return false
end
Expand All @@ -978,27 +988,21 @@ function const_prop_entry_heuristic(interp::AbstractInterpreter, result::MethodC
if rt === Bottom
add_remark!(interp, sv, "[constprop] Disabled by entry heuristic (erroneous result)")
return false
else
return true
end
return true
elseif isa(rt, PartialStruct) || isa(rt, InterConditional) || isa(rt, InterMustAlias)
# could be improved to `Const` or a more precise wrapper
return true
elseif isa(rt, LimitedAccuracy)
# optimizations like inlining are disabled for limited frames,
# thus there won't be much benefit in constant-prop' here
add_remark!(interp, sv, "[constprop] Disabled by entry heuristic (limited accuracy)")
return false
else
if isa(rt, Const)
if !is_nothrow(result.effects)
# Could still be improved to Bottom (or at least could see the effects improved)
return true
end
elseif isa(rt, Const)
if is_nothrow(result.effects)
add_remark!(interp, sv, "[constprop] Disabled by entry heuristic (nothrow const)")
return false
end
add_remark!(interp, sv, "[constprop] Disabled by entry heuristic (unimprovable result)")
return false
# Could still be improved to Bottom (or at least could see the effects improved)
return true
end
add_remark!(interp, sv, "[constprop] Disabled by entry heuristic (unimprovable result)")
return false
end

# determines heuristically whether if constant propagation can be worthwhile
Expand Down Expand Up @@ -2021,10 +2025,10 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
elseif isa(f, Core.OpaqueClosure)
# calling an OpaqueClosure about which we have no information returns no information
return CallMeta(typeof(f).parameters[2], Effects(), NoCallInfo())
elseif f === TypeVar
elseif f === TypeVar && !isvarargtype(argtypes[end])
# Manually look through the definition of TypeVar to
# make sure to be able to get `PartialTypeVar`s out.
(la < 2 || la > 4) && return CallMeta(Bottom, EFFECTS_THROWS, NoCallInfo())
2 la 4 || return CallMeta(Bottom, EFFECTS_THROWS, NoCallInfo())
n = argtypes[2]
ub_var = Const(Any)
lb_var = Const(Union{})
Expand Down Expand Up @@ -2267,11 +2271,7 @@ function abstract_eval_value_expr(interp::AbstractInterpreter, e::Expr, vtypes::
end

function abstract_eval_special_value(interp::AbstractInterpreter, @nospecialize(e), vtypes::Union{VarTable,Nothing}, sv::AbsIntState)
if isa(e, QuoteNode)
merge_effects!(interp, sv, Effects(EFFECTS_TOTAL;
inaccessiblememonly = is_mutation_free_argtype(typeof(e.value)) ? ALWAYS_TRUE : ALWAYS_FALSE))
return Const(e.value)
elseif isa(e, SSAValue)
if isa(e, SSAValue)
return abstract_eval_ssavalue(e, sv)
elseif isa(e, SlotNumber)
if vtypes !== nothing
Expand All @@ -2293,7 +2293,11 @@ function abstract_eval_special_value(interp::AbstractInterpreter, @nospecialize(
elseif isa(e, GlobalRef)
return abstract_eval_globalref(interp, e, sv)
end

if isa(e, QuoteNode)
e = e.value
end
merge_effects!(interp, sv, Effects(EFFECTS_TOTAL;
inaccessiblememonly = is_mutation_free_argtype(typeof(e)) ? ALWAYS_TRUE : ALWAYS_FALSE))
return Const(e)
end

Expand Down
4 changes: 2 additions & 2 deletions base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1615,7 +1615,7 @@ function escape_builtin!(::typeof(arrayref), astate::AnalysisState, pc::Int, arg
argtypes = Any[argextype(args[i], astate.ir) for i in 2:length(args)]
boundcheckt = argtypes[1]
aryt = argtypes[2]
if !array_builtin_common_typecheck(boundcheckt, aryt, argtypes, 3)
if !array_builtin_common_typecheck(𝕃ₒ, boundcheckt, aryt, argtypes, 3)
add_thrown_escapes!(astate, pc, args, 2)
end
ary = args[3]
Expand Down Expand Up @@ -1679,7 +1679,7 @@ function escape_builtin!(::typeof(arrayset), astate::AnalysisState, pc::Int, arg
boundcheckt = argtypes[1]
aryt = argtypes[2]
valt = argtypes[3]
if !(array_builtin_common_typecheck(boundcheckt, aryt, argtypes, 4) &&
if !(array_builtin_common_typecheck(𝕃ₒ, boundcheckt, aryt, argtypes, 4) &&
arrayset_typecheck(aryt, valt))
add_thrown_escapes!(astate, pc, args, 2)
end
Expand Down
4 changes: 2 additions & 2 deletions base/compiler/ssair/inlining.jl
Original file line number Diff line number Diff line change
Expand Up @@ -837,7 +837,7 @@ function compileable_specialization(mi::MethodInstance, effects::Effects,
end
end
add_inlining_backedge!(et, mi) # to the dispatch lookup
push!(et.edges, method.sig, mi_invoke) # add_inlining_backedge to the invoke call
mi_invoke !== mi && push!(et.edges, method.sig, mi_invoke) # add_inlining_backedge to the invoke call, if that is different
return InvokeCase(mi_invoke, effects, info)
end

Expand Down Expand Up @@ -1408,7 +1408,7 @@ function compute_inlining_cases(@nospecialize(info::CallInfo), flag::UInt8, sig:
fully_covered &= split_fully_covered
end

fully_covered || (joint_effects = Effects(joint_effects; nothrow=false))
(handled_all_cases & fully_covered) || (joint_effects = Effects(joint_effects; nothrow=false))

if handled_all_cases && revisit_idx !== nothing
# we handled everything except one match with unmatched sparams,
Expand Down
27 changes: 17 additions & 10 deletions base/compiler/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -95,25 +95,31 @@ add_tfunc(throw, 1, 1, @nospecs((𝕃::AbstractLattice, x)->Bottom), 0)
# if isexact is false, the actual runtime type may (will) be a subtype of t
# if isconcrete is true, the actual runtime type is definitely concrete (unreachable if not valid as a typeof)
# if istype is true, the actual runtime value will definitely be a type (e.g. this is false for Union{Type{Int}, Int})
function instanceof_tfunc(@nospecialize(t))
function instanceof_tfunc(@nospecialize(t), @nospecialize(troot) = t)
if isa(t, Const)
if isa(t.val, Type) && valid_as_lattice(t.val)
return t.val, true, isconcretetype(t.val), true
end
return Bottom, true, false, false # runtime throws on non-Type
end
t = widenconst(t)
troot = widenconst(troot)
if t === Bottom
return Bottom, true, true, false # runtime unreachable
elseif t === typeof(Bottom) || !hasintersect(t, Type)
return Bottom, true, false, false # literal Bottom or non-Type
elseif isType(t)
tp = t.parameters[1]
valid_as_lattice(tp) || return Bottom, true, false, false # runtime unreachable / throws on non-Type
if troot isa UnionAll
# Free `TypeVar`s inside `Type` has violated the "diagonal" rule.
# Widen them before `UnionAll` rewraping to relax concrete constraint.
tp = widen_diagonal(tp, troot)
end
return tp, !has_free_typevars(tp), isconcretetype(tp), true
elseif isa(t, UnionAll)
t′ = unwrap_unionall(t)
t′′, isexact, isconcrete, istype = instanceof_tfunc(t′)
t′′, isexact, isconcrete, istype = instanceof_tfunc(t′, rewrap_unionall(t, troot))
tr = rewrap_unionall(t′′, t)
if t′′ isa DataType && t′′.name !== Tuple.name && !has_free_typevars(tr)
# a real instance must be within the declared bounds of the type,
Expand All @@ -128,8 +134,8 @@ function instanceof_tfunc(@nospecialize(t))
end
return tr, isexact, isconcrete, istype
elseif isa(t, Union)
ta, isexact_a, isconcrete_a, istype_a = instanceof_tfunc(t.a)
tb, isexact_b, isconcrete_b, istype_b = instanceof_tfunc(t.b)
ta, isexact_a, isconcrete_a, istype_a = instanceof_tfunc(t.a, troot)
tb, isexact_b, isconcrete_b, istype_b = instanceof_tfunc(t.b, troot)
isconcrete = isconcrete_a && isconcrete_b
istype = istype_a && istype_b
# most users already handle the Union case, so here we assume that
Expand Down Expand Up @@ -2034,12 +2040,12 @@ function array_type_undefable(@nospecialize(arytype))
end
end

function array_builtin_common_nothrow(argtypes::Vector{Any}, isarrayref::Bool)
function array_builtin_common_nothrow(𝕃::AbstractLattice, argtypes::Vector{Any}, isarrayref::Bool)
first_idx_idx = isarrayref ? 3 : 4
length(argtypes) first_idx_idx || return false
boundscheck = argtypes[1]
arytype = argtypes[2]
array_builtin_common_typecheck(boundscheck, arytype, argtypes, first_idx_idx) || return false
array_builtin_common_typecheck(𝕃, boundscheck, arytype, argtypes, first_idx_idx) || return false
if isarrayref
# If we could potentially throw undef ref errors, bail out now.
arytype = widenconst(arytype)
Expand All @@ -2056,8 +2062,9 @@ function array_builtin_common_nothrow(argtypes::Vector{Any}, isarrayref::Bool)
return false
end

@nospecs function array_builtin_common_typecheck(boundscheck, arytype,
argtypes::Vector{Any}, first_idx_idx::Int)
@nospecs function array_builtin_common_typecheck(𝕃::AbstractLattice,
boundscheck, arytype, argtypes::Vector{Any}, first_idx_idx::Int)
= Core.Compiler.:(𝕃)
(boundscheck Bool && arytype Array) || return false
for i = first_idx_idx:length(argtypes)
argtypes[i] Int || return false
Expand All @@ -2080,11 +2087,11 @@ end
@nospecs function _builtin_nothrow(𝕃::AbstractLattice, f, argtypes::Vector{Any}, rt)
= Core.Compiler.:(𝕃)
if f === arrayset
array_builtin_common_nothrow(argtypes, #=isarrayref=#false) || return false
array_builtin_common_nothrow(𝕃, argtypes, #=isarrayref=#false) || return false
# Additionally check element type compatibility
return arrayset_typecheck(argtypes[2], argtypes[3])
elseif f === arrayref || f === const_arrayref
return array_builtin_common_nothrow(argtypes, #=isarrayref=#true)
return array_builtin_common_nothrow(𝕃, argtypes, #=isarrayref=#true)
elseif f === Core._expr
length(argtypes) >= 1 || return false
return argtypes[1] Symbol
Expand Down
13 changes: 7 additions & 6 deletions base/env.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,22 @@
if Sys.iswindows()
const ERROR_ENVVAR_NOT_FOUND = UInt32(203)

const env_dict = IdDict{String, Vector{Cwchar_t}}()
const env_dict = Dict{String, Vector{Cwchar_t}}()
const env_lock = ReentrantLock()

function memoized_env_lookup(str::AbstractString)
# Windows environment variables have a different format from Linux / MacOS, and previously
# incurred allocations because we had to convert a String to a Vector{Cwchar_t} each time
# an environment variable was looked up. This function memoizes that lookup process, storing
# the String => Vector{Cwchar_t} pairs in env_dict
var = get(env_dict, str, nothing)
if isnothing(var)
var = @lock env_lock begin
env_dict[str] = cwstring(str)
@lock env_lock begin
var = get(env_dict, str, nothing)
if isnothing(var)
var = cwstring(str)
env_dict[str] = var
end
return var
end
var
end

_getenvlen(var::Vector{UInt16}) = ccall(:GetEnvironmentVariableW,stdcall,UInt32,(Ptr{UInt16},Ptr{UInt16},UInt32),var,C_NULL,0)
Expand Down
5 changes: 5 additions & 0 deletions base/essentials.jl
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,11 @@ function rename_unionall(@nospecialize(u))
return UnionAll(nv, body{nv})
end

# remove concrete constraint on diagonal TypeVar if it comes from troot
function widen_diagonal(@nospecialize(t), troot::UnionAll)
body = ccall(:jl_widen_diagonal, Any, (Any, Any), t, troot)
end

function isvarargtype(@nospecialize(t))
return isa(t, Core.TypeofVararg)
end
Expand Down
5 changes: 4 additions & 1 deletion base/float.jl
Original file line number Diff line number Diff line change
Expand Up @@ -882,7 +882,10 @@ for Ti in (Int8, Int16, Int32, Int64, Int128, UInt8, UInt16, UInt32, UInt64, UIn
end
end
function (::Type{$Ti})(x::$Tf)
if ($(Tf(typemin(Ti))) <= x <= $(Tf(typemax(Ti)))) && isinteger(x)
# When typemax(Ti) is not representable by Tf but typemax(Ti) + 1 is,
# then < Tf(typemax(Ti) + 1) is stricter than <= Tf(typemax(Ti)). Using
# the former causes us to throw on UInt64(Float64(typemax(UInt64))+1)
if ($(Tf(typemin(Ti))) <= x < $(Tf(typemax(Ti))+one(Tf))) && isinteger(x)
return unsafe_trunc($Ti,x)
else
throw(InexactError($(Expr(:quote,Ti.name.name)), $Ti, x))
Expand Down
Loading

0 comments on commit 1dfdf66

Please sign in to comment.