Skip to content

Commit 1c59231

Browse files
authored
opaque_closure: Allow opting out of PartialOpaque (#54734)
`PartialOpaque` is a powerful mechanism to recover some amount of identity from opaque closure for inlining and other optimizations. However, there are two downsides: 1. It causes additional inference work, which is unnecessary if you already know that you don't want the identity-based optimization. 2. We (currently) disallow :new_opaque_closure in code returned from generated functions, because we cannot ensure that the identity of any resulting PartialOpaque will be stable. This somewhat defeats the purpose of having the opaque closure be, well, opaque. This PR adds an additional argument to `new_opaque_closure` that decides whether or not inference is allowed to form `PartialOpaque` for this `:new_opaque_closure`. If not, it is also permitted to run during precompile.
1 parent 1b6ec0d commit 1c59231

File tree

15 files changed

+89
-42
lines changed

15 files changed

+89
-42
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2547,7 +2547,7 @@ function abstract_eval_new_opaque_closure(interp::AbstractInterpreter, e::Expr,
25472547
𝕃ᵢ = typeinf_lattice(interp)
25482548
rt = Union{}
25492549
effects = Effects() # TODO
2550-
if length(e.args) >= 4
2550+
if length(e.args) >= 5
25512551
ea = e.args
25522552
argtypes = collect_argtypes(interp, ea, vtypes, sv)
25532553
if argtypes === nothing
@@ -2556,7 +2556,11 @@ function abstract_eval_new_opaque_closure(interp::AbstractInterpreter, e::Expr,
25562556
else
25572557
mi = frame_instance(sv)
25582558
rt = opaque_closure_tfunc(𝕃ᵢ, argtypes[1], argtypes[2], argtypes[3],
2559-
argtypes[4], argtypes[5:end], mi)
2559+
argtypes[5], argtypes[6:end], mi)
2560+
if ea[4] !== true && isa(rt, PartialOpaque)
2561+
rt = widenconst(rt)
2562+
# Propagation of PartialOpaque disabled
2563+
end
25602564
if isa(rt, PartialOpaque) && isa(sv, InferenceState) && !call_result_unused(sv, sv.currpc)
25612565
# Infer this now so that the specialization is available to
25622566
# optimization.

base/compiler/optimize.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ function stmt_effect_flags(𝕃ₒ::AbstractLattice, @nospecialize(stmt), @nospe
347347
(𝕃ₒ, typ, Tuple) || return (false, false, false)
348348
rt_lb = argextype(args[2], src)
349349
rt_ub = argextype(args[3], src)
350-
source = argextype(args[4], src)
350+
source = argextype(args[5], src)
351351
if !((𝕃ₒ, rt_lb, Type) && (𝕃ₒ, rt_ub, Type) && (𝕃ₒ, source, Method))
352352
return (false, false, false)
353353
end

base/compiler/ssair/passes.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -443,8 +443,8 @@ function lift_leaves(compact::IncrementalCompact, field::Int,
443443
ocleaf = simple_walk(compact, ocleaf)
444444
end
445445
ocdef, _ = walk_to_def(compact, ocleaf)
446-
if isexpr(ocdef, :new_opaque_closure) && isa(field, Int) && 1 field length(ocdef.args)-4
447-
lift_arg!(compact, leaf, cache_key, ocdef, 4+field, lifted_leaves)
446+
if isexpr(ocdef, :new_opaque_closure) && isa(field, Int) && 1 field length(ocdef.args)-5
447+
lift_arg!(compact, leaf, cache_key, ocdef, 5+field, lifted_leaves)
448448
continue
449449
end
450450
return nothing

base/compiler/validation.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ const VALID_EXPR_HEADS = IdDict{Symbol,UnitRange{Int}}(
3434
:throw_undef_if_not => 2:2,
3535
:aliasscope => 0:0,
3636
:popaliasscope => 0:0,
37-
:new_opaque_closure => 4:typemax(Int),
37+
:new_opaque_closure => 5:typemax(Int),
3838
:import => 1:typemax(Int),
3939
:using => 1:typemax(Int),
4040
:export => 1:typemax(Int),

base/deprecated.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ const __internal_changes_list = (
2424
:invertedlinetables,
2525
:codeinforefactor,
2626
:miuninferredrm,
27-
:codeinfonargs # #54341
27+
:codeinfonargs, # #54341
28+
:ocnopartial,
2829
# Add new change names above this line
2930
)
3031

doc/src/devdocs/ast.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -519,18 +519,22 @@ These symbols appear in the `head` field of [`Expr`](@ref)s in lowered form.
519519

520520
The function signature of the opaque closure. Opaque closures don't participate in dispatch, but the input types can be restricted.
521521

522-
* `args[2]` : isva
523-
524-
Indicates whether the closure accepts varargs.
525-
526-
* `args[3]` : lb
522+
* `args[2]` : lb
527523

528524
Lower bound on the output type. (Defaults to `Union{}`)
529525

530-
* `args[4]` : ub
526+
* `args[3]` : ub
531527

532528
Upper bound on the output type. (Defaults to `Any`)
533529

530+
* `args[4]` : constprop
531+
532+
Indicates whether the opaque closure's identity may be used for constant
533+
propagation. The `@opaque` macro enables this by default, but this will
534+
cause additional inference which may be undesirable and prevents the
535+
code from running during precompile.
536+
If `args[4]` is a method, the argument is considered skipped.
537+
534538
* `args[5]` : method
535539

536540
The actual method as an `opaque_closure_method` expression.

src/ast.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ static jl_value_t *scm_to_julia(fl_context_t *fl_ctx, value_t e, jl_module_t *mo
464464
}
465465
JL_CATCH {
466466
// if expression cannot be converted, replace with error expr
467-
//jl_(jl_current_exception(ct));
467+
//jl_(jl_current_exception(jl_current_task));
468468
//jlbacktrace();
469469
jl_expr_t *ex = jl_exprn(jl_error_sym, 1);
470470
v = (jl_value_t*)ex;

src/codegen.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6513,15 +6513,16 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaidx_
65136513
return mark_julia_type(ctx, val, true, (jl_value_t*)jl_any_type);
65146514
}
65156515
else if (head == jl_new_opaque_closure_sym) {
6516-
assert(nargs >= 4 && "Not enough arguments in new_opaque_closure");
6517-
SmallVector<jl_cgval_t, 4> argv(nargs, jl_cgval_t());
6516+
assert(nargs >= 5 && "Not enough arguments in new_opaque_closure");
6517+
SmallVector<jl_cgval_t, 5> argv(nargs, jl_cgval_t());
65186518
for (size_t i = 0; i < nargs; ++i) {
65196519
argv[i] = emit_expr(ctx, args[i]);
65206520
}
65216521
const jl_cgval_t &argt = argv[0];
65226522
const jl_cgval_t &lb = argv[1];
65236523
const jl_cgval_t &ub = argv[2];
6524-
const jl_cgval_t &source = argv[3];
6524+
// argv[3] - constprop marker not used here
6525+
const jl_cgval_t &source = argv[4];
65256526
if (source.constant == NULL) {
65266527
// For now, we require non-constant source to be handled by using
65276528
// eval. This should probably be a verifier error and an abort here.
@@ -6539,17 +6540,18 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaidx_
65396540
jl_value_t *env_t = NULL;
65406541
JL_GC_PUSH2(&closure_t, &env_t);
65416542

6542-
SmallVector<jl_value_t *, 0> env_component_ts(nargs-4);
6543-
for (size_t i = 0; i < nargs - 4; ++i) {
6544-
jl_value_t *typ = argv[4+i].typ;
6543+
size_t ncapture_args = nargs-5;
6544+
SmallVector<jl_value_t *, 0> env_component_ts(ncapture_args);
6545+
for (size_t i = 0; i < ncapture_args; ++i) {
6546+
jl_value_t *typ = argv[nargs-ncapture_args+i].typ;
65456547
if (typ == jl_bottom_type) {
65466548
JL_GC_POP();
65476549
return jl_cgval_t();
65486550
}
65496551
env_component_ts[i] = typ;
65506552
}
65516553

6552-
env_t = jl_apply_tuple_type_v(env_component_ts.data(), nargs-4);
6554+
env_t = jl_apply_tuple_type_v(env_component_ts.data(), ncapture_args);
65536555
// we need to know the full env type to look up the right specialization
65546556
if (jl_is_concrete_type(env_t)) {
65556557
jl_tupletype_t *argt_typ = (jl_tupletype_t*)argt.constant;
@@ -6567,7 +6569,7 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaidx_
65676569
fptr = mark_julia_type(ctx, Constant::getNullValue(ctx.types().T_size), false, jl_voidpointer_type);
65686570

65696571
// TODO: Inline the env at the end of the opaque closure and generate a descriptor for GC
6570-
jl_cgval_t env = emit_new_struct(ctx, env_t, nargs-4, ArrayRef<jl_cgval_t>(argv).drop_front(4));
6572+
jl_cgval_t env = emit_new_struct(ctx, env_t, ncapture_args, ArrayRef<jl_cgval_t>(argv).drop_front(nargs-ncapture_args));
65716573

65726574
jl_cgval_t closure_fields[5] = {
65736575
env,

src/interpreter.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ static jl_value_t *eval_value(jl_value_t *e, interpreter_state *s)
298298
argv[i] = eval_value(args[i], s);
299299
JL_NARGSV(new_opaque_closure, 4);
300300
jl_value_t *ret = (jl_value_t*)jl_new_opaque_closure((jl_tupletype_t*)argv[0], argv[1], argv[2],
301-
argv[3], argv+4, nargs-4, 1);
301+
argv[4], argv+5, nargs-5, 1);
302302
JL_GC_POP();
303303
return ret;
304304
}

src/julia-syntax.scm

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3998,7 +3998,7 @@ f(x) = yt(x)
39983998
v)))
39993999
cvs)))
40004000
`(new_opaque_closure
4001-
,(cadr e) (call (core apply_type) (core Union)) (core Any)
4001+
,(cadr e) (call (core apply_type) (core Union)) (core Any) (true)
40024002
(opaque_closure_method (null) ,nargs ,isva ,functionloc ,(convert-lambda lam2 (car (lam:args lam2)) #f '() (symbol-to-idx-map cvs)))
40034003
,@var-exprs))))
40044004
((method)
@@ -4564,13 +4564,13 @@ f(x) = yt(x)
45644564
(cons (cadr e) (cons fptr (cdddr e)))))
45654565
;; Leave a literal lambda in place for later global expansion
45664566
((eq? (car e) 'new_opaque_closure)
4567-
(let* ((oc_method (car (list-tail (cdr e) 3))) ;; opaque_closure_method
4567+
(let* ((oc_method (car (list-tail (cdr e) 4))) ;; opaque_closure_method
45684568
(lambda (list-ref oc_method 5))
45694569
(lambda (linearize lambda)))
45704570
(append
4571-
(compile-args (list-head (cdr e) 3) break-labels)
4571+
(compile-args (list-head (cdr e) 4) break-labels)
45724572
(list (append (butlast oc_method) (list lambda)))
4573-
(compile-args (list-tail (cdr e) 4) break-labels))))
4573+
(compile-args (list-tail (cdr e) 5) break-labels))))
45744574
;; NOTE: 1st argument to cglobal treated same as for ccall
45754575
((and (length> e 2)
45764576
(or (eq? (cadr e) 'cglobal)

0 commit comments

Comments
 (0)