Revision 08bda040b76603878c56a3eb42d6afa3fe74cb7d authored by Valentin Churavy on 15 June 2023, 22:41:38 UTC, committed by Kristoffer on 26 June 2023, 07:43:44 UTC
(cherry picked from commit 432f300eea6bd65d4575fe9ae0969e6ebbc208c7)
1 parent 461d17d
opaque_closure.jl
# This file is a part of Julia. License is MIT: https://julialang.org/license
"""
@opaque ([type, ]args...) -> body
Marks a given closure as "opaque". Opaque closures capture the
world age of their creation (as opposed to their invocation).
This allows for more aggressive optimization of the capture
list, but trades off against the ability to inline opaque
closures at the call site, if their creation is not statically
visible.
An argument tuple type (`type`) may optionally be specified, to
specify allowed argument types in a more flexible way. In particular,
the argument type may be fixed length even if the function is variadic.
!!! warning
This interface is experimental and subject to change or removal without notice.
"""
macro opaque(ex)
esc(Expr(:opaque_closure, ex))
end
macro opaque(ty, ex)
esc(Expr(:opaque_closure, ty, ex))
end
# OpaqueClosure construction from pre-inferred CodeInfo/IRCode
using Core.Compiler: IRCode
using Core: CodeInfo
function compute_ir_rettype(ir::IRCode)
rt = Union{}
for i = 1:length(ir.stmts)
stmt = ir.stmts[i][:inst]
if isa(stmt, Core.Compiler.ReturnNode) && isdefined(stmt, :val)
rt = Core.Compiler.tmerge(Core.Compiler.argextype(stmt.val, ir), rt)
end
end
return Core.Compiler.widenconst(rt)
end
function compute_oc_argtypes(ir, nargs, isva)
argtypes = ir.argtypes[2:end]
@assert nargs == length(argtypes)
argtypes = Core.Compiler.anymap(Core.Compiler.widenconst, argtypes)
if isva
lastarg = pop!(argtypes)
if lastarg <: Tuple
append!(argtypes, lastarg.parameters)
else
push!(argtypes, Vararg{Any})
end
end
Tuple{argtypes...}
end
function Core.OpaqueClosure(ir::IRCode, env...;
nargs::Int = length(ir.argtypes)-1,
isva::Bool = false,
rt = compute_ir_rettype(ir))
if (isva && nargs > length(ir.argtypes)) || (!isva && nargs != length(ir.argtypes)-1)
throw(ArgumentError("invalid argument count"))
end
src = ccall(:jl_new_code_info_uninit, Ref{CodeInfo}, ())
src.slotflags = UInt8[]
src.slotnames = fill(:none, nargs+1)
src.slottypes = copy(ir.argtypes)
Core.Compiler.replace_code_newstyle!(src, ir, nargs+1)
Core.Compiler.widen_all_consts!(src)
src.inferred = true
# NOTE: we need ir.argtypes[1] == typeof(env)
ccall(:jl_new_opaque_closure_from_code_info, Any, (Any, Any, Any, Any, Any, Cint, Any, Cint, Cint, Any),
compute_oc_argtypes(ir, nargs, isva), Union{}, rt, @__MODULE__, src, 0, nothing, nargs, isva, env)
end
function Core.OpaqueClosure(src::CodeInfo, env...)
M = src.parent.def
sig = Base.tuple_type_tail(src.parent.specTypes)
ccall(:jl_new_opaque_closure_from_code_info, Any, (Any, Any, Any, Any, Any, Cint, Any, Cint, Cint, Any),
sig, Union{}, src.rettype, @__MODULE__, src, 0, nothing, M.nargs - 1, M.isva, env)
end
![swh spinner](/static/img/swh-spinner.gif)
Computing file changes ...