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 }