drchase@5800: /* drchase@5800: * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. drchase@5800: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. drchase@5800: * drchase@5800: * This code is free software; you can redistribute it and/or modify it drchase@5800: * under the terms of the GNU General Public License version 2 only, as drchase@5800: * published by the Free Software Foundation. drchase@5800: * drchase@5800: * This code is distributed in the hope that it will be useful, but WITHOUT drchase@5800: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or drchase@5800: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License drchase@5800: * version 2 for more details (a copy is included in the LICENSE file that drchase@5800: * accompanied this code). drchase@5800: * drchase@5800: * You should have received a copy of the GNU General Public License version drchase@5800: * 2 along with this work; if not, write to the Free Software Foundation, drchase@5800: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. drchase@5800: * drchase@5800: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA drchase@5800: * or visit www.oracle.com if you need additional information or have any drchase@5800: * questions. drchase@5800: * drchase@5800: */ drchase@5800: import java.lang.reflect.InvocationTargetException; drchase@6134: import java.lang.reflect.Method; drchase@6134: import java.util.ArrayList; drchase@6134: import java.util.List; drchase@5800: import jdk.internal.org.objectweb.asm.ClassWriter; drchase@5800: import jdk.internal.org.objectweb.asm.Handle; drchase@5800: import jdk.internal.org.objectweb.asm.MethodVisitor; drchase@5800: import jdk.internal.org.objectweb.asm.Opcodes; drchase@6134: import p.Dok; drchase@5800: drchase@5800: /** drchase@6134: * @test @bug 8025260 8016839 drchase@6134: * @summary Ensure that AbstractMethodError and IllegalAccessError are thrown appropriately, not NullPointerException drchase@5800: * drchase@6134: * @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 drchase@6134: * drchase@5800: * @run main/othervm TestAMEnotNPE drchase@6134: * @run main/othervm -Xint TestAMEnotNPE drchase@6134: * @run main/othervm -Xcomp TestAMEnotNPE drchase@5800: */ drchase@5800: public class TestAMEnotNPE implements Opcodes { drchase@5800: drchase@6134: static boolean writeJarFiles = false; drchase@6134: static boolean readJarFiles = false; drchase@6134: drchase@5800: /** drchase@6134: * Optional command line parameter (any case-insensitive prefix of) drchase@6134: * "writejarfiles" or "readjarfiles". drchase@6134: * drchase@6134: * "Writejarfiles" creates a jar file for each different set of tested classes. drchase@6134: * "Readjarfiles" causes the classloader to use the copies of the classes drchase@6134: * found in the corresponding jar files. drchase@6134: * drchase@6134: * Jarfilenames look something like pD_ext_pF (p.D extends p.F) drchase@6134: * and qD_m_pp_imp_pI (q.D with package-private m implements p.I) drchase@6134: * drchase@6134: */ drchase@6134: public static void main(String args[]) throws Throwable { drchase@6134: ArrayList lt = new ArrayList(); drchase@5800: drchase@6134: if (args.length > 0) { drchase@6134: String a0 = args[0].toLowerCase(); drchase@6134: if (a0.length() > 0) { drchase@6134: writeJarFiles = ("writejarfiles").startsWith(a0); drchase@6134: readJarFiles = ("readjarfiles").startsWith(a0); drchase@6134: } drchase@6134: if (!(writeJarFiles || readJarFiles)) { drchase@6134: throw new Error("Command line parameter (if any) should be prefix of writeJarFiles or readJarFiles"); drchase@6134: } drchase@6134: } drchase@5800: drchase@6134: try { drchase@6134: System.out.println("TRYING p.D.m PRIVATE interface-invoked as p.I.m, p.D extends p.F, p.F.m FINAL"); drchase@6134: tryAndCheckThrown(lt, bytesForDprivateSubWhat("p/F"), drchase@6134: "p.D extends p.F (p.F implements p.I, FINAL public m), private m", drchase@6134: IllegalAccessError.class, "pD_ext_pF"); drchase@6134: // We'll take either a VerifyError (pre 2013-11-30) drchase@6134: // or an IllegalAccessError (post 2013-11-22) drchase@6134: } catch (VerifyError ve) { drchase@6134: System.out.println("Saw expected VerifyError " + ve); drchase@6134: } drchase@6134: System.out.println(); drchase@6134: drchase@6134: System.out.println("TRYING p.D.m PRIVATE interface-invoked as p.I.m, p.D extends p.E"); drchase@6134: tryAndCheckThrown(lt, bytesForDprivateSubWhat("p/E"), drchase@6134: "p.D extends p.E (p.E implements p.I, public m), private m", drchase@6134: IllegalAccessError.class, "pD_ext_pE"); drchase@6134: drchase@6134: System.out.println("TRYING p.D.m ABSTRACT interface-invoked as p.I.m"); drchase@6134: tryAndCheckThrown(lt, bytesForD(), drchase@6134: "D extends abstract C, no m", drchase@6134: AbstractMethodError.class, "pD_ext_pC"); drchase@6134: drchase@6134: System.out.println("TRYING q.D.m PACKAGE interface-invoked as p.I.m"); drchase@6134: tryAndCheckThrown(lt, "q.D", bytesForDsomeAccess("q/D", 0), drchase@6134: "q.D implements p.I, protected m", IllegalAccessError.class, drchase@6134: "qD_m_pp_imp_pI"); drchase@6134: drchase@6134: // Note jar file name is used in the plural-arg case. drchase@6134: System.out.println("TRYING p.D.m PRIVATE interface-invoked as p.I.m"); drchase@6134: tryAndCheckThrown(lt, bytesForDsomeAccess("p/D", ACC_PRIVATE), drchase@6134: "p.D implements p.I, private m", drchase@6134: IllegalAccessError.class, "pD_m_pri_imp_pI"); drchase@6134: drchase@6134: // Plural-arg test. drchase@6134: System.out.println("TRYING p.D.m PRIVATE MANY ARG interface-invoked as p.I.m"); drchase@6134: tryAndCheckThrownMany(lt, bytesForDsomeAccess("p/D", ACC_PRIVATE), drchase@6134: "p.D implements p.I, private m", IllegalAccessError.class); drchase@6134: drchase@6134: if (lt.size() > 0) { drchase@6134: System.out.flush(); drchase@6134: Thread.sleep(250); // This de-interleaves output and error in Netbeans, sigh. drchase@6134: for (Throwable th : lt) drchase@6134: System.err.println(th); drchase@6134: throw new Error("Test failed, there were " + lt.size() + " failures listed above"); drchase@6134: } else { drchase@6134: System.out.println("ALL PASS, HOORAY!"); drchase@6134: } drchase@6134: } drchase@6134: drchase@6134: /** drchase@6134: * The bytes for D, a NOT abstract class extending abstract class C without drchase@6134: * supplying an implementation for abstract method m. There is a default drchase@6134: * method in the interface I, but it should lose to the abstract class. drchase@6134: * drchase@5800: * @return drchase@5800: * @throws Exception drchase@5800: */ drchase@5800: public static byte[] bytesForD() throws Exception { drchase@5800: drchase@6134: ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES drchase@6134: | ClassWriter.COMPUTE_MAXS); drchase@5800: MethodVisitor mv; drchase@5800: drchase@6134: cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "p/D", null, "p/C", null); drchase@5800: drchase@5800: { drchase@5800: mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); drchase@5800: mv.visitCode(); drchase@5800: mv.visitVarInsn(ALOAD, 0); drchase@6134: mv.visitMethodInsn(INVOKESPECIAL, "p/C", "", "()V"); drchase@5800: mv.visitInsn(RETURN); drchase@5800: mv.visitMaxs(0, 0); drchase@5800: mv.visitEnd(); drchase@5800: } drchase@5800: cw.visitEnd(); drchase@5800: drchase@5800: return cw.toByteArray(); drchase@5800: } drchase@5800: drchase@6134: /** drchase@6134: * The bytes for D, implements I, does not extend C, declares m()I with drchase@6134: * access method_acc. drchase@6134: * drchase@6134: * @param d_name Name of class defined drchase@6134: * @param method_acc Accessibility of that class's method m. drchase@6134: * @return drchase@6134: * @throws Exception drchase@6134: */ drchase@6134: public static byte[] bytesForDsomeAccess(String d_name, int method_acc) throws Exception { drchase@6134: return bytesForSomeDsubSomethingSomeAccess(d_name, "java/lang/Object", method_acc); drchase@6134: } drchase@5800: drchase@5800: /** drchase@6134: * The bytes for D implements I, extends some class, declares m()I as drchase@6134: * private. drchase@6134: * drchase@6134: * Invokeinterface of I.m applied to this D should throw IllegalAccessError drchase@6134: * drchase@6134: * @param sub_what The name of the class that D will extend. drchase@6134: * @return drchase@6134: * @throws Exception drchase@6134: */ drchase@6134: public static byte[] bytesForDprivateSubWhat(String sub_what) throws Exception { drchase@6134: return bytesForSomeDsubSomethingSomeAccess("p/D", sub_what, ACC_PRIVATE); drchase@6134: } drchase@5800: drchase@6134: /** drchase@6134: * Returns the bytes for a class with name d_name (presumably "D" in some drchase@6134: * package), extending some class with name sub_what, implementing p.I, drchase@6134: * and defining two methods m() and m(11args) with access method_acc. drchase@6134: * drchase@6134: * @param d_name Name of class that is defined drchase@6134: * @param sub_what Name of class that it extends drchase@6134: * @param method_acc Accessibility of method(s) m in defined class. drchase@6134: * @return drchase@6134: * @throws Exception drchase@6134: */ drchase@6134: public static byte[] bytesForSomeDsubSomethingSomeAccess drchase@6134: (String d_name, String sub_what, int method_acc) drchase@6134: throws Exception { drchase@6134: drchase@6134: ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES drchase@6134: | ClassWriter.COMPUTE_MAXS); drchase@6134: MethodVisitor mv; drchase@6134: String[] interfaces = {"p/I"}; drchase@6134: drchase@6134: cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, d_name, null, sub_what, interfaces); drchase@6134: { drchase@6134: mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); drchase@6134: mv.visitCode(); drchase@6134: mv.visitVarInsn(ALOAD, 0); drchase@6134: mv.visitMethodInsn(INVOKESPECIAL, sub_what, "", "()V"); drchase@6134: mv.visitInsn(RETURN); drchase@6134: mv.visitMaxs(0, 0); drchase@6134: mv.visitEnd(); drchase@5800: } drchase@6134: // int m() {return 3;} drchase@6134: { drchase@6134: mv = cw.visitMethod(method_acc, "m", "()I", null, null); drchase@6134: mv.visitCode(); drchase@6134: mv.visitLdcInsn(new Integer(3)); drchase@6134: mv.visitInsn(IRETURN); drchase@6134: mv.visitMaxs(0, 0); drchase@6134: mv.visitEnd(); drchase@6134: } drchase@6134: // int m(11args) {return 3;} drchase@6134: { drchase@6134: mv = cw.visitMethod(method_acc, "m", "(BCSIJ" drchase@6134: + "Ljava/lang/Object;" drchase@6134: + "Ljava/lang/Object;" drchase@6134: + "Ljava/lang/Object;" drchase@6134: + "Ljava/lang/Object;" drchase@6134: + "Ljava/lang/Object;" drchase@6134: + "Ljava/lang/Object;" drchase@6134: + ")I", null, null); drchase@6134: mv.visitCode(); drchase@6134: mv.visitLdcInsn(new Integer(3)); drchase@6134: mv.visitInsn(IRETURN); drchase@6134: mv.visitMaxs(0, 0); drchase@6134: mv.visitEnd(); drchase@6134: } drchase@6134: cw.visitEnd(); drchase@6134: return cw.toByteArray(); drchase@6134: } drchase@5800: drchase@6134: /** drchase@6134: * The bytecodes for a class p/T defining a methods test() and test(11args) drchase@6134: * that contain an invokeExact of a particular methodHandle, I.m. drchase@6134: * drchase@6134: * Test will be passed values that may imperfectly implement I, drchase@6134: * and thus may in turn throw exceptions. drchase@6134: * drchase@5800: * @return drchase@5800: * @throws Exception drchase@5800: */ drchase@5800: public static byte[] bytesForT() throws Exception { drchase@5800: drchase@6134: ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES drchase@6134: | ClassWriter.COMPUTE_MAXS); drchase@5800: MethodVisitor mv; drchase@5800: drchase@6134: cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "p/T", null, "java/lang/Object", null); drchase@5800: { drchase@5800: mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); drchase@5800: mv.visitCode(); drchase@5800: mv.visitVarInsn(ALOAD, 0); drchase@5800: mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V"); drchase@5800: mv.visitInsn(RETURN); drchase@6134: mv.visitMaxs(0, 0); drchase@5800: mv.visitEnd(); drchase@5800: } drchase@6134: // static int test(I) drchase@5800: { drchase@6134: mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "test", "(Lp/I;)I", null, null); drchase@5800: mv.visitCode(); drchase@6134: mv.visitLdcInsn(new Handle(Opcodes.H_INVOKEINTERFACE, "p/I", "m", "()I")); drchase@6134: mv.visitVarInsn(ALOAD, 0); drchase@6134: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", drchase@6134: "invokeExact", "(Lp/I;)I"); drchase@5800: mv.visitInsn(IRETURN); drchase@6134: mv.visitMaxs(0, 0); drchase@6134: mv.visitEnd(); drchase@6134: } drchase@6134: // static int test(I,11args) drchase@6134: { drchase@6134: 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); drchase@6134: mv.visitCode(); drchase@6134: 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")); drchase@6134: mv.visitVarInsn(ALOAD, 0); drchase@6134: mv.visitVarInsn(ILOAD, 1); drchase@6134: mv.visitVarInsn(ILOAD, 2); drchase@6134: mv.visitVarInsn(ILOAD, 3); drchase@6134: mv.visitVarInsn(ILOAD, 4); drchase@6134: mv.visitVarInsn(LLOAD, 5); drchase@6134: mv.visitVarInsn(ALOAD, 7); drchase@6134: mv.visitVarInsn(ALOAD, 8); drchase@6134: mv.visitVarInsn(ALOAD, 9); drchase@6134: mv.visitVarInsn(ALOAD, 10); drchase@6134: mv.visitVarInsn(ALOAD, 11); drchase@6134: mv.visitVarInsn(ALOAD, 12); drchase@6134: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", drchase@6134: "invokeExact", "(Lp/I;BCSIJLjava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)I"); drchase@6134: mv.visitInsn(IRETURN); drchase@6134: mv.visitMaxs(0, 0); drchase@5800: mv.visitEnd(); drchase@5800: } drchase@5800: cw.visitEnd(); drchase@5800: return cw.toByteArray(); drchase@5800: } drchase@5800: drchase@6134: private static void tryAndCheckThrown( drchase@6134: List lt, byte[] dBytes, String what, Class expected, String jar_name) drchase@6134: throws Throwable { drchase@6134: tryAndCheckThrown(lt, "p.D", dBytes, what, expected, jar_name); drchase@6134: } drchase@6134: drchase@6134: private static void tryAndCheckThrown(List lt, String d_name, byte[] dBytes, String what, Class expected, String jar_name) drchase@6134: throws Throwable { drchase@6134: drchase@6134: System.out.println("Methodhandle invokeExact I.m() for instance of " + what); drchase@6134: ByteClassLoader bcl1 = new ByteClassLoader(jar_name, readJarFiles, writeJarFiles); drchase@5800: try { drchase@6134: Class d1 = bcl1.loadBytes(d_name, dBytes); drchase@6134: Class t1 = bcl1.loadBytes("p.T", bytesForT()); drchase@6134: invokeTest(t1, d1, expected, lt); drchase@6134: } finally { drchase@6134: // Not necessary for others -- all class files are written in this call. drchase@6134: // (unless the VM crashes first). drchase@6134: bcl1.close(); drchase@6134: } drchase@6134: drchase@6134: System.out.println("Reflection invoke I.m() for instance of " + what); drchase@6134: ByteClassLoader bcl3 = new ByteClassLoader(jar_name, readJarFiles, false); drchase@6134: Class d3 = bcl3.loadBytes(d_name, dBytes); drchase@6134: Class t3 = bcl3.loadClass("p.Treflect"); drchase@6134: invokeTest(t3, d3, expected, lt); drchase@6134: drchase@6134: System.out.println("Bytecode invokeInterface I.m() for instance of " + what); drchase@6134: ByteClassLoader bcl2 = new ByteClassLoader(jar_name, readJarFiles, false); drchase@6134: Class d2 = bcl2.loadBytes(d_name, dBytes); drchase@6134: Class t2 = bcl2.loadClass("p.Tdirect"); drchase@6134: badGoodBadGood(t2, d2, expected, lt); drchase@6134: } drchase@6134: drchase@6134: private static void invokeTest(Class t, Class d, Class expected, List lt) drchase@6134: throws Throwable { drchase@6134: try { drchase@6134: Method m = t.getMethod("test", p.I.class); drchase@6134: Object o = d.newInstance(); drchase@6134: Object result = m.invoke(null, o); drchase@6134: if (expected != null) { drchase@6134: System.out.println("FAIL, Expected " + expected.getName() drchase@6134: + " wrapped in InvocationTargetException, but nothing was thrown"); drchase@6134: lt.add(new Error("Exception " + expected.getName() + " was not thrown")); drchase@6134: } else { drchase@6134: System.out.println("PASS, saw expected return."); drchase@6134: } drchase@5800: } catch (InvocationTargetException e) { drchase@5800: Throwable th = e.getCause(); drchase@6134: th.printStackTrace(System.out); drchase@6134: if (expected != null) { drchase@6134: if (expected.isInstance(th)) { drchase@6134: System.out.println("PASS, saw expected exception (" + expected.getName() + ")."); drchase@6134: } else { drchase@6134: System.out.println("FAIL, Expected " + expected.getName() drchase@6134: + " wrapped in InvocationTargetException, saw " + th); drchase@6134: lt.add(th); drchase@6134: } drchase@5800: } else { drchase@6134: System.out.println("FAIL, expected no exception, saw " + th); drchase@6134: lt.add(th); drchase@5800: } drchase@5800: } drchase@6134: System.out.println(); drchase@6134: } drchase@6134: drchase@6134: /* Many-arg versions of above */ drchase@6134: private static void tryAndCheckThrownMany(List lt, byte[] dBytes, String what, Class expected) drchase@6134: throws Throwable { drchase@6134: drchase@6134: System.out.println("Methodhandle invokeExact I.m(11params) for instance of " + what); drchase@6134: ByteClassLoader bcl1 = new ByteClassLoader("p.D", readJarFiles, false); drchase@6134: try { drchase@6134: Class d1 = bcl1.loadBytes("p.D", dBytes); drchase@6134: Class t1 = bcl1.loadBytes("p.T", bytesForT()); drchase@6134: invokeTestMany(t1, d1, expected, lt); drchase@6134: } finally { drchase@6134: bcl1.close(); // Not necessary for others -- all class files are written in this call. drchase@6134: } drchase@6134: drchase@6134: { drchase@6134: System.out.println("Bytecode invokeInterface I.m(11params) for instance of " + what); drchase@6134: ByteClassLoader bcl2 = new ByteClassLoader("pD_m_pri_imp_pI", readJarFiles, false); drchase@6134: Class d2 = bcl2.loadBytes("p.D", dBytes); drchase@6134: Class t2 = bcl2.loadClass("p.Tdirect"); drchase@6134: badGoodBadGoodMany(t2, d2, expected, lt); drchase@6134: drchase@6134: } drchase@6134: { drchase@6134: System.out.println("Reflection invokeInterface I.m(11params) for instance of " + what); drchase@6134: ByteClassLoader bcl2 = new ByteClassLoader("pD_m_pri_imp_pI", readJarFiles, false); drchase@6134: Class d2 = bcl2.loadBytes("p.D", dBytes); drchase@6134: Class t2 = bcl2.loadClass("p.Treflect"); drchase@6134: invokeTestMany(t2, d2, expected, lt); drchase@6134: } drchase@6134: } drchase@6134: drchase@6134: private static void invokeTestMany(Class t, Class d, Class expected, List lt) drchase@6134: throws Throwable { drchase@6134: try { drchase@6134: Method m = t.getMethod("test", p.I.class, drchase@6134: Byte.TYPE, Character.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE, drchase@6134: Object.class, Object.class, Object.class, drchase@6134: Object.class, Object.class, Object.class); drchase@6134: Object o = d.newInstance(); drchase@6134: Byte b = 1; drchase@6134: Character c = 2; drchase@6134: Short s = 3; drchase@6134: Integer i = 4; drchase@6134: Long j = 5L; drchase@6134: Object o1 = b; drchase@6134: Object o2 = c; drchase@6134: Object o3 = s; drchase@6134: Object o4 = i; drchase@6134: Object o5 = j; drchase@6134: Object o6 = "6"; drchase@6134: drchase@6134: Object result = m.invoke(null, o, b, c, s, i, j, drchase@6134: o1, o2, o3, o4, o5, o6); drchase@6134: if (expected != null) { drchase@6134: System.out.println("FAIL, Expected " + expected.getName() drchase@6134: + " wrapped in InvocationTargetException, but nothing was thrown"); drchase@6134: lt.add(new Error("Exception " + expected.getName() drchase@6134: + " was not thrown")); drchase@6134: } else { drchase@6134: System.out.println("PASS, saw expected return."); drchase@6134: } drchase@6134: } catch (InvocationTargetException e) { drchase@6134: Throwable th = e.getCause(); drchase@6134: th.printStackTrace(System.out); drchase@6134: if (expected != null) { drchase@6134: if (expected.isInstance(th)) { drchase@6134: System.out.println("PASS, saw expected exception (" drchase@6134: + expected.getName() + ")."); drchase@6134: } else { drchase@6134: System.out.println("FAIL, Expected " + expected.getName() drchase@6134: + " wrapped in InvocationTargetException, saw " + th); drchase@6134: lt.add(th); drchase@6134: } drchase@6134: } else { drchase@6134: System.out.println("FAIL, expected no exception, saw " + th); drchase@6134: lt.add(th); drchase@6134: } drchase@6134: } drchase@6134: System.out.println(); drchase@6134: } drchase@6134: drchase@6134: /** drchase@6134: * This tests a peculiar idiom for tickling the bug on older VMs that lack drchase@6134: * methodhandles. The bug (if not fixed) acts in the following way: drchase@6134: * drchase@6134: * When a broken receiver is passed to the first execution of an invokeinterface drchase@6134: * bytecode, the illegal access is detected before the effects of resolution are drchase@6134: * cached for later use, and so repeated calls with a broken receiver will always drchase@6134: * throw the correct error. drchase@6134: * drchase@6134: * If, however, a good receiver is passed to the invokeinterface, the effects of drchase@6134: * resolution will be successfully cached. A subsequent execution with a broken drchase@6134: * receiver will reuse the cached information, skip the detailed resolution work, drchase@6134: * and instead encounter a null pointer. By convention, that is the encoding for a drchase@6134: * missing abstract method, and an AbstractMethodError is thrown -- not the expected drchase@6134: * IllegalAccessError. drchase@6134: * drchase@6134: * @param t2 Test invocation class drchase@6134: * @param d2 Test receiver class drchase@6134: * @param expected expected exception type drchase@6134: * @param lt list of unexpected throwables seen drchase@6134: */ drchase@6134: private static void badGoodBadGood(Class t2, Class d2, Class expected, List lt) drchase@6134: throws Throwable { drchase@6134: System.out.println(" Error input 1st time"); drchase@6134: invokeTest(t2, d2, expected, lt); drchase@6134: System.out.println(" Good input (instance of Dok)"); drchase@6134: invokeTest(t2, Dok.class, null, lt); drchase@6134: System.out.println(" Error input 2nd time"); drchase@6134: invokeTest(t2, d2, expected, lt); drchase@6134: System.out.println(" Good input (instance of Dok)"); drchase@6134: invokeTest(t2, Dok.class, null, lt); drchase@6134: } drchase@6134: drchase@6134: private static void badGoodBadGoodMany(Class t2, Class d2, Class expected, List lt) drchase@6134: throws Throwable { drchase@6134: System.out.println(" Error input 1st time"); drchase@6134: invokeTestMany(t2, d2, expected, lt); drchase@6134: System.out.println(" Good input (instance of Dok)"); drchase@6134: invokeTestMany(t2, Dok.class, null, lt); drchase@6134: System.out.println(" Error input 2nd time"); drchase@6134: invokeTestMany(t2, d2, expected, lt); drchase@6134: System.out.println(" Good input (instance of Dok)"); drchase@6134: invokeTestMany(t2, Dok.class, null, lt); drchase@5800: } drchase@5800: }