Skip to content

Commit 865739e

Browse files
committed
Merge branch 'master' of github.com:JuliaLang/julia into interactive-utils-functors
2 parents 76f030c + 6efd218 commit 865739e

File tree

12 files changed

+142
-83
lines changed

12 files changed

+142
-83
lines changed

Compiler/src/ssair/show.jl

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,30 @@ function print_stmt(io::IO, idx::Int, @nospecialize(stmt), code::Union{IRCode,Co
105105
printstyled(io, "dynamic invoke "; color = :yellow)
106106
abi = (ci::Core.MethodInstance).specTypes
107107
end
108-
show_unquoted(io, stmt.args[2], indent)
109-
print(io, "(")
110108
# XXX: this is wrong if `sig` is not a concretetype method
111109
# more correct would be to use `fieldtype(sig, i)`, but that would obscure / discard Varargs information in show
112110
sig = abi == Tuple ? Core.svec() : Base.unwrap_unionall(abi).parameters::Core.SimpleVector
111+
f = stmt.args[2]
112+
ft = maybe_argextype(f, code, sptypes)
113+
114+
# We can elide the type for arg0 if it...
115+
skip_ftype = (length(sig) == 0) # doesn't exist...
116+
skip_ftype = skip_ftype || (
117+
# ... or, f prints as a user-accessible value...
118+
(f isa GlobalRef) &&
119+
# ... and matches the value of the singleton type of the invoked MethodInstance
120+
(singleton_type(ft) === singleton_type(sig[1]) !== nothing)
121+
)
122+
if skip_ftype
123+
show_unquoted(io, f, indent)
124+
else
125+
print(io, "(")
126+
show_unquoted(io, f, indent)
127+
print(io, "::", sig[1], ")")
128+
end
129+
130+
# Print the remaining arguments (with type annotations from the invoked MethodInstance)
131+
print(io, "(")
113132
print_arg(i) = sprint(; context=io) do io
114133
show_unquoted(io, stmt.args[i], indent)
115134
if (i - 1) <= length(sig)

Compiler/src/stmtinfo.jl

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ function _add_edges_impl(edges::Vector{Any}, info::MethodMatchInfo, mi_edge::Boo
6060
end
6161
end
6262
nmatches = length(info.results)
63-
if nmatches == length(info.edges) == 1
63+
if nmatches == length(info.edges) == 1 && fully_covering(info)
6464
# try the optimized format for the representation, if possible and applicable
6565
# if this doesn't succeed, the backedge will be less precise,
6666
# but the forward edge will maintain the precision
@@ -78,13 +78,15 @@ function _add_edges_impl(edges::Vector{Any}, info::MethodMatchInfo, mi_edge::Boo
7878
end
7979
end
8080
# add check for whether this lookup already existed in the edges list
81+
# encode nmatches as negative if fully_covers is false
82+
encoded_nmatches = fully_covering(info) ? nmatches : -nmatches
8183
for i in 1:length(edges)
82-
if edges[i] === nmatches && edges[i+1] == info.atype
84+
if edges[i] === encoded_nmatches && edges[i+1] == info.atype
8385
# TODO: must also verify the CodeInstance match too
8486
return nothing
8587
end
8688
end
87-
push!(edges, nmatches, info.atype)
89+
push!(edges, encoded_nmatches, info.atype)
8890
for i = 1:nmatches
8991
edge = info.edges[i]
9092
m = info.results[i]
@@ -101,7 +103,7 @@ function add_one_edge!(edges::Vector{Any}, edge::MethodInstance)
101103
i = 1
102104
while i <= length(edges)
103105
edgeᵢ = edges[i]
104-
edgeᵢ isa Int && (i += 2 + edgeᵢ; continue)
106+
edgeᵢ isa Int && (i += 2 + abs(edgeᵢ); continue)
105107
edgeᵢ isa CodeInstance && (edgeᵢ = get_ci_mi(edgeᵢ))
106108
edgeᵢ isa MethodInstance || (i += 1; continue)
107109
if edgeᵢ === edge && !(i > 1 && edges[i-1] isa Type)
@@ -116,7 +118,7 @@ function add_one_edge!(edges::Vector{Any}, edge::CodeInstance)
116118
i = 1
117119
while i <= length(edges)
118120
edgeᵢ_orig = edgeᵢ = edges[i]
119-
edgeᵢ isa Int && (i += 2 + edgeᵢ; continue)
121+
edgeᵢ isa Int && (i += 2 + abs(edgeᵢ); continue)
120122
edgeᵢ isa CodeInstance && (edgeᵢ = get_ci_mi(edgeᵢ))
121123
edgeᵢ isa MethodInstance || (i += 1; continue)
122124
if edgeᵢ === edge.def && !(i > 1 && edges[i-1] isa Type)

base/combinatorics.jl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,13 +184,12 @@ end
184184
"""
185185
permute!(v, p)
186186
187-
Permute vector `v` in-place, according to permutation `p`. No checking is done
188-
to verify that `p` is a permutation.
187+
Permute vector `v` according to permutation `p`, storing the result back into `v`.
188+
No checking is done to verify that `p` is a permutation.
189189
190190
To return a new permutation, use `v[p]`. This is generally faster than `permute!(v, p)`;
191191
it is even faster to write into a pre-allocated output array with `u .= @view v[p]`.
192-
(Even though `permute!` overwrites `v` in-place, it internally requires some allocation
193-
to keep track of which elements have been moved.)
192+
(Even though `permute!` overwrites `v` in-place, it internally requires some allocation.)
194193
195194
$(_DOCS_ALIASING_WARNING)
196195

base/iterators.jl

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,20 +1239,48 @@ flatten_length(f, T) = throw(ArgumentError(
12391239
length(f::Flatten{I}) where {I} = flatten_length(f, eltype(I))
12401240
length(f::Flatten{Tuple{}}) = 0
12411241

1242-
@propagate_inbounds function iterate(f::Flatten, state=())
1243-
if state !== ()
1244-
y = iterate(tail(state)...)
1245-
y !== nothing && return (y[1], (state[1], state[2], y[2]))
1242+
@propagate_inbounds function iterate(fl::Flatten)
1243+
it_result = iterate(fl.it)
1244+
it_result === nothing && return nothing
1245+
1246+
inner_iterator, next_outer_state = it_result
1247+
inner_it_result = iterate(inner_iterator)
1248+
1249+
while inner_it_result === nothing
1250+
it_result = iterate(fl.it, next_outer_state)
1251+
it_result === nothing && return nothing
1252+
1253+
inner_iterator, next_outer_state = it_result
1254+
inner_it_result = iterate(inner_iterator)
12461255
end
1247-
x = (state === () ? iterate(f.it) : iterate(f.it, state[1]))
1248-
x === nothing && return nothing
1249-
y = iterate(x[1])
1250-
while y === nothing
1251-
x = iterate(f.it, x[2])
1252-
x === nothing && return nothing
1253-
y = iterate(x[1])
1256+
1257+
item, next_inner_state = inner_it_result
1258+
return item, (next_outer_state, inner_iterator, next_inner_state)
1259+
end
1260+
1261+
@propagate_inbounds function iterate(fl::Flatten, state)
1262+
next_outer_state, inner_iterator, next_inner_state = state
1263+
1264+
# try to advance the inner iterator
1265+
inner_it_result = iterate(inner_iterator, next_inner_state)
1266+
if inner_it_result !== nothing
1267+
item, next_inner_state = inner_it_result
1268+
return item, (next_outer_state, inner_iterator, next_inner_state)
1269+
end
1270+
1271+
# advance the outer iterator
1272+
while true
1273+
outer_it_result = iterate(fl.it, next_outer_state)
1274+
outer_it_result === nothing && return nothing
1275+
1276+
inner_iterator, next_outer_state = outer_it_result
1277+
inner_it_result = iterate(inner_iterator)
1278+
1279+
if inner_it_result !== nothing
1280+
item, next_inner_state = inner_it_result
1281+
return item, (next_outer_state, inner_iterator, next_inner_state)
1282+
end
12541283
end
1255-
return y[1], (x[2], x[1], y[2])
12561284
end
12571285

12581286
reverse(f::Flatten) = Flatten(reverse(itr) for itr in reverse(f.it))

base/staticdata.jl

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -168,12 +168,15 @@ function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visi
168168
end
169169
if edge isa MethodInstance
170170
sig = edge.specTypes
171-
min_valid2, max_valid2, matches = verify_call(sig, callees, j, 1, world)
171+
min_valid2, max_valid2, matches = verify_call(sig, callees, j, 1, world, true)
172172
j += 1
173173
elseif edge isa Int
174174
sig = callees[j+1]
175-
min_valid2, max_valid2, matches = verify_call(sig, callees, j+2, edge, world)
176-
j += 2 + edge
175+
# Handle negative counts (fully_covers=false)
176+
nmatches = abs(edge)
177+
fully_covers = edge > 0
178+
min_valid2, max_valid2, matches = verify_call(sig, callees, j+2, nmatches, world, fully_covers)
179+
j += 2 + nmatches
177180
edge = sig
178181
elseif edge isa Core.Binding
179182
j += 1
@@ -279,7 +282,7 @@ function verify_method(codeinst::CodeInstance, stack::Vector{CodeInstance}, visi
279282
return 0, minworld, maxworld
280283
end
281284

282-
function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n::Int, world::UInt)
285+
function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n::Int, world::UInt, fully_covers::Bool)
283286
# verify that these edges intersect with the same methods as before
284287
mi = nothing
285288
if n == 1
@@ -295,20 +298,25 @@ function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n
295298
mi = t::MethodInstance
296299
end
297300
meth = mi.def::Method
298-
if !iszero(mi.dispatch_status & METHOD_SIG_LATEST_ONLY)
301+
# Fast path is legal when fully_covers=true OR when METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC is unset
302+
if (fully_covers || iszero(meth.dispatch_status & METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC)) &&
303+
!iszero(mi.dispatch_status & METHOD_SIG_LATEST_ONLY)
299304
minworld = meth.primary_world
300305
@assert minworld world
301306
maxworld = typemax(UInt)
302307
result = Any[] # result is unused
303308
return minworld, maxworld, result
304309
end
305310
end
306-
if !iszero(meth.dispatch_status & METHOD_SIG_LATEST_ONLY)
307-
minworld = meth.primary_world
308-
@assert minworld world
309-
maxworld = typemax(UInt)
310-
result = Any[] # result is unused
311-
return minworld, maxworld, result
311+
# Fast path is legal when fully_covers=true OR when METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC is unset
312+
if fully_covers || iszero(meth.dispatch_status & METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC)
313+
if !iszero(meth.dispatch_status & METHOD_SIG_LATEST_ONLY)
314+
minworld = meth.primary_world
315+
@assert minworld world
316+
maxworld = typemax(UInt)
317+
result = Any[] # result is unused
318+
return minworld, maxworld, result
319+
end
312320
end
313321
end
314322
end
@@ -373,6 +381,8 @@ end
373381
const METHOD_SIG_LATEST_WHICH = 0x1
374382
# true indicates this method would be returned as the only result from `methods` when calling `method.sig` in the current latest world
375383
const METHOD_SIG_LATEST_ONLY = 0x2
384+
# true indicates there exists some other method that is not more specific than this one in the current latest world (which might be more fully covering)
385+
const METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC = 0x8
376386

377387
function verify_invokesig(@nospecialize(invokesig), expected::Method, world::UInt)
378388
@assert invokesig isa Type

doc/src/manual/functions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ julia> function hypot(x, y)
178178
return x*sqrt(1 + r*r)
179179
end
180180
if y == 0
181-
return x
181+
return float(x)
182182
end
183183
r = x/y
184184
return y*sqrt(1 + r*r)

doc/src/manual/profile.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -562,8 +562,7 @@ Passing `sample_rate=1.0` will make it record everything (which is slow);
562562

563563
Since Julia 1.11, all allocations should have a type reported.
564564

565-
For more details on how to use this tool, please see the following talk from JuliaCon 2022:
566-
https://www.youtube.com/watch?v=BFvpwC8hEWQ
565+
For more details on how to use this tool, please see [the talk from JuliaCon 2022](https://www.youtube.com/watch?v=BFvpwC8hEWQ).
567566

568567
##### Allocation Profiler Example
569568

0 commit comments

Comments
 (0)