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

oc: code_typed support for optimized opaque closures #53929

Merged
merged 4 commits into from
Apr 3, 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
38 changes: 28 additions & 10 deletions base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1584,7 +1584,7 @@ julia> code_typed(+, (Float64, Float64))
"""
function code_typed(@nospecialize(f), @nospecialize(types=default_tt(f)); kwargs...)
if isa(f, Core.OpaqueClosure)
return code_typed_opaque_closure(f; kwargs...)
return code_typed_opaque_closure(f, types; kwargs...)
end
tt = signature_type(f, types)
return code_typed_by_type(tt; kwargs...)
Expand Down Expand Up @@ -1639,20 +1639,38 @@ function code_typed_by_type(@nospecialize(tt::Type);
return asts
end

function get_oc_code_rt(@nospecialize(oc::Core.OpaqueClosure))
ccall(:jl_is_in_pure_context, Bool, ()) && error("code reflection cannot be used from generated functions")
function get_oc_code_rt(oc::Core.OpaqueClosure, types, optimize::Bool)
@nospecialize oc types
ccall(:jl_is_in_pure_context, Bool, ()) &&
error("code reflection cannot be used from generated functions")
m = oc.source
if isa(m, Method)
code = _uncompressed_ir(m)
return Pair{CodeInfo,Any}(code, typeof(oc).parameters[2])
if isdefined(m, :source)
if optimize
tt = Tuple{typeof(oc.captures), to_tuple_type(types).parameters...}
mi = Core.Compiler.specialize_method(m, tt, Core.svec())
interp = Core.Compiler.NativeInterpreter(m.primary_world)
return Core.Compiler.typeinf_code(interp, mi, optimize)
else
code = _uncompressed_ir(m)
return Pair{CodeInfo,Any}(code, typeof(oc).parameters[2])
end
else
# OC constructed from optimized IR
codeinst = m.specializations.cache
return Pair{CodeInfo, Any}(codeinst.inferred, codeinst.rettype)
end
else
error("encountered invalid Core.OpaqueClosure object")
end
end

function code_typed_opaque_closure(@nospecialize(oc::Core.OpaqueClosure);
debuginfo::Symbol=:default, _...)
(code, rt) = get_oc_code_rt(oc)
function code_typed_opaque_closure(oc::Core.OpaqueClosure, types;
debuginfo::Symbol=:default,
optimize::Bool=true,
_...)
@nospecialize oc types
(code, rt) = get_oc_code_rt(oc, types, optimize)
debuginfo === :none && remove_linenums!(code)
return Any[Pair{CodeInfo,Any}(code, rt)]
end
Expand Down Expand Up @@ -1807,7 +1825,7 @@ function return_types(@nospecialize(f), @nospecialize(types=default_tt(f));
interp::Core.Compiler.AbstractInterpreter=Core.Compiler.NativeInterpreter(world))
check_generated_context(world)
if isa(f, Core.OpaqueClosure)
_, rt = only(code_typed_opaque_closure(f))
_, rt = only(code_typed_opaque_closure(f, types))
return Any[rt]
end
if isa(f, Core.Builtin)
Expand Down Expand Up @@ -1876,7 +1894,7 @@ function infer_return_type(@nospecialize(f), @nospecialize(types=default_tt(f));
interp::Core.Compiler.AbstractInterpreter=Core.Compiler.NativeInterpreter(world))
check_generated_context(world)
if isa(f, Core.OpaqueClosure)
return last(only(code_typed_opaque_closure(f)))
return last(only(code_typed_opaque_closure(f, types)))
end
if isa(f, Core.Builtin)
return _builtin_return_type(interp, f, types)
Expand Down
6 changes: 3 additions & 3 deletions stdlib/InteractiveUtils/src/codeview.jl
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ See the [`@code_warntype`](@ref man-code-warntype) section in the Performance Ti

See also: [`@code_warntype`](@ref), [`code_typed`](@ref), [`code_lowered`](@ref), [`code_llvm`](@ref), [`code_native`](@ref).
"""
function code_warntype(io::IO, @nospecialize(f), @nospecialize(t=Base.default_tt(f));
function code_warntype(io::IO, @nospecialize(f), @nospecialize(tt=Base.default_tt(f));
world=Base.get_world_counter(),
interp::Core.Compiler.AbstractInterpreter=Core.Compiler.NativeInterpreter(world),
debuginfo::Symbol=:default, optimize::Bool=false, kwargs...)
Expand All @@ -154,10 +154,10 @@ function code_warntype(io::IO, @nospecialize(f), @nospecialize(t=Base.default_tt
nargs::Int = 0
if isa(f, Core.OpaqueClosure)
isa(f.source, Method) && (nargs = f.nargs)
print_warntype_codeinfo(io, Base.code_typed_opaque_closure(f)[1]..., nargs; lineprinter)
print_warntype_codeinfo(io, Base.code_typed_opaque_closure(f, tt)[1]..., nargs; lineprinter)
return nothing
end
matches = Base._methods_by_ftype(Base.signature_type(f, t), #=lim=#-1, world)::Vector
matches = Base._methods_by_ftype(Base.signature_type(f, tt), #=lim=#-1, world)::Vector
for match in matches
match = match::Core.MethodMatch
(src, rettype) = Core.Compiler.typeinf_code(interp, match, optimize)
Expand Down
9 changes: 8 additions & 1 deletion test/opaque_closure.jl
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,13 @@ let foo::Int = 42
end

let oc = @opaque a->sin(a)
@test length(code_typed(oc, (Int,))) == 1
let opt = code_typed(oc, (Int,))
@test length(opt) == 1
@test opt[1][2] === Float64
end
let unopt = code_typed(oc, (Int,); optimize=false)
@test length(unopt) == 1
end
end

# constructing an opaque closure from IRCode
Expand All @@ -257,6 +263,7 @@ end
let ir = first(only(Base.code_ircode(sin, (Int,))))
@test OpaqueClosure(ir)(42) == sin(42)
@test OpaqueClosure(ir)(42) == sin(42) # the `OpaqueClosure(::IRCode)` constructor should be non-destructive
@test length(code_typed(OpaqueClosure(ir))) == 1
ir = first(only(Base.code_ircode(sin, (Float64,))))
@test OpaqueClosure(ir)(42.) == sin(42.)
@test OpaqueClosure(ir)(42.) == sin(42.) # the `OpaqueClosure(::IRCode)` constructor should be non-destructive
Expand Down