[
https://issues.apache.org/jira/browse/GROOVY-12492?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Scott Murphy Heiberg updated GROOVY-12492:
------------------------------------------
Description:
Under {{@CompileStatic}}, a closure literal whose target is a functional
interface is still compiled to a {{Closure}} subclass and converted at run
time. That covers a literal passed to a SAM parameter, assigned or returned as
a SAM type, cast with {{(SAM)}}, or coerced with {{as SAM}}. For example:
{code:groovy}
@CompileStatic
int sum(int n) { IntStream.range(0, n).reduce(0) { int a, int b -> a + b } }
{code}
compiles to {{invokedynamic
cast:(Lgroovy/lang/Closure;)Ljava/util/function/IntBinaryOperator;}}, and the
same closure coerced with {{as IntBinaryOperator}} to an {{asType}} call. At
run time, {{CachedSAMClass.coerceToSAM}} /
{{TypeTransformers.createSAMTransform}} create a {{java.lang.reflect.Proxy}}
with a {{ConvertedClosure}} handler, and each call goes through the proxy and
{{Closure.call(Object...)}}. The same code written as a lambda uses
{{LambdaMetafactory}}.
Consequences: the proxy and reflective dispatch cost on every call, and in a
GraalVM native image each interface must be registered as a proxy, otherwise
the statically compiled conversion fails with {{GroovyCastException}}.
Proposal: an incubating {{groovy.target.closure.sam}} compiler option, off by
default, that converts such literals at compile time with a generated adapter
class that behaves as the proxy does.
PR: https://github.com/apache/groovy/pull/3026
was:
Under {{@CompileStatic}}, a closure literal whose target is a functional
interface is still compiled to a {{Closure}} subclass and converted at run
time. That covers a literal passed to a SAM parameter, assigned or returned as
a SAM type, cast with {{(SAM)}}, or coerced with {{as SAM}}. For example:
{code:groovy}
@CompileStatic
int sum(int n) { IntStream.range(0, n).reduce(0) { int a, int b -> a + b } }
{code}
compiles to {{invokedynamic
cast:(Lgroovy/lang/Closure;)Ljava/util/function/IntBinaryOperator;}}, and {{\{
... \} as IntBinaryOperator}} to an {{asType}} call. At run time,
{{CachedSAMClass.coerceToSAM}} / {{TypeTransformers.createSAMTransform}} create
a {{java.lang.reflect.Proxy}} with a {{ConvertedClosure}} handler, and each
call goes through the proxy and {{Closure.call(Object...)}}. The same code
written as a lambda uses {{LambdaMetafactory}}.
Consequences: the proxy and reflective dispatch cost on every call, and in a
GraalVM native image each interface must be registered as a proxy, otherwise
the statically compiled conversion fails with {{GroovyCastException}}.
Proposal: an incubating {{groovy.target.closure.sam}} compiler option, off by
default, that converts such literals at compile time with a generated adapter
class that behaves as the proxy does.
PR: https://github.com/apache/groovy/pull/3026
> Static compilation converts closure literals to functional interfaces through
> a runtime proxy
> ---------------------------------------------------------------------------------------------
>
> Key: GROOVY-12492
> URL: https://issues.apache.org/jira/browse/GROOVY-12492
> Project: Groovy
> Issue Type: Improvement
> Components: Static compilation
> Affects Versions: 6.0.0
> Reporter: Scott Murphy Heiberg
> Priority: Major
>
> Under {{@CompileStatic}}, a closure literal whose target is a functional
> interface is still compiled to a {{Closure}} subclass and converted at run
> time. That covers a literal passed to a SAM parameter, assigned or returned
> as a SAM type, cast with {{(SAM)}}, or coerced with {{as SAM}}. For example:
> {code:groovy}
> @CompileStatic
> int sum(int n) { IntStream.range(0, n).reduce(0) { int a, int b -> a + b } }
> {code}
> compiles to {{invokedynamic
> cast:(Lgroovy/lang/Closure;)Ljava/util/function/IntBinaryOperator;}}, and the
> same closure coerced with {{as IntBinaryOperator}} to an {{asType}} call. At
> run time, {{CachedSAMClass.coerceToSAM}} /
> {{TypeTransformers.createSAMTransform}} create a {{java.lang.reflect.Proxy}}
> with a {{ConvertedClosure}} handler, and each call goes through the proxy and
> {{Closure.call(Object...)}}. The same code written as a lambda uses
> {{LambdaMetafactory}}.
> Consequences: the proxy and reflective dispatch cost on every call, and in a
> GraalVM native image each interface must be registered as a proxy, otherwise
> the statically compiled conversion fails with {{GroovyCastException}}.
> Proposal: an incubating {{groovy.target.closure.sam}} compiler option, off by
> default, that converts such literals at compile time with a generated adapter
> class that behaves as the proxy does.
> PR: https://github.com/apache/groovy/pull/3026
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)