JDK-8029852 : Bad code generated (VerifyError) when lambda instantiates enclosing local class and has captured variables
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2013-12-10
  • Updated: 2014-07-29
  • Resolved: 2014-05-01
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.
JDK 8 JDK 9
8u20 b15Fixed 9Fixed
Related Reports
Blocks :  
Relates :  
Description
The compiler generates bad code that raises a verification error at class load time.

public class SingleLocalTest {
    interface F {void f();}
    
    static F f;

    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer();
        class Local1 {
            public Local1() {
                f = () -> new Local1();
                sb.append("1");
            }
        }
        new Local1();
        f.f();
        System.err.printf("Result: %s\n", sb);
    }
}

The above code currently crashes the compiler (JDK-8029725).  But if JDK-8029725 is fixed, then the code generated for the program above throws a VerifyError at run-time:

Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    SingleLocalTest$1Local1.lambda$new$0(Ljava/lang/StringBuffer;)V @5: getfield
  Reason:
    Type 'java/lang/StringBuffer' (current frame, stack[2]) is not assignable to 'SingleLocalTest$1Local1'
  Current Frame:
    bci: @5
    flags: { }
    locals: { 'java/lang/StringBuffer' }
    stack: { uninitialized 0, uninitialized 0, 'java/lang/StringBuffer' }
  Bytecode:
    0000000: bb00 0759 2ab4 0001 b700 0857 b1       

        at SingleLocalTest.main(SingleLocalTest.java:14)

This bad code will be generated in cases where a local variable is referenced within the local class.  In the generated code, we see that two different mechanisms of capturing the local variable (sb) are both at play and both incomplete:

  final java.lang.StringBuffer val$sb;

  private static void lambda$new$0(java.lang.StringBuffer);
         0: new           #7                  // class SingleLocalTest$1Local1
         3: dup           
         4: aload_0       
         5: getfield      #1                  // Field val$sb:Ljava/lang/StringBuffer;
         8: invokespecial #8                  // Method "<init>":(Ljava/lang/StringBuffer;)V
        11: pop           
        12: return        

-----

Fix should also address nested locals:

public class OuterLocalTest {
    interface F {void f();}
    
    static F f;

    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer();
        class Local1 {
            public Local1() {
                class Local2 {
                    public Local2() {
                        f = () -> new Local1();
                        sb.append("2");
                    }
                }
                sb.append("1");
                new Local2();
            }
        }
        new Local1();
        f.f();
        System.err.printf("Result: %s\n", sb);
    }
}


Comments
Still reproducible in 4/18 jdk9
20-04-2014

Release team: Approved for deferral.
12-12-2013

8-defer-request : The analysis that precedes the bad code generation and the code generation itself are both complex, and to address this problem would need to interact with other passes of the compiler which handle the capture of local variable into local classes. This bug cannot currently be encountered because instanciation of the containing local class from within a lambda causes the compiler to crash. While both would be important to fix, their combined complexity and fragility seems inappropriate for the small remaining time window.
10-12-2013