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.


-- 
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