[ 
https://issues.apache.org/jira/browse/GROOVY-11905?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Daniel Sun updated GROOVY-11905:
--------------------------------
    Description: 
*Problem* Previously, every non-capturing lambda call site incurred unnecessary 
allocation overhead. The compiler would:
 # Generate a {{Closure}} wrapper instance via {{NEW}} + {{{}INVOKESPECIAL{}}}.

 # Pass it as a captured argument to the {{invokedynamic}} instruction.

This forced {{LambdaMetafactory}} to generate a new proxy instance per 
invocation, completely defeating JVM singleton optimizations.

*Solution* For non-capturing lambdas (no shared variables, no instance member 
access, non-serializable), we now align the compilation strategy with Java's 
behavior by eliminating the capture phase. The new emitted bytecode features:
 * A {{static}} modifier on the generated {{doCall}} method.

 * A capture-free {{invokedynamic}} instruction with the descriptor 
{{{}()LFunctionalInterface;{}}}.

 * An {{H_INVOKESTATIC}} method handle pointing directly to the static 
{{{}doCall{}}}.

*Impact*
 * {{LambdaMetafactory}} now creates and caches a singleton instance, returning 
a {{{}ConstantCallSite{}}}.

 * Achieves *zero-allocation* at the call site for non-capturing lambdas.

 * Matches standard Java execution behavior, significantly reducing GC 
footprint.

  was:
*Problem* Non-capturing lambdas currently allocate a {{Closure}} wrapper 
instance ({{{}NEW{}}} + {{{}INVOKESPECIAL{}}}) passed as an argument to 
{{{}invokedynamic{}}}. This forces {{LambdaMetafactory}} to generate a new 
proxy instance per call site, defeating JVM singleton optimizations.

*Solution* Align with {{javac}} stateless lambda compilation:
 # Generate the lambda {{doCall}} method as {{{}static{}}}.

 # Eliminate {{Closure}} instantiation at the call site.

 # Emit capture-free {{invokedynamic}} (descriptor: 
{{{}()LFunctionalInterface;{}}}).

 # Use {{H_INVOKESTATIC}} method handle pointing to the static {{{}doCall{}}}.

*Impact* Allows {{LambdaMetafactory}} to link a {{ConstantCallSite}} with a 
singleton proxy. Achieves zero-allocation and reduces GC footprint for 
non-capturing lambdas.


> Optimize non-capturing lambdas
> ------------------------------
>
>                 Key: GROOVY-11905
>                 URL: https://issues.apache.org/jira/browse/GROOVY-11905
>             Project: Groovy
>          Issue Type: Improvement
>            Reporter: Daniel Sun
>            Priority: Major
>
> *Problem* Previously, every non-capturing lambda call site incurred 
> unnecessary allocation overhead. The compiler would:
>  # Generate a {{Closure}} wrapper instance via {{NEW}} + 
> {{{}INVOKESPECIAL{}}}.
>  # Pass it as a captured argument to the {{invokedynamic}} instruction.
> This forced {{LambdaMetafactory}} to generate a new proxy instance per 
> invocation, completely defeating JVM singleton optimizations.
> *Solution* For non-capturing lambdas (no shared variables, no instance member 
> access, non-serializable), we now align the compilation strategy with Java's 
> behavior by eliminating the capture phase. The new emitted bytecode features:
>  * A {{static}} modifier on the generated {{doCall}} method.
>  * A capture-free {{invokedynamic}} instruction with the descriptor 
> {{{}()LFunctionalInterface;{}}}.
>  * An {{H_INVOKESTATIC}} method handle pointing directly to the static 
> {{{}doCall{}}}.
> *Impact*
>  * {{LambdaMetafactory}} now creates and caches a singleton instance, 
> returning a {{{}ConstantCallSite{}}}.
>  * Achieves *zero-allocation* at the call site for non-capturing lambdas.
>  * Matches standard Java execution behavior, significantly reducing GC 
> footprint.



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

Reply via email to