Hi, All

   Can I have a review for
   bug: https://bugs.openjdk.java.net/browse/JDK-8147755
   Webrev:  http://cr.openjdk.java.net/~minqi/8147755/webrev-01/

    Summary: When fix bug 8145148 to follow:

JVMS-5.4.3.3 Method Resolution:
" If C is an interface, method resolution throws an IncompatibleClassChangeError."
JVMS-5.4.3.4 Interface Method Resolution:
"If C is not an interface, interface method resolution throws an IncompatibleClassChangeError"

In defmeth(default method) tests, a MethodHandle pointing to interface static method will violate the spec. Since such a handle in asm will generate a tag of Methodref in constantpool for the call site, with the fix of 8145148, it requires a tag of InterfaceMethodref.

Fix by create a new constructor of Handle with extra boolean to indicate if the handle points to interface static method.

Tests: A test case and resulted constantpool data attached. The fix will not affect existing code. Also tested with fixed 8145148 and revised defmeth with the new version Handle and passed.

Thanks
Yumin


import jdk.internal.org.objectweb.asm.*;
import java.io.FileOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import static jdk.internal.org.objectweb.asm.Opcodes.*;

public class TestStaticInterfaceHandle {

    // interface I {
    //   static void m() {
    //     System.out.println("Hello from interface I, static m()!");
    //   }
    // }
    final static int version = 52;
    static byte[] dumpI() {
        ClassWriter cw = new ClassWriter(0);
        cw.visit(version, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "I", null, 
"java/lang/Object", null);
        {
            MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "m", 
"()V", null, null);
            mv.visitCode();
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", 
"Ljava/io/PrintStream;");
            mv.visitLdcInsn("Hello from interface I, m()!");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", 
"(Ljava/lang/String;)V", false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(3, 1);
            mv.visitEnd();
        }
        cw.visitEnd();
        return cw.toByteArray();
    }

    static byte[] dumpTestIm() {
        ClassWriter cw = new ClassWriter(0);
        cw.visit(version, ACC_PUBLIC | ACC_SUPER, "TestIm", null, 
"java/lang/Object", null);
        Handle handle =
            new Handle(Opcodes.H_INVOKESTATIC, "I", "m", "()V", true/* 
interface static version*/);

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

        {
            MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, 
"staticCallIm", "()V", null, null);
            mv.visitCode();
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", 
"Ljava/io/PrintStream;");
            mv.visitLdcInsn("Calling static I.m():");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", 
"(Ljava/lang/String;)V", false/*intf*/);
            mv.visitLdcInsn(handle);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", 
"invoke", "()V", false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(3, 1);
            mv.visitEnd();
        }

        cw.visitEnd();
        return cw.toByteArray();
    }

    static class CL extends ClassLoader {
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException 
{
            byte[] classBytes = null;
            switch (name) {
            case "TestIm"               : classBytes = dumpTestIm(); break;
            case "I"                    : classBytes = dumpI(); break;
            default                     : throw new 
ClassNotFoundException(name);
            }
            return defineClass(name, classBytes, 0, classBytes.length);
        }
    }


    public static void main(String[] args) throws Throwable {
        try (FileOutputStream fos = new FileOutputStream("I.class")) {
          fos.write(dumpI());
        }
        try (FileOutputStream fos = new FileOutputStream("TestIm.class")) {
          fos.write(dumpTestIm());
        }
        String cName = "TestIm";
        String mName = "staticCallIm";

        Class<?> cls = (new CL()).loadClass(cName);
        System.out.println("Test " + cName + "." + mName + ":");
        try {
            cls.getMethod(mName).invoke(cls.newInstance());
        } catch (Throwable e) {
            System.out.println("FAILED");
            throw e;
        }
    }
}


Classfile /scratch/yqi/ws/test/java/8147419/TestIm.class
  Last modified Jan 20, 2016; size 413 bytes
  MD5 checksum cafde171a1e44138b00e389d8bb944a1
public class TestIm
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Utf8               TestIm
   #2 = Class              #1             // TestIm
   #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               staticCallIm
  #10 = Utf8               java/lang/System
  #11 = Class              #10            // java/lang/System
  #12 = Utf8               out
  #13 = Utf8               Ljava/io/PrintStream;
  #14 = NameAndType        #12:#13        // out:Ljava/io/PrintStream;
  #15 = Fieldref           #11.#14        // 
java/lang/System.out:Ljava/io/PrintStream;
  #16 = Utf8               Calling static I.m():
  #17 = String             #16            // Calling static I.m():
  #18 = Utf8               java/io/PrintStream
  #19 = Class              #18            // java/io/PrintStream
  #20 = Utf8               println
  #21 = Utf8               (Ljava/lang/String;)V
  #22 = NameAndType        #20:#21        // println:(Ljava/lang/String;)V
  #23 = Methodref          #19.#22        // 
java/io/PrintStream.println:(Ljava/lang/String;)V
  #24 = Utf8               I
  #25 = Class              #24            // I
  #26 = Utf8               m
  #27 = NameAndType        #26:#6         // m:()V
  #28 = InterfaceMethodref #25.#27        // I.m:()V
  #29 = MethodHandle       #6:#28         // invokestatic I.m:()V
  #30 = Utf8               java/lang/invoke/MethodHandle
  #31 = Class              #30            // java/lang/invoke/MethodHandle
  #32 = Utf8               invoke
  #33 = NameAndType        #32:#6         // invoke:()V
  #34 = Methodref          #31.#33        // 
java/lang/invoke/MethodHandle.invoke:()V
  #35 = Utf8               Code
{
  public TestIm();
    descriptor: ()V
    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 static void staticCallIm();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=1, args_size=0
         0: getstatic     #15                 // Field 
java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #17                 // String Calling static I.m():
         5: invokevirtual #23                 // Method 
java/io/PrintStream.println:(Ljava/lang/String;)V
         8: ldc           #29                 // MethodHandle invokestatic 
I.m:()V
        10: invokevirtual #34                 // Method 
java/lang/invoke/MethodHandle.invoke:()V
        13: return
}

Reply via email to