Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8336786

VerifyError with lambda capture and enclosing instance references

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P2 P2
    • 24
    • None
    • tools
    • None
    • b08
    • Verified

      === ./T.java
      public class T extends a.A {

        public static void main(String[] args) {
          new T().f(42);
        }

        public void f(int x) {
          Runnable r;
          r = () -> {
            System.err.println(x);
            new I();
          };
          // r = () -> new I();
        }
      }
      === ./a/A.java
      package a;

      public class A {
        public class I {}
      }
      ===

      ```
      $ javac -fullversion
      javac full version "24-ea+6-619"
      $ javac a/A.java T.java
      $ java T
      ...
      Caused by: java.lang.VerifyError: Bad local variable type
      Exception Details:
        Location:
          T.lambda$f$0(I)V @11: aload_0
        Reason:
          Type integer (current frame, locals[0]) is not assignable to reference type
        Current Frame:
          bci: @11
          flags: { }
          locals: { integer }
          stack: { uninitialized 7, uninitialized 7 }
        Bytecode:
          0000000: b200 121a b600 18bb 001d 592a b700 1f57
          0000010: b1
      ```

      If the line with `r = () -> new I();` is uncommented, javac crashes:

      ```
      javac a/A.java T.java
      ...
      java.lang.NullPointerException: Cannot read field "sym" because "this.lvar[0]" is null
              at jdk.compiler/com.sun.tools.javac.jvm.Code.emitop0(Code.java:572)
              at jdk.compiler/com.sun.tools.javac.jvm.Items$SelfItem.load(Items.java:369)
              at jdk.compiler/com.sun.tools.javac.jvm.Gen.genArgs(Gen.java:884)
              at jdk.compiler/com.sun.tools.javac.jvm.Gen.visitNewClass(Gen.java:2041)
              at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCNewClass.accept(JCTree.java:1912)
              at jdk.compiler/com.sun.tools.javac.jvm.Gen.genExpr(Gen.java:859)
              at jdk.compiler/com.sun.tools.javac.jvm.Gen.visitExec(Gen.java:1802)
              at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCExpressionStatement.accept(JCTree.java:1644)
              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:1133)
              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.genMethod(Gen.java:949)
              at jdk.compiler/com.sun.tools.javac.jvm.Gen.visitMethodDef(Gen.java:912)
              at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:957)
              at jdk.compiler/com.sun.tools.javac.jvm.Gen.genDef(Gen.java:588)
              at jdk.compiler/com.sun.tools.javac.jvm.Gen.genClass(Gen.java:2494)
              at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.genCode(JavaCompiler.java:770)
              at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.generate(JavaCompiler.java:1702)
              at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.generate(JavaCompiler.java:1670)
              at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:977)
              at jdk.compiler/com.sun.tools.javac.main.Main.compile(Main.java:319)
              at jdk.compiler/com.sun.tools.javac.main.Main.compile(Main.java:178)
              at jdk.compiler/com.sun.tools.javac.Main.compile(Main.java:66)
              at jdk.compiler/com.sun.tools.javac.Main.main(Main.java:52)
      ```

      The code for the lambda is change from

      ```
        private void lambda$f$0(int);
          Code:
             0: getstatic #18 // Field java/lang/System.err:Ljava/io/PrintStream;
             3: iload_1
             4: invokevirtual #24 // Method java/io/PrintStream.println:(I)V
             7: new #29 // class a/A$I
            10: dup
            11: aload_0
            12: invokespecial #31 // Method a/A$I."<init>":(La/A;)V
            15: pop
            16: return
      ```

      to

      ```
        private static void lambda$f$0(int);
          Code:
             0: getstatic #18 // Field java/lang/System.err:Ljava/io/PrintStream;
             3: iload_0
             4: invokevirtual #24 // Method java/io/PrintStream.println:(I)V
             7: new #29 // class a/A$I
            10: dup
            11: aload_0
            12: invokespecial #31 // Method a/A$I."<init>":(La/A;)V
            15: pop
            16: return
      ```

      Note that the lambda is become static and failing to implicitly capture the enclosing instance, and then it is trying to pass aload_0 to the inner class constructor, which is the captured int parameter.

            cushon Liam Miller-Cushon
            cushon Liam Miller-Cushon
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: