test/compiler/jsr292/methodHandleExceptions/TestAMEnotNPE.java

changeset 0
f90c822e73f8
child 6876
710a3c8b516e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/test/compiler/jsr292/methodHandleExceptions/TestAMEnotNPE.java	Wed Apr 27 01:25:04 2016 +0800
     1.3 @@ -0,0 +1,496 @@
     1.4 +/*
     1.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.
    1.11 + *
    1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.15 + * version 2 for more details (a copy is included in the LICENSE file that
    1.16 + * accompanied this code).
    1.17 + *
    1.18 + * You should have received a copy of the GNU General Public License version
    1.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.21 + *
    1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.23 + * or visit www.oracle.com if you need additional information or have any
    1.24 + * questions.
    1.25 + *
    1.26 + */
    1.27 +import java.lang.reflect.InvocationTargetException;
    1.28 +import java.lang.reflect.Method;
    1.29 +import java.util.ArrayList;
    1.30 +import java.util.List;
    1.31 +import jdk.internal.org.objectweb.asm.ClassWriter;
    1.32 +import jdk.internal.org.objectweb.asm.Handle;
    1.33 +import jdk.internal.org.objectweb.asm.MethodVisitor;
    1.34 +import jdk.internal.org.objectweb.asm.Opcodes;
    1.35 +import p.Dok;
    1.36 +
    1.37 +/**
    1.38 + * @test @bug 8025260 8016839
    1.39 + * @summary Ensure that AbstractMethodError and IllegalAccessError are thrown appropriately, not NullPointerException
    1.40 + *
    1.41 + * @compile -XDignore.symbol.file TestAMEnotNPE.java ByteClassLoader.java p/C.java p/Dok.java p/E.java p/F.java p/I.java p/Tdirect.java p/Treflect.java
    1.42 + *
    1.43 + * @run main/othervm TestAMEnotNPE
    1.44 + * @run main/othervm -Xint TestAMEnotNPE
    1.45 + * @run main/othervm -Xcomp TestAMEnotNPE
    1.46 + */
    1.47 +public class TestAMEnotNPE implements Opcodes {
    1.48 +
    1.49 +    static boolean writeJarFiles = false;
    1.50 +    static boolean readJarFiles = false;
    1.51 +
    1.52 +    /**
    1.53 +     * Optional command line parameter (any case-insensitive prefix of)
    1.54 +     * "writejarfiles" or "readjarfiles".
    1.55 +     *
    1.56 +     * "Writejarfiles" creates a jar file for each different set of tested classes.
    1.57 +     * "Readjarfiles" causes the classloader to use the copies of the classes
    1.58 +     * found in the corresponding jar files.
    1.59 +     *
    1.60 +     * Jarfilenames look something like pD_ext_pF (p.D extends p.F)
    1.61 +     * and qD_m_pp_imp_pI (q.D with package-private m implements p.I)
    1.62 +     *
    1.63 +     */
    1.64 +    public static void main(String args[]) throws Throwable {
    1.65 +        ArrayList<Throwable> lt = new ArrayList<Throwable>();
    1.66 +
    1.67 +        if (args.length > 0) {
    1.68 +            String a0 = args[0].toLowerCase();
    1.69 +            if (a0.length() > 0) {
    1.70 +                writeJarFiles = ("writejarfiles").startsWith(a0);
    1.71 +                readJarFiles = ("readjarfiles").startsWith(a0);
    1.72 +            }
    1.73 +            if (!(writeJarFiles || readJarFiles)) {
    1.74 +                throw new Error("Command line parameter (if any) should be prefix of writeJarFiles or readJarFiles");
    1.75 +            }
    1.76 +        }
    1.77 +
    1.78 +        try {
    1.79 +            System.out.println("TRYING p.D.m PRIVATE interface-invoked as p.I.m, p.D extends p.F, p.F.m FINAL");
    1.80 +            tryAndCheckThrown(lt, bytesForDprivateSubWhat("p/F"),
    1.81 +                    "p.D extends p.F (p.F implements p.I, FINAL public m), private m",
    1.82 +                    IllegalAccessError.class, "pD_ext_pF");
    1.83 +            // We'll take either a VerifyError (pre 2013-11-30)
    1.84 +            // or an IllegalAccessError (post 2013-11-22)
    1.85 +        } catch (VerifyError ve) {
    1.86 +            System.out.println("Saw expected VerifyError " + ve);
    1.87 +        }
    1.88 +        System.out.println();
    1.89 +
    1.90 +        System.out.println("TRYING p.D.m PRIVATE interface-invoked as p.I.m, p.D extends p.E");
    1.91 +        tryAndCheckThrown(lt, bytesForDprivateSubWhat("p/E"),
    1.92 +                "p.D extends p.E (p.E implements p.I, public m), private m",
    1.93 +                IllegalAccessError.class, "pD_ext_pE");
    1.94 +
    1.95 +        System.out.println("TRYING p.D.m ABSTRACT interface-invoked as p.I.m");
    1.96 +        tryAndCheckThrown(lt, bytesForD(),
    1.97 +                "D extends abstract C, no m",
    1.98 +                AbstractMethodError.class, "pD_ext_pC");
    1.99 +
   1.100 +        System.out.println("TRYING q.D.m PACKAGE interface-invoked as p.I.m");
   1.101 +        tryAndCheckThrown(lt, "q.D", bytesForDsomeAccess("q/D", 0),
   1.102 +                "q.D implements p.I, protected m", IllegalAccessError.class,
   1.103 +                "qD_m_pp_imp_pI");
   1.104 +
   1.105 +        // Note jar file name is used in the plural-arg case.
   1.106 +        System.out.println("TRYING p.D.m PRIVATE interface-invoked as p.I.m");
   1.107 +        tryAndCheckThrown(lt, bytesForDsomeAccess("p/D", ACC_PRIVATE),
   1.108 +                "p.D implements p.I, private m",
   1.109 +                IllegalAccessError.class, "pD_m_pri_imp_pI");
   1.110 +
   1.111 +        // Plural-arg test.
   1.112 +        System.out.println("TRYING p.D.m PRIVATE MANY ARG interface-invoked as p.I.m");
   1.113 +        tryAndCheckThrownMany(lt, bytesForDsomeAccess("p/D", ACC_PRIVATE),
   1.114 +                "p.D implements p.I, private m", IllegalAccessError.class);
   1.115 +
   1.116 +        if (lt.size() > 0) {
   1.117 +            System.out.flush();
   1.118 +            Thread.sleep(250); // This de-interleaves output and error in Netbeans, sigh.
   1.119 +            for (Throwable th : lt)
   1.120 +              System.err.println(th);
   1.121 +            throw new Error("Test failed, there were " + lt.size() + " failures listed above");
   1.122 +        } else {
   1.123 +            System.out.println("ALL PASS, HOORAY!");
   1.124 +        }
   1.125 +    }
   1.126 +
   1.127 +    /**
   1.128 +     * The bytes for D, a NOT abstract class extending abstract class C without
   1.129 +     * supplying an implementation for abstract method m. There is a default
   1.130 +     * method in the interface I, but it should lose to the abstract class.
   1.131 +     *
   1.132 +     * @return
   1.133 +     * @throws Exception
   1.134 +     */
   1.135 +    public static byte[] bytesForD() throws Exception {
   1.136 +
   1.137 +        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES
   1.138 +                | ClassWriter.COMPUTE_MAXS);
   1.139 +        MethodVisitor mv;
   1.140 +
   1.141 +        cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "p/D", null, "p/C", null);
   1.142 +
   1.143 +        {
   1.144 +            mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
   1.145 +            mv.visitCode();
   1.146 +            mv.visitVarInsn(ALOAD, 0);
   1.147 +            mv.visitMethodInsn(INVOKESPECIAL, "p/C", "<init>", "()V");
   1.148 +            mv.visitInsn(RETURN);
   1.149 +            mv.visitMaxs(0, 0);
   1.150 +            mv.visitEnd();
   1.151 +        }
   1.152 +        cw.visitEnd();
   1.153 +
   1.154 +        return cw.toByteArray();
   1.155 +    }
   1.156 +
   1.157 +    /**
   1.158 +     * The bytes for D, implements I, does not extend C, declares m()I with
   1.159 +     * access method_acc.
   1.160 +     *
   1.161 +     * @param d_name Name of class defined
   1.162 +     * @param method_acc Accessibility of that class's method m.
   1.163 +     * @return
   1.164 +     * @throws Exception
   1.165 +     */
   1.166 +    public static byte[] bytesForDsomeAccess(String d_name, int method_acc) throws Exception {
   1.167 +        return bytesForSomeDsubSomethingSomeAccess(d_name, "java/lang/Object", method_acc);
   1.168 +    }
   1.169 +
   1.170 +    /**
   1.171 +     * The bytes for D implements I, extends some class, declares m()I as
   1.172 +     * private.
   1.173 +     *
   1.174 +     * Invokeinterface of I.m applied to this D should throw IllegalAccessError
   1.175 +     *
   1.176 +     * @param sub_what The name of the class that D will extend.
   1.177 +     * @return
   1.178 +     * @throws Exception
   1.179 +     */
   1.180 +    public static byte[] bytesForDprivateSubWhat(String sub_what) throws Exception {
   1.181 +        return bytesForSomeDsubSomethingSomeAccess("p/D", sub_what, ACC_PRIVATE);
   1.182 +    }
   1.183 +
   1.184 +    /**
   1.185 +     * Returns the bytes for a class with name d_name (presumably "D" in some
   1.186 +     * package), extending some class with name sub_what, implementing p.I,
   1.187 +     * and defining two methods m() and m(11args) with access method_acc.
   1.188 +     *
   1.189 +     * @param d_name      Name of class that is defined
   1.190 +     * @param sub_what    Name of class that it extends
   1.191 +     * @param method_acc  Accessibility of method(s) m in defined class.
   1.192 +     * @return
   1.193 +     * @throws Exception
   1.194 +     */
   1.195 +    public static byte[] bytesForSomeDsubSomethingSomeAccess
   1.196 +            (String d_name, String sub_what, int method_acc)
   1.197 +            throws Exception {
   1.198 +
   1.199 +        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES
   1.200 +                | ClassWriter.COMPUTE_MAXS);
   1.201 +        MethodVisitor mv;
   1.202 +        String[] interfaces = {"p/I"};
   1.203 +
   1.204 +        cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, d_name, null, sub_what, interfaces);
   1.205 +        {
   1.206 +            mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
   1.207 +            mv.visitCode();
   1.208 +            mv.visitVarInsn(ALOAD, 0);
   1.209 +            mv.visitMethodInsn(INVOKESPECIAL, sub_what, "<init>", "()V");
   1.210 +            mv.visitInsn(RETURN);
   1.211 +            mv.visitMaxs(0, 0);
   1.212 +            mv.visitEnd();
   1.213 +        }
   1.214 +        // int m() {return 3;}
   1.215 +        {
   1.216 +            mv = cw.visitMethod(method_acc, "m", "()I", null, null);
   1.217 +            mv.visitCode();
   1.218 +            mv.visitLdcInsn(new Integer(3));
   1.219 +            mv.visitInsn(IRETURN);
   1.220 +            mv.visitMaxs(0, 0);
   1.221 +            mv.visitEnd();
   1.222 +        }
   1.223 +        // int m(11args) {return 3;}
   1.224 +        {
   1.225 +            mv = cw.visitMethod(method_acc, "m", "(BCSIJ"
   1.226 +                    + "Ljava/lang/Object;"
   1.227 +                    + "Ljava/lang/Object;"
   1.228 +                    + "Ljava/lang/Object;"
   1.229 +                    + "Ljava/lang/Object;"
   1.230 +                    + "Ljava/lang/Object;"
   1.231 +                    + "Ljava/lang/Object;"
   1.232 +                    + ")I", null, null);
   1.233 +            mv.visitCode();
   1.234 +            mv.visitLdcInsn(new Integer(3));
   1.235 +            mv.visitInsn(IRETURN);
   1.236 +            mv.visitMaxs(0, 0);
   1.237 +            mv.visitEnd();
   1.238 +        }
   1.239 +        cw.visitEnd();
   1.240 +        return cw.toByteArray();
   1.241 +    }
   1.242 +
   1.243 +    /**
   1.244 +     * The bytecodes for a class p/T defining a methods test() and test(11args)
   1.245 +     * that contain an invokeExact of a particular methodHandle, I.m.
   1.246 +     *
   1.247 +     * Test will be passed values that may imperfectly implement I,
   1.248 +     * and thus may in turn throw exceptions.
   1.249 +     *
   1.250 +     * @return
   1.251 +     * @throws Exception
   1.252 +     */
   1.253 +    public static byte[] bytesForT() throws Exception {
   1.254 +
   1.255 +        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES
   1.256 +                | ClassWriter.COMPUTE_MAXS);
   1.257 +        MethodVisitor mv;
   1.258 +
   1.259 +        cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "p/T", null, "java/lang/Object", null);
   1.260 +        {
   1.261 +            mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
   1.262 +            mv.visitCode();
   1.263 +            mv.visitVarInsn(ALOAD, 0);
   1.264 +            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
   1.265 +            mv.visitInsn(RETURN);
   1.266 +            mv.visitMaxs(0, 0);
   1.267 +            mv.visitEnd();
   1.268 +        }
   1.269 +        // static int test(I)
   1.270 +        {
   1.271 +            mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "test", "(Lp/I;)I", null, null);
   1.272 +            mv.visitCode();
   1.273 +            mv.visitLdcInsn(new Handle(Opcodes.H_INVOKEINTERFACE, "p/I", "m", "()I"));
   1.274 +            mv.visitVarInsn(ALOAD, 0);
   1.275 +            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle",
   1.276 +                    "invokeExact", "(Lp/I;)I");
   1.277 +            mv.visitInsn(IRETURN);
   1.278 +            mv.visitMaxs(0, 0);
   1.279 +            mv.visitEnd();
   1.280 +        }
   1.281 +        // static int test(I,11args)
   1.282 +        {
   1.283 +            mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "test", "(Lp/I;BCSIJLjava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)I", null, null);
   1.284 +            mv.visitCode();
   1.285 +            mv.visitLdcInsn(new Handle(Opcodes.H_INVOKEINTERFACE, "p/I", "m", "(BCSIJLjava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)I"));
   1.286 +            mv.visitVarInsn(ALOAD, 0);
   1.287 +            mv.visitVarInsn(ILOAD, 1);
   1.288 +            mv.visitVarInsn(ILOAD, 2);
   1.289 +            mv.visitVarInsn(ILOAD, 3);
   1.290 +            mv.visitVarInsn(ILOAD, 4);
   1.291 +            mv.visitVarInsn(LLOAD, 5);
   1.292 +            mv.visitVarInsn(ALOAD, 7);
   1.293 +            mv.visitVarInsn(ALOAD, 8);
   1.294 +            mv.visitVarInsn(ALOAD, 9);
   1.295 +            mv.visitVarInsn(ALOAD, 10);
   1.296 +            mv.visitVarInsn(ALOAD, 11);
   1.297 +            mv.visitVarInsn(ALOAD, 12);
   1.298 +            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle",
   1.299 +                    "invokeExact", "(Lp/I;BCSIJLjava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)I");
   1.300 +            mv.visitInsn(IRETURN);
   1.301 +            mv.visitMaxs(0, 0);
   1.302 +            mv.visitEnd();
   1.303 +        }
   1.304 +        cw.visitEnd();
   1.305 +        return cw.toByteArray();
   1.306 +    }
   1.307 +
   1.308 +    private static void tryAndCheckThrown(
   1.309 +            List<Throwable> lt, byte[] dBytes, String what, Class<?> expected, String jar_name)
   1.310 +            throws Throwable {
   1.311 +        tryAndCheckThrown(lt, "p.D", dBytes, what, expected, jar_name);
   1.312 +    }
   1.313 +
   1.314 +    private static void tryAndCheckThrown(List<Throwable> lt, String d_name, byte[] dBytes, String what, Class<?> expected, String jar_name)
   1.315 +            throws Throwable {
   1.316 +
   1.317 +        System.out.println("Methodhandle invokeExact I.m() for instance of " + what);
   1.318 +        ByteClassLoader bcl1 = new ByteClassLoader(jar_name, readJarFiles, writeJarFiles);
   1.319 +        try {
   1.320 +            Class<?> d1 = bcl1.loadBytes(d_name, dBytes);
   1.321 +            Class<?> t1 = bcl1.loadBytes("p.T", bytesForT());
   1.322 +            invokeTest(t1, d1, expected, lt);
   1.323 +        } finally {
   1.324 +            // Not necessary for others -- all class files are written in this call.
   1.325 +            // (unless the VM crashes first).
   1.326 +            bcl1.close();
   1.327 +        }
   1.328 +
   1.329 +        System.out.println("Reflection invoke I.m() for instance of " + what);
   1.330 +        ByteClassLoader bcl3 = new ByteClassLoader(jar_name, readJarFiles, false);
   1.331 +        Class<?> d3 = bcl3.loadBytes(d_name, dBytes);
   1.332 +        Class<?> t3 = bcl3.loadClass("p.Treflect");
   1.333 +        invokeTest(t3, d3, expected, lt);
   1.334 +
   1.335 +        System.out.println("Bytecode invokeInterface I.m() for instance of " + what);
   1.336 +        ByteClassLoader bcl2 = new ByteClassLoader(jar_name, readJarFiles, false);
   1.337 +        Class<?> d2 = bcl2.loadBytes(d_name, dBytes);
   1.338 +        Class<?> t2 = bcl2.loadClass("p.Tdirect");
   1.339 +        badGoodBadGood(t2, d2, expected, lt);
   1.340 +    }
   1.341 +
   1.342 +    private static void invokeTest(Class<?> t, Class<?> d, Class<?> expected, List<Throwable> lt)
   1.343 +            throws Throwable {
   1.344 +        try {
   1.345 +            Method m = t.getMethod("test", p.I.class);
   1.346 +            Object o = d.newInstance();
   1.347 +            Object result = m.invoke(null, o);
   1.348 +            if (expected != null) {
   1.349 +                System.out.println("FAIL, Expected " + expected.getName()
   1.350 +                        + " wrapped in InvocationTargetException, but nothing was thrown");
   1.351 +                lt.add(new Error("Exception " + expected.getName() + " was not thrown"));
   1.352 +            } else {
   1.353 +                System.out.println("PASS, saw expected return.");
   1.354 +            }
   1.355 +        } catch (InvocationTargetException e) {
   1.356 +            Throwable th = e.getCause();
   1.357 +            th.printStackTrace(System.out);
   1.358 +            if (expected != null) {
   1.359 +                if (expected.isInstance(th)) {
   1.360 +                    System.out.println("PASS, saw expected exception (" + expected.getName() + ").");
   1.361 +                } else {
   1.362 +                    System.out.println("FAIL, Expected " + expected.getName()
   1.363 +                            + " wrapped in InvocationTargetException, saw " + th);
   1.364 +                    lt.add(th);
   1.365 +                }
   1.366 +            } else {
   1.367 +                System.out.println("FAIL, expected no exception, saw " + th);
   1.368 +                lt.add(th);
   1.369 +            }
   1.370 +        }
   1.371 +        System.out.println();
   1.372 +    }
   1.373 +
   1.374 +    /* Many-arg versions of above */
   1.375 +    private static void tryAndCheckThrownMany(List<Throwable> lt, byte[] dBytes, String what, Class<?> expected)
   1.376 +            throws Throwable {
   1.377 +
   1.378 +        System.out.println("Methodhandle invokeExact I.m(11params) for instance of " + what);
   1.379 +        ByteClassLoader bcl1 = new ByteClassLoader("p.D", readJarFiles, false);
   1.380 +        try {
   1.381 +            Class<?> d1 = bcl1.loadBytes("p.D", dBytes);
   1.382 +            Class<?> t1 = bcl1.loadBytes("p.T", bytesForT());
   1.383 +            invokeTestMany(t1, d1, expected, lt);
   1.384 +        } finally {
   1.385 +            bcl1.close(); // Not necessary for others -- all class files are written in this call.
   1.386 +        }
   1.387 +
   1.388 +        {
   1.389 +            System.out.println("Bytecode invokeInterface I.m(11params) for instance of " + what);
   1.390 +            ByteClassLoader bcl2 = new ByteClassLoader("pD_m_pri_imp_pI", readJarFiles, false);
   1.391 +            Class<?> d2 = bcl2.loadBytes("p.D", dBytes);
   1.392 +            Class<?> t2 = bcl2.loadClass("p.Tdirect");
   1.393 +            badGoodBadGoodMany(t2, d2, expected, lt);
   1.394 +
   1.395 +        }
   1.396 +        {
   1.397 +            System.out.println("Reflection invokeInterface I.m(11params) for instance of " + what);
   1.398 +            ByteClassLoader bcl2 = new ByteClassLoader("pD_m_pri_imp_pI", readJarFiles, false);
   1.399 +            Class<?> d2 = bcl2.loadBytes("p.D", dBytes);
   1.400 +            Class<?> t2 = bcl2.loadClass("p.Treflect");
   1.401 +            invokeTestMany(t2, d2, expected, lt);
   1.402 +        }
   1.403 +    }
   1.404 +
   1.405 +    private static void invokeTestMany(Class<?> t, Class<?> d, Class<?> expected, List<Throwable> lt)
   1.406 +            throws Throwable {
   1.407 +        try {
   1.408 +            Method m = t.getMethod("test", p.I.class,
   1.409 +                    Byte.TYPE, Character.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE,
   1.410 +                    Object.class, Object.class, Object.class,
   1.411 +                    Object.class, Object.class, Object.class);
   1.412 +            Object o = d.newInstance();
   1.413 +            Byte b = 1;
   1.414 +            Character c = 2;
   1.415 +            Short s = 3;
   1.416 +            Integer i = 4;
   1.417 +            Long j = 5L;
   1.418 +            Object o1 = b;
   1.419 +            Object o2 = c;
   1.420 +            Object o3 = s;
   1.421 +            Object o4 = i;
   1.422 +            Object o5 = j;
   1.423 +            Object o6 = "6";
   1.424 +
   1.425 +            Object result = m.invoke(null, o, b, c, s, i, j,
   1.426 +                    o1, o2, o3, o4, o5, o6);
   1.427 +            if (expected != null) {
   1.428 +                System.out.println("FAIL, Expected " + expected.getName()
   1.429 +                        + " wrapped in InvocationTargetException, but nothing was thrown");
   1.430 +                lt.add(new Error("Exception " + expected.getName()
   1.431 +                        + " was not thrown"));
   1.432 +            } else {
   1.433 +                System.out.println("PASS, saw expected return.");
   1.434 +            }
   1.435 +        } catch (InvocationTargetException e) {
   1.436 +            Throwable th = e.getCause();
   1.437 +            th.printStackTrace(System.out);
   1.438 +            if (expected != null) {
   1.439 +                if (expected.isInstance(th)) {
   1.440 +                    System.out.println("PASS, saw expected exception ("
   1.441 +                            + expected.getName() + ").");
   1.442 +                } else {
   1.443 +                    System.out.println("FAIL, Expected " + expected.getName()
   1.444 +                            + " wrapped in InvocationTargetException, saw " + th);
   1.445 +                    lt.add(th);
   1.446 +                }
   1.447 +            } else {
   1.448 +                System.out.println("FAIL, expected no exception, saw " + th);
   1.449 +                lt.add(th);
   1.450 +            }
   1.451 +        }
   1.452 +        System.out.println();
   1.453 +    }
   1.454 +
   1.455 +    /**
   1.456 +     * This tests a peculiar idiom for tickling the bug on older VMs that lack
   1.457 +     * methodhandles.  The bug (if not fixed) acts in the following way:
   1.458 +     *
   1.459 +     *  When a broken receiver is passed to the first execution of an invokeinterface
   1.460 +     * bytecode, the illegal access is detected before the effects of resolution are
   1.461 +     * cached for later use, and so repeated calls with a broken receiver will always
   1.462 +     * throw the correct error.
   1.463 +     *
   1.464 +     * If, however, a good receiver is passed to the invokeinterface, the effects of
   1.465 +     * resolution will be successfully cached.  A subsequent execution with a broken
   1.466 +     * receiver will reuse the cached information, skip the detailed resolution work,
   1.467 +     * and instead encounter a null pointer.  By convention, that is the encoding for a
   1.468 +     * missing abstract method, and an AbstractMethodError is thrown -- not the expected
   1.469 +     * IllegalAccessError.
   1.470 +     *
   1.471 +     * @param t2 Test invocation class
   1.472 +     * @param d2 Test receiver class
   1.473 +     * @param expected expected exception type
   1.474 +     * @param lt list of unexpected throwables seen
   1.475 +     */
   1.476 +    private static void badGoodBadGood(Class<?> t2, Class<?> d2, Class<?> expected, List<Throwable> lt)
   1.477 +            throws Throwable {
   1.478 +        System.out.println("  Error input 1st time");
   1.479 +        invokeTest(t2, d2, expected, lt);
   1.480 +        System.out.println("  Good input (instance of Dok)");
   1.481 +        invokeTest(t2, Dok.class, null, lt);
   1.482 +        System.out.println("  Error input 2nd time");
   1.483 +        invokeTest(t2, d2, expected, lt);
   1.484 +        System.out.println("  Good input (instance of Dok)");
   1.485 +        invokeTest(t2, Dok.class, null, lt);
   1.486 +    }
   1.487 +
   1.488 +    private static void badGoodBadGoodMany(Class<?> t2, Class<?> d2, Class<?> expected, List<Throwable> lt)
   1.489 +            throws Throwable {
   1.490 +        System.out.println("  Error input 1st time");
   1.491 +        invokeTestMany(t2, d2, expected, lt);
   1.492 +        System.out.println("  Good input (instance of Dok)");
   1.493 +        invokeTestMany(t2, Dok.class, null, lt);
   1.494 +        System.out.println("  Error input 2nd time");
   1.495 +        invokeTestMany(t2, d2, expected, lt);
   1.496 +        System.out.println("  Good input (instance of Dok)");
   1.497 +        invokeTestMany(t2, Dok.class, null, lt);
   1.498 +    }
   1.499 +}

mercurial