Skip to content

Commit a5f4366

Browse files
committed
8353565: Javac throws "inconsistent stack types at join point" exception
Reviewed-by: vromero, liach, mcimadamore
1 parent c8ce61c commit a5f4366

File tree

3 files changed

+127
-14
lines changed

3 files changed

+127
-14
lines changed

src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -1807,11 +1807,7 @@ State join(State other) {
18071807
for (int i=0; i<stacksize; ) {
18081808
Type t = stack[i];
18091809
Type tother = other.stack[i];
1810-
Type result =
1811-
t==tother ? t :
1812-
types.isSubtype(t, tother) ? tother :
1813-
types.isSubtype(tother, t) ? t :
1814-
error();
1810+
Type result = commonSuperClass(t, tother);
18151811
int w = width(result);
18161812
stack[i] = result;
18171813
if (w == 2) Assert.checkNull(stack[i+1]);
@@ -1820,8 +1816,23 @@ State join(State other) {
18201816
return this;
18211817
}
18221818

1823-
Type error() {
1824-
throw new AssertionError("inconsistent stack types at join point");
1819+
private Type commonSuperClass(Type t1, Type t2) {
1820+
if (t1 == t2) {
1821+
return t1;
1822+
} else if (types.isSubtype(t1, t2)) {
1823+
return t2;
1824+
} else if (types.isSubtype(t2, t1)) {
1825+
return t1;
1826+
} else {
1827+
Type lub = types.lub(t1, t2);
1828+
1829+
if (lub.hasTag(BOT)) {
1830+
throw Assert.error("Cannot find a common super class of: " +
1831+
t1 + " and " + t2);
1832+
}
1833+
1834+
return types.erasure(lub);
1835+
}
18251836
}
18261837

18271838
void dump() {

src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -1853,7 +1853,6 @@ public void visitYield(JCYield tree) {
18531853
if (switchResult != null)
18541854
switchResult.load();
18551855

1856-
code.state.forceStackTop(tree.target.type);
18571856
targetEnv.info.addExit(code.branch(goto_));
18581857
code.markDead();
18591858
}
@@ -1969,7 +1968,6 @@ public void visitConditional(JCConditional tree) {
19691968
int startpc = genCrt ? code.curCP() : 0;
19701969
code.statBegin(tree.truepart.pos);
19711970
genExpr(tree.truepart, pt).load();
1972-
code.state.forceStackTop(tree.type);
19731971
if (genCrt) code.crt.put(tree.truepart, CRT_FLOW_TARGET,
19741972
startpc, code.curCP());
19751973
thenExit = code.branch(goto_);
@@ -1979,7 +1977,6 @@ public void visitConditional(JCConditional tree) {
19791977
int startpc = genCrt ? code.curCP() : 0;
19801978
code.statBegin(tree.falsepart.pos);
19811979
genExpr(tree.falsepart, pt).load();
1982-
code.state.forceStackTop(tree.type);
19831980
if (genCrt) code.crt.put(tree.falsepart, CRT_FLOW_TARGET,
19841981
startpc, code.curCP());
19851982
}

test/langtools/tools/javac/switchexpr/ExpressionSwitchEmbedding.java

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
2323

2424
/*
2525
* @test
26-
* @bug 8214031 8214114 8236546
26+
* @bug 8214031 8214114 8236546 8353565
2727
* @summary Verify switch expressions embedded in various statements work properly.
2828
* @compile ExpressionSwitchEmbedding.java
2929
* @run main ExpressionSwitchEmbedding
@@ -32,6 +32,7 @@
3232
public class ExpressionSwitchEmbedding {
3333
public static void main(String... args) {
3434
new ExpressionSwitchEmbedding().run();
35+
new ExpressionSwitchEmbedding().runStackMapMergingTest();
3536
}
3637

3738
private void run() {
@@ -330,6 +331,110 @@ yield switch (i) {
330331
}
331332
}
332333

334+
private void runStackMapMergingTest() {
335+
//JDK-8353565: verify that two types neither of which is a subtype of the other
336+
//can be merged while computing StackMaps.
337+
if (!(computeTypeAtMergePoint1(E.A, E.A) instanceof Impl1a)) {
338+
throw new AssertionError("Unexpected result");
339+
}
340+
if (runMethodForInterfaceTypeAtMergePoint1(E.A, E.A) != 1) {
341+
throw new AssertionError("Unexpected result");
342+
}
343+
if (runMethodForInterfaceTypeAtMergePoint2(E.A, E.A) != 2) {
344+
throw new AssertionError("Unexpected result");
345+
}
346+
}
347+
348+
private Root computeTypeAtMergePoint1(E e1, E e2) {
349+
return (Root) switch (e1) {
350+
case A -> switch (e2) {
351+
case A -> new Impl1a();
352+
case B -> new Impl1b();
353+
case C -> new Impl1c();
354+
};
355+
case B -> switch (e2) {
356+
case A -> new Impl2a();
357+
case B -> new Impl2b();
358+
case C -> new Impl2c();
359+
};
360+
case C -> switch (e2) {
361+
case A -> new Impl3a();
362+
case B -> new Impl3b();
363+
case C -> new Impl3c();
364+
};
365+
};
366+
}
367+
368+
private int runMethodForInterfaceTypeAtMergePoint1(E e1, E e2) {
369+
return (switch (e1) {
370+
case A -> switch (e2) {
371+
case A -> new C1();
372+
case B -> new C1();
373+
case C -> new C1();
374+
};
375+
case B -> switch (e2) {
376+
case A -> new C2();
377+
case B -> new C2();
378+
case C -> new C2();
379+
};
380+
case C -> switch (e2) {
381+
case A -> new C3();
382+
case B -> new C3();
383+
case C -> new C3();
384+
};
385+
}).test1();
386+
}
387+
388+
private int runMethodForInterfaceTypeAtMergePoint2(E e1, E e2) {
389+
return (switch (e1) {
390+
case A -> switch (e2) {
391+
case A -> new C1();
392+
case B -> new C1();
393+
case C -> new C1();
394+
};
395+
case B -> switch (e2) {
396+
case A -> new C2();
397+
case B -> new C2();
398+
case C -> new C2();
399+
};
400+
case C -> switch (e2) {
401+
case A -> new C3();
402+
case B -> new C3();
403+
case C -> new C3();
404+
};
405+
}).test2();
406+
}
407+
408+
private static class Root {}
409+
private static class Base1 extends Root {}
410+
private static class Impl1a extends Base1 {}
411+
private static class Impl1b extends Base1 {}
412+
private static class Impl1c extends Base1 {}
413+
private static class Base2 extends Root {}
414+
private static class Impl2a extends Base2 {}
415+
private static class Impl2b extends Base2 {}
416+
private static class Impl2c extends Base2 {}
417+
private static class Base3 extends Root {}
418+
private static class Impl3a extends Base3 {}
419+
private static class Impl3b extends Base3 {}
420+
private static class Impl3c extends Base3 {}
421+
422+
private static interface RootInterface1 {
423+
public default int test1() {
424+
return 1;
425+
}
426+
}
427+
private static interface RootInterface2 {
428+
public default int test2() {
429+
return 2;
430+
}
431+
}
432+
private static class C1 implements RootInterface1, RootInterface2 {}
433+
private static class C2 implements RootInterface1, RootInterface2 {}
434+
private static class C3 implements RootInterface1, RootInterface2 {}
435+
436+
enum E {A, B, C;}
437+
333438
private void throwException() {
334439
throw new RuntimeException();
335440
}

0 commit comments

Comments
 (0)