[ 
https://issues.apache.org/jira/browse/GROOVY-12240?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18102952#comment-18102952
 ] 

ASF GitHub Bot commented on GROOVY-12240:
-----------------------------------------

testlens-app[bot] commented on PR #2772:
URL: https://github.com/apache/groovy/pull/2772#issuecomment-5222369543

   ## ✅ All tests passed ✅
   
   🏷️ Commit: 4d53a4e3dfce02e147815e7ffc14b4234d8f8d97
   ▶️ Tests:  108926 executed
   ⚪️ Checks: 31/31 completed
   
   ---
   _Learn more about TestLens at [testlens.app](https://testlens.app)._
   




> Initialize argument-less enum constants with a direct constructor call
> ----------------------------------------------------------------------
>
>                 Key: GROOVY-12240
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12240
>             Project: Groovy
>          Issue Type: Improvement
>          Components: Compiler
>    Affects Versions: 5.0.8
>            Reporter: Scott Murphy Heiberg
>            Priority: Minor
>
> {{EnumVisitor}} creates every enum constant through a synthetic helper:
> {code:groovy}
> def $INIT(Object[] para) {
>     return this(*para)
> }
> {code}
> {{this(*para)}} is a spread constructor call, so 
> {{InvocationWriter.makeDirectConstructorCall}} refuses it — it bails on 
> {{SpreadExpression}}, and again on {{!controller.isConstructor()}} — and the 
> body compiles to {{ScriptBytecodeAdapter.despreadList}} plus 
> {{selectConstructorAndTransformArguments}}. The meta class then picks the 
> constructor at run time by reflecting over {{getDeclaredConstructors()}}. The 
> static initializer reaches {{$INIT}} itself through a dynamic call site.
> For {{enum Colors { RED, GREEN, BLUE }}} that is the entire constant-creation 
> path, even though the only arguments are the compiler-supplied name and 
> ordinal, both known at compile time.
> Where reflection over the enum is not available, the class cannot initialize 
> at all. In a GraalVM native image built without reachability metadata for the 
> enum, {{getDeclaredConstructors()}} returns nothing and class initialization 
> throws:
> {noformat}
> groovy.lang.GroovyRuntimeException: Could not find matching constructor for: 
> com.example.MyEnum(String, Integer)
> {noformat}
> (note the boxed {{Integer}} — the ordinal has been through {{Object[]}}). 
> This kills the application in a static initializer before any user code runs.
> {{@CompileStatic}} does not help. Groovy already compiles the *call site* 
> statically (StaticTypeCheckingVisitor, GROOVY-10845); it is {{$INIT}}'s own 
> body that is necessarily dynamic.
> h3. Proposal
> When every constant of an enum is a plain identifier, the arguments are 
> provably {{[name, ordinal]}}, and the static initializer can call the enum's 
> {{(String, int)}} constructor directly:
> {noformat}
> static {};                                   static {};
>  0: ldc           // class Colors             0: new           // class Colors
>  2: ldc           // String RED               3: dup
>  4: iconst_0                                  4: ldc           // String RED
>  5: invokestatic  Integer.valueOf             6: iconst_0
>  8: invokedynamic invoke:(Class;String;       7: invokespecial 
> "<init>":(Ljava/lang/String;I)V
>                   Integer;)Object;           10: putstatic     Field 
> RED:LColors;
> 13: invokedynamic cast:(Object;)LColors;
> 18: putstatic     Field RED:LColors;
> {noformat}
> The same shape javac emits for a Java enum: 21 bytes and two invokedynamic 
> call sites per constant become 13 bytes and none.
> Anything else — constants with arguments, named-argument form, anonymous 
> constant bodies, or a mixture — keeps the existing {{$INIT}} path, as does 
> any enum lacking a {{(String, int)}} constructor (checked at bytecode 
> generation, after {{Verifier}} has run). {{$INIT}} itself is unchanged and 
> still generated for every enum.
> h3. Scope, stated honestly
> This is a *compile-time* change. It only helps code compiled by a Groovy that 
> carries the fix; bytecode already compiled by an earlier Groovy keeps its 
> {{$INIT}} path whichever Groovy runs it. Confirmed by building a GraalVM 
> native image of an application against a patched Groovy: the framework's own 
> enums, compiled by an earlier Groovy, still failed with {{Could not find 
> matching constructor}} until reachability metadata was restored.
> Enums whose constants take arguments ({{RED(255, 0, 0)}}) are not addressed 
> and still require reachability metadata in a native image. Fixing those would 
> mean relaxing {{InvocationWriter.makeDirectConstructorCall}} to work outside 
> a constructor, which is a much wider change.
> Related to GROOVY-12234.
> I have a patch with tests ({{./gradlew :test}} passes in full: 16,548 tests, 
> 0 failures) and will open a pull request against this issue.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to