Skip to content

GROOVY-12227: GeneratedDispatcher: avoid runtime class definition so … - #2762

Closed
paulk-asert wants to merge 1 commit into
apache:masterfrom
paulk-asert:packed-dispatcher-native-image
Closed

GROOVY-12227: GeneratedDispatcher: avoid runtime class definition so …#2762
paulk-asert wants to merge 1 commit into
apache:masterfrom
paulk-asert:packed-dispatcher-native-image

Conversation

@paulk-asert

Copy link
Copy Markdown
Contributor

…packed closures work in native images

Two layered changes to the GROOVY-12151 packed-closure machinery (GEP-27):

  1. ClosureWriter now passes the three dispatch tables as constant bootstrap arguments (CONSTANT_MethodHandle), resolved by the VM's constant pool rather than a runtime Lookup.findStatic -- which under GraalVM native image demanded per-class reflection metadata. Verified: the tracing agent records zero packedDispatch entries for the new bytecode.

  2. GeneratedDispatcher.bootstrap keeps the LambdaMetafactory hidden-class adapters on a regular JVM (the JIT-inlining rationale in the class javadoc), but where classes cannot be defined at run time -- native image, detected per link so build-time class init cannot bake in the wrong answer -- it adapts the tables with method-handle-invoking wrappers instead: ordinary bytecode of this class, AOT-compiled into the image. A catch-based fallback covers AOT runtimes the property probe misses. -Dgroovy.packed.dispatch.handles=true forces the wrapper path on a JVM, for parity testing.

Permanent behaviour, no user-facing flag: JVM semantics are unchanged and the fallback engages only where the hidden-class path cannot work. The old 3-arg bootstrap remains for class files from earlier 6.0 snapshots.

Before/after on GraalVM 25.2.4 (native-image 25.0.4): the packed repro previously failed with 'Classes cannot be defined at runtime ... M$$Lambda...'; it now runs correctly (single emitted class, 30MB image, ~12ms total run time). Parity + undeclared-checked-exception propagation covered by PackedDispatcherHandleBundleTest; all existing packed-closure suites green.

…packed closures work in native images

Two layered changes to the GROOVY-12151 packed-closure machinery (GEP-27):

1. ClosureWriter now passes the three dispatch tables as constant bootstrap
   arguments (CONSTANT_MethodHandle), resolved by the VM's constant pool
   rather than a runtime Lookup.findStatic -- which under GraalVM native
   image demanded per-class reflection metadata. Verified: the tracing
   agent records zero packedDispatch entries for the new bytecode.

2. GeneratedDispatcher.bootstrap keeps the LambdaMetafactory hidden-class
   adapters on a regular JVM (the JIT-inlining rationale in the class
   javadoc), but where classes cannot be defined at run time -- native
   image, detected per link so build-time class init cannot bake in the
   wrong answer -- it adapts the tables with method-handle-invoking
   wrappers instead: ordinary bytecode of this class, AOT-compiled into
   the image. A catch-based fallback covers AOT runtimes the property
   probe misses. -Dgroovy.packed.dispatch.handles=true forces the wrapper
   path on a JVM, for parity testing.

Permanent behaviour, no user-facing flag: JVM semantics are unchanged and
the fallback engages only where the hidden-class path cannot work. The
old 3-arg bootstrap remains for class files from earlier 6.0 snapshots.

Before/after on GraalVM 25.2.4 (native-image 25.0.4): the packed repro
previously failed with 'Classes cannot be defined at runtime ...
M$$Lambda...'; it now runs correctly (single emitted class, 30MB image,
~12ms total run time). Parity + undeclared-checked-exception propagation
covered by PackedDispatcherHandleBundleTest; all existing packed-closure
suites green.
@paulk-asert
paulk-asert marked this pull request as draft August 4, 2026 00:49
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 57.14286% with 15 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.9715%. Comparing base (7a34d45) to head (6464647).
⚠️ Report is 5 commits behind head on master.

Files with missing lines Patch % Lines
...g/codehaus/groovy/runtime/GeneratedDispatcher.java 54.5454% 14 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                 @@
##               master      #2762        +/-   ##
==================================================
- Coverage     69.9738%   69.9715%   -0.0023%     
- Complexity      35505      35515        +10     
==================================================
  Files            1557       1557                
  Lines          131675     131705        +30     
  Branches        24169      24170         +1     
==================================================
+ Hits            92138      92156        +18     
- Misses          31193      31209        +16     
+ Partials         8344       8340         -4     
Files with missing lines Coverage Δ
...rg/codehaus/groovy/classgen/asm/ClosureWriter.java 89.7931% <100.0000%> (ø)
...org/codehaus/groovy/vmplugin/v8/IndyInterface.java 83.5165% <100.0000%> (-0.4614%) ⬇️
...g/codehaus/groovy/runtime/GeneratedDispatcher.java 57.6923% <54.5454%> (-29.2642%) ⬇️

... and 6 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@testlens-app

testlens-app Bot commented Aug 4, 2026

Copy link
Copy Markdown

✅ All tests passed ✅

🏷️ Commit: 6464647
▶️ Tests: 108605 executed
⚪️ Checks: 31/31 completed


Learn more about TestLens at testlens.app.

@paulk-asert

Copy link
Copy Markdown
Contributor Author

Superseded by #2765

@paulk-asert paulk-asert closed this Aug 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants