codeconsole opened a new pull request, #3022:
URL: https://github.com/apache/groovy/pull/3022
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 was not
statically compiled:
```
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
```
So every call selected the constructor through the meta-class at run time.
In a GraalVM native image the constructor also needed reflection metadata,
although the code is statically compiled; Grails replaced `X::new` with `() ->
new X()` for this reason. Other method references (`String::length`,
`Math::abs`) already link their target directly.
The cause is in
`StaticTypesMethodReferenceExpressionWriter.addSyntheticMethodForConstructorReference`.
It built `ctorX(type, args)` without a target constructor and set
`STATIC_COMPILE_NODE` to false, as its TODO described.
`StaticInvocationWriter.writeInvokeConstructor` emits a direct call only when
the constructor call carries `DIRECT_METHOD_CALL_TARGET`.
The writer now selects the constructor with
`StaticTypeCheckingSupport.chooseBestMethod`, matching it against the
functional interface's parameter types the same way a constructor call
expression is matched. When exactly one constructor matches and the current
class can call it, the writer sets it as `DIRECT_METHOD_CALL_TARGET` and
compiles the synthetic method statically. The result is `NEW`/`INVOKESPECIAL`,
with the existing writer handling boxing, unboxing, widening and variadic
arrays. Private constructors of nestmates are called directly.
Run-time selection is kept in two cases:
- when no single constructor accepts the parameter types, e.g.
`Function<Object,Foo>` where `Foo` only has `Foo(String)` (GROOVY-10971);
- for a protected constructor from another package, which only `super(...)`
can call.
Array constructor references are unchanged; they already create the array
directly.
One observable difference: as with other method references and with Java,
the constructor is now chosen from the declared parameter types rather than the
run-time argument types. So `Function<CharSequence,X> f = X::new` calls
`X(CharSequence)` even when it is given a `String`.
Tests, all in `MethodReferenceTest`:
- bytecode tests for the no-argument, overloaded, primitive/widening,
variadic, generic and private-nestmate cases, plus the two fallbacks; the
existing test that pinned the dynamic `init`/`cast` sequence is updated;
- behavior tests for the same cases, plus non-static inner classes,
default-argument constructors, a protected constructor of another package, and
the static selection.
Seven of the new tests fail on master. The method-reference, lambda,
`groovy.transform.stc.*` and `org.codehaus.groovy.classgen.asm.sc.*` suites
pass, as do `checkstyleGate` and `codenarcGate`.
There is no JIRA issue for this yet.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]