RFR: 8147755: ASM should create correct constant tag for invokestatic on handle point to interface static method
Yumin Qi
yumin.qi at oracle.com
Fri Jan 22 20:22:06 UTC 2016
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
-------------- next part --------------
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
}
More information about the core-libs-dev
mailing list