Skip to content

Commit

Permalink
Look through SSAValue to find include
Browse files Browse the repository at this point in the history
There's no guarantee that all include calls will be literal GlobalRefs
and in fact JuliaLang/julia#56746 will likely
make them never GlobalRef.
  • Loading branch information
Keno committed Dec 5, 2024
1 parent 71eb16a commit 687c7d5
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 8 deletions.
26 changes: 19 additions & 7 deletions src/lowered.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ add_dependencies!(methodinfo::MethodInfo, be::CodeEdges, src, isrequired) = meth
add_includes!(methodinfo::MethodInfo, mod::Module, filename) = methodinfo

function is_some_include(@nospecialize(f))
@assert !isa(f, Core.SSAValue) && !isa(f, JuliaInterpreter.SSAValue)
if isa(f, GlobalRef)
return f.name === :include
elseif isa(f, Symbol)
Expand All @@ -44,17 +45,21 @@ function is_some_include(@nospecialize(f))
end

# This is not generally used, see `is_method_or_eval` instead
function hastrackedexpr(stmt; heads=LoweredCodeUtils.trackedheads)
function hastrackedexpr(stmt, code; heads=LoweredCodeUtils.trackedheads)
haseval = false
if isa(stmt, Expr)
haseval = matches_eval(stmt)
if stmt.head === :call
f = stmt.args[1]
while isa(f, Core.SSAValue) || isa(f, JuliaInterpreter.SSAValue)
f = code[f.id]
end

Check warning on line 56 in src/lowered.jl

View check run for this annotation

Codecov / codecov/patch

src/lowered.jl#L54-L56

Added lines #L54 - L56 were not covered by tests
callee_matches(f, Core, :_typebody!) && return true, haseval
callee_matches(f, Core, :_setsuper!) && return true, haseval
is_some_include(f) && return true, haseval
elseif stmt.head === :thunk
any(s->any(hastrackedexpr(s; heads=heads)), (stmt.args[1]::Core.CodeInfo).code) && return true, haseval
newcode = (stmt.args[1]::Core.CodeInfo).code
any(s->any(hastrackedexpr(s, newcode; heads=heads)), newcode) && return true, haseval
elseif stmt.head heads
return true, haseval
end
Expand All @@ -70,14 +75,21 @@ function matches_eval(stmt::Expr)
(isa(f, GlobalRef) && f.name === :eval) || is_quotenode_egal(f, Core.eval)
end

function categorize_stmt(@nospecialize(stmt))
function categorize_stmt(@nospecialize(stmt), code::Vector{Any})
ismeth, haseval, isinclude, isnamespace, istoplevel = false, false, false, false, false
if isa(stmt, Expr)
haseval = matches_eval(stmt)
ismeth = stmt.head === :method || (stmt.head === :thunk && defines_function(only(stmt.args)))
istoplevel = stmt.head === :toplevel
isnamespace = stmt.head === :export || stmt.head === :import || stmt.head === :using
isinclude = stmt.head === :call && is_some_include(stmt.args[1])
isinclude = false
if stmt.head === :call && length(stmt.args) >= 1
callee = stmt.args[1]
while isa(callee, Core.SSAValue) || isa(callee, JuliaInterpreter.SSAValue)
callee = code[callee.id]
end
isinclude = is_some_include(callee)
end
end
return ismeth, haseval, isinclude, isnamespace, istoplevel
end
Expand Down Expand Up @@ -112,7 +124,7 @@ function minimal_evaluation!(@nospecialize(predicate), methodinfo, mod::Module,
evalassign = false
for (i, stmt) in enumerate(src.code)
if !isrequired[i]
isrequired[i], haseval = predicate(stmt)::Tuple{Bool,Bool}
isrequired[i], haseval = predicate(stmt, src.code)::Tuple{Bool,Bool}
if haseval # line `i` may be the equivalent of `f = Core.eval`, so...
isrequired[edges.succs[i]] .= true # ...require each stmt that calls `eval` via `f(expr)`
isrequired[i] = true
Expand Down Expand Up @@ -169,8 +181,8 @@ end
minimal_evaluation!(predicate, methodinfo, moduleof(frame), frame.framecode.src, mode)

function minimal_evaluation!(methodinfo, frame::JuliaInterpreter.Frame, mode::Symbol)
minimal_evaluation!(methodinfo, frame, mode) do @nospecialize(stmt)
ismeth, haseval, isinclude, isnamespace, istoplevel = categorize_stmt(stmt)
minimal_evaluation!(methodinfo, frame, mode) do @nospecialize(stmt), code
ismeth, haseval, isinclude, isnamespace, istoplevel = categorize_stmt(stmt, code)
isreq = ismeth | isinclude | istoplevel
return mode === :sigs ? (isreq, haseval) : (isreq | isnamespace, haseval)
end
Expand Down
2 changes: 1 addition & 1 deletion src/packagedef.jl
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ function add_dependencies!(methodinfo::CodeTrackingMethodInfo, edges::CodeEdges,
# It is aimed at solving #249, but this will have to be generalized for anything real.
for (stmt, me) in zip(src.code, musteval)
me || continue
if hastrackedexpr(stmt)[1]
if hastrackedexpr(stmt, src.code)[1]
push!(methodinfo.deps, dep)
break
end
Expand Down

0 comments on commit 687c7d5

Please sign in to comment.