1 /*
   2  * Copyright (c) 2013, 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 import java.lang.reflect.InvocationTargetException;
  26 import jdk.internal.org.objectweb.asm.ClassWriter;
  27 import jdk.internal.org.objectweb.asm.Handle;
  28 import jdk.internal.org.objectweb.asm.MethodVisitor;
  29 import jdk.internal.org.objectweb.asm.Opcodes;
  30 
  31 /**
  32  * @test
  33  * @bug 8025260
  34  * @summary Ensure that AbstractMethodError is thrown, not NullPointerException, through MethodHandles::jump_from_method_handle code path
  35  *
  36  * @compile -XDignore.symbol.file ByteClassLoader.java I.java C.java TestAMEnotNPE.java
  37  * @run main/othervm TestAMEnotNPE
  38  */
  39 
  40 public class TestAMEnotNPE implements Opcodes {
  41 
  42     /**
  43      * The bytes for D, a NOT abstract class extending abstract class C
  44      * without supplying an implementation for abstract method m.
  45      * There is a default method in the interface I, but it should lose to
  46      * the abstract class.
  47      *
  48      * @return
  49      * @throws Exception
  50      */
  51     public static byte[] bytesForD() throws Exception {
  52 
  53         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES| ClassWriter.COMPUTE_MAXS);
  54         MethodVisitor mv;
  55 
  56         cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "D", null, "C", null);
  57 
  58         {
  59             mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
  60             mv.visitCode();
  61             mv.visitVarInsn(ALOAD, 0);
  62             mv.visitMethodInsn(INVOKESPECIAL, "C", "<init>", "()V");
  63             mv.visitInsn(RETURN);
  64             mv.visitMaxs(0, 0);
  65             mv.visitEnd();
  66         }
  67         cw.visitEnd();
  68 
  69         return cw.toByteArray();
  70     }
  71 
  72 
  73     /**
  74      * The bytecodes for an invokeExact of a particular methodHandle, D.m viewed as I.m
  75      * @return
  76      * @throws Exception
  77      */
  78     public static byte[] bytesForT() throws Exception {
  79 
  80         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES| ClassWriter.COMPUTE_MAXS);
  81         MethodVisitor mv;
  82 
  83         cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "T", null, "java/lang/Object", null);
  84         {
  85             mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
  86             mv.visitCode();
  87             mv.visitVarInsn(ALOAD, 0);
  88             mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
  89             mv.visitInsn(RETURN);
  90             mv.visitMaxs(0,0);
  91             mv.visitEnd();
  92         }
  93         {
  94             mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "test", "()I", null, null);
  95             mv.visitCode();
  96             mv.visitLdcInsn(new Handle(Opcodes.H_INVOKEINTERFACE, "I", "m", "()I"));
  97             mv.visitTypeInsn(NEW, "D");
  98             mv.visitInsn(DUP);
  99             mv.visitMethodInsn(INVOKESPECIAL, "D", "<init>", "()V");
 100             mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invokeExact", "(LI;)I");
 101             mv.visitInsn(IRETURN);
 102             mv.visitMaxs(0,0);
 103             mv.visitEnd();
 104         }
 105         cw.visitEnd();
 106         return cw.toByteArray();
 107     }
 108 
 109     public static void main(String args[] ) throws Throwable {
 110         ByteClassLoader bcl = new ByteClassLoader();
 111         Class<?> d = bcl.loadBytes("D", bytesForD());
 112         Class<?> t = bcl.loadBytes("T", bytesForT());
 113         Object[] arg_for_args = new Object[0];
 114         try {
 115         Object result = t.getMethod("test").invoke(null, arg_for_args);
 116         } catch (InvocationTargetException e) {
 117             Throwable th = e.getCause();
 118             if (th instanceof AbstractMethodError) {
 119                 th.printStackTrace(System.out);
 120                 System.out.println("PASS, saw expected exception (AbstractMethodError).");
 121             } else {
 122                 System.out.println("Expected AbstractMethodError wrapped in InvocationTargetException, saw " + th);
 123                 throw th;
 124             }
 125         }
 126     }
 127 }