oracle/graal · error · AssertionError

Performance warning detected and is treated as a compilation

Error message

Performance warning detected and is treated as a compilation error.

What it means

Thrown as an AssertionError at the end of Truffle performance-warning reporting when any warning kind recorded for the compiled graph intersects the kinds listed in TruffleCompilerOptions.TreatPerformanceWarningsAsErrors. It is a deliberate escape hatch: the compiler detected a coding pattern known to hurt Truffle peak performance (e.g. megamorphic virtual calls in hot code) and the configuration says to fail the compilation instead of just logging. This is not a compiler bug; it is a lint gate for guest-language bytecode produced by partial evaluation.

Source

Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/truffle/PerformanceInformationHandler.java:241

                        if (!ProfileSource.isTrusted(split.getProfileData().getProfileSource())) {
                            logPerformanceWarning(TruffleCompilerOptions.PerformanceWarningKind.MISSING_LOOP_FREQUENCY_INFO, context.compilable, Arrays.asList(loop.getHeader().getBeginNode()),
                                            String.format("Missing loop profile for %s at loop %s.", split, loop.getHeader().getBeginNode()), null);
                        }
                    }
                }
            }
        }

        if (debug.areScopesEnabled() && !warnings.isEmpty()) {
            try (DebugContext.Scope s = debug.scope("TrufflePerformanceWarnings", graph)) {
                debug.dump(DebugContext.BASIC_LEVEL, graph, "performance warnings %s", warnings);
            } catch (Throwable t) {
                debug.handle(t);
            }
        }

        if (!Collections.disjoint(getWarnings(), TruffleCompilerOptions.TreatPerformanceWarningsAsErrors.getValue(options).kinds())) {
            throw new AssertionError("Performance warning detected and is treated as a compilation error.");
        }
    }

    /**
     * On HotSpot, a type check against a class that is at a depth <= 8 in the class hierarchy
     * (including Object) is just one extra memory load.
     */
    private static boolean isPrimarySupertype(ResolvedJavaType type) {
        if (type.isInterface()) {
            return false;
        }
        ResolvedJavaType supr = type;
        int depth = 0;
        while (supr != null) {
            depth++;
            supr = supr.getSuperclass();
        }
        return depth <= 8;

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Run with -Dgraal.TrufflePerformanceWarningsAsErrors= to disable the error conversion, or remove the specific kind matching the warning, then recompile to see the dumped warnings (enable -Dgraal.Dump=TrufflePerformanceWarnings to get the 'performance warnings %s' dump).
  2. Inspect the graph dump named 'performance warnings' to identify which node/warning kind fired (e.g. megamorphic dispatch, virtual call not inlined).
  3. Fix the guest-language code or node implementation that produced the warning (specialize, use @Specialization guards, avoid megamorphic call sites).
  4. If the warning is a false positive for your language, exclude only that warning kind from TreatPerformanceWarningsAsErrors instead of disabling the check entirely.

Example fix

// before
-Dgraal.TrufflePerformanceWarningsAsErrors=all

// after: narrow to the kinds you actually enforce, dump details first
-Dgraal.Dump=TrufflePerformanceWarnings,level=1 -Dgraal.TrufflePerformanceWarningsAsErrors=Megamorphic
Defensive patterns

Strategy: try-catch

Validate before calling

// Before compiling, check the option value yourself
import static jdk.graal.compiler.truffle.TruffleCompilerOptions.TreatPerformanceWarningsAsErrors;

var kinds = TreatPerformanceWarningsAsErrors.getValue(options).kinds();
if (!kinds.isEmpty()) {
    System.err.println("strict perf warnings active: " + kinds);
}

Try / catch

// At the compilation-request boundary
try {
    compile(graph, options);
} catch (AssertionError e) {
    if (e.getMessage() != null && e.getMessage().contains("Performance warning detected")) {
        // treat as code-quality failure: log, collect CI artifact, recompile with warnings non-fatal
        reportPerfWarnings(compilationId);
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Compiling a Truffle guest-language method whose graph accumulates performance warnings (via PerformanceInformationHandler.getWarnings()), while -Dgraal.TrufflePerformanceWarningsAsErrors (TreatPerformanceWarningsAsErrors) is set to a kind set such as 'all' or 'Megamorphic' that overlaps those warnings. The check runs Collections.disjoint(getWarnings(), optionKinds) after every compilation, so any single matching warning triggers it.

Common situations: Language implementers enabling strict performance checking in CI to catch regressions; upgrading a Truffle language after new warning kinds were added (a pattern previously silent now fails); running with TreatPerformanceWarningsAsErrors=AnNOTATED/Bailout on code that uses @NeverValidTruffleBundle or optimistic assumptions that became megamorphic.

Related errors


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