jamesnetherton opened a new issue, #9001:
URL: https://github.com/apache/camel-quarkus/issues/9001

   ### Bug description
   
   Native image builds fail during `[5/8] Inlining methods...` with a 
`PermanentBailoutException` raised from the single callsite inlining stage 
(`-H:+AOTSingleCallsiteInline`, added by 
[graalvm/mandrel@11b6c9c](https://github.com/graalvm/mandrel/commit/11b6c9c87a9a)
 "single callsite inlining").
   
   Quarkus 3.39 enables this option automatically for non-Oracle distributions 
in the version range `[25.0.4, 25.1.0)`, so applications hit it by default 
rather than opting into it 
([quarkusio/quarkus@2071c57](https://github.com/quarkusio/quarkus/commit/2071c57b3614099fa955cb41dac8295d0247b097),
 on the 3.39 branch as a cherry-pick of quarkusio/quarkus#55482):
   
   ```java
   if 
(graalVMVersion.compareTo(io.quarkus.runtime.graal.GraalVM.Version.VERSION_25_0_4)
 >= 0
           && 
graalVMVersion.compareTo(io.quarkus.runtime.graal.GraalVM.Version.VERSION_25_1_0)
 < 0
           && graalVMVersion.getDistribution() != Distribution.ORACLE) {
       final List<String> additionalBuildArgs = 
NativeConfigUtils.getNativeAdditionalBuildArgs(nativeConfig);
       if (additionalBuildArgs.stream().noneMatch(arg -> 
arg.contains("AOTSingleCallsiteInline"))) {
           log.info("Single callsite inlining has been enabled for this build. 
...");
           addExperimentalVMOption(nativeImageArgs, 
"-H:+AOTSingleCallsiteInline");
       }
   }
   ```
   
   ## CI build logs
   
   ```
   [2/8] Performing analysis...  [*****]   (88.9s @ 4.50GB)
      22,896 types,  29,324 fields, and 103,018 methods found reachable
   [3/8] Building universe...              (12.0s @ 4.93GB)
   [4/8] Parsing methods...      [***]     (9.7s  @ 5.24GB)
   [5/8] Inlining methods...     [*****]   (13.7s @ 6.07GB)
   
   Fatal error: jdk.graal.compiler.core.common.PermanentBailoutException: 
Number of elements in a node list too high: 65537
        at 
jdk.graal.compiler/jdk.graal.compiler.graph.NodeList.checkMaxSize(NodeList.java:124)
        at 
jdk.graal.compiler/jdk.graal.compiler.graph.NodeList.add(NodeList.java:180)
        at 
jdk.graal.compiler/jdk.graal.compiler.graph.NodeList.add(NodeList.java:40)
        at 
jdk.graal.compiler/jdk.graal.compiler.nodes.AbstractMergeNode.addForwardEnd(AbstractMergeNode.java:74)
        at 
jdk.graal.compiler/jdk.graal.compiler.nodes.AbstractMergeNode.simplify(AbstractMergeNode.java:226)
        at 
jdk.graal.compiler/jdk.graal.compiler.phases.common.CanonicalizerPhase.tryCanonicalize(CanonicalizerPhase.java:731)
        at 
jdk.graal.compiler/jdk.graal.compiler.phases.common.CanonicalizerPhase.processNode(CanonicalizerPhase.java:611)
        at 
jdk.graal.compiler/jdk.graal.compiler.phases.common.CanonicalizerPhase.processWorkSet(CanonicalizerPhase.java:384)
        at 
jdk.graal.compiler/jdk.graal.compiler.phases.common.CanonicalizerPhase.run(CanonicalizerPhase.java:275)
        at 
jdk.graal.compiler/jdk.graal.compiler.phases.common.CanonicalizerPhase.run(CanonicalizerPhase.java:102)
        at 
jdk.graal.compiler/jdk.graal.compiler.phases.BasePhase.apply(BasePhase.java:468)
        at 
jdk.graal.compiler/jdk.graal.compiler.phases.BasePhase.apply(BasePhase.java:334)
        at 
org.graalvm.nativeimage.builder/com.oracle.svm.hosted.code.CompileQueue.doInlineSingleCallsite(CompileQueue.java:992)
        at 
org.graalvm.nativeimage.builder/com.oracle.svm.hosted.code.CompileQueue$SingleCallsiteInlineTask.run(CompileQueue.java:371)
        at 
org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.util.CompletionExecutor.executeCommand(CompletionExecutor.java:166)
        ...
   
------------------------------------------------------------------------------------------------------------------------
                          12.4s (9.0% of total time) in 755 GCs | Peak RSS: 
7.04GB | CPU load: 3.41
   
========================================================================================================================
   Failed generating 
'camel-quarkus-integration-test-milo-3.39.0-SNAPSHOT-runner' after 2m 16s.
   ```
   
   ## What appears to be broken
   
   The following is from reading `CompileQueue.java` at tag 
`mandrel-25.0.4.0-Final`; I have not identified which specific method exceeds 
the limit.
   
   The trace line numbers match that tag exactly: `CompileQueue.java:992` is 
the `CanonicalizerPhase.create().apply(graph, providers)` call inside 
`doInlineSingleCallsite`, and `CompileQueue.java:371` is 
`doInlineSingleCallsite(debug, method)` in `SingleCallsiteInlineTask.run`.
   
   `NodeList` caps at 65536 entries, and the graph being canonicalized after 
single callsite inlining has an `AbstractMergeNode` acquiring its 65537th 
forward end. The stage does have a size guard, but three properties look like 
they let a caller graph grow past any intended bound:
   
   1. **The guard operands are stale within a round.** 
`makeSingleCallsiteInlineDecision` (line 1019) tests 
`caller.compilationInfo.sizeLastRound + callee.compilationInfo.sizeLastRound >= 
FALLBACK_SIZE` (line 1034), but `sizeLastRound` is only assigned at the end of 
`doInlineSingleCallsite` (line 996), after the whole `InlinePhase` has run. 
During a single decode the plugin can inline many callees into the same caller 
while both operands remain at their previous-round values, so growth 
accumulated within that round is never observed by the guard.
   
   2. **`FALLBACK_SIZE` is not in node-count units.** It is `50000` (line 166) 
compared against `NodeCostUtil.computeGraphSize(graph)`, a cost estimate, so it 
was never a bound on `NodeList` size in the first place.
   
   3. **`FALLBACK_SIZE` is a hardcoded constant** with no corresponding 
`@Option`, so it cannot be tuned downward.
   
   Additionally, `doInlineSingleCallsite` ends in `catch (Throwable ex) { throw 
debug.handle(ex); }` (lines 998-1000), so the bailout propagates and terminates 
the image build.
   
   ## Workaround
   
   Disabling the stage avoids the failure:
   
   ```
   -Dquarkus.native.additional-build-args-append=-H:-AOTSingleCallsiteInline
   ```
   
   ## References
   
   The stage reached `mandrel-25.0.4.0-Final` through graalvm/mandrel#985 
("Merge upstream graalvm-community-jdk25u/master into mandrel/25.0"), in these 
commits:
   
   - [`11b6c9c`](https://github.com/graalvm/mandrel/commit/11b6c9c87a9a) 
(2026-01-23) — "single callsite inlining": adds 
`SubstrateOptions.AOTSingleCallsiteInline`, `InliningGraphDecoder`, and the 
`CompileQueue` stage
   - [`86a715a`](https://github.com/graalvm/mandrel/commit/86a715a8c357) 
(2026-02-02) — "account for NeverInline annotation": adds the 
`callee.getWrapped().canBeInlined()` check
   - [`db6ab61`](https://github.com/graalvm/mandrel/commit/db6ab616fdec) 
(2026-05-13) — "revert name change of UnpublishedTrivialMethods and 
unpublishedTrivialMethods"
   
   The corresponding review thread is oracle/graal#12899 ("Add an inlining 
stage for single callsite methods"), which is still open on GitHub even though 
the commits above are in the release.
   
   
   _Claude Code on behalf of James Netherton_


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