Skip to content

Commit 4bce889

Browse files
committed
thread min/max validity of ml-matches results out of jl_matching_methods into inference
eventually should probably switch this to use a Ref, or return the value, or something similarly more efficient than a singleton Array, but currently refpointer.jl is not part of Core.Inference
1 parent a84105f commit 4bce889

File tree

4 files changed

+112
-50
lines changed

4 files changed

+112
-50
lines changed

base/REPLCompletions.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,9 @@ function get_type_call(expr::Expr)
281281
found ? push!(args, typ) : push!(args, Any)
282282
end
283283
# use _methods_by_ftype as the function is supplied as a type
284-
mt = Base._methods_by_ftype(Tuple{ft, args...}, -1, typemax(UInt))
284+
min = UInt[typemin(UInt)]
285+
max = UInt[typemax(UInt)]
286+
mt = Base._methods_by_ftype(Tuple{ft, args...}, -1, typemax(UInt), min, max)
285287
length(mt) == 1 || return (Any, false)
286288
m = first(mt)
287289
# Typeinference

base/inference.jl

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,9 @@ function abstract_call_gf_by_type(f::ANY, atype::ANY, sv::InferenceState)
826826
return Any
827827
end
828828
end
829-
applicable = _methods_by_ftype(argtype, 4, sv.world)
829+
min_valid = UInt[typemin(UInt)]
830+
max_valid = UInt[typemax(UInt)]
831+
applicable = _methods_by_ftype(argtype, 4, sv.world, min_valid, max_valid)
830832
rettype = Bottom
831833
if is(applicable, false)
832834
# this means too many methods matched
@@ -956,6 +958,7 @@ function abstract_call_gf_by_type(f::ANY, atype::ANY, sv::InferenceState)
956958
# also need an edge to the method table in case something gets
957959
# added that did not intersect with any existing method
958960
add_mt_backedge(ft.name.mt, argtype, sv)
961+
update_valid_age!(min_valid[1], max_valid[1], sv)
959962
end
960963
if isempty(x)
961964
# TODO: this is needed because type intersection is wrong in some cases
@@ -1060,7 +1063,9 @@ function pure_eval_call(f::ANY, argtypes::ANY, atype, vtypes, sv::InferenceState
10601063
end
10611064
end
10621065

1063-
meth = _methods_by_ftype(atype, 1, sv.world)
1066+
min_valid = UInt[typemin(UInt)]
1067+
max_valid = UInt[typemax(UInt)]
1068+
meth = _methods_by_ftype(atype, 1, sv.world, min_valid, max_valid)
10641069
if meth === false || length(meth) != 1
10651070
return false
10661071
end
@@ -1074,6 +1079,7 @@ function pure_eval_call(f::ANY, argtypes::ANY, atype, vtypes, sv::InferenceState
10741079
args = Any[ isa(a,Const) ? a.val : a.parameters[1] for a in drop(argtypes,1) ]
10751080
try
10761081
value = Core._apply_pure(f, args)
1082+
# TODO: add some sort of edge(s)
10771083
return abstract_eval_constant(value)
10781084
catch
10791085
return false
@@ -1530,23 +1536,24 @@ function converge_valid_age!(sv::InferenceState)
15301536
i.max_valid = sv.max_valid
15311537
updated = true
15321538
end
1539+
@assert !isdefined(i.linfo, :def) || i.min_valid <= i.world <= i.max_valid "invalid age range update"
15331540
if updated
15341541
converge_valid_age!(i)
15351542
end
15361543
end
15371544
end
15381545
nothing
15391546
end
1540-
function update_valid_age!(edge::InferenceState, sv::InferenceState)
1541-
sv.min_valid = max(edge.min_valid, sv.min_valid)
1542-
sv.max_valid = min(edge.max_valid, sv.max_valid)
1543-
nothing
1544-
end
1545-
function update_valid_age!(li::MethodInstance, sv::InferenceState)
1546-
sv.min_valid = max(sv.min_valid, min_age(li))
1547-
sv.max_valid = min(sv.max_valid, max_age(li))
1547+
1548+
function update_valid_age!(min_valid::UInt, max_valid::UInt, sv::InferenceState)
1549+
sv.min_valid = max(sv.min_valid, min_valid)
1550+
sv.max_valid = min(sv.max_valid, max_valid)
1551+
@assert !isdefined(sv.linfo, :def) || sv.min_valid <= sv.world <= sv.max_valid "invalid age range update"
15481552
nothing
15491553
end
1554+
update_valid_age!(edge::InferenceState, sv::InferenceState) = update_valid_age!(edge.min_valid, edge.max_valid, sv)
1555+
update_valid_age!(li::MethodInstance, sv::InferenceState) = update_valid_age!(min_age(li), max_age(li), sv)
1556+
15501557
function add_backedge(li::MethodInstance, caller::InferenceState)
15511558
isdefined(caller.linfo, :def) || return # don't add backedges to toplevel exprs
15521559
if caller.stmt_edges[caller.currpc] === ()
@@ -1556,6 +1563,7 @@ function add_backedge(li::MethodInstance, caller::InferenceState)
15561563
update_valid_age!(li, caller)
15571564
nothing
15581565
end
1566+
15591567
function add_mt_backedge(mt::MethodTable, typ::ANY, caller::InferenceState)
15601568
isdefined(caller.linfo, :def) || return # don't add backedges to toplevel exprs
15611569
if caller.stmt_edges[caller.currpc] === ()
@@ -1566,6 +1574,7 @@ function add_mt_backedge(mt::MethodTable, typ::ANY, caller::InferenceState)
15661574
# TODO: how to compute the affect this has on valid ages for caller?
15671575
nothing
15681576
end
1577+
15691578
function finalize_backedges(frame::InferenceState)
15701579
caller = frame.linfo
15711580
for edges in frame.stmt_edges
@@ -1666,7 +1675,7 @@ function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, caller
16661675
code = code_for_method(method, atypes, sparams, caller.world)
16671676
code === nothing && return Any
16681677
code = code::MethodInstance
1669-
add_backedge(code, caller)
1678+
add_backedge(code, caller) # TODO: need to defer the tracking of this backedge till later
16701679
if isdefined(code, :inferred)
16711680
# return rettype if the code is already inferred
16721681
# staged functions make this hard since they have two "inferred" conditions,
@@ -2682,7 +2691,9 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
26822691
else
26832692
atype = atype_unlimited
26842693
end
2685-
meth = _methods_by_ftype(atype, 1, sv.world)
2694+
min_valid = UInt[typemin(UInt)]
2695+
max_valid = UInt[typemax(UInt)]
2696+
meth = _methods_by_ftype(atype, 1, sv.world, min_valid, max_valid)
26862697
if meth === false || length(meth) != 1
26872698
return invoke_NF()
26882699
end
@@ -4083,9 +4094,9 @@ end
40834094
# make sure that typeinf is executed before turning on typeinf_ext
40844095
# this ensures that typeinf_ext doesn't recurse before it can add the item to the workq
40854096

4086-
for m in _methods_by_ftype(Tuple{typeof(typeinf_loop), Vararg{Any}}, 10, typemax(UInt))
4097+
for m in _methods_by_ftype(Tuple{typeof(typeinf_loop), Vararg{Any}}, 10, typemax(UInt), UInt[typemin(UInt)], UInt[typemax(UInt)])
40874098
typeinf_type(m[3], m[1], m[2], typemax(UInt))
40884099
end
4089-
for m in _methods_by_ftype(Tuple{typeof(typeinf_edge), Vararg{Any}}, 10, typemax(UInt))
4100+
for m in _methods_by_ftype(Tuple{typeof(typeinf_edge), Vararg{Any}}, 10, typemax(UInt), UInt[typemin(UInt)], UInt[typemax(UInt)])
40904101
typeinf_type(m[3], m[1], m[2], typemax(UInt))
40914102
end

base/reflection.jl

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -349,10 +349,12 @@ end
349349
function _methods(f::ANY, t::ANY, lim::Int, world::UInt)
350350
ft = isa(f,Type) ? Type{f} : typeof(f)
351351
tt = isa(t,Type) ? Tuple{ft, t.parameters...} : Tuple{ft, t...}
352-
return _methods_by_ftype(tt, lim, world)
352+
min = UInt[typemin(UInt)]
353+
max = UInt[typemax(UInt)]
354+
return _methods_by_ftype(tt, lim, world, min, max)
353355
end
354356

355-
function _methods_by_ftype(t::ANY, lim::Int, world::UInt)
357+
function _methods_by_ftype(t::ANY, lim::Int, world::UInt, min::Array{UInt,1}, max::Array{UInt,1})
356358
tp = t.parameters::SimpleVector
357359
nu = 1
358360
for ti in tp
@@ -361,31 +363,31 @@ function _methods_by_ftype(t::ANY, lim::Int, world::UInt)
361363
end
362364
end
363365
if 1 < nu <= 64
364-
return _methods(Any[tp...], length(tp), lim, [], world)
366+
return _methods_by_ftype(Any[tp...], length(tp), lim, [], world, min, max)
365367
end
366368
# XXX: the following can return incorrect answers that the above branch would have corrected
367-
return ccall(:jl_matching_methods, Any, (Any, Cint, Cint, UInt), t, lim, 0, world)
369+
return ccall(:jl_matching_methods, Any, (Any, Cint, Cint, UInt, Ptr{UInt}, Ptr{UInt}), t, lim, 0, world, min, max)
368370
end
369371

370-
function _methods(t::Array, i, lim::Integer, matching::Array{Any,1}, world::UInt)
372+
function _methods_by_ftype(t::Array, i, lim::Integer, matching::Array{Any,1}, world::UInt, min::Array{UInt,1}, max::Array{UInt,1})
371373
if i == 0
372374
world = typemax(UInt)
373-
new = ccall(:jl_matching_methods, Any, (Any, Cint, Cint, UInt), Tuple{t...}, lim, 0, world)
375+
new = ccall(:jl_matching_methods, Any, (Any, Cint, Cint, UInt, Ptr{UInt}, Ptr{UInt}), Tuple{t...}, lim, 0, world, min, max)
374376
new === false && return false
375377
append!(matching, new::Array{Any,1})
376378
else
377379
ti = t[i]
378380
if isa(ti, Union)
379381
for ty in (ti::Union).types
380382
t[i] = ty
381-
if _methods(t, i - 1, lim, matching, world) === false
383+
if _methods_by_ftype(t, i - 1, lim, matching, world, min, max) === false
382384
t[i] = ti
383385
return false
384386
end
385387
end
386388
t[i] = ti
387389
else
388-
return _methods(t, i - 1, lim, matching, world)
390+
return _methods_by_ftype(t, i - 1, lim, matching, world, min, max)
389391
end
390392
end
391393
return matching
@@ -435,7 +437,9 @@ function methods_including_ambiguous(f::ANY, t::ANY)
435437
ft = isa(f,Type) ? Type{f} : typeof(f)
436438
tt = isa(t,Type) ? Tuple{ft, t.parameters...} : Tuple{ft, t...}
437439
world = typemax(UInt)
438-
ms = ccall(:jl_matching_methods, Any, (Any, Cint, Cint, UInt), tt, -1, 1, world)::Array{Any,1}
440+
min = UInt[typemin(UInt)]
441+
max = UInt[typemax(UInt)]
442+
ms = ccall(:jl_matching_methods, Any, (Any, Cint, Cint, UInt, Ptr{UInt}, Ptr{UInt}), tt, -1, 1, world, min, max)::Array{Any,1}
439443
return MethodList(Method[m[3] for m in ms], typeof(f).name.mt)
440444
end
441445
function methods(f::ANY)
@@ -745,7 +749,9 @@ end
745749
function isambiguous(m1::Method, m2::Method)
746750
ti = typeintersect(m1.sig, m2.sig)
747751
ti === Bottom && return false
748-
ml = _methods_by_ftype(ti, -1, typemax(UInt))
752+
min = UInt[typemin(UInt)]
753+
max = UInt[typemax(UInt)]
754+
ml = _methods_by_ftype(ti, -1, typemax(UInt), min, max)
749755
isempty(ml) && return true
750756
for m in ml
751757
if ti <: m[3].sig

0 commit comments

Comments
 (0)