mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 03:58:21 +00:00
8369654: javac OutOfMemoryError for complex intersection type
Reviewed-by: liach, mcimadamore
This commit is contained in:
parent
1922c4fd6f
commit
9f972008ff
@ -4090,19 +4090,20 @@ public class Types {
|
||||
return lub(classes);
|
||||
}
|
||||
}
|
||||
// where
|
||||
List<Type> erasedSupertypes(Type t) {
|
||||
ListBuffer<Type> buf = new ListBuffer<>();
|
||||
for (Type sup : closure(t)) {
|
||||
if (sup.hasTag(TYPEVAR)) {
|
||||
buf.append(sup);
|
||||
} else {
|
||||
buf.append(erasure(sup));
|
||||
}
|
||||
}
|
||||
return buf.toList();
|
||||
}
|
||||
|
||||
public List<Type> erasedSupertypes(Type t) {
|
||||
ListBuffer<Type> buf = new ListBuffer<>();
|
||||
for (Type sup : closure(t)) {
|
||||
if (sup.hasTag(TYPEVAR)) {
|
||||
buf.append(sup);
|
||||
} else {
|
||||
buf.append(erasure(sup));
|
||||
}
|
||||
}
|
||||
return buf.toList();
|
||||
}
|
||||
|
||||
// where
|
||||
private Type arraySuperType;
|
||||
private Type arraySuperType() {
|
||||
// initialized lazily to avoid problems during compiler startup
|
||||
|
||||
@ -34,10 +34,12 @@ import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
|
||||
import java.util.function.ToIntBiFunction;
|
||||
import java.util.function.ToIntFunction;
|
||||
|
||||
import static com.sun.tools.javac.code.TypeTag.ARRAY;
|
||||
import static com.sun.tools.javac.code.TypeTag.BOT;
|
||||
import static com.sun.tools.javac.code.TypeTag.DOUBLE;
|
||||
import static com.sun.tools.javac.code.TypeTag.INT;
|
||||
import static com.sun.tools.javac.code.TypeTag.LONG;
|
||||
import static com.sun.tools.javac.code.TypeTag.TYPEVAR;
|
||||
import static com.sun.tools.javac.jvm.ByteCodes.*;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Class;
|
||||
import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_Double;
|
||||
@ -1824,14 +1826,42 @@ public class Code {
|
||||
} else if (types.isSubtype(t2, t1)) {
|
||||
return t1;
|
||||
} else {
|
||||
Type lub = types.lub(t1, t2);
|
||||
|
||||
if (lub.hasTag(BOT)) {
|
||||
/* the most semantically correct approach here would be to invoke Types::lub
|
||||
* and then erase the result.
|
||||
* But this approach can be too slow for some complex cases, see JDK-8369654.
|
||||
* This is why the method below leverages the fact that the result
|
||||
* will be erased to produce a correct supertype using a simpler approach compared
|
||||
* to a full blown lub.
|
||||
*/
|
||||
Type es = erasedSuper(t1, t2);
|
||||
if (es == null || es.hasTag(BOT)) {
|
||||
throw Assert.error("Cannot find a common super class of: " +
|
||||
t1 + " and " + t2);
|
||||
}
|
||||
return es;
|
||||
}
|
||||
}
|
||||
|
||||
return types.erasure(lub);
|
||||
private Type erasedSuper(Type t1, Type t2) {
|
||||
if (t1.hasTag(ARRAY) && t2.hasTag(ARRAY)) {
|
||||
Type elem1 = types.elemtype(t1);
|
||||
Type elem2 = types.elemtype(t2);
|
||||
if (elem1.isPrimitive() || elem2.isPrimitive()) {
|
||||
return (elem1.tsym == elem2.tsym) ? t1 : syms.serializableType;
|
||||
} else { // both are arrays of references
|
||||
return new ArrayType(erasedSuper(elem1, elem2), syms.arrayClass);
|
||||
}
|
||||
} else {
|
||||
t1 = types.skipTypeVars(t1, false);
|
||||
t2 = types.skipTypeVars(t2, false);
|
||||
List<Type> intersection = types.intersect(
|
||||
t1.hasTag(ARRAY) ?
|
||||
List.of(syms.serializableType, syms.cloneableType, syms.objectType) :
|
||||
types.erasedSupertypes(t1),
|
||||
t2.hasTag(ARRAY) ?
|
||||
List.of(syms.serializableType, syms.cloneableType, syms.objectType) :
|
||||
types.erasedSupertypes(t2));
|
||||
return intersection.head;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8369654
|
||||
* @summary javac OutOfMemoryError for complex intersection type
|
||||
* @compile ExpressionSwitchComplexIntersectionTest.java
|
||||
*/
|
||||
|
||||
public class ExpressionSwitchComplexIntersectionTest {
|
||||
interface WithMixin01<T> {}
|
||||
interface WithMixin02<T> {}
|
||||
interface WithMixin03<T> {}
|
||||
interface WithMixin04<T> {}
|
||||
interface WithMixin05<T> {}
|
||||
interface WithMixin06<T> {}
|
||||
interface WithMixin07<T> {}
|
||||
interface WithMixin08<T> {}
|
||||
interface WithMixin09<T> {}
|
||||
interface WithMixin10<T> {}
|
||||
interface WithMixin11<T> {}
|
||||
interface WithMixin12<T> {}
|
||||
interface WithMixin13<T> {}
|
||||
interface WithMixin14<T> {}
|
||||
interface WithMixin15<T> {}
|
||||
interface WithMixin16<T> {}
|
||||
interface WithMixin17<T> {}
|
||||
interface WithMixin18<T> {}
|
||||
interface WithMixin19<T> {}
|
||||
interface WithMixin20<T> {}
|
||||
|
||||
interface ClientA extends
|
||||
WithMixin01<ClientA>,
|
||||
WithMixin02<ClientA>,
|
||||
WithMixin03<ClientA>,
|
||||
WithMixin04<ClientA>,
|
||||
WithMixin05<ClientA>,
|
||||
WithMixin06<ClientA>,
|
||||
WithMixin07<ClientA>,
|
||||
WithMixin08<ClientA>,
|
||||
WithMixin09<ClientA>,
|
||||
WithMixin10<ClientA>,
|
||||
WithMixin11<ClientA>,
|
||||
WithMixin12<ClientA>,
|
||||
WithMixin13<ClientA>,
|
||||
WithMixin14<ClientA>,
|
||||
WithMixin15<ClientA>,
|
||||
WithMixin16<ClientA>,
|
||||
WithMixin17<ClientA>,
|
||||
WithMixin18<ClientA>,
|
||||
WithMixin19<ClientA>,
|
||||
WithMixin20<ClientA> {
|
||||
}
|
||||
|
||||
interface ClientB extends
|
||||
WithMixin01<ClientB>,
|
||||
WithMixin02<ClientB>,
|
||||
WithMixin03<ClientB>,
|
||||
WithMixin04<ClientB>,
|
||||
WithMixin05<ClientB>,
|
||||
WithMixin06<ClientB>,
|
||||
WithMixin07<ClientB>,
|
||||
WithMixin08<ClientB>,
|
||||
WithMixin09<ClientB>,
|
||||
WithMixin10<ClientB>,
|
||||
WithMixin11<ClientB>,
|
||||
WithMixin12<ClientB>,
|
||||
WithMixin13<ClientB>,
|
||||
WithMixin14<ClientB>,
|
||||
WithMixin15<ClientB>,
|
||||
WithMixin16<ClientB>,
|
||||
WithMixin17<ClientB>,
|
||||
WithMixin18<ClientB>,
|
||||
WithMixin19<ClientB>,
|
||||
WithMixin20<ClientB> {
|
||||
}
|
||||
|
||||
Object f1(boolean b, ClientA c1, ClientB c2) {
|
||||
return b ? c1 : c2;
|
||||
}
|
||||
|
||||
Object f2(boolean b, ClientA[] array1, ClientB[] array2) {
|
||||
return b ? array1 : array2;
|
||||
}
|
||||
|
||||
<TA extends ClientA, TB extends ClientB> Object f3(boolean b, TA[] array1, TB[] array2) {
|
||||
return b ? array1 : array2;
|
||||
}
|
||||
|
||||
<TA extends ClientA, TB extends ClientB, TAA extends TA, TBB extends TB> Object f4(boolean b, TAA[] array1, TBB[] array2) {
|
||||
return b ? array1 : array2;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user