Skip to content

Commit

Permalink
Add RTCallInfo for runtime calls
Browse files Browse the repository at this point in the history
The list of call sites serves two purposes:

- it gives you options to descend into
- it summarizes the calls made by your function

Given the second purpose, I've sometimes been confused by the absence
of an entry for the "worst" of all cases, runtime dispatch. This seems
particularly accute for #345, but may have value even when examining
the CodeInfo/IRCode.
  • Loading branch information
timholy committed Mar 1, 2023
1 parent 70a600f commit d76d18a
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 23 deletions.
5 changes: 5 additions & 0 deletions src/Cthulhu.jl
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,11 @@ function _descend(term::AbstractTerminal, interp::AbstractInterpreter, curs::Abs
"""
additional_descend(get_mi(info)::MethodInstance)
continue
elseif info isa RTCallInfo
@info """
This is a runtime call. You cannot descend into it.
"""
@goto show_menu
end

# recurse
Expand Down
16 changes: 16 additions & 0 deletions src/callsite.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ struct LimitedCallInfo <: WrappedCallInfo
wrapped::CallInfo
end

# Runtime CallInfo
struct RTCallInfo <: CallInfo
f
argtyps
rt
end
get_mi(ci::RTCallInfo) = nothing
get_effects(ci::RTCallInfo) = Effects()

# uncached callsite, we can't recurse into this call
struct UncachedCallInfo <: WrappedCallInfo
wrapped::CallInfo
Expand Down Expand Up @@ -309,6 +318,8 @@ function show_callinfo(limiter, ci::Union{MultiCallInfo, FailedCallInfo, Generat
__show_limited(limiter, name::String, tt, get_rt(ci), get_effects(ci))
end

show_callinfo(limiter, ci::RTCallInfo) = __show_limited(limiter, "$(ci.f)", ci.argtyps, get_rt(ci), get_effects(ci))

function show_callinfo(limiter, pci::PureCallInfo)
ft, tt... = pci.argtypes
f = CC.singleton_type(ft)
Expand Down Expand Up @@ -366,6 +377,11 @@ function print_callsite_info(limiter::IO, info::Union{MultiCallInfo, FailedCallI
show_callinfo(limiter, info)
end

function print_callsite_info(limiter::IO, info::RTCallInfo)
print(limiter, "RT call ")
show_callinfo(limiter, info)
end

function print_callsite_info(limiter::IO, info::TaskCallInfo)
print(limiter, "task < ")
show_callinfo(limiter, info.ci)
Expand Down
46 changes: 24 additions & 22 deletions src/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,28 +32,26 @@ function find_callsites(interp::AbstractInterpreter, CI::Union{Core.CodeInfo, IR
callsite = nothing
if stmt_infos !== nothing && is_call_expr(stmt, optimize)
info = stmt_infos[id]
if info !== NoCallInfo()
rt = ignorelimited(argextype(SSAValue(id), CI, sptypes, slottypes))
# in unoptimized IR, there may be `slot = rhs` expressions, which `argextype` doesn't handle
# so extract rhs for such an case
local args = stmt.args
if !optimize
args = (ignorelhs(stmt)::Expr).args
end
argtypes = mapany(function (@nospecialize(arg),)
t = argextype(arg, CI, sptypes, slottypes)
return ignorelimited(t)
end, args)
callinfos = process_info(interp, info, argtypes, rt, optimize)
isempty(callinfos) && continue
callsite = let
if length(callinfos) == 1
callinfo = callinfos[1]
else
callinfo = MultiCallInfo(argtypes_to_type(argtypes), rt, callinfos)
end
Callsite(id, callinfo, stmt.head)
rt = ignorelimited(argextype(SSAValue(id), CI, sptypes, slottypes))
# in unoptimized IR, there may be `slot = rhs` expressions, which `argextype` doesn't handle
# so extract rhs for such an case
local args = stmt.args
if !optimize
args = (ignorelhs(stmt)::Expr).args
end
argtypes = mapany(function (@nospecialize(arg),)
t = argextype(arg, CI, sptypes, slottypes)
return ignorelimited(t)
end, args)
callinfos = process_info(interp, info, argtypes, rt, optimize)
isempty(callinfos) && continue
callsite = let
if length(callinfos) == 1
callinfo = callinfos[1]
else
callinfo = MultiCallInfo(argtypes_to_type(argtypes), rt, callinfos)
end
Callsite(id, callinfo, stmt.head)
end
end

Expand Down Expand Up @@ -211,7 +209,11 @@ function process_info(interp::AbstractInterpreter, @nospecialize(info::CCCallInf
vmi = FailedCallInfo(sig, Union{})
end
return Any[ReturnTypeCallInfo(vmi)]
elseif info == NoCallInfo() || info === false
elseif info == NoCallInfo()
f = unwrapconst(argtypes[1])
isa(f, Core.Builtin) && return []
return [RTCallInfo(f, argtypes[2:end], rt)]
elseif info === false
return []
else
@eval Main begin
Expand Down
3 changes: 2 additions & 1 deletion test/test_terminal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,9 @@ end
Base.text_colors[Base.error_color()]
end
@test occursin("$(warncolor)%\e[39m2 = call → fmulti(::Any)::Union{Float32, Int64}", lines)
write(in, keydict[:down])
write(in, keydict[:enter])
lines = cread1(out)
lines = cread(out)
@test occursin("%2 = fmulti(::Int32)::Union{Float32, $Int}", lines)
@test occursin("%2 = fmulti(::Float32)::Union{Float32, $Int}", lines)
@test occursin("%2 = fmulti(::Char)::Union{Float32, $Int}", lines)
Expand Down

0 comments on commit d76d18a

Please sign in to comment.