[ 
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)

Reply via email to