codeconsole opened a new issue, #16755:
URL: https://github.com/apache/grails-core/issues/16755

   To start in a native image without recorded metadata, the framework 
registers a JDK proxy for every interface a closure is coerced to 
(`BytecodeRuntimeHints`, added in #16180: the `coercedTo` loop in `register`). 
Its javadoc gives the reason. A closure that becomes an interface, whether it 
is passed where a method takes one or coerced with `as`, becomes it through a 
`java.lang.reflect.Proxy` created as the call is made. An image creates a proxy 
only for an interface it was told about. That holds even in statically compiled 
code: `IntStream.range(0, n).reduce(0) { int a, int b -> a + b }` in a 
`@CompileStatic` class compiles to an invokedynamic `cast` to 
`IntBinaryOperator`, and the runtime makes the proxy.
   
   apache/groovy#3026 adds an incubating compiler option, 
`-Dgroovy.target.closure.sam=true`, that converts such closures at compile 
time. With it, a statically compiled closure literal that is passed, assigned, 
returned, cast or coerced with `as` to a functional interface is wrapped in a 
class the compiler generates instead of a proxy. When the arguments already 
have the types the closure declares, the call reaches the closure without 
reflection either. In a rough JVM loop, two interface calls went from about 26 
ns to 2.8 ns. Groovy leaves the option off by default because the converted 
value is no longer a `java.lang.reflect.Proxy`.
   
   The scan needs no change. A conversion compiled with the option no longer 
contains the invokedynamic `cast` or `asType` call the scan looks for, so no 
proxy is registered for it. What still converts at run time keeps its 
registration: dynamic code, maps coerced with `as`, trait or abstract-class 
targets, and closures chosen by a conditional or Elvis expression.
   
   ## What to change once a Groovy release with apache/groovy#3026 is in use
   
   - [ ] Turn the option on for the framework's own Groovy compiles: add 
`-Dgroovy.target.closure.sam=true` to the forked compiler's JVM arguments in 
`CompilePlugin.configureCompiler` (build-logic), beside 
`-Dgrails.isolated.build=true`.
   - [ ] Decide whether the Grails Gradle plugin turns it on for applications, 
from `GrailsGradlePlugin` beside the other `forkOptions.jvmArgumentProviders` 
of the `GroovyCompile` tasks, with a `grails { }` switch to turn it off. Since 
the option is incubating and changes the class of a converted value, it could 
start on for native and AOT builds only.
   - [ ] Update `BytecodeRuntimeHintsSpec`. Its statically compiled closure 
fixtures will no longer be converted through a proxy:
     - `ClosureCoercionFixture.sum` no longer contains the invokedynamic 
`cast`, so 'an interface a closure is coerced to can be proxied' fails;
     - `StaticCoercionFixture.closureLiteral()` returns the generated class, so 
the row 'a closure literal in statically compiled code' of 'the interface 
#coercion is coerced to can be proxied' fails on `Proxy.isProxyClass`.
   
     Invert both, so they assert that no proxy is registered or created, and 
they then pin that the option is in effect. The map row and the dynamic rows 
stay as they are.
   - [ ] Update the closure bullet in `BytecodeRuntimeHints`' javadoc and the 
matching part of the `deploymentAot.adoc` bullet ("turning a closure or a map 
into an interface, wherever statically compiled code passes or assigns a 
closure to one"). Both should say that code compiled with the option converts 
its closure literals without a proxy, and what is still registered.
   - [ ] Build the native-i18n image and run its checks: `./gradlew 
:native-i18n:check -PnativeTests` from `end-to-end`, with a GraalVM `JAVA_HOME`.
   
   ## Groovy version
   
   apache/groovy#3026 targets Groovy master (7.0.0-SNAPSHOT). Grails 9 builds 
with Groovy 6.0.x, so it only benefits once the change is backported to 
`GROOVY_6_0_X`; the PR asks for that. The option is off by default, so the 
backport changes nothing until it is set.
   


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