Skip to content

Commit

Permalink
proper support for interpreting opaque closures (#593)
Browse files Browse the repository at this point in the history
* proper support for interpreting opaque closures

* correctly handle `getfield` on #self#

* don't error on older versions

* move oc -> oc.captures transform to prepare_frame

* don't interpret inferred

* remove diffractor test
  • Loading branch information
simeonschaub authored Sep 10, 2024
1 parent f3a34a3 commit 958bd73
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 9 deletions.
11 changes: 8 additions & 3 deletions bin/generate_builtins.jl
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,15 @@ function maybe_evaluate_builtin(frame, call_expr, expand::Bool)
f = @lookup(frame, fex)
end
@static if isdefined(Core, :OpaqueClosure)
if f isa Core.OpaqueClosure
return Some{Any}(f(args...))
if @static isdefined(Core, :OpaqueClosure) && f isa Core.OpaqueClosure
if expand
if !Core.Compiler.uncompressed_ir(f.source).inferred
return Expr(:call, f, args[2:end]...)
else
@debug "not interpreting opaque closure \$f since it contains inferred code"
end
end
return Some{Any}(f(args...))
end
if !(isa(f, Core.Builtin) || isa(f, Core.IntrinsicFunction))
return call_expr
Expand Down
11 changes: 8 additions & 3 deletions src/builtins.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,15 @@ function maybe_evaluate_builtin(frame, call_expr, expand::Bool)
f = @lookup(frame, fex)
end

@static if isdefined(Core, :OpaqueClosure)
if f isa Core.OpaqueClosure
return Some{Any}(f(args...))
if @static isdefined(Core, :OpaqueClosure) && f isa Core.OpaqueClosure
if expand
if !Core.Compiler.uncompressed_ir(f.source).inferred
return Expr(:call, f, args[2:end]...)
else
@debug "not interpreting opaque closure $f since it contains inferred code"
end
end
return Some{Any}(f(args...))
end
if !(isa(f, Core.Builtin) || isa(f, Core.IntrinsicFunction))
return call_expr
Expand Down
16 changes: 14 additions & 2 deletions src/construct.jl
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,16 @@ function prepare_call(@nospecialize(f), allargs; enter_generated = false)
end
argtypesv = Any[_Typeof(a) for a in allargs]
argtypes = Tuple{argtypesv...}
method = whichtt(argtypes)
if @static isdefined(Core, :OpaqueClosure) && f isa Core.OpaqueClosure
method = f.source
# don't try to interpret optimized ir
if Core.Compiler.uncompressed_ir(method).inferred
@debug "not interpreting opaque closure $f since it contains inferred code"
return nothing
end
else
method = whichtt(argtypes)
end
if method === nothing
# Call it to generate the exact error
return f(allargs[2:end]...)
Expand Down Expand Up @@ -298,7 +307,10 @@ function prepare_framedata(framecode, argvals::Vector{Any}, lenv::SimpleVector=e
nargs, meth_nargs = length(argvals), Int(meth.nargs)
islastva = meth.isva && nargs >= meth_nargs
for i = 1:meth_nargs-islastva
if nargs >= i
# for OCs #self# actually refers to the captures instead
if @static isdefined(Core, :OpaqueClosure) && i == 1 && (oc = argvals[1]) isa Core.OpaqueClosure
locals[i], last_reference[i] = Some{Any}(oc.captures), 1
elseif i <= nargs
locals[i], last_reference[i] = Some{Any}(argvals[i]), 1
else
locals[i] = Some{Any}(())
Expand Down
11 changes: 10 additions & 1 deletion test/interpret.jl
Original file line number Diff line number Diff line change
Expand Up @@ -944,7 +944,16 @@ end
@test @interpret foo_536(UInt8('A'))

@static if isdefined(Base.Experimental, Symbol("@opaque"))
@test @interpret (Base.Experimental.@opaque x->3*x)(4) == 12
@testset "opaque closures" begin
g(x) = 3x
f = Base.Experimental.@opaque x -> g(x)
@test @interpret f(4) == 12

# test stepping into opaque closures
@breakpoint g(1)
fr = JuliaInterpreter.enter_call_expr(Expr(:call, f, 4))
@test JuliaInterpreter.finish_and_return!(fr) isa JuliaInterpreter.BreakpointRef
end
end

# CassetteOverlay, issue #552
Expand Down

0 comments on commit 958bd73

Please sign in to comment.