Skip to content

Commit 4accf8a

Browse files
authored
Merge pull request #16929 from JuliaLang/jb/linfocopying
try to simplify information flow around inference
2 parents 7ad5eee + f57fd54 commit 4accf8a

File tree

4 files changed

+120
-153
lines changed

4 files changed

+120
-153
lines changed

base/inference.jl

Lines changed: 96 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ type InferenceState
4747

4848
# info on the state of inference and the linfo
4949
linfo::LambdaInfo
50-
destination::LambdaInfo # results need to be copied here when we finish
5150
nargs::Int
5251
stmt_types::Vector{Any}
5352
# return type
@@ -73,11 +72,9 @@ type InferenceState
7372
inworkq::Bool
7473
optimize::Bool
7574
inferred::Bool
76-
tfunc_bp::Union{TypeMapEntry, Void}
7775

7876
function InferenceState(linfo::LambdaInfo, optimize::Bool)
7977
@assert isa(linfo.code,Array{Any,1})
80-
linfo.inInference = true
8178
nslots = length(linfo.slotnames)
8279
nl = label_counter(linfo.code)+1
8380

@@ -156,12 +153,12 @@ type InferenceState
156153
inmodule = isdefined(linfo, :def) ? linfo.def.module : current_module() # toplevel thunks are inferred in the current module
157154
frame = new(
158155
sp, nl, Dict{SSAValue, Bool}(), inmodule, 0, false,
159-
linfo, linfo, la, s, Union{}, W, n,
156+
linfo, la, s, Union{}, W, n,
160157
cur_hand, handler_at, n_handlers,
161158
ssavalue_uses, ssavalue_init,
162159
ObjectIdDict(), #Dict{InferenceState, Vector{LineNum}}(),
163160
Vector{Tuple{InferenceState, Vector{LineNum}}}(),
164-
false, false, false, optimize, false, nothing)
161+
false, false, false, optimize, false)
165162
push!(active, frame)
166163
nactive[] += 1
167164
return frame
@@ -1387,25 +1384,25 @@ function newvar!(sv::InferenceState, typ)
13871384
end
13881385

13891386
# create a specialized LambdaInfo from a method
1390-
function specialize_method(method::Method, types::ANY, sp::SimpleVector)
1391-
li = ccall(:jl_get_specialized, Ref{LambdaInfo}, (Any, Any, Any), method, types, sp)
1392-
return li
1387+
function specialize_method(method::Method, types::ANY, sp::SimpleVector, cached)
1388+
if cached
1389+
return ccall(:jl_specializations_get_linfo, Ref{LambdaInfo}, (Any, Any, Any), method, types, sp)
1390+
else
1391+
return ccall(:jl_get_specialized, Ref{LambdaInfo}, (Any, Any, Any), method, types, sp)
1392+
end
13931393
end
13941394

13951395
# create copies of any field that type-inference might modify
13961396
function unshare_linfo!(li::LambdaInfo)
1397-
if !isa(li.code, Array{Any,1})
1397+
orig = li.def.lambda_template
1398+
if isa(li.code, Array{UInt8,1})
13981399
li.code = ccall(:jl_uncompress_ast, Any, (Any,Any), li, li.code)
1399-
else
1400-
li.code = copy_exprargs(li.code)
1400+
elseif li.code === orig.code
1401+
li.code = copy_exprargs(orig.code)
14011402
end
1402-
li.slotnames = copy(li.slotnames)
1403-
li.slotflags = copy(li.slotflags)
1404-
if isa(li.slottypes, Array)
1405-
li.slottypes = copy(li.slottypes)
1406-
end
1407-
if isa(li.ssavaluetypes, Array)
1408-
li.ssavaluetypes = copy(li.ssavaluetypes)
1403+
if !li.def.isstaged
1404+
li.slotnames = copy(li.slotnames)
1405+
li.slotflags = copy(li.slotflags)
14091406
end
14101407
return li
14111408
end
@@ -1414,9 +1411,11 @@ end
14141411
function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, needtree::Bool, optimize::Bool, cached::Bool, caller)
14151412
local code = nothing
14161413
local frame = nothing
1417-
# check cached specializations
1418-
# for an existing result stored there
1419-
if cached
1414+
if isa(caller, LambdaInfo)
1415+
code = caller
1416+
elseif cached
1417+
# check cached specializations
1418+
# for an existing result stored there
14201419
if !is(method.specializations, nothing)
14211420
code = ccall(:jl_specializations_lookup, Any, (Any, Any), method, atypes)
14221421
if isa(code, Void)
@@ -1436,89 +1435,80 @@ function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, needtr
14361435
code = nothing
14371436
end
14381437
end
1438+
end
14391439

1440-
if isa(code, LambdaInfo) && code.inInference
1441-
# inference on this signature may be in progress,
1442-
# find the corresponding frame in the active list
1443-
for infstate in active
1444-
infstate === nothing && continue
1445-
infstate = infstate::InferenceState
1446-
if code === infstate.linfo
1447-
frame = infstate
1448-
break
1440+
if caller === nothing && in_typeinf_loop
1441+
# if the caller needed the ast, but we are already in the typeinf loop
1442+
# then just return early -- we can't fulfill this request
1443+
# if the client was inlining, then this means we decided not to try to infer this
1444+
# particular signature (due to signature coarsening in abstract_call_gf_by_type)
1445+
# and attempting to force it now would be a bad idea (non terminating)
1446+
skip = true
1447+
if method.module == _topmod(method.module) || (isdefined(Main, :Base) && method.module == Main.Base)
1448+
# however, some gf have special tfunc and meaning they wouldn't have been inferred yet
1449+
# check the same conditions from abstract_call to detect this case
1450+
if method.name == :promote_type || method.name == :typejoin
1451+
skip = false
1452+
elseif method.name == :getindex || method.name == :next || method.name == :indexed_next
1453+
argtypes = atypes.parameters
1454+
if length(argtypes)>2 && argtypes[3] Int
1455+
at2 = widenconst(argtypes[2])
1456+
if (at2 <: Tuple ||
1457+
(isa(at2, DataType) && isdefined(Main, :Base) && isdefined(Main.Base, :Pair) &&
1458+
(at2::DataType).name === Main.Base.Pair.name))
1459+
skip = false
1460+
end
14491461
end
14501462
end
14511463
end
1464+
if skip
1465+
return (nothing, Union{}, false)
1466+
end
14521467
end
14531468

1454-
if isa(caller, LambdaInfo)
1455-
code = caller
1456-
end
1457-
1458-
if frame === nothing
1459-
# inference not started yet, make a new frame for a new lambda
1460-
# add lam to be inferred and record the edge
1461-
1462-
if caller === nothing && in_typeinf_loop
1463-
# if the caller needed the ast, but we are already in the typeinf loop
1464-
# then just return early -- we can't fulfill this request
1465-
# if the client was inlining, then this means we decided not to try to infer this
1466-
# particular signature (due to signature coarsening in abstract_call_gf_by_type)
1467-
# and attempting to force it now would be a bad idea (non terminating)
1468-
skip = true
1469-
if method.module == _topmod(method.module) || (isdefined(Main, :Base) && method.module == Main.Base)
1470-
# however, some gf have special tfunc and meaning they wouldn't have been inferred yet
1471-
# check the same conditions from abstract_call to detect this case
1472-
if method.name == :promote_type || method.name == :typejoin
1473-
skip = false
1474-
elseif method.name == :getindex || method.name == :next || method.name == :indexed_next
1475-
argtypes = atypes.parameters
1476-
if length(argtypes)>2 && argtypes[3] Int
1477-
at2 = widenconst(argtypes[2])
1478-
if (at2 <: Tuple ||
1479-
(isa(at2, DataType) && isdefined(Main, :Base) && isdefined(Main.Base, :Pair) &&
1480-
(at2::DataType).name === Main.Base.Pair.name))
1481-
skip = false
1482-
end
1483-
end
1484-
end
1485-
end
1486-
if skip
1487-
return (nothing, Union{}, false)
1488-
end
1469+
if isa(code, LambdaInfo) && code.code !== nothing
1470+
# reuse the existing code object
1471+
linfo = code
1472+
@assert typeseq(linfo.specTypes, atypes)
1473+
elseif method.isstaged
1474+
if !isleaftype(atypes)
1475+
# don't call staged functions on abstract types.
1476+
# (see issues #8504, #10230)
1477+
# we can't guarantee that their type behavior is monotonic.
1478+
return (nothing, Any, false)
1479+
end
1480+
try
1481+
# user code might throw errors – ignore them
1482+
linfo = specialize_method(method, atypes, sparams, cached)
1483+
catch
1484+
return (nothing, Any, false)
14891485
end
1486+
else
1487+
linfo = specialize_method(method, atypes, sparams, cached)
1488+
end
14901489

1491-
if isa(code, LambdaInfo) && code.code !== nothing
1492-
# reuse the existing code object
1493-
linfo = code
1494-
@assert typeseq(linfo.specTypes, atypes)
1495-
elseif method.isstaged
1496-
if !isleaftype(atypes)
1497-
# don't call staged functions on abstract types.
1498-
# (see issues #8504, #10230)
1499-
# we can't guarantee that their type behavior is monotonic.
1500-
return (nothing, Any, false)
1501-
end
1502-
try
1503-
# user code might throw errors – ignore them
1504-
linfo = specialize_method(method, atypes, sparams)
1505-
catch
1506-
return (nothing, Any, false)
1490+
if linfo.inInference
1491+
# inference on this signature may be in progress,
1492+
# find the corresponding frame in the active list
1493+
for infstate in active
1494+
infstate === nothing && continue
1495+
infstate = infstate::InferenceState
1496+
if linfo === infstate.linfo
1497+
frame = infstate
1498+
break
15071499
end
1508-
else
1509-
linfo = specialize_method(method, atypes, sparams)
15101500
end
1511-
# our stack frame inference context
1501+
# TODO: this assertion seems iffy
1502+
assert(frame !== nothing)
1503+
else
1504+
# inference not started yet, make a new frame for a new lambda
1505+
linfo.inInference = true
15121506
frame = InferenceState(unshare_linfo!(linfo::LambdaInfo), optimize)
1513-
if cached
1514-
frame.tfunc_bp = ccall(:jl_specializations_insert, Ref{TypeMapEntry}, (Any, Any, Any), method, atypes, linfo)
1515-
end
15161507
end
15171508
frame = frame::InferenceState
15181509

1519-
if !isa(caller, Void) && !isa(caller, LambdaInfo)
1520-
# if we were called from inside inference,
1521-
# the caller will be the InferenceState object
1510+
if isa(caller, InferenceState)
1511+
# if we were called from inside inference, the caller will be the InferenceState object
15221512
# for which the edge was required
15231513
caller = caller::InferenceState
15241514
if haskey(caller.edges, frame)
@@ -1554,26 +1544,30 @@ function typeinf_ext(linfo::LambdaInfo)
15541544
if isdefined(linfo, :def)
15551545
# method lambda - infer this specialization via the method cache
15561546
(code, _t, _) = typeinf_edge(linfo.def, linfo.specTypes, linfo.sparam_vals, true, true, true, linfo)
1557-
if code.inferred
1547+
if code.inferred && linfo !== code
1548+
# This case occurs when the IR for a function has been deleted.
1549+
# `code` will be a newly-created LambdaInfo, and we need to copy its
1550+
# contents to the existing one to copy the info to the method cache.
15581551
linfo.inferred = true
15591552
linfo.inInference = false
1560-
if linfo !== code
1561-
linfo.code = code.code
1562-
linfo.slotnames = code.slotnames
1563-
linfo.slottypes = code.slottypes
1564-
linfo.slotflags = code.slotflags
1565-
linfo.ssavaluetypes = code.ssavaluetypes
1566-
linfo.rettype = code.rettype
1567-
linfo.pure = code.pure
1568-
end
1569-
end
1553+
linfo.code = code.code
1554+
linfo.slotnames = code.slotnames
1555+
linfo.slottypes = code.slottypes
1556+
linfo.slotflags = code.slotflags
1557+
linfo.ssavaluetypes = code.ssavaluetypes
1558+
linfo.rettype = code.rettype
1559+
linfo.pure = code.pure
1560+
linfo.inlineable = code.inlineable
1561+
end
1562+
return code
15701563
else
15711564
# toplevel lambda - infer directly
1565+
linfo.inInference = true
15721566
frame = InferenceState(linfo, true)
15731567
typeinf_loop(frame)
15741568
@assert frame.inferred # TODO: deal with this better
1569+
return linfo
15751570
end
1576-
nothing
15771571
end
15781572

15791573

@@ -1947,20 +1941,6 @@ function finish(me::InferenceState)
19471941
end
19481942
me.linfo.rettype = me.bestguess
19491943

1950-
if me.destination !== me.linfo
1951-
out = me.destination
1952-
out.inferred = true
1953-
out.inInference = false
1954-
out.code = me.linfo.code
1955-
out.slotnames = me.linfo.slotnames
1956-
out.slottypes = me.linfo.slottypes
1957-
out.slotflags = me.linfo.slotflags
1958-
out.ssavaluetypes = me.linfo.ssavaluetypes
1959-
out.rettype = me.linfo.rettype
1960-
out.pure = me.linfo.pure
1961-
out.inlineable = me.linfo.inlineable
1962-
end
1963-
19641944
# lazy-delete the item from active for several reasons:
19651945
# efficiency, correctness, and recursion-safety
19661946
nactive[] -= 1

src/codegen.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1141,7 +1141,7 @@ void *jl_get_llvmf(jl_tupletype_t *tt, bool getwrapper, bool getdeclarations)
11411141

11421142
if (linfo->code == jl_nothing) {
11431143
// re-infer if we've deleted the code
1144-
jl_type_infer(linfo, 0);
1144+
linfo = jl_type_infer(linfo, 0);
11451145
if (linfo->code == jl_nothing) {
11461146
JL_GC_POP();
11471147
return NULL;

0 commit comments

Comments
 (0)