Skip to content

Commit

Permalink
Backports for 1.10.0. (#52622)
Browse files Browse the repository at this point in the history
  • Loading branch information
KristofferC authored Dec 24, 2023
2 parents b6dd527 + 3fd8bae commit 85d852d
Show file tree
Hide file tree
Showing 13 changed files with 235 additions and 59 deletions.
4 changes: 1 addition & 3 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ Language changes
Compiler/Runtime improvements
-----------------------------

* Updated GC heuristics to count allocated pages instead of object sizes ([#50144]). This should help
some programs that consumed excessive memory before.
* The mark phase of the garbage collector is now multi-threaded ([#48600]).
* [JITLink](https://llvm.org/docs/JITLink.html) is enabled by default on Linux aarch64 when Julia is linked to LLVM 15 or later versions ([#49745]).
This should resolve many segmentation faults previously observed on this platform.
Expand Down Expand Up @@ -158,6 +156,7 @@ Deprecated or removed
[#48899]: https://github.com/JuliaLang/julia/issues/48899
[#48979]: https://github.com/JuliaLang/julia/issues/48979
[#49020]: https://github.com/JuliaLang/julia/issues/49020
[#49052]: https://github.com/JuliaLang/julia/issues/49052
[#49110]: https://github.com/JuliaLang/julia/issues/49110
[#49266]: https://github.com/JuliaLang/julia/issues/49266
[#49405]: https://github.com/JuliaLang/julia/issues/49405
Expand All @@ -167,5 +166,4 @@ Deprecated or removed
[#49745]: https://github.com/JuliaLang/julia/issues/49745
[#49795]: https://github.com/JuliaLang/julia/issues/49795
[#49959]: https://github.com/JuliaLang/julia/issues/49959
[#50144]: https://github.com/JuliaLang/julia/issues/50144
[#50218]: https://github.com/JuliaLang/julia/issues/50218
2 changes: 1 addition & 1 deletion base/compiler/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1731,7 +1731,7 @@ const _tvarnames = Symbol[:_A, :_B, :_C, :_D, :_E, :_F, :_G, :_H, :_I, :_J, :_K,
end
return allconst ? Const(ty) : Type{ty}
end
istuple = isa(headtype, Type) && (headtype == Tuple)
istuple = headtype === Tuple
if !istuple && !isa(headtype, UnionAll) && !isvarargtype(headtype)
return Union{}
end
Expand Down
37 changes: 24 additions & 13 deletions base/methodshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,29 @@ function show_method_list_header(io::IO, ms::MethodList, namefmt::Function)
!iszero(n) && print(io, ":")
end

# Determine the `modulecolor` value to pass to `show_method`
function _modulecolor(method::Method)
mmt = get_methodtable(method)
if mmt === nothing || mmt.module === parentmodule(method)
return nothing
end
# `mmt` is only particularly relevant for external method tables. Since the primary
# method table is shared, we now need to distinguish "primary" methods by trying to
# check if there is a primary `DataType` to identify it with. c.f. how `jl_method_def`
# would derive this same information (for the name).
ft = argument_datatype((unwrap_unionall(method.sig)::DataType).parameters[1])
# `ft` should be the type associated with the first argument in the method signature.
# If it's `Type`, try to unwrap it again.
if isType(ft)
ft = argument_datatype(ft.parameters[1])
end
if ft === nothing || parentmodule(method) === parentmodule(ft) !== Core
return nothing
end
m = parentmodule_before_main(method)
return get!(() -> popfirst!(STACKTRACE_MODULECOLORS), STACKTRACE_FIXEDCOLORS, m)
end

function show_method_table(io::IO, ms::MethodList, max::Int=-1, header::Bool=true)
mt = ms.mt
name = mt.name
Expand All @@ -300,12 +323,6 @@ function show_method_table(io::IO, ms::MethodList, max::Int=-1, header::Bool=tru
last_shown_line_infos = get(io, :last_shown_line_infos, nothing)
last_shown_line_infos === nothing || empty!(last_shown_line_infos)

modul = if mt === _TYPE_NAME.mt && length(ms) > 0 # type constructor
which(ms.ms[1].module, ms.ms[1].name)
else
mt.module
end

digit_align_width = length(string(max > 0 ? max : length(ms)))

for meth in ms
Expand All @@ -315,13 +332,7 @@ function show_method_table(io::IO, ms::MethodList, max::Int=-1, header::Bool=tru

print(io, " ", lpad("[$n]", digit_align_width + 2), " ")

modulecolor = if parentmodule(meth) == modul
nothing
else
m = parentmodule_before_main(meth)
get!(() -> popfirst!(STACKTRACE_MODULECOLORS), STACKTRACE_FIXEDCOLORS, m)
end
show_method(io, meth; modulecolor)
show_method(io, meth; modulecolor=_modulecolor(meth))

file, line = updated_methodloc(meth)
if last_shown_line_infos !== nothing
Expand Down
6 changes: 5 additions & 1 deletion base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2033,7 +2033,11 @@ function delete_method(m::Method)
end

function get_methodtable(m::Method)
return ccall(:jl_method_get_table, Any, (Any,), m)::Core.MethodTable
mt = ccall(:jl_method_get_table, Any, (Any,), m)
if mt === nothing
return nothing
end
return mt::Core.MethodTable
end

"""
Expand Down
9 changes: 9 additions & 0 deletions doc/src/manual/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,15 @@ If set to `true`, Pkg operations which use the git protocol will use an external

The accuracy of the package resolver. This should be a positive integer, the default is `1`.

### [`JULIA_PKG_PRESERVE_TIERED_INSTALLED`](@id JULIA_PKG_PRESERVE_TIERED_INSTALLED)

Change the default package installation strategy to `Pkg.PRESERVE_TIERED_INSTALLED`
to let the package manager try to install versions of packages while keeping as many
versions of packages already installed as possible.

!!! compat "Julia 1.9"
This only affects Julia 1.9 and above.

## Network transport

### `JULIA_NO_VERIFY_HOSTS` / `JULIA_SSL_NO_VERIFY_HOSTS` / `JULIA_SSH_NO_VERIFY_HOSTS` / `JULIA_ALWAYS_VERIFY_HOSTS`
Expand Down
2 changes: 1 addition & 1 deletion src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -3580,7 +3580,7 @@ f(x) = yt(x)
(rhs (convert-for-type-decl rhs1 (cl-convert vt fname lam #f #f #f interp opaq (table) locals) #t lam))
(ex (cond (closed `(call (core setfield!)
,(if interp
`($ ,var)
`($ (call (core QuoteNode) ,var))
(capt-var-access var fname opaq))
(inert contents)
,rhs))
Expand Down
50 changes: 23 additions & 27 deletions stdlib/REPL/src/REPLCompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export completions, shell_completions, bslash_completions, completion_text
using Core: CodeInfo, MethodInstance, CodeInstance, Const
const CC = Core.Compiler
using Base.Meta
using Base: propertynames, something
using Base: propertynames, something, IdSet

abstract type Completion end

Expand Down Expand Up @@ -659,6 +659,26 @@ function complete_methods(ex_org::Expr, context_module::Module=Main, shift::Bool
end

MAX_ANY_METHOD_COMPLETIONS::Int = 10
function recursive_explore_names!(seen::IdSet, callee_module::Module, initial_module::Module, exploredmodules::IdSet{Module}=IdSet{Module}())
push!(exploredmodules, callee_module)
for name in names(callee_module; all=true, imported=true)
if !Base.isdeprecated(callee_module, name) && !startswith(string(name), '#') && isdefined(initial_module, name)
func = getfield(callee_module, name)
if !isa(func, Module)
funct = Core.Typeof(func)
push!(seen, funct)
elseif isa(func, Module) && func exploredmodules
recursive_explore_names!(seen, func, initial_module, exploredmodules)
end
end
end
end
function recursive_explore_names(callee_module::Module, initial_module::Module)
seen = IdSet{Any}()
recursive_explore_names!(seen, callee_module, initial_module)
seen
end

function complete_any_methods(ex_org::Expr, callee_module::Module, context_module::Module, moreargs::Bool, shift::Bool)
out = Completion[]
args_ex, kwargs_ex, kwargs_flag = try
Expand All @@ -674,32 +694,8 @@ function complete_any_methods(ex_org::Expr, callee_module::Module, context_modul
# semicolon for the ".?(" syntax
moreargs && push!(args_ex, Vararg{Any})

seen = Base.IdSet()
for name in names(callee_module; all=true)
if !Base.isdeprecated(callee_module, name) && isdefined(callee_module, name) && !startswith(string(name), '#')
func = getfield(callee_module, name)
if !isa(func, Module)
funct = Core.Typeof(func)
if !in(funct, seen)
push!(seen, funct)
complete_methods!(out, funct, args_ex, kwargs_ex, MAX_ANY_METHOD_COMPLETIONS, false)
end
elseif callee_module === Main && isa(func, Module)
callee_module2 = func
for name in names(callee_module2)
if !Base.isdeprecated(callee_module2, name) && isdefined(callee_module2, name) && !startswith(string(name), '#')
func = getfield(callee_module, name)
if !isa(func, Module)
funct = Core.Typeof(func)
if !in(funct, seen)
push!(seen, funct)
complete_methods!(out, funct, args_ex, kwargs_ex, MAX_ANY_METHOD_COMPLETIONS, false)
end
end
end
end
end
end
for seen_name in recursive_explore_names(callee_module, callee_module)
complete_methods!(out, seen_name, args_ex, kwargs_ex, MAX_ANY_METHOD_COMPLETIONS, false)
end

if !shift
Expand Down
7 changes: 7 additions & 0 deletions stdlib/REPL/test/replcompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ let ex = quote
struct WeirdNames end
Base.propertynames(::WeirdNames) = (Symbol("oh no!"), Symbol("oh yes!"))

# https://github.com/JuliaLang/julia/issues/52551#issuecomment-1858543413
export exported_symbol
exported_symbol(::WeirdNames) = nothing

end # module CompletionFoo
test_repl_comp_dict = CompletionFoo.test_dict
test_repl_comp_customdict = CompletionFoo.test_customdict
Expand Down Expand Up @@ -740,6 +744,9 @@ end

#TODO: @test_nocompletion("CompletionFoo.?(3; len2=5; ")

# https://github.com/JuliaLang/julia/issues/52551
@test !isempty(test_complete("?("))

#################################################################

# Test method completion with varargs
Expand Down
81 changes: 70 additions & 11 deletions stdlib/Unicode/src/Unicode.jl
Original file line number Diff line number Diff line change
Expand Up @@ -208,12 +208,19 @@ end

using Base.Unicode: utf8proc_error, UTF8PROC_DECOMPOSE, UTF8PROC_CASEFOLD, UTF8PROC_STRIPMARK

function _decompose_char!(codepoint::Union{Integer,Char}, dest::Vector{UInt32}, options::Integer)
ret = @ccall utf8proc_decompose_char(codepoint::UInt32, dest::Ptr{UInt32}, length(dest)::Int, options::Cint, C_NULL::Ptr{Cint})::Int
function _decompose_char!(codepoint::Union{Integer,Char}, dest::Vector{UInt32}, offset::Integer, options::Integer)
ret = GC.@preserve dest @ccall utf8proc_decompose_char(codepoint::UInt32, pointer(dest, 1+offset)::Ptr{UInt32}, (length(dest)-offset)::Int, options::Cint, C_NULL::Ptr{Cint})::Int
ret < 0 && utf8proc_error(ret)
return ret
end

# would be good to have higher-level accessor functions in utf8proc. alternatively,
# we could mirror the whole utf8proc_property_t struct in Julia, but that is annoying
# because of the bitfields.
combining_class(uc::Integer) =
0x000301 uc 0x10ffff ? unsafe_load(ccall(:utf8proc_get_property, Ptr{UInt16}, (UInt32,), uc), 2) : 0x0000
combining_class(c::AbstractChar) = ismalformed(c) ? 0x0000 : combining_class(UInt32(c))

"""
isequal_normalized(s1::AbstractString, s2::AbstractString; casefold=false, stripmark=false, chartransform=identity)
Expand All @@ -225,6 +232,9 @@ As with [`Unicode.normalize`](@ref), you can also pass an arbitrary
function via the `chartransform` keyword (mapping `Integer` codepoints to codepoints)
to perform custom normalizations, such as [`Unicode.julia_chartransform`](@ref).
!!! compat "Julia 1.8"
The `isequal_normalized` function was added in Julia 1.8.
# Examples
For example, the string `"noël"` can be constructed in two canonically equivalent ways
Expand All @@ -251,29 +261,78 @@ julia> isequal_normalized(s1, "NOËL", casefold=true)
true
```
"""
function isequal_normalized(s1::AbstractString, s2::AbstractString; casefold::Bool=false, stripmark::Bool=false, chartransform=identity)
function decompose_next_char!(c, state, d, options, s)
n = _decompose_char!(c, d, options)
if n > length(d) # may be possible in future Unicode versions?
n = _decompose_char!(c, resize!(d, n), options)
isequal_normalized(s1::AbstractString, s2::AbstractString; casefold::Bool=false, stripmark::Bool=false, chartransform=identity) =
_isequal_normalized!(s1, s2, Vector{UInt32}(undef, 4), Vector{UInt32}(undef, 4), chartransform; casefold, stripmark)

# like isequal_normalized, but takes pre-allocated codepoint buffers as arguments, and chartransform is a positional argument
function _isequal_normalized!(s1::AbstractString, s2::AbstractString,
d1::Vector{UInt32}, d2::Vector{UInt32}, chartransform::F=identity;
casefold::Bool=false, stripmark::Bool=false) where {F}
function decompose_next_chars!(state, d, options, s)
local n
offset = 0
@inbounds while true
# read a char and decompose it to d
c = chartransform(UInt32(state[1]))
state = iterate(s, state[2])
if c < 0x80 # fast path for common ASCII case
n = 1 + offset
n > length(d) && resize!(d, 2n)
d[n] = casefold ? (0x41 c 0x5A ? c+0x20 : c) : c
break # ASCII characters are all zero combining class
else
while true
n = _decompose_char!(c, d, offset, options) + offset
if n > length(d)
resize!(d, 2n)
continue
end
break
end
end

# decomposed chars must be sorted in ascending order of combining class,
# which means we need to keep fetching chars until we get to non-combining
(iszero(combining_class(d[n])) || isnothing(state)) && break # non-combining
offset = n
end
return 1, n, iterate(s, state)

# sort by combining class
if n < 32 # almost always true
for j1 = 2:n # insertion sort
cc = combining_class(d[j1])
iszero(cc) && continue # don't re-order non-combiners
for j2 = j1:-1:2
combining_class(d[j2-1]) cc && break
d[j2-1], d[j2] = d[j2], d[j2-1]
end
end
else # avoid n^2 complexity in crazy large-n case
j = 1
@views while j < n
j₀ = j + something(findnext(iszero combining_class, d[j+1:n], 1), n+1-j)
sort!(d[j:j₀-1], by=combining_class)
j = j₀
end
end

# split return statement to help type inference:
return state === nothing ? (1, n, nothing) : (1, n, state)
end
options = UTF8PROC_DECOMPOSE
casefold && (options |= UTF8PROC_CASEFOLD)
stripmark && (options |= UTF8PROC_STRIPMARK)
i1,i2 = iterate(s1),iterate(s2)
d1,d2 = Vector{UInt32}(undef, 4), Vector{UInt32}(undef, 4) # codepoint buffers
n1 = n2 = 0 # lengths of codepoint buffers
j1 = j2 = 1 # indices in d1, d2
while true
if j1 > n1
i1 === nothing && return i2 === nothing && j2 > n2
j1, n1, i1 = decompose_next_char!(chartransform(UInt32(i1[1])), i1[2], d1, options, s1)
j1, n1, i1 = decompose_next_chars!(i1, d1, options, s1)
end
if j2 > n2
i2 === nothing && return false
j2, n2, i2 = decompose_next_char!(chartransform(UInt32(i2[1])), i2[2], d2, options, s2)
j2, n2, i2 = decompose_next_chars!(i2, d2, options, s2)
end
d1[j1] == d2[j2] || return false
j1 += 1; j2 += 1
Expand Down
Loading

0 comments on commit 85d852d

Please sign in to comment.