RFR: 8353565: Javac throws "inconsistent stack types at join point" exception [v2]
Maurizio Cimadamore
mcimadamore at openjdk.org
Mon Apr 28 13:44:48 UTC 2025
On Tue, 15 Apr 2025 17:45:28 GMT, Jan Lahoda <jlahoda at openjdk.org> wrote:
>> Consider code like:
>>
>> public class T {
>> private Object computeTypeAtMergePoint1(int i) {
>> return (Object) switch (i) {
>> case 0 -> switch (i) {
>> case 0 -> { yield new A(); }
>> default -> { yield new B(); }
>> };
>> default -> switch (i) {
>> case 0 -> { yield new C(); }
>> default -> { yield new D(); }
>> };
>> };
>> }
>> enum E {A, B}
>> interface I1 {}
>> class A implements I1 {}
>> class B implements I1 {}
>> interface I2 {}
>> class C implements I2 {}
>> class D implements I2 {}
>>
>> }
>>
>>
>> Compiling this leads to a crash:
>>
>> $ .../jdk-24/bin/javac /tmp/T.java
>> An exception has occurred in the compiler (24-internal). Please file a bug against the Java compiler via the Java bug reporting page (https://bugreport.java.com) after checking the Bug Database (https://bugs.java.com) for duplicates. Include your program, the following diagnostic, and the parameters passed to the Java compiler in your report. Thank you.
>> java.lang.AssertionError: inconsistent stack types at join point
>> at jdk.compiler/com.sun.tools.javac.jvm.Code$State.error(Code.java:1824)
>> at jdk.compiler/com.sun.tools.javac.jvm.Code$State.join(Code.java:1814)
>> at jdk.compiler/com.sun.tools.javac.jvm.Code.resolve(Code.java:1525)
>> at jdk.compiler/com.sun.tools.javac.jvm.Code.resolvePending(Code.java:1556)
>> at jdk.compiler/com.sun.tools.javac.jvm.Code.emitop(Code.java:382)
>> at jdk.compiler/com.sun.tools.javac.jvm.Code.emitop0(Code.java:511)
>> at jdk.compiler/com.sun.tools.javac.jvm.Gen.visitReturn(Gen.java:1905)
>> at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCReturn.accept(JCTree.java:1773)
>> at jdk.compiler/com.sun.tools.javac.jvm.Gen.genDef(Gen.java:588)
>> at jdk.compiler/com.sun.tools.javac.jvm.Gen.genStat(Gen.java:623)
>> at jdk.compiler/com.sun.tools.javac.jvm.Gen.genStat(Gen.java:609)
>> at jdk.compiler/com.sun.tools.javac.jvm.Gen.genStats(Gen.java:660)
>> at jdk.compiler/com.sun.tools.javac.jvm.Gen.internalVisitBlock(Gen.java:1121)
>> at jdk.compiler/com.sun.tools.javac.jvm.Gen.visitBlock(Gen.java:1085)
>> at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:1137)
>> at jdk.compiler/com.sun.tools.javac.jvm.Gen.genDef(Gen.java:588)
>> at jdk.compiler/com.sun.tools.jav...
>
> Jan Lahoda has updated the pull request incrementally with one additional commit since the last revision:
>
> Reflecting review feedback - moving subtyping checks to commonSuperClass.
Seems a nice generalization of what the code used to do. One possible problematic aspect is non-denotable types. E.g. if `A` and `B` both implements _two_ interfaces like `I1` and `I2`. In that case the lub will be `I1 & I2` which erased will lead you to `I1`. I *think* this is still correct because the verifier doesn't concern with interface types -- but would probably be better to double check.
Another alternative would be to use Object as the stackmap type is the join is non-denotable. But then I'm not sure what would be the ramifications of doing that. Using the erasure seems safer because javac will insert synthetic cast if e.g. accessing a member on something that doesn't look like the erasure (e.g. calling a method in `I2` on a `I1 & I2`).
-------------
PR Review: https://git.openjdk.org/jdk/pull/24617#pullrequestreview-2799349579
More information about the compiler-dev
mailing list