1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * $bug 8087223 27 * @summary Adding constantTag to keep method call consistent with it. 28 * @compile -XDignore.symbol.file BadMethodHandles.java 29 * @run main/othervm BadMethodHandles 30 */ 31 32 import jdk.internal.org.objectweb.asm.*; 33 import java.io.FileOutputStream; 34 import java.lang.reflect.InvocationTargetException; 35 import java.lang.invoke.MethodHandle; 36 import java.lang.invoke.MethodHandles; 37 import java.lang.invoke.MethodType; 38 import static jdk.internal.org.objectweb.asm.Opcodes.*; 39 40 public class BadMethodHandles { 41 42 static byte[] dumpBadInterfaceMethodref() { 43 ClassWriter cw = new ClassWriter(0); 44 cw.visit(52, ACC_PUBLIC | ACC_SUPER, "BadInterfaceMethodref", null, "java/lang/Object", null); 45 Handle handle1 = 46 new Handle(Opcodes.H_INVOKEINTERFACE, "BadInterfaceMethodref", "m", "()V"); 47 Handle handle2 = 48 new Handle(Opcodes.H_INVOKEINTERFACE, "BadInterfaceMethodref", "staticM", "()V"); 49 50 { 51 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 52 mv.visitCode(); 53 mv.visitVarInsn(ALOAD, 0); 54 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); 55 mv.visitInsn(RETURN); 56 mv.visitMaxs(1, 1); 57 mv.visitEnd(); 58 } 59 { 60 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "m", "()V", null, null); 61 mv.visitCode(); 62 mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 63 mv.visitLdcInsn("hello from m"); 64 mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/); 65 mv.visitInsn(RETURN); 66 mv.visitMaxs(3, 1); 67 mv.visitEnd(); 68 } 69 { 70 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "staticM", "()V", null, null); 71 mv.visitCode(); 72 mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 73 mv.visitLdcInsn("hello from staticM"); 74 mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/); 75 mv.visitInsn(RETURN); 76 mv.visitMaxs(3, 1); 77 mv.visitEnd(); 78 } 79 80 { 81 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runm", "()V", null, null); 82 mv.visitCode(); 83 // REF_invokeStatic 84 mv.visitLdcInsn(handle1); 85 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false); 86 mv.visitInsn(RETURN); 87 mv.visitMaxs(1, 1); 88 mv.visitEnd(); 89 } 90 91 { 92 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runStaticM", "()V", null, null); 93 mv.visitCode(); 94 // REF_invokeStatic 95 mv.visitLdcInsn(handle2); 96 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false); 97 mv.visitInsn(RETURN); 98 mv.visitMaxs(1, 1); 99 mv.visitEnd(); 100 } 101 102 cw.visitEnd(); 103 return cw.toByteArray(); 104 } 105 106 static byte[] dumpIBad() { 107 ClassWriter cw = new ClassWriter(0); 108 cw.visit(52, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "IBad", null, "java/lang/Object", null); 109 { 110 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "m", "()V", null, null); 111 mv.visitCode(); 112 mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 113 mv.visitLdcInsn("hello from m"); 114 mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/); 115 mv.visitInsn(RETURN); 116 mv.visitMaxs(3, 1); 117 mv.visitEnd(); 118 } 119 { 120 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "staticM", "()V", null, null); 121 mv.visitCode(); 122 mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 123 mv.visitLdcInsn("hello from staticM"); 124 mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/); 125 mv.visitInsn(RETURN); 126 mv.visitMaxs(3, 1); 127 mv.visitEnd(); 128 } 129 cw.visitEnd(); 130 return cw.toByteArray(); 131 } 132 133 static byte[] dumpBadMethodref() { 134 ClassWriter cw = new ClassWriter(0); 135 cw.visit(52, ACC_PUBLIC | ACC_SUPER, "BadMethodref", null, "java/lang/Object", new String[]{"IBad"}); 136 Handle handle1 = 137 new Handle(Opcodes.H_INVOKEINTERFACE, "BadMethodref", "m", "()V"); 138 Handle handle2 = 139 new Handle(Opcodes.H_INVOKEINTERFACE, "BadMethodref", "staticM", "()V"); 140 141 { 142 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 143 mv.visitCode(); 144 mv.visitVarInsn(ALOAD, 0); 145 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); 146 mv.visitInsn(RETURN); 147 mv.visitMaxs(1, 1); 148 mv.visitEnd(); 149 } 150 151 { 152 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runm", "()V", null, null); 153 mv.visitCode(); 154 // REF_invokeStatic 155 mv.visitLdcInsn(handle1); 156 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false); 157 mv.visitInsn(RETURN); 158 mv.visitMaxs(1, 1); 159 mv.visitEnd(); 160 } 161 162 { 163 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runStaticM", "()V", null, null); 164 mv.visitCode(); 165 // REF_invokeStatic 166 mv.visitLdcInsn(handle2); 167 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false); 168 mv.visitInsn(RETURN); 169 mv.visitMaxs(1, 1); 170 mv.visitEnd(); 171 } 172 173 cw.visitEnd(); 174 return cw.toByteArray(); 175 } 176 static class CL extends ClassLoader { 177 @Override 178 protected Class<?> findClass(String name) throws ClassNotFoundException { 179 byte[] classBytes = null; 180 switch (name) { 181 case "BadInterfaceMethodref": classBytes = dumpBadInterfaceMethodref(); break; 182 case "BadMethodref" : classBytes = dumpBadMethodref(); break; 183 case "IBad" : classBytes = dumpIBad(); break; 184 default : throw new ClassNotFoundException(name); 185 } 186 return defineClass(name, classBytes, 0, classBytes.length); 187 } 188 } 189 190 public static void main(String[] args) throws Throwable { 191 try (FileOutputStream fos = new FileOutputStream("BadInterfaceMethodref.class")) { 192 fos.write(dumpBadInterfaceMethodref()); 193 } 194 try (FileOutputStream fos = new FileOutputStream("IBad.class")) { 195 fos.write(dumpIBad()); 196 } 197 try (FileOutputStream fos = new FileOutputStream("BadMethodref.class")) { 198 fos.write(dumpBadMethodref()); 199 } 200 201 Class<?> cls = (new CL()).loadClass("BadInterfaceMethodref"); 202 String[] methods = {"runm", "runStaticM"}; 203 System.out.println("Test BadInterfaceMethodref:"); 204 int success = 0; 205 for (String name : methods) { 206 try { 207 System.out.printf("invoke %s: \n", name); 208 cls.getMethod(name).invoke(cls.newInstance()); 209 System.out.println("FAILED (no exception)"); // ICCE should be thrown 210 } catch (Throwable e) { 211 if (e instanceof InvocationTargetException && e.getCause() != null && 212 e.getCause() instanceof IncompatibleClassChangeError) { 213 System.out.println("PASSED"); 214 success++; 215 continue; 216 } else { 217 System.out.println("FAILED with exception"); 218 throw e; 219 } 220 } 221 } 222 if (success != methods.length) { 223 throw new Exception("BadInterfaceMethodRef Failed to catch IncompatibleClassChangeError"); 224 } 225 System.out.println("Test BadMethodref:"); 226 cls = (new CL()).loadClass("BadMethodref"); 227 success = 0; 228 for (String name : methods) { 229 try { 230 System.out.printf("invoke %s: \n", name); 231 cls.getMethod(name).invoke(cls.newInstance()); 232 System.out.println("FAILED (no exception)"); // ICCE should be thrown 233 } catch (Throwable e) { 234 if (e instanceof InvocationTargetException && e.getCause() != null && 235 e.getCause() instanceof IncompatibleClassChangeError) { 236 System.out.println("PASSED"); 237 success++; 238 continue; 239 } else { 240 System.out.println("FAILED with exception"); 241 throw e; 242 } 243 } 244 } 245 if (success != methods.length) { 246 throw new Exception("BadMethodRef Failed to catch IncompatibleClassChangeError"); 247 } 248 249 } 250 }