test/compiler/jsr292/methodHandleExceptions/TestAMEnotNPE.java

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

mercurial