Skip to content

Commit

Permalink
implement recursive type-inference
Browse files Browse the repository at this point in the history
since in the common case, the call graph is a simple DAG,
and it is faster / more efficient to infer immediately rather than building
the edges graph and repeating method lookup process after the backedge finishes
  • Loading branch information
vtjnash committed Mar 2, 2016
1 parent af81431 commit 6382116
Showing 1 changed file with 50 additions and 37 deletions.
87 changes: 50 additions & 37 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1599,32 +1599,26 @@ function typeinf_edge(linfo::LambdaInfo, atypes::ANY, sparams::SimpleVector, nee
end

if tfunc_idx == -1
if caller === nothing && needtree && in_typeinf_loop
if caller === nothing && needtree && in_typeinf_loop && !linfo.inInference
# if the caller needed the ast, but we are already in the typeinf loop
# then just return early -- we can't fulfill this request
# if the client was typeinf_ext(toplevel), then we cancel the inInference request
# if the client was inlining, then this means we decided not to try to infer this
# particular signature (due to signature coarsening in abstract_call_gf_by_type)
# and attempting to force it now would be a bad idea (non terminating)
linfo.inInference = false
return (nothing, Union{}, false)
end
# add lam to be inferred and record the edge
ast = ccall(:jl_prepare_ast, Any, (Any,), linfo)::Expr
sv = VarInfo(linfo, atypes, ast)

if length(linfo.sparam_vals) > 0
# handled by VarInfo constructor
elseif isempty(sparams) && !isempty(linfo.sparam_syms)
sv.sp = svec(Any[ TypeVar(sym, Any, true) for sym in linfo.sparam_syms ]...)
else
sv.sp = sparams
end

# our stack frame inference context
frame = InferenceState(sv, linfo, optimize)
push!(workq, frame)
frame.inworkq = true

if cached
#println(linfo)
Expand Down Expand Up @@ -1658,7 +1652,7 @@ function typeinf_edge(linfo::LambdaInfo, atypes::ANY, sparams::SimpleVector, nee
push!(frame.backedges, (me, Ws))
end
end
typeinf_loop()
typeinf_loop(frame)
return (frame.sv.ast, frame.bestguess, frame.inferred)
end

Expand All @@ -1676,14 +1670,15 @@ function typeinf_uncached(linfo::LambdaInfo, atypes::ANY, sparams::SimpleVector,
return typeinf_edge(linfo, atypes, sparams, true, optimize, false, nothing)
end
function typeinf_ext(linfo::LambdaInfo, toplevel::Bool)
return typeinf_edge(linfo, linfo.specTypes, svec(), toplevel, true, true, nothing)
return typeinf_edge(linfo, linfo.specTypes, svec(), true, true, true, nothing)
end


in_typeinf_loop = false
function typeinf_loop()
function typeinf_loop(frame)
global in_typeinf_loop
if in_typeinf_loop
frame.inworkq || typeinf_frame(frame)
return
end
in_typeinf_loop = true
Expand All @@ -1700,10 +1695,38 @@ function typeinf_loop()
frame = pop!(workq)
frame.inworkq = false
end
global global_sv = frame.sv # TODO: actually pass this to all functions that need it
typeinf_frame(frame)
if isempty(workq) && nactive[] > 0
# nothing in active has an edge that hasn't reached a fixed-point
# so all of them can be considered finished now
for i in active
i === nothing && continue
i = i::InferenceState
i.fixedpoint && finish(i)
end
end
end
# cleanup the active queue
empty!(active)
# while active[end] === nothing
# # this pops everything, but with exaggerated care just in case
# # something managed to add something to the queue at the same time
# # (or someone decides to use an alternative termination condition)
# pop!(active)
# end
in_typeinf_loop = false
nothing
end

global_sv = nothing
function typeinf_frame(frame)
global global_sv # TODO: actually pass this to all functions that need it
last_global_sv = global_sv
global_sv = frame.sv
W = frame.ip
s = frame.stmt_types
n = frame.nstmts
@label restart_typeinf
while !isempty(W)
# make progress on the active ip set
local pc::Int = first(W), pc´::Int
Expand Down Expand Up @@ -1844,6 +1867,13 @@ function typeinf_loop()
end
end

if frame.inferred
# during recursive compilation, this can happen.
# now just need to bail since it's already finished.
last_global_sv = global_sv
return
end

# with no active ip's, type inference on frame is done if there are no outstanding (unfinished) edges
finished = isempty(frame.edges)
if isempty(workq)
Expand All @@ -1852,7 +1882,6 @@ function typeinf_loop()
frame.fixedpoint = true
end

restart = false
if finished || frame.fixedpoint
if frame.typegotoredo
# if any type_gotos changed, clear state and restart.
Expand All @@ -1866,7 +1895,7 @@ function typeinf_loop()
frame.handler_at = Any[ () for i=1:n ]
frame.n_handlers = 0
frame.sv.gensym_types[:] = frame.gensym_init
restart = true
@goto restart_typeinf
else
# if a static_typeof was never reached,
# use Union{} as its real type and continue
Expand All @@ -1882,15 +1911,12 @@ function typeinf_loop()
push!(W, r)
end
end
restart = true
@goto restart_typeinf
end
end
end

if restart
push!(workq, frame)
frame.inworkq = true
elseif finished
if finished
finish(frame)
else # fixedpoint propagation
for (i,_) in frame.edges
Expand All @@ -1903,25 +1929,7 @@ function typeinf_loop()
end
end
end
if !restart && isempty(workq) && nactive[] > 0
# nothing in active has an edge that hasn't reached a fixed-point
# so all of them can be considered finished now
for i in active
i === nothing && continue
i = i::InferenceState
i.fixedpoint && finish(i)
end
end
end
# cleanup the active queue
empty!(active)
# while active[end] === nothing
# # this pops everything, but with exaggerated care just in case
# # something managed to add something to the queue at the same time
# # (or someone decides to use an alternative termination condition)
# pop!(active)
# end
in_typeinf_loop = false
global_sv = last_global_sv
nothing
end

Expand Down Expand Up @@ -1950,6 +1958,11 @@ function finish(me::InferenceState)
for (i,_) in me.edges
@assert (i::InferenceState).fixedpoint
end
# below may call back into inference and
# see this InferenceState is in an imcomplete state
# set `inworkq` to prevent it from trying to look
# at the object in any detail
me.inworkq = true

# annotate fulltree with type information
for i = 1:length(me.sv.gensym_types)
Expand Down

0 comments on commit 6382116

Please sign in to comment.