Skip to content

Commit

Permalink
add a fallback implementation for (pass::$PassName)(fargs...) (#46)
Browse files Browse the repository at this point in the history
When dynamic dispatch occurs for the generated function and the dispatch
signature is `!isdispatchtuple` (e.g. since it includes a `Type`-object
argument with a free type variable), it will result in unintended code
generation, leading to issues like #39 and #45.
In this commit, the generated function is now not marked as
`:generated_only`, and it will simply fallback to original
implementations.

This fix introduces a regression where overlays will not occur for the
entire call graph of such `!isdispatchtuple` dynamic dispatches.
But since it would require a redesign of the runtime system to
completely resolve this issue, this regression seems to be acceptable
for now.
  • Loading branch information
aviatesk authored Jun 21, 2024
1 parent 55204f9 commit 81323e9
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 15 deletions.
31 changes: 17 additions & 14 deletions src/CassetteOverlay.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,8 @@ function overlay_generator(world::UInt, source::LineNumberNode, passtype, fargty
match = _which(tt; method_table=method_table(passtype), raise=false, world)
match === nothing && return nothing
mi = specialize_method(match)::MethodInstance
src = @static if has_generated_worlds
copy(retrieve_code_info(mi, world)::CodeInfo)
else
copy(retrieve_code_info(mi)::CodeInfo)
end
src = (@static has_generated_worlds ?
retrieve_code_info(mi, world) : retrieve_code_info(mi))::CodeInfo
overlay_transform!(src, mi, length(fargtypes))
return src
end
Expand Down Expand Up @@ -253,21 +250,27 @@ macro overlaypass(args...)
mainpass = @static if has_generated_worlds
quote
function (pass::$PassName)(fargs...)
$(Expr(:meta, :generated_only))
$(Expr(:meta, :generated, pass_generator))
# also include a fallback implementation that will be used when this method
# is dynamically dispatched with `!isdispatchtuple` signatures.
return first(fargs)(Base.tail(fargs)...)
end
end
else
quote
@generated function (pass::$PassName)($(esc(:fargs))...)
world = Base.get_world_counter()
source = LineNumberNode(@__LINE__, @__FILE__)
src = $overlay_generator(world, source, pass, fargs)
if src === nothing
# a code generation failed – make it raise a proper MethodError
return :(first(fargs)(Base.tail(fargs)...))
function (pass::$PassName)($(esc(:fargs))...)
if @generated
world = Base.get_world_counter()
source = LineNumberNode(@__LINE__, @__FILE__)
src = $overlay_generator(world, source, pass, fargs)
if src === nothing
# a code generation failed – make it raise a proper MethodError
return :(first(fargs)(Base.tail(fargs)...))
end
return src
else
return first(fargs)(Base.tail(fargs)...)
end
return src
end
end
end
Expand Down
17 changes: 16 additions & 1 deletion test/simple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,19 @@ let pass = @overlaypass Issue8.Issue8Table
@test pass(identity, 42) == nothing
end

end
# JuliaDebug/CassetteOverlay#39 & JuliaDebug/CassetteOverlay#45:
# use the fallback implementation for `!isdispatchtuple` dynamic dispatches
issue39() = UnionAll(TypeVar(:T,Integer), Array{TypeVar(:T,Integer)})
@test pass() do
issue39()
end isa UnionAll

issue45(x::UnionAll) = issue45(x.body)
issue45(x) = x
@test pass(issue45, NamedTuple) == issue45(NamedTuple)

pr46_regression(x::UnionAll) = pr46_regression(x.body)
pr46_regression(x) = myidentity(x)
@test_broken pass(fallback_regression, NamedTuple) == 42

end # module simple

0 comments on commit 81323e9

Please sign in to comment.