Skip to content

[GR-79187][Native Image] Ristretto: mixed SubstrateType/RistrettoType stamp meet throws ClassCastException #14311

Description

@sgammon

Describe the Issue

Ristretto can infer a phi stamp whose inputs contain one AOT SubstrateType and one runtime-loaded RistrettoType. AbstractObjectStamp.meetTypes calls findLeastCommonAncestor across those two type universes. Because RistrettoType inherits SubstrateType.findLeastCommonAncestor, the mixed pair passes that method's outer SubstrateType cast, then fails when virtual dispatch reaches RistrettoType.isAssignableFrom, which requires its argument to already be a RistrettoType.

The runtime compilation is abandoned and the method remains interpreted. A minimal Maven project triggers this deterministically during Maven startup: 5 of 221–227 compilations failed in repeated runs (about 2%). Maven output remains correct and may still exit 0, but stderr reports a systemic compiler failure.

Using the latest version of GraalVM can resolve many issues.

  • Reproduced with the latest available Oracle GraalVM EA build; the relevant code is also unchanged on oracle/graal master at 8f1ea8c43038.

GraalVM Version

java version "25.0.4.1" 2026-08-18 LTS
Oracle GraalVM 25.3.4.1-dev+0.1 (build 25.0.4.1+0-LTS-jvmci-25.3-b21)
Substrate VM Oracle GraalVM 25.3.4.1-dev+0.1 (serial gc, compressed references)

Also reproduced previously with Oracle GraalVM 25.2.4+7.1 on linux-amd64.

Operating System and Version

macOS 26.5 (Darwin 25.5.0), arm64. Also reproduced on Linux 6.6 / WSL2, amd64.

Troubleshooting Confirmation

  • I tried the suggestions in the Native Image troubleshooting guide.

Run Command

With a Crema/Ristretto image installed as JAVA_HOME:

JAVA_HOME=/path/to/runtime MAVEN_OPTS=-Djdk.graal.CompilationFailureAction=Print mvn clean

Expected Behavior

Runtime compilation should normalize type metadata into one universe before computing a least common ancestor, and the Sisu method should compile successfully.

Actual Behavior

Compilation of org.eclipse.sisu.inject.InjectorBindings.isAssignableFrom(TypeLiteral, Binding) throws ClassCastException; the compilation is discarded and repeated attempts trip SystemicCompilationFailureRate.

Steps to Reproduce

Create this pom.xml in an empty directory:

<project xmlns="http://maven.apache.org/POM/4.0.0">
  <modelVersion>4.0.0</modelVersion>
  <groupId>demo</groupId>
  <artifactId>demo</artifactId>
  <version>1.0</version>
</project>

Then run Maven 3.9.x with a -H:+RuntimeClassLoading -H:+GraalJITCompileAtRuntime native-image runtime as JAVA_HOME:

mkdir -p target/classes
touch target/classes/marker
JAVA_HOME=/path/to/runtime \
  MAVEN_OPTS=-Djdk.graal.CompilationFailureAction=Print \
  mvn clean

The failure occurs during Maven/Sisu startup. The pom.xml has no dependencies and the build goal itself is not material.

Additional Context

Current master makes the incompatible assumptions visible:

// SubstrateType.java:302-318
public ResolvedJavaType findLeastCommonAncestor(ResolvedJavaType otherType) {
    ...
    SubstrateType t1 = this;                       // RistrettoType
    SubstrateType t2 = (SubstrateType) otherType;  // plain SubstrateType; succeeds
    while (true) {
        if (t1.isAssignableFrom(t2)) {              // virtual dispatch
// RistrettoType.java:117-122
public boolean isAssignableFrom(ResolvedJavaType other) {
    assert other instanceof RistrettoType : Assertions.errorMessage("Must already be wrapped", this, other);
    RistrettoType rTypeOther = (RistrettoType) other; // ClassCastException
    return this.interpreterType.isAssignableFrom(rTypeOther.interpreterType);
}

With assertions enabled, the same path should fail earlier with the clearer Must already be wrapped assertion. In a product image it reaches the cast.

Possible normalization points include RistrettoType.isAssignableFrom, SubstrateType.findLeastCommonAncestor, or the stamp producer that permits an AOT/runtime mixed phi. I am not asserting which layer should own the fix, only that findLeastCommonAncestor currently dispatches a plain SubstrateType into an override whose stated invariant forbids it.

Run-Time Log Output and Error Messages

Compilation of org.eclipse.sisu.inject.InjectorBindings.isAssignableFrom(TypeLiteral, Binding) failed:
java.lang.ClassCastException: com.oracle.svm.graal.meta.SubstrateType cannot be cast to
com.oracle.svm.interpreter.ristretto.meta.RistrettoType
    at org.graalvm.nativeimage.builder/com.oracle.svm.interpreter.ristretto.meta.RistrettoType.isAssignableFrom(RistrettoType.java:120)
    at org.graalvm.nativeimage.builder/com.oracle.svm.graal.meta.SubstrateType.findLeastCommonAncestor(SubstrateType.java:310)
    at jdk.graal.compiler/jdk.graal.compiler.core.common.type.AbstractObjectStamp.meetTypes(AbstractObjectStamp.java:316)
    at jdk.graal.compiler/jdk.graal.compiler.core.common.type.AbstractObjectStamp.meet(AbstractObjectStamp.java:181)
    at jdk.graal.compiler/jdk.graal.compiler.nodes.type.StampTool.meetOrNull(StampTool.java:69)
    at jdk.graal.compiler/jdk.graal.compiler.nodes.ValuePhiNode.inferStamp(ValuePhiNode.java:92)
    at jdk.graal.compiler/jdk.graal.compiler.phases.common.CanonicalizerPhase.tryInferStamp(CanonicalizerPhase.java:888)
    ...
    at org.graalvm.nativeimage.builder/com.oracle.svm.interpreter.ristretto.RistrettoUtils.compileAndInstallForPublication(RistrettoUtils.java:365)

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions