Skip to content

Commit

Permalink
oc: code_typed support for optimized opaque closures (#53929)
Browse files Browse the repository at this point in the history
Reflection version of #53878.

---------

Co-authored-by: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com>
Co-authored-by: Shuhei Kadowaki <aviatesk@gmail.com>
  • Loading branch information
3 people authored Apr 3, 2024
1 parent 854170a commit a69aa30
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 14 deletions.
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

0 comments on commit a69aa30

Please sign in to comment.