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

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

paulk-asert opened a new pull request, #2680:
URL: https://github.com/apache/groovy/pull/2680

   A statically compiled lambda targeting a functional interface currently 
generates a per-lambda class extending groovy.lang.Closure, even though its 
runtime value is a LambdaMetafactory-produced functional-interface instance. 
For a capturing lambda the class also holds the captured state 
(Reference-wrapped) and is instantiated per lambda.
   
   Like the JVM does for Java lambdas, hoist the lambda body onto the enclosing 
class as a private static method and bootstrap LambdaMetafactory directly 
against it, so no per-lambda class is generated:
   
   - Non-capturing: re-home the already-static doCall onto the enclosing class; 
the metafactory produces the same zero-allocation singleton.
   - Read-only capturing: emit a static method taking the captured values as 
leading parameters and have the metafactory capture those values directly - 
eliminating the lambda class, its instance, and the Reference wrapping. 
Captured Reference-field reads in the doCall are repointed to the value 
parameters (codegen then loads the value directly).
   
   Only lambdas sitting directly in a real method are hoisted. Serializable, 
nested, instance- accessing, and mutated-capture lambdas (which need the shared 
Reference) are unchanged and keep their generated class. Behaviour and metadata 
are preserved (verified: Predicate/ BiFunction, multi-capture, mixed 
capture/SAM types, lambdas in static methods, qualified outer static calls, 
serializable round-trips, singleton identity for non-capturing, mutated- 
capture mutation across invocations, parameter type annotations on the hoisted 
method); stack traces now name a $lambda$ method on the enclosing class 
(Java-like).
   
   Gated by an opt-in system property, groovy.target.lambda.hoist (default 
off), read per lambda so it can be toggled without a JVM restart, while 
IDE/tooling compatibility with the changed generated-class shape is verified. 
Default off keeps existing behaviour unchanged.
   
   Testing:
   - LambdaHoistTest covers the opt-in path (non-capturing and 
read-only-capturing hoist, singleton identity, multi-capture behaviour) and the 
fall-back cases (mutated capture, instance-access, serializable, nested, 
default-off).
   - Existing tests that assert the pre-hoist generated-class structure 
(LambdaTest.NonCapturingLambdaOptimizationTest, 
LambdaTest.NativeLambdaBytecodeTest, LambdaTest.testLambdaClassIsntSynthetic, 
TypeAnnotationsTest.testTypeAnnotationsForLambda) are annotated 
@DisabledIfSystemProperty so they skip when the flag is on; the build forwards 
-P/-Dgroovy.target.lambda.hoist to the test JVM.
   - The full core test suite passes with the flag on (0 failures; only the 
pre-hoist bytecode-shape tests skip) and is unchanged with it off.
   
   See GEP-27 (Compact Closure and Lambda Compilation) for the broader design.




> GEP-27: lambda hoisting 
> ------------------------
>
>                 Key: GROOVY-12143
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12143
>             Project: Groovy
>          Issue Type: Improvement
>            Reporter: Paul King
>            Assignee: Paul King
>            Priority: Major
>




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

Reply via email to