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 }