oracle/graal · critical · ForceDeoptSpeculationPhase.TooManyDeoptimizationsError

too many decompiles: {} {}

Error message

too many decompiles: {} {}

What it means

Before (re)compiling a method, CompilationTask.performRecompilationCheck verifies that the method's deoptimization count has reached MethodRecompilationLimit; if so it throws ForceDeoptSpeculationPhase.TooManyDeoptimizationsError with the decompile count and a deopt summary. This aborts a pathological compile/deoptimize cycle instead of looping forever.

Source

Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/CompilationTask.java:395

                }
                ListIterator<BasePhase<? super LowTierContext>> lowTierPhasesIterator = suites.getLowTier().findPhase(SchedulePhase.FinalSchedulePhase.class);
                if (lowTierPhasesIterator != null) {
                    lowTierPhasesIterator.previous();
                    lowTierPhasesIterator.add(new ForceDeoptSpeculationPhase(decompileCount));
                }
            }
        }

        /**
         * Checks whether the recompilation limit is exceeded, and if so, throws an exception.
         *
         * @param options the option values
         * @param method the compiled method
         */
        private void performRecompilationCheck(OptionValues options, HotSpotResolvedJavaMethod method) {
            if (checkRecompileCycle && (MethodRecompilationLimit.getValue(options) >= 0 && decompileCount >= MethodRecompilationLimit.getValue(options))) {
                ProfilingInfo info = profileProvider.getProfilingInfo(null, method);
                throw new ForceDeoptSpeculationPhase.TooManyDeoptimizationsError("too many decompiles: " + decompileCount + " " + ForceDeoptSpeculationPhase.getDeoptSummary(info));
            }
        }

        private static final TimerKey CompilationReplayTime = DebugContext.timer("CompilationReplayTime").doc("The time spent in recorded/replayed compilations.");

        private static final CounterKey CompilationReplayBytecodes = DebugContext.counter("CompilationReplayBytecodes").doc("The size of bytecodes compiled in recorded/replayed compilations.");

        /**
         * Performs a recorded or replayed compilation.
         *
         * @param initialDebug the initial debug context
         * @return the compilation result
         */
        @SuppressWarnings("try")
        private HotSpotCompilationRequestResult performCompilationWithReplaySupport(DebugContext initialDebug) {
            OptionValues options = initialDebug.getOptions();
            HotSpotGraalCompiler selectedCompiler;
            if (compiler.getGraalRuntime().getReplayCompilationSupport() != null) {

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Inspect the deopt summary in the message to find which speculation/deopt reason loops, and fix the root cause (e.g. stabilizing profiles or fixing the custom phase/speculation)
  2. Raise or disable the guard for diagnosis: -Dgraal.MethodRecompilationLimit=-1 (or a larger value)
  3. Report the reproducer to the Graal team if it occurs with a stock configuration on unmodified code

Example fix

# before
java -XX:+UseJVMCICompiler MyApp
# TooManyDeoptimizationsError: too many decompiles: 5 ...

# after (diagnosis: raise the limit while investigating the deopt loop)
java -XX:+UseJVMCICompiler -Dgraal.MethodRecompilationLimit=-1 MyApp
# then use -Dgraal.Dump=... and the deopt summary to find the unstable speculation
Defensive patterns

Strategy: fallback

Try / catch

// usually not caught: TooManyDeoptimizationsError is a Graal-internal Error surfaced via a crashed compilation; treat as a bug report trigger, not a recoverable path

Prevention

When it happens

Trigger: Running with checkRecompilationCycle enabled and MethodRecompilationLimit >= 0 (it is on by default with a finite limit), when a method's accumulated decompiles (decompileCount) >= the limit at the start of a compilation; the summary comes from profileProvider.getProfilingInfo(null, method) for the failing method.

Common situations: Degenerate profiling feedback or unstable speculation causing the method to deopt and recompile repeatedly (e.g. flipping branch profiles in benchmarks, broken custom speculation plugins); lowering MethodRecompilationLimit too far; class redefinition (instrumentation) churn.

Related errors


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/c021255f0a099426. Report an issue: GitHub.