[
https://issues.apache.org/jira/browse/GROOVY-12488?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Scott Murphy Heiberg updated GROOVY-12488:
------------------------------------------
Description:
Under {{@CompileStatic}}, a constructor reference such as {{Made::new}} is
implemented by a synthetic method {{ctorRef$<method>$<n>}} on the enclosing
class, which the LambdaMetafactory call site targets. That method is not
statically compiled:
{noformat}
private static final Made ctorRef$ctorRef$0();
0: ldc class Made
2: invokedynamic init:(Ljava/lang/Class;)Ljava/lang/Object;
7: invokedynamic cast:(Ljava/lang/Object;)LMade;
12: areturn
{noformat}
So every call selects the constructor through the meta-class at run time, while
other method references ({{String::length}}, {{Math::abs}}) link their target
directly. In a GraalVM native image the constructor also needs reflection
metadata although the code is statically compiled.
The cause is
{{StaticTypesMethodReferenceExpressionWriter.addSyntheticMethodForConstructorReference}}:
it builds the constructor call without a target constructor and sets
{{STATIC_COMPILE_NODE}} to false (there is a TODO for it).
Proposed fix: select the constructor at compile time among the constructors
visible from the enclosing class, matched against the functional interface's
parameter types as for a constructor call expression, and call it directly.
Keep the run-time selection when no single constructor matches (GROOVY-10971),
for a protected constructor in another package, and for a protected or
package-private constructor of a class compiled in another compilation unit,
which may come from another class loader. As with other method references and
with Java, the constructor is then chosen from the declared parameter types
rather than the run-time argument types.
PR: https://github.com/apache/groovy/pull/3022
was:
Under {{@CompileStatic}}, a constructor reference such as {{Made::new}} is
implemented by a synthetic method {{ctorRef$<method>$<n>}} on the enclosing
class, which the LambdaMetafactory call site targets. That method is not
statically compiled:
{noformat}
private static final Made ctorRef$ctorRef$0();
0: ldc class Made
2: invokedynamic init:(Ljava/lang/Class;)Ljava/lang/Object;
7: invokedynamic cast:(Ljava/lang/Object;)LMade;
12: areturn
{noformat}
So every call selects the constructor through the meta-class at run time, while
other method references ({{String::length}}, {{Math::abs}}) link their target
directly. In a GraalVM native image the constructor also needs reflection
metadata although the code is statically compiled.
The cause is
{{StaticTypesMethodReferenceExpressionWriter.addSyntheticMethodForConstructorReference}}:
it builds the constructor call without a target constructor and sets
{{STATIC_COMPILE_NODE}} to false (there is a TODO for it).
Proposed fix: select the constructor at compile time from the functional
interface's parameter types, as for a constructor call expression, and call it
directly. Keep the run-time selection when no single constructor matches
(GROOVY-10971) and for a protected constructor in another package. As with
other method references and with Java, the constructor is then chosen from the
declared parameter types rather than the run-time argument types.
PR: https://github.com/apache/groovy/pull/3022
> SC: constructor reference calls the constructor through the meta-class
> instead of directly
> ------------------------------------------------------------------------------------------
>
> Key: GROOVY-12488
> URL: https://issues.apache.org/jira/browse/GROOVY-12488
> Project: Groovy
> Issue Type: Improvement
> Components: Static compilation
> Affects Versions: 6.0.0
> Reporter: Scott Murphy Heiberg
> Priority: Major
>
> Under {{@CompileStatic}}, a constructor reference such as {{Made::new}} is
> implemented by a synthetic method {{ctorRef$<method>$<n>}} on the enclosing
> class, which the LambdaMetafactory call site targets. That method is not
> statically compiled:
> {noformat}
> private static final Made ctorRef$ctorRef$0();
> 0: ldc class Made
> 2: invokedynamic init:(Ljava/lang/Class;)Ljava/lang/Object;
> 7: invokedynamic cast:(Ljava/lang/Object;)LMade;
> 12: areturn
> {noformat}
> So every call selects the constructor through the meta-class at run time,
> while other method references ({{String::length}}, {{Math::abs}}) link their
> target directly. In a GraalVM native image the constructor also needs
> reflection metadata although the code is statically compiled.
> The cause is
> {{StaticTypesMethodReferenceExpressionWriter.addSyntheticMethodForConstructorReference}}:
> it builds the constructor call without a target constructor and sets
> {{STATIC_COMPILE_NODE}} to false (there is a TODO for it).
> Proposed fix: select the constructor at compile time among the constructors
> visible from the enclosing class, matched against the functional interface's
> parameter types as for a constructor call expression, and call it directly.
> Keep the run-time selection when no single constructor matches
> (GROOVY-10971), for a protected constructor in another package, and for a
> protected or package-private constructor of a class compiled in another
> compilation unit, which may come from another class loader. As with other
> method references and with Java, the constructor is then chosen from the
> declared parameter types rather than the run-time argument types.
> PR: https://github.com/apache/groovy/pull/3022
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)