[
https://issues.apache.org/jira/browse/GROOVY-12488?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18131903#comment-18131903
]
ASF GitHub Bot commented on GROOVY-12488:
-----------------------------------------
codeconsole commented on PR #3022:
URL: https://github.com/apache/groovy/pull/3022#issuecomment-6400832477
Pushed 51893aeb83. Several points refer to code that changed after
f35e7257b6; replies describe the current head, in the order of the review:
1. Since 0b89f6c523 the check is `AsmClassGenerator.isInSameRuntimePackage`,
and only compilations a `GroovyClassLoader` defines in memory treat another
compilation's class as another run-time package; class files, incremental and
joint compilation keep direct access. Its Javadoc now says that
`isPrimaryClassNode()` stands for "defined by the class loader of the accessing
class", not "compiled from source" (932d9e698d).
2. Documented on `StaticInvocationWriter.isDirectlyAccessible` (932d9e698d):
there is no subclass rule, since only `super(...)` and anonymous classes may
call a protected constructor of another package. `new` of one is now a type
checking error (fe92a5fc2e), and `::new` keeps run-time selection. a358ba1983
adds the anonymous-subclass case (`testFunctionCN27`,
`testProtectedConstructorOfAnotherPackageIsSelectedAtRuntimeFromAnonymousSubclass`).
3. Done in this PR, 416969588d: the synthetic method of an array constructor
reference is compiled as statically compiled code. Its bytecode does not
change: it already used `NEWARRAY`/`ANEWARRAY`/`MULTIANEWARRAY` with the size
unboxed as a statically compiled `new String[s]` does.
`testArrayConstructorReferenceCreatesArrayLikeStaticallyCompiledNewArray` pins
the bytecode, `testArrayConstructorReferencesWithEachSizeType` the behavior.
4. The constructors generated for default arguments are not synthetic:
`Verifier.addConstructor` copies the declared constructor's modifiers (javap:
`flags: (0x0001) ACC_PUBLIC`). Every class of the compilation is verified
before any is generated, so the writer always sees them. a358ba1983 pins direct
calls for a class declared after the reference, all-default and package-private
constructors, and a class of an earlier parse
(`testConstructorReferenceCallsConstructorGeneratedForDefaultArgumentsDirectly`,
`testConstructorReferenceCallsConstructorGeneratedForDefaultArgumentsOfClassCompiledBefore`,
`testFunctionCN26`). The first fails if generated constructors are filtered
out.
5. All helper kinds share `addSyntheticMethod`; the comment now cites JVMS
4.6 (932d9e698d). f85f7e24d1 tests the array, static-extension
(`Thread::startDaemon`), `Class` method (`String::getName`) and
other-class-loader (`M::spm`, `M::pm`) helpers in static and default interface
methods; with `ACC_FINAL` put back they fail with `ClassFormatError` (0x101A).
6. Added to the Javadoc of `findConstructorReferenceTarget` (932d9e698d);
`testFunctionCN24` pins it.
7. No change; the split is pinned by
`testPrivateConstructorOfNestedClassIsCalledDirectlyFromClosureOrLambda`, which
reads the helpers from the closure and lambda classes.
Test gaps:
- Array `::new`: item 3.
- Default-parameter constructor chosen by arity: item 4.
- Enum: `testEnumConstructorReferenceSelectsConstructorAtRuntime`
(a358ba1983). `E::new` as `Function<String,E>` does not type-check (the
constructor is rewritten to take name and ordinal), so the test uses an
interface matching `(String, int, String)` inside the enum, where the private
constructor would be callable: the reference stays `INVOKEDYNAMIC init`, and
the test fails without the enum guard.
- Abstract class: a reference to its constructor is a type checking error,
also in an anonymous subclass ("Cannot instantiate the type p.A",
GROOVY-11385), so there is no run-time path. For a concrete class with a
protected constructor of another package, the anonymous subclass's `p.B::new`
is selected at run time (`testFunctionCN27`).
Nits:
- Kept.
- Moved to `AbstractBytecodeTestCase` as `compileAgainstLibrary`,
`extractMethodSequence` and `selectMethod` (51893aeb83);
`StaticCompileRuntimePackageTest` uses them too.
- No change.
16 of the 35 new `MethodReferenceTest` tests and the updated test fail on
master, and 21 of the 30 `StaticCompileRuntimePackageTest` tests.
> 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)