JDK-8225508 : Compiler OOM Error with Type Inference Hierarchy
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8,11,12,13
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: generic
  • CPU: generic
  • Submitted: 2019-06-07
  • Updated: 2022-08-08
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Relates :  
Description
ADDITIONAL SYSTEM INFORMATION :
Attempted with JDKs 1.8.0_191, 1.8.0_212, 11.0.3, and 12.01, on both OS X High Sierra and Ubuntu 18.04.

A DESCRIPTION OF THE PROBLEM :
When calling Arrays.asList() without type arguments and on arguments within a nested type hierarchy, the compiler uses exponentially more memory as interfaces are added; with the source code provided, adding 4 interfaces to the classes compiles with a max heap size of 128m, 5 interfaces fails as 2g but succeeds with 3g, and 6 interfaces still fails at 12g.

This may have something to do with Arrays.asList() using parametrically polymorphic variadic arguments; on the initial case, List.of() presented the same issues with 11 arguments (tripping the varargs case), but not with 10 when it switched back to an overload using 10 explicit arguments.  However, the current test case shows Arrays.asList() and List.of() behaving identically.

Perhaps related to https://bugs.openjdk.java.net/browse/JDK-8055984.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Following the provided source code:
1) Create a class (ConsStruct) with subclasses (Empty and Cons) extending it
2) Create interfaces which are intended to carry the class implementing them as type witnesses (interfaces I through M)
3) Create extensions of the main class (ConsStruct) defined in terms of each other (in the source code, as tuples: A4/5/6, B4/5/6, and C4/5/6, with C being defined in terms of B defined in terms of A)
4) Have the extensions implement the interfaces (5 for failure with heap size of 2g, 6 for failure beyond that)
5) Call Arrays.asList() (or List.of()) without additional type arguments on instances of the extensions

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The code would correctly infer and compile with a reasonably-growing amount of heap space
ACTUAL -
The code does not compile, due to lack of heap space

---------- BEGIN SOURCE ----------
import java.util.Arrays;

public class InterfaceOverload {
    private interface I<X, IWitness extends I<?, IWitness>> { }
    private interface J<X, JWitness extends J<?, JWitness>> { }
    private interface K<X, KWitness extends K<?, KWitness>> { }
    private interface L<X, LWitness extends L<?, LWitness>> { }
    private interface M<X, MWitness extends M<?, MWitness>> { }
    private interface N<X, MWitness extends N<?, MWitness>> { }

    private static class ConsStruct {
        private static class Empty extends ConsStruct { }
        private static class Cons<X, Y extends ConsStruct> extends ConsStruct { }
    }

    // Cons-ing types: (C5, (B5, (A5, Empty)))
    // Implementing I through M (5 interfaces)
    private static class A5<X> extends ConsStruct.Cons<X, ConsStruct.Empty> implements
            I<X, A5<?>>, J<X, A5<?>>, K<X, A5<?>>, L<X, A5<?>>, M<X, A5<?>> { }
    private static class B5<X, Y> extends ConsStruct.Cons<X, A5<Y>> implements
            I<Y, B5<X, ?>>, J<Y, B5<X, ?>>, K<Y, B5<X, ?>>, L<Y, B5<X, ?>>, M<Y, B5<X, ?>> { }
    private static class C5<X, Y, Z> extends ConsStruct.Cons<X, B5<Y, Z>> implements
            I<Z, C5<X, Y, ?>>, J<Z, C5<X, Y, ?>>, K<Z, C5<X, Y, ?>>, L<Z, C5<X, Y, ?>>, M<Z, C5<X, Y, ?>> { }

    // Cons-ing types: (C4, (B4, (A4, Empty)))
    // Implementing I through L (4 interfaces)
    private static class A4<X> extends ConsStruct.Cons<X, ConsStruct.Empty> implements
            I<X, A4<?>>, J<X, A4<?>>, K<X, A4<?>>, L<X, A4<?>> { }
    private static class B4<X, Y> extends ConsStruct.Cons<X, A4<Y>> implements
            I<Y, B4<X, ?>>, J<Y, B4<X, ?>>, K<Y, B4<X, ?>>, L<Y, B4<X, ?>> { }
    private static class C4<X, Y, Z> extends ConsStruct.Cons<X, B4<Y, Z>> implements
            I<Z, C4<X, Y, ?>>, J<Z, C4<X, Y, ?>>, K<Z, C4<X, Y, ?>>, L<Z, C4<X, Y, ?>> { }

    // Cons-ing types: (C6, (B6, (A6, Empty)))
    // Implementing I through N (6 interfaces)
    private static class A6<X> extends ConsStruct.Cons<X, ConsStruct.Empty> implements
            I<X, A6<?>>, J<X, A6<?>>, K<X, A6<?>>, L<X, A6<?>>, M<X, A6<?>>, N<X, A6<?>> { }
    private static class B6<X, Y> extends ConsStruct.Cons<X, A6<Y>> implements
            I<Y, B6<X, ?>>, J<Y, B6<X, ?>>, K<Y, B6<X, ?>>, L<Y, B6<X, ?>>, M<Y, B6<X, ?>>, N<Y, B6<X, Y>> { }
    private static class C6<X, Y, Z> extends ConsStruct.Cons<X, B6<Y, Z>> implements
            I<Z, C6<X, Y, ?>>, J<Z, C6<X, Y, ?>>, K<Z, C6<X, Y, ?>>, L<Z, C6<X, Y, ?>>, M<Z, C6<X, Y, ?>>, N<Z, C6<X, Y, ?>> { }

    public static void main(String[] args) {
        A5<Boolean> foo1 = new A5<>();
        B5<Boolean, Integer> foo2 = new B5<>();
        C5<Boolean, Integer, String> foo3 = new C5<>();

        A4<Boolean> bar1 = new A4<>();
        B4<Boolean, Integer> bar2 = new B4<>();
        C4<Boolean, Integer, String> bar3 = new C4<>();

        A6<Boolean> baz1 = new A6<>();
        B6<Boolean, Integer> baz2 = new B6<>();
        C6<Boolean, Integer, String> baz3 = new C6<>();

        // Compiles - type hints
        java.util.List<ConsStruct.Cons<Boolean, ? extends ConsStruct>> asList5WithHints =
                Arrays.<ConsStruct.Cons<Boolean, ? extends ConsStruct>>asList(foo1, foo2, foo3);
        java.util.List<ConsStruct.Cons<Boolean, ? extends ConsStruct>> asList6WithHints =
                Arrays.<ConsStruct.Cons<Boolean, ? extends ConsStruct>>asList(baz1, baz2, baz3);

        // Compiles at 128m - only 4 interfaces
        java.util.List<ConsStruct.Cons<Boolean, ? extends ConsStruct>> asList4WithoutHints =
                Arrays.asList(bar1, bar2, bar3);

        // Runs out of memory at -Xmx2g, but not -Xmx3g
        java.util.List<ConsStruct.Cons<Boolean, ? extends ConsStruct>> asList5WithoutHints =
                Arrays.asList(foo1, foo2, foo3);

        // Runs out of memory at -Xmx3g and above
        java.util.List<ConsStruct.Cons<Boolean, ? extends ConsStruct>> asList6WithoutHints =
                Arrays.asList(baz1, baz2, baz3);
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Provide type arguments

FREQUENCY : always



Comments
still failing
08-08-2022

This issue is observed in all the versions, 8u112 - Fail 11.0.3 - Fail 12.0.1 - Fail 13 ea b22 - Fail
10-06-2019