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

MethodHandleInfo reports refKind as invokespecial instead of invokevirtual for some method handles

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P2 P2
    • 8
    • None
    • core-libs
    • OpenJDK build of jdk8/tl repository.

      For some virtual method handles, MethodHandleInfo reports their reference kind incorrectly. The following program (runnable TestNG test case) produces a classfile which does an LDC on "invokevirtual String.toUpperCase", but it is reported as being an invokespecial MH instead.

      @Test
      public class GenBadMHTest {
          public void testMHForStringToUpper() throws IOException, ReflectiveOperationException {
              ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
              cw.visit(51, ACC_SUPER + ACC_PUBLIC, "Foo", null, "java/lang/Object", new String[0]);

              // Constructor
              MethodVisitor ctor = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
              ctor.visitCode();
              ctor.visitVarInsn(ALOAD, 0);
              ctor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
              ctor.visitInsn(RETURN);
              ctor.visitMaxs(-1, -1);
              ctor.visitEnd();

              MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "foo", "()Ljava/lang/Object;", null, null);
              mv.visitLdcInsn(new Handle(Opcodes.H_INVOKEVIRTUAL, "java/lang/String", "toUpperCase", "()Ljava/lang/String;"));
              mv.visitInsn(ARETURN);
              mv.visitMaxs(-1, -1);
              mv.visitEnd();

              cw.visitEnd();

              byte[] bytes = cw.toByteArray();
              File f = new File("Foo.class");
              try (FileOutputStream fos = new FileOutputStream(f)) {
                  fos.write(bytes);
              }

              List<URL> list = new ArrayList<>();
              System.out.println(f.getCanonicalFile().getParent());
              list.add(new URL("file:" + f.getCanonicalFile().getParent().toString().replace("\\", "/") + "/"));
              Class clazz = Class.forName("Foo", true, new URLClassLoader(list.toArray(new URL[list.size()])));
              Method m = clazz.getMethod("foo");
              MethodHandle mh = (MethodHandle) m.invoke(clazz.newInstance());
              MethodHandleInfo mhi = new MethodHandleInfo(mh);
              assertTrue(mhi.getReferenceKind() == MethodHandleInfo.REF_invokeVirtual);
          }
      }


      Javap listing of generated class:

      brian:test-ng$ javap -c -v Foo
      Classfile /home/brian/work/lambda/lambda/jdk/test-ng/Foo.class
        Last modified Dec 17, 2012; size 249 bytes
        MD5 checksum bec790a14e97276bf262412294213fea
      public class Foo
        minor version: 0
        major version: 51
        flags: ACC_PUBLIC, ACC_SUPER
      Constant pool:
         #1 = Utf8 Foo
         #2 = Class #1 // Foo
         #3 = Utf8 java/lang/Object
         #4 = Class #3 // java/lang/Object
         #5 = Utf8 <init>
         #6 = Utf8 ()V
         #7 = NameAndType #5:#6 // "<init>":()V
         #8 = Methodref #4.#7 // java/lang/Object."<init>":()V
         #9 = Utf8 foo
        #10 = Utf8 ()Ljava/lang/Object;
        #11 = Utf8 java/lang/String
        #12 = Class #11 // java/lang/String
        #13 = Utf8 toUpperCase
        #14 = Utf8 ()Ljava/lang/String;
        #15 = NameAndType #13:#14 // toUpperCase:()Ljava/lang/String;
        #16 = Methodref #12.#15 // java/lang/String.toUpperCase:()Ljava/lang/String;
        #17 = MethodHandle #5:#16 // invokevirtual java/lang/String.toUpperCase:()Ljava/lang/String;
        #18 = Utf8 Code
      {
        public Foo();
          flags: ACC_PUBLIC
          Code:
            stack=1, locals=1, args_size=1
               0: aload_0
               1: invokespecial #8 // Method java/lang/Object."<init>":()V
               4: return

        public java.lang.Object foo();
          flags: ACC_PUBLIC
          Code:
            stack=1, locals=1, args_size=1
               0: ldc #17 // MethodHandle invokevirtual java/lang/String.toUpperCase:()Ljava/lang/String;
               2: areturn
      }


            bharadwaj Bharadwaj Yadavalli (Inactive)
            briangoetz Brian Goetz
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: