Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix on Julia 1.11 #108

Merged
merged 5 commits into from
Jun 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 61 additions & 40 deletions src/signatures.jl
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,19 @@ function identify_framemethod_calls(frame)
key = key::Union{Symbol,Bool,Nothing}
for (j, mstmt) in enumerate(msrc.code)
isa(mstmt, Expr) || continue
jj = j
if mstmt.head === :call
mkey = mstmt.args[1]
if isa(mkey, SSAValue) || isa(mkey, Core.SSAValue)
refstmt = msrc.code[mkey.id]
if isa(refstmt, Symbol)
jj = mkey.id
mkey = refstmt
end
end
if isa(mkey, Symbol)
# Could be a GlobalRef but then it's outside frame
haskey(methodinfos, mkey) && push!(selfcalls, SelfCall(i, j, mkey, key))
haskey(methodinfos, mkey) && push!(selfcalls, SelfCall(i, jj, mkey, key))
elseif is_global_ref(mkey, Core, isdefined(Core, :_apply_iterate) ? :_apply_iterate : :_apply)
ssaref = mstmt.args[end-1]
if isa(ssaref, JuliaInterpreter.SSAValue)
Expand All @@ -202,15 +210,15 @@ function identify_framemethod_calls(frame)
end
mkey = mstmt.args[end-2]
if isa(mkey, Symbol)
haskey(methodinfos, mkey) && push!(selfcalls, SelfCall(i, j, mkey, key))
haskey(methodinfos, mkey) && push!(selfcalls, SelfCall(i, jj, mkey, key))
end
end
elseif mstmt.head === :meta && mstmt.args[1] === :generated
newex = mstmt.args[2]
if isa(newex, Expr)
if newex.head === :new && length(newex.args) >= 2 && is_global_ref(newex.args[1], Core, :GeneratedFunctionStub)
mkey = newex.args[2]::Symbol
haskey(methodinfos, mkey) && push!(selfcalls, SelfCall(i, j, mkey, key))
haskey(methodinfos, mkey) && push!(selfcalls, SelfCall(i, jj, mkey, key))
end
end
end
Expand Down Expand Up @@ -356,7 +364,7 @@ function find_name_caller_sig(@nospecialize(recurse), frame, pc, name, parentnam
end
if length(body.code) > 1
bodystmt = body.code[end-1] # the line before the final return
iscallto(bodystmt, name) && return signature_top(frame, stmt, pc), false
iscallto(bodystmt, name, body) && return signature_top(frame, stmt, pc), false
end
end
pc = next_or_nothing(frame, pc)
Expand Down Expand Up @@ -426,6 +434,9 @@ function get_running_name(@nospecialize(recurse), frame, pc, name, parentname)
bodystmt = bodyparent.code[end-1]
@assert isexpr(bodystmt, :call)
ref = getcallee(bodystmt)
if isa(ref, SSAValue) || isa(ref, Core.SSAValue)
ref = bodyparent.code[ref.id]
end
isa(ref, GlobalRef) || @show ref typeof(ref)
@assert isa(ref, GlobalRef)
@assert ref.mod == moduleof(frame)
Expand Down Expand Up @@ -581,7 +592,7 @@ function _methoddefs!(@nospecialize(recurse), signatures, frame::Frame, pc; defi
return pc
end

function is_self_call(@nospecialize(stmt), slotnames, argno=1)
function is_self_call(@nospecialize(stmt), slotnames, argno::Integer=1)
if isa(stmt, Expr)
if stmt.head == :call
a = stmt.args[argno]
Expand Down Expand Up @@ -612,44 +623,54 @@ Return the "body method" for a method `m`. `mbody` contains the code of the func
when `m` was defined.
"""
function bodymethod(mkw::Method)
m = mkw
local src
while true
framecode = JuliaInterpreter.get_framecode(m)
fakeargs = Any[nothing for i = 1:(framecode.scope::Method).nargs]
frame = JuliaInterpreter.prepare_frame(framecode, fakeargs, isa(m.sig, UnionAll) ? sparam_ub(m) : Core.svec())
src = framecode.src
(length(src.code) > 1 && is_self_call(src.code[end-1], src.slotnames)) || break
# Build the optional arg, so we can get its type
pc = frame.pc
while pc < length(src.code) - 1
pc = step_expr!(frame)
@static if isdefined(Core, :kwcall)
Base.unwrap_unionall(mkw.sig).parameters[1] !== typeof(Core.kwcall) && isempty(Base.kwarg_decl(mkw)) && return mkw
mths = methods(Base.bodyfunction(mkw))
if length(mths) != 1
@show mkw
display(mths)
end
val = pc > 1 ? frame.framedata.ssavalues[pc-1] : (src.code[1]::Expr).args[end]
sig = Tuple{(Base.unwrap_unionall(m.sig)::DataType).parameters..., typeof(val)}
m = whichtt(sig)
end
length(src.code) > 1 || return m
stmt = src.code[end-1]
if isexpr(stmt, :call) && (f = (stmt::Expr).args[1]; isa(f, QuoteNode))
if f.value === (isdefined(Core, :_apply_iterate) ? Core._apply_iterate : Core._apply)
ssaref = stmt.args[end-1]
if isa(ssaref, JuliaInterpreter.SSAValue)
id = ssaref.id
has_self_call(src, src.code[id]) || return m
end
f = stmt.args[end-2]
if isa(f, JuliaInterpreter.SSAValue)
f = src.code[f.id]
return only(mths)
else
m = mkw
local src
while true
framecode = JuliaInterpreter.get_framecode(m)
fakeargs = Any[nothing for i = 1:(framecode.scope::Method).nargs]
frame = JuliaInterpreter.prepare_frame(framecode, fakeargs, isa(m.sig, UnionAll) ? sparam_ub(m) : Core.svec())
src = framecode.src
(length(src.code) > 1 && is_self_call(src.code[end-1], src.slotnames)) || break
# Build the optional arg, so we can get its type
pc = frame.pc
while pc < length(src.code) - 1
pc = step_expr!(frame)
end
else
has_self_call(src, stmt) || return m
val = pc > 1 ? frame.framedata.ssavalues[pc-1] : (src.code[1]::Expr).args[end]
sig = Tuple{(Base.unwrap_unionall(m.sig)::DataType).parameters..., typeof(val)}
m = whichtt(sig)
end
f = f.value
mths = methods(f)
if length(mths) == 1
return first(mths)
length(src.code) > 1 || return m
stmt = src.code[end-1]
if isexpr(stmt, :call) && (f = (stmt::Expr).args[1]; isa(f, QuoteNode))
if f.value === (isdefined(Core, :_apply_iterate) ? Core._apply_iterate : Core._apply)
ssaref = stmt.args[end-1]
if isa(ssaref, JuliaInterpreter.SSAValue)
id = ssaref.id
has_self_call(src, src.code[id]) || return m
end
f = stmt.args[end-2]
if isa(f, JuliaInterpreter.SSAValue)
f = src.code[f.id]
end
else
has_self_call(src, stmt) || return m
end
f = f.value
mths = methods(f)
if length(mths) == 1
return first(mths)
end
end
return m
end
return m
end
15 changes: 9 additions & 6 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,17 @@ macro issslotnum(stmt)
end

"""
iscallto(stmt, name)
iscallto(stmt, name, src)

Returns `true` is `stmt` is a call expression to `name`.
"""
function iscallto(@nospecialize(stmt), name)
function iscallto(@nospecialize(stmt), name, src)
if isa(stmt, Expr)
if stmt.head === :call
a = stmt.args[1]
if isa(a, SSAValue) || isa(a, Core.SSAValue)
a = src.code[a.id]
end
a === name && return true
is_global_ref(a, Core, :_apply) && stmt.args[2] === name && return true
is_global_ref(a, Core, :_apply_iterate) && stmt.args[3] === name && return true
Expand Down Expand Up @@ -110,15 +113,15 @@ function isanonymous_typedef(stmt)
if isa(stmt, CodeInfo)
src = stmt # just for naming consistency
length(src.code) >= 4 || return false
stmt = src.code[end-1]
isexpr(stmt, :call) || return false
is_global_ref(stmt.args[1], Core, :_typebody!) || return false
@static if VERSION ≥ v"1.9.0-DEV.391"
stmt = src.code[end-2]
stmt = isa(stmt.args[3], Core.SSAValue) ? src.code[end-3] : src.code[end-2]
isexpr(stmt, :(=)) || return false
name = stmt.args[1]
isa(name, Symbol) || return false
else
stmt = src.code[end-1]
isexpr(stmt, :call) || return false
is_global_ref(stmt.args[1], Core, :_typebody!) || return false
name = stmt.args[2]::Symbol
end
return startswith(String(name), "#")
Expand Down
8 changes: 6 additions & 2 deletions test/codeedges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,12 @@ module ModSelective end
src = frame.framecode.src
edges = CodeEdges(src)
isrequired = fill(false, length(src.code))
@assert Meta.isexpr(src.code[end-1], :method, 3)
isrequired[end-1] = true
j = length(src.code) - 1
if !Meta.isexpr(src.code[end-1], :method, 3)
j -= 1
end
@assert Meta.isexpr(src.code[j], :method, 3)
isrequired[j] = true
lines_required!(isrequired, src, edges)
selective_eval_fromstart!(frame, isrequired, true)
@test ModSelective.max_values(Int16) === 65536
Expand Down
2 changes: 1 addition & 1 deletion test/signatures.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module signatures
module Signatures

using LoweredCodeUtils
using InteractiveUtils
Expand Down
Loading