codeconsole opened a new pull request, #3025:
URL: https://github.com/apache/groovy/pull/3025

   When a class implements a trait, Groovy adds a call to the trait helper's 
`$init$` to the class's object initializer, so every constructor runs the 
trait's field initializers. That call is dispatched through the helper's meta 
class:
   
   ```groovy
   trait Greeting { String greeting = 'hello' }
   @CompileStatic class StaticGreeter implements Greeting {}
   class DynamicGreeter implements Greeting {}
   ```
   
   - `StaticGreeter.<init>`: `ldc Greeting$Trait$Helper; ldc "$init$"; … 
invokestatic ScriptBytecodeAdapter.invokeMethodN`, a meta class dispatch inside 
statically compiled code.
   - `DynamicGreeter.<init>`: `invokedynamic 
invoke:(Class,LDynamicGreeter;)Object`.
   - Both `<clinit>`s: `invokestatic 
Greeting$Trait$Helper.$static$init$(Class)`, which is direct.
   
   So every instantiation of a class that implements a trait makes one dynamic 
dispatch per trait. In a GraalVM native image, every helper's `$init$` must 
also be registered for reflection, or construction fails with "No signature of 
static method: $init$"; Grails scans for and registers every trait helper for 
this reason alone.
   
   `TraitComposer.applyTrait` builds `callX(classX(helperClassNode), 
Traits.INIT_METHOD, varX("this"))` without a method target, unlike the 
`$static$init$` call a few lines earlier and the forwarder methods 
(GROOVY-11776). For `@CompileStatic` classes the type checker does resolve the 
call. But `StaticTypeCheckingVisitor.visitObjectInitializerStatements` checks 
object initializers against a placeholder `ConstructorNode` without a declaring 
class. `StaticCompilationVisitor.visitMethodCallExpression` therefore returns 
early, and the resolved target never reaches the call.
   
   The fix sets the call's method target to the `$init$(TraitType)` method the 
helper declares: the AST node for a trait compiled in the same unit, and the 
node built from the class file for a precompiled trait. 
`TraitASTTransformation` always generates `$init$`, even for traits without 
fields. If the lookup ever finds nothing, the call stays dynamic as before. 
Both invocation writers now emit:
   
   ```
   ALOAD 0
   INVOKESTATIC Greeting$Trait$Helper.$init$ (LGreeting;)V
   ```
   
   That includes the adapter classes `withTraits` and `as Trait` generate at 
run time. The statement and its position are unchanged, so what the 
initializers do, and the order in which several traits' initializers run, stay 
the same. One consequence: a method added to a trait helper's meta class no 
longer replaces `$init$`, just as it already could not replace `$static$init$`.
   
   `TraitInitBytecodeTest` checks the constructor bytecode in dynamic, 
type-checked and statically compiled classes for:
   
   - traits with and without fields;
   - several traits, including a super trait, with the calls in order;
   - a generic trait;
   - a `@SelfType` trait;
   - a trait precompiled in a separate compilation unit.
   
   It also checks field initialization, initialization order, runtime trait 
application, and that a meta-class override of `$init$` is no longer called, 
including for `withTraits` and `as` proxies.
   
   The 18 bytecode tests and the meta-class test fail on master; the 7 behavior 
tests pass on both master and this branch. The trait, stub generator, static 
compilation, STC, transform and bugs suites pass (7,947 tests), as do the 
Checkstyle and CodeNarc gates.
   
   The same call has had no target since traits were introduced, and the javap 
above is from 6.0.0. A backport to `GROOVY_6_0_X` would let Grails 9, which 
builds with Groovy 6, stop registering trait helpers for reflection.
   
   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]

Reply via email to