Mercurial > hg > truffle
comparison test/compiler/jsr292/methodHandleExceptions/TestAMEnotNPE.java @ 13403:9d15b81d5d1b
8016839: JSR292: AME instead of IAE when calling a method
Summary: Catch missing-because-illegal case for itable entries and use an exception-throwing method instead of null.
Reviewed-by: acorn, jrose, coleenp
author | drchase |
---|---|
date | Tue, 26 Nov 2013 18:16:04 -0500 |
parents | dc261f466b6d |
children |
comparison
equal
deleted
inserted
replaced
13397:e51d73189692 | 13403:9d15b81d5d1b |
---|---|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
20 * or visit www.oracle.com if you need additional information or have any | 20 * or visit www.oracle.com if you need additional information or have any |
21 * questions. | 21 * questions. |
22 * | 22 * |
23 */ | 23 */ |
24 | |
25 import java.lang.reflect.InvocationTargetException; | 24 import java.lang.reflect.InvocationTargetException; |
25 import java.lang.reflect.Method; | |
26 import java.util.ArrayList; | |
27 import java.util.List; | |
26 import jdk.internal.org.objectweb.asm.ClassWriter; | 28 import jdk.internal.org.objectweb.asm.ClassWriter; |
27 import jdk.internal.org.objectweb.asm.Handle; | 29 import jdk.internal.org.objectweb.asm.Handle; |
28 import jdk.internal.org.objectweb.asm.MethodVisitor; | 30 import jdk.internal.org.objectweb.asm.MethodVisitor; |
29 import jdk.internal.org.objectweb.asm.Opcodes; | 31 import jdk.internal.org.objectweb.asm.Opcodes; |
32 import p.Dok; | |
30 | 33 |
31 /** | 34 /** |
32 * @test | 35 * @test @bug 8025260 8016839 |
33 * @bug 8025260 | 36 * @summary Ensure that AbstractMethodError and IllegalAccessError are thrown appropriately, not NullPointerException |
34 * @summary Ensure that AbstractMethodError is thrown, not NullPointerException, through MethodHandles::jump_from_method_handle code path | 37 * |
35 * | 38 * @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 |
36 * @compile -XDignore.symbol.file ByteClassLoader.java I.java C.java TestAMEnotNPE.java | 39 * |
37 * @run main/othervm TestAMEnotNPE | 40 * @run main/othervm TestAMEnotNPE |
41 * @run main/othervm -Xint TestAMEnotNPE | |
42 * @run main/othervm -Xcomp TestAMEnotNPE | |
38 */ | 43 */ |
39 | |
40 public class TestAMEnotNPE implements Opcodes { | 44 public class TestAMEnotNPE implements Opcodes { |
41 | 45 |
42 /** | 46 static boolean writeJarFiles = false; |
43 * The bytes for D, a NOT abstract class extending abstract class C | 47 static boolean readJarFiles = false; |
44 * without supplying an implementation for abstract method m. | 48 |
45 * There is a default method in the interface I, but it should lose to | 49 /** |
46 * the abstract class. | 50 * Optional command line parameter (any case-insensitive prefix of) |
47 | 51 * "writejarfiles" or "readjarfiles". |
48 class D extends C { | 52 * |
49 D() { super(); } | 53 * "Writejarfiles" creates a jar file for each different set of tested classes. |
50 // does not define m | 54 * "Readjarfiles" causes the classloader to use the copies of the classes |
51 } | 55 * found in the corresponding jar files. |
52 | 56 * |
57 * Jarfilenames look something like pD_ext_pF (p.D extends p.F) | |
58 * and qD_m_pp_imp_pI (q.D with package-private m implements p.I) | |
59 * | |
60 */ | |
61 public static void main(String args[]) throws Throwable { | |
62 ArrayList<Throwable> lt = new ArrayList<Throwable>(); | |
63 | |
64 if (args.length > 0) { | |
65 String a0 = args[0].toLowerCase(); | |
66 if (a0.length() > 0) { | |
67 writeJarFiles = ("writejarfiles").startsWith(a0); | |
68 readJarFiles = ("readjarfiles").startsWith(a0); | |
69 } | |
70 if (!(writeJarFiles || readJarFiles)) { | |
71 throw new Error("Command line parameter (if any) should be prefix of writeJarFiles or readJarFiles"); | |
72 } | |
73 } | |
74 | |
75 try { | |
76 System.out.println("TRYING p.D.m PRIVATE interface-invoked as p.I.m, p.D extends p.F, p.F.m FINAL"); | |
77 tryAndCheckThrown(lt, bytesForDprivateSubWhat("p/F"), | |
78 "p.D extends p.F (p.F implements p.I, FINAL public m), private m", | |
79 IllegalAccessError.class, "pD_ext_pF"); | |
80 // We'll take either a VerifyError (pre 2013-11-30) | |
81 // or an IllegalAccessError (post 2013-11-22) | |
82 } catch (VerifyError ve) { | |
83 System.out.println("Saw expected VerifyError " + ve); | |
84 } | |
85 System.out.println(); | |
86 | |
87 System.out.println("TRYING p.D.m PRIVATE interface-invoked as p.I.m, p.D extends p.E"); | |
88 tryAndCheckThrown(lt, bytesForDprivateSubWhat("p/E"), | |
89 "p.D extends p.E (p.E implements p.I, public m), private m", | |
90 IllegalAccessError.class, "pD_ext_pE"); | |
91 | |
92 System.out.println("TRYING p.D.m ABSTRACT interface-invoked as p.I.m"); | |
93 tryAndCheckThrown(lt, bytesForD(), | |
94 "D extends abstract C, no m", | |
95 AbstractMethodError.class, "pD_ext_pC"); | |
96 | |
97 System.out.println("TRYING q.D.m PACKAGE interface-invoked as p.I.m"); | |
98 tryAndCheckThrown(lt, "q.D", bytesForDsomeAccess("q/D", 0), | |
99 "q.D implements p.I, protected m", IllegalAccessError.class, | |
100 "qD_m_pp_imp_pI"); | |
101 | |
102 // Note jar file name is used in the plural-arg case. | |
103 System.out.println("TRYING p.D.m PRIVATE interface-invoked as p.I.m"); | |
104 tryAndCheckThrown(lt, bytesForDsomeAccess("p/D", ACC_PRIVATE), | |
105 "p.D implements p.I, private m", | |
106 IllegalAccessError.class, "pD_m_pri_imp_pI"); | |
107 | |
108 // Plural-arg test. | |
109 System.out.println("TRYING p.D.m PRIVATE MANY ARG interface-invoked as p.I.m"); | |
110 tryAndCheckThrownMany(lt, bytesForDsomeAccess("p/D", ACC_PRIVATE), | |
111 "p.D implements p.I, private m", IllegalAccessError.class); | |
112 | |
113 if (lt.size() > 0) { | |
114 System.out.flush(); | |
115 Thread.sleep(250); // This de-interleaves output and error in Netbeans, sigh. | |
116 for (Throwable th : lt) | |
117 System.err.println(th); | |
118 throw new Error("Test failed, there were " + lt.size() + " failures listed above"); | |
119 } else { | |
120 System.out.println("ALL PASS, HOORAY!"); | |
121 } | |
122 } | |
123 | |
124 /** | |
125 * The bytes for D, a NOT abstract class extending abstract class C without | |
126 * supplying an implementation for abstract method m. There is a default | |
127 * method in the interface I, but it should lose to the abstract class. | |
128 * | |
53 * @return | 129 * @return |
54 * @throws Exception | 130 * @throws Exception |
55 */ | 131 */ |
56 public static byte[] bytesForD() throws Exception { | 132 public static byte[] bytesForD() throws Exception { |
57 | 133 |
58 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS); | 134 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES |
135 | ClassWriter.COMPUTE_MAXS); | |
59 MethodVisitor mv; | 136 MethodVisitor mv; |
60 | 137 |
61 cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "D", null, "C", null); | 138 cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "p/D", null, "p/C", null); |
62 | 139 |
63 { | 140 { |
64 mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); | 141 mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); |
65 mv.visitCode(); | 142 mv.visitCode(); |
66 mv.visitVarInsn(ALOAD, 0); | 143 mv.visitVarInsn(ALOAD, 0); |
67 mv.visitMethodInsn(INVOKESPECIAL, "C", "<init>", "()V"); | 144 mv.visitMethodInsn(INVOKESPECIAL, "p/C", "<init>", "()V"); |
68 mv.visitInsn(RETURN); | 145 mv.visitInsn(RETURN); |
69 mv.visitMaxs(0, 0); | 146 mv.visitMaxs(0, 0); |
70 mv.visitEnd(); | 147 mv.visitEnd(); |
71 } | 148 } |
72 cw.visitEnd(); | 149 cw.visitEnd(); |
73 | 150 |
74 return cw.toByteArray(); | 151 return cw.toByteArray(); |
75 } | 152 } |
76 | 153 |
77 | 154 /** |
78 /** | 155 * The bytes for D, implements I, does not extend C, declares m()I with |
79 * The bytecodes for an invokeExact of a particular methodHandle, I.m, invoked on a D | 156 * access method_acc. |
80 | 157 * |
81 class T { | 158 * @param d_name Name of class defined |
82 T() { super(); } // boring constructor | 159 * @param method_acc Accessibility of that class's method m. |
83 int test() { | |
84 MethodHandle mh = `I.m():int`; | |
85 D d = new D(); | |
86 return mh.invokeExact(d); // Should explode here, AbstractMethodError | |
87 } | |
88 } | |
89 | |
90 * @return | 160 * @return |
91 * @throws Exception | 161 * @throws Exception |
92 */ | 162 */ |
163 public static byte[] bytesForDsomeAccess(String d_name, int method_acc) throws Exception { | |
164 return bytesForSomeDsubSomethingSomeAccess(d_name, "java/lang/Object", method_acc); | |
165 } | |
166 | |
167 /** | |
168 * The bytes for D implements I, extends some class, declares m()I as | |
169 * private. | |
170 * | |
171 * Invokeinterface of I.m applied to this D should throw IllegalAccessError | |
172 * | |
173 * @param sub_what The name of the class that D will extend. | |
174 * @return | |
175 * @throws Exception | |
176 */ | |
177 public static byte[] bytesForDprivateSubWhat(String sub_what) throws Exception { | |
178 return bytesForSomeDsubSomethingSomeAccess("p/D", sub_what, ACC_PRIVATE); | |
179 } | |
180 | |
181 /** | |
182 * Returns the bytes for a class with name d_name (presumably "D" in some | |
183 * package), extending some class with name sub_what, implementing p.I, | |
184 * and defining two methods m() and m(11args) with access method_acc. | |
185 * | |
186 * @param d_name Name of class that is defined | |
187 * @param sub_what Name of class that it extends | |
188 * @param method_acc Accessibility of method(s) m in defined class. | |
189 * @return | |
190 * @throws Exception | |
191 */ | |
192 public static byte[] bytesForSomeDsubSomethingSomeAccess | |
193 (String d_name, String sub_what, int method_acc) | |
194 throws Exception { | |
195 | |
196 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | |
197 | ClassWriter.COMPUTE_MAXS); | |
198 MethodVisitor mv; | |
199 String[] interfaces = {"p/I"}; | |
200 | |
201 cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, d_name, null, sub_what, interfaces); | |
202 { | |
203 mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); | |
204 mv.visitCode(); | |
205 mv.visitVarInsn(ALOAD, 0); | |
206 mv.visitMethodInsn(INVOKESPECIAL, sub_what, "<init>", "()V"); | |
207 mv.visitInsn(RETURN); | |
208 mv.visitMaxs(0, 0); | |
209 mv.visitEnd(); | |
210 } | |
211 // int m() {return 3;} | |
212 { | |
213 mv = cw.visitMethod(method_acc, "m", "()I", null, null); | |
214 mv.visitCode(); | |
215 mv.visitLdcInsn(new Integer(3)); | |
216 mv.visitInsn(IRETURN); | |
217 mv.visitMaxs(0, 0); | |
218 mv.visitEnd(); | |
219 } | |
220 // int m(11args) {return 3;} | |
221 { | |
222 mv = cw.visitMethod(method_acc, "m", "(BCSIJ" | |
223 + "Ljava/lang/Object;" | |
224 + "Ljava/lang/Object;" | |
225 + "Ljava/lang/Object;" | |
226 + "Ljava/lang/Object;" | |
227 + "Ljava/lang/Object;" | |
228 + "Ljava/lang/Object;" | |
229 + ")I", null, null); | |
230 mv.visitCode(); | |
231 mv.visitLdcInsn(new Integer(3)); | |
232 mv.visitInsn(IRETURN); | |
233 mv.visitMaxs(0, 0); | |
234 mv.visitEnd(); | |
235 } | |
236 cw.visitEnd(); | |
237 return cw.toByteArray(); | |
238 } | |
239 | |
240 /** | |
241 * The bytecodes for a class p/T defining a methods test() and test(11args) | |
242 * that contain an invokeExact of a particular methodHandle, I.m. | |
243 * | |
244 * Test will be passed values that may imperfectly implement I, | |
245 * and thus may in turn throw exceptions. | |
246 * | |
247 * @return | |
248 * @throws Exception | |
249 */ | |
93 public static byte[] bytesForT() throws Exception { | 250 public static byte[] bytesForT() throws Exception { |
94 | 251 |
95 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS); | 252 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES |
253 | ClassWriter.COMPUTE_MAXS); | |
96 MethodVisitor mv; | 254 MethodVisitor mv; |
97 | 255 |
98 cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "T", null, "java/lang/Object", null); | 256 cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "p/T", null, "java/lang/Object", null); |
99 { | 257 { |
100 mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); | 258 mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); |
101 mv.visitCode(); | 259 mv.visitCode(); |
102 mv.visitVarInsn(ALOAD, 0); | 260 mv.visitVarInsn(ALOAD, 0); |
103 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); | 261 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); |
104 mv.visitInsn(RETURN); | 262 mv.visitInsn(RETURN); |
105 mv.visitMaxs(0,0); | 263 mv.visitMaxs(0, 0); |
106 mv.visitEnd(); | 264 mv.visitEnd(); |
107 } | 265 } |
108 { | 266 // static int test(I) |
109 mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "test", "()I", null, null); | 267 { |
110 mv.visitCode(); | 268 mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "test", "(Lp/I;)I", null, null); |
111 mv.visitLdcInsn(new Handle(Opcodes.H_INVOKEINTERFACE, "I", "m", "()I")); | 269 mv.visitCode(); |
112 mv.visitTypeInsn(NEW, "D"); | 270 mv.visitLdcInsn(new Handle(Opcodes.H_INVOKEINTERFACE, "p/I", "m", "()I")); |
113 mv.visitInsn(DUP); | 271 mv.visitVarInsn(ALOAD, 0); |
114 mv.visitMethodInsn(INVOKESPECIAL, "D", "<init>", "()V"); | 272 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", |
115 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invokeExact", "(LI;)I"); | 273 "invokeExact", "(Lp/I;)I"); |
116 mv.visitInsn(IRETURN); | 274 mv.visitInsn(IRETURN); |
117 mv.visitMaxs(0,0); | 275 mv.visitMaxs(0, 0); |
276 mv.visitEnd(); | |
277 } | |
278 // static int test(I,11args) | |
279 { | |
280 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); | |
281 mv.visitCode(); | |
282 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")); | |
283 mv.visitVarInsn(ALOAD, 0); | |
284 mv.visitVarInsn(ILOAD, 1); | |
285 mv.visitVarInsn(ILOAD, 2); | |
286 mv.visitVarInsn(ILOAD, 3); | |
287 mv.visitVarInsn(ILOAD, 4); | |
288 mv.visitVarInsn(LLOAD, 5); | |
289 mv.visitVarInsn(ALOAD, 7); | |
290 mv.visitVarInsn(ALOAD, 8); | |
291 mv.visitVarInsn(ALOAD, 9); | |
292 mv.visitVarInsn(ALOAD, 10); | |
293 mv.visitVarInsn(ALOAD, 11); | |
294 mv.visitVarInsn(ALOAD, 12); | |
295 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", | |
296 "invokeExact", "(Lp/I;BCSIJLjava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)I"); | |
297 mv.visitInsn(IRETURN); | |
298 mv.visitMaxs(0, 0); | |
118 mv.visitEnd(); | 299 mv.visitEnd(); |
119 } | 300 } |
120 cw.visitEnd(); | 301 cw.visitEnd(); |
121 return cw.toByteArray(); | 302 return cw.toByteArray(); |
122 } | 303 } |
123 | 304 |
124 public static void main(String args[] ) throws Throwable { | 305 private static void tryAndCheckThrown( |
125 ByteClassLoader bcl = new ByteClassLoader(); | 306 List<Throwable> lt, byte[] dBytes, String what, Class<?> expected, String jar_name) |
126 Class<?> d = bcl.loadBytes("D", bytesForD()); | 307 throws Throwable { |
127 Class<?> t = bcl.loadBytes("T", bytesForT()); | 308 tryAndCheckThrown(lt, "p.D", dBytes, what, expected, jar_name); |
309 } | |
310 | |
311 private static void tryAndCheckThrown(List<Throwable> lt, String d_name, byte[] dBytes, String what, Class<?> expected, String jar_name) | |
312 throws Throwable { | |
313 | |
314 System.out.println("Methodhandle invokeExact I.m() for instance of " + what); | |
315 ByteClassLoader bcl1 = new ByteClassLoader(jar_name, readJarFiles, writeJarFiles); | |
128 try { | 316 try { |
129 Object result = t.getMethod("test").invoke(null); | 317 Class<?> d1 = bcl1.loadBytes(d_name, dBytes); |
130 System.out.println("Expected AbstractMethodError wrapped in InvocationTargetException, saw no exception"); | 318 Class<?> t1 = bcl1.loadBytes("p.T", bytesForT()); |
131 throw new Error("Missing expected exception"); | 319 invokeTest(t1, d1, expected, lt); |
320 } finally { | |
321 // Not necessary for others -- all class files are written in this call. | |
322 // (unless the VM crashes first). | |
323 bcl1.close(); | |
324 } | |
325 | |
326 System.out.println("Reflection invoke I.m() for instance of " + what); | |
327 ByteClassLoader bcl3 = new ByteClassLoader(jar_name, readJarFiles, false); | |
328 Class<?> d3 = bcl3.loadBytes(d_name, dBytes); | |
329 Class<?> t3 = bcl3.loadClass("p.Treflect"); | |
330 invokeTest(t3, d3, expected, lt); | |
331 | |
332 System.out.println("Bytecode invokeInterface I.m() for instance of " + what); | |
333 ByteClassLoader bcl2 = new ByteClassLoader(jar_name, readJarFiles, false); | |
334 Class<?> d2 = bcl2.loadBytes(d_name, dBytes); | |
335 Class<?> t2 = bcl2.loadClass("p.Tdirect"); | |
336 badGoodBadGood(t2, d2, expected, lt); | |
337 } | |
338 | |
339 private static void invokeTest(Class<?> t, Class<?> d, Class<?> expected, List<Throwable> lt) | |
340 throws Throwable { | |
341 try { | |
342 Method m = t.getMethod("test", p.I.class); | |
343 Object o = d.newInstance(); | |
344 Object result = m.invoke(null, o); | |
345 if (expected != null) { | |
346 System.out.println("FAIL, Expected " + expected.getName() | |
347 + " wrapped in InvocationTargetException, but nothing was thrown"); | |
348 lt.add(new Error("Exception " + expected.getName() + " was not thrown")); | |
349 } else { | |
350 System.out.println("PASS, saw expected return."); | |
351 } | |
132 } catch (InvocationTargetException e) { | 352 } catch (InvocationTargetException e) { |
133 Throwable th = e.getCause(); | 353 Throwable th = e.getCause(); |
134 if (th instanceof AbstractMethodError) { | 354 th.printStackTrace(System.out); |
135 th.printStackTrace(System.out); | 355 if (expected != null) { |
136 System.out.println("PASS, saw expected exception (AbstractMethodError, wrapped in InvocationTargetException)."); | 356 if (expected.isInstance(th)) { |
357 System.out.println("PASS, saw expected exception (" + expected.getName() + ")."); | |
358 } else { | |
359 System.out.println("FAIL, Expected " + expected.getName() | |
360 + " wrapped in InvocationTargetException, saw " + th); | |
361 lt.add(th); | |
362 } | |
137 } else { | 363 } else { |
138 System.out.println("Expected AbstractMethodError wrapped in InvocationTargetException, saw " + th); | 364 System.out.println("FAIL, expected no exception, saw " + th); |
139 throw th; | 365 lt.add(th); |
140 } | 366 } |
141 } | 367 } |
368 System.out.println(); | |
369 } | |
370 | |
371 /* Many-arg versions of above */ | |
372 private static void tryAndCheckThrownMany(List<Throwable> lt, byte[] dBytes, String what, Class<?> expected) | |
373 throws Throwable { | |
374 | |
375 System.out.println("Methodhandle invokeExact I.m(11params) for instance of " + what); | |
376 ByteClassLoader bcl1 = new ByteClassLoader("p.D", readJarFiles, false); | |
377 try { | |
378 Class<?> d1 = bcl1.loadBytes("p.D", dBytes); | |
379 Class<?> t1 = bcl1.loadBytes("p.T", bytesForT()); | |
380 invokeTestMany(t1, d1, expected, lt); | |
381 } finally { | |
382 bcl1.close(); // Not necessary for others -- all class files are written in this call. | |
383 } | |
384 | |
385 { | |
386 System.out.println("Bytecode invokeInterface I.m(11params) for instance of " + what); | |
387 ByteClassLoader bcl2 = new ByteClassLoader("pD_m_pri_imp_pI", readJarFiles, false); | |
388 Class<?> d2 = bcl2.loadBytes("p.D", dBytes); | |
389 Class<?> t2 = bcl2.loadClass("p.Tdirect"); | |
390 badGoodBadGoodMany(t2, d2, expected, lt); | |
391 | |
392 } | |
393 { | |
394 System.out.println("Reflection invokeInterface I.m(11params) for instance of " + what); | |
395 ByteClassLoader bcl2 = new ByteClassLoader("pD_m_pri_imp_pI", readJarFiles, false); | |
396 Class<?> d2 = bcl2.loadBytes("p.D", dBytes); | |
397 Class<?> t2 = bcl2.loadClass("p.Treflect"); | |
398 invokeTestMany(t2, d2, expected, lt); | |
399 } | |
400 } | |
401 | |
402 private static void invokeTestMany(Class<?> t, Class<?> d, Class<?> expected, List<Throwable> lt) | |
403 throws Throwable { | |
404 try { | |
405 Method m = t.getMethod("test", p.I.class, | |
406 Byte.TYPE, Character.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE, | |
407 Object.class, Object.class, Object.class, | |
408 Object.class, Object.class, Object.class); | |
409 Object o = d.newInstance(); | |
410 Byte b = 1; | |
411 Character c = 2; | |
412 Short s = 3; | |
413 Integer i = 4; | |
414 Long j = 5L; | |
415 Object o1 = b; | |
416 Object o2 = c; | |
417 Object o3 = s; | |
418 Object o4 = i; | |
419 Object o5 = j; | |
420 Object o6 = "6"; | |
421 | |
422 Object result = m.invoke(null, o, b, c, s, i, j, | |
423 o1, o2, o3, o4, o5, o6); | |
424 if (expected != null) { | |
425 System.out.println("FAIL, Expected " + expected.getName() | |
426 + " wrapped in InvocationTargetException, but nothing was thrown"); | |
427 lt.add(new Error("Exception " + expected.getName() | |
428 + " was not thrown")); | |
429 } else { | |
430 System.out.println("PASS, saw expected return."); | |
431 } | |
432 } catch (InvocationTargetException e) { | |
433 Throwable th = e.getCause(); | |
434 th.printStackTrace(System.out); | |
435 if (expected != null) { | |
436 if (expected.isInstance(th)) { | |
437 System.out.println("PASS, saw expected exception (" | |
438 + expected.getName() + ")."); | |
439 } else { | |
440 System.out.println("FAIL, Expected " + expected.getName() | |
441 + " wrapped in InvocationTargetException, saw " + th); | |
442 lt.add(th); | |
443 } | |
444 } else { | |
445 System.out.println("FAIL, expected no exception, saw " + th); | |
446 lt.add(th); | |
447 } | |
448 } | |
449 System.out.println(); | |
450 } | |
451 | |
452 /** | |
453 * This tests a peculiar idiom for tickling the bug on older VMs that lack | |
454 * methodhandles. The bug (if not fixed) acts in the following way: | |
455 * | |
456 * When a broken receiver is passed to the first execution of an invokeinterface | |
457 * bytecode, the illegal access is detected before the effects of resolution are | |
458 * cached for later use, and so repeated calls with a broken receiver will always | |
459 * throw the correct error. | |
460 * | |
461 * If, however, a good receiver is passed to the invokeinterface, the effects of | |
462 * resolution will be successfully cached. A subsequent execution with a broken | |
463 * receiver will reuse the cached information, skip the detailed resolution work, | |
464 * and instead encounter a null pointer. By convention, that is the encoding for a | |
465 * missing abstract method, and an AbstractMethodError is thrown -- not the expected | |
466 * IllegalAccessError. | |
467 * | |
468 * @param t2 Test invocation class | |
469 * @param d2 Test receiver class | |
470 * @param expected expected exception type | |
471 * @param lt list of unexpected throwables seen | |
472 */ | |
473 private static void badGoodBadGood(Class<?> t2, Class<?> d2, Class<?> expected, List<Throwable> lt) | |
474 throws Throwable { | |
475 System.out.println(" Error input 1st time"); | |
476 invokeTest(t2, d2, expected, lt); | |
477 System.out.println(" Good input (instance of Dok)"); | |
478 invokeTest(t2, Dok.class, null, lt); | |
479 System.out.println(" Error input 2nd time"); | |
480 invokeTest(t2, d2, expected, lt); | |
481 System.out.println(" Good input (instance of Dok)"); | |
482 invokeTest(t2, Dok.class, null, lt); | |
483 } | |
484 | |
485 private static void badGoodBadGoodMany(Class<?> t2, Class<?> d2, Class<?> expected, List<Throwable> lt) | |
486 throws Throwable { | |
487 System.out.println(" Error input 1st time"); | |
488 invokeTestMany(t2, d2, expected, lt); | |
489 System.out.println(" Good input (instance of Dok)"); | |
490 invokeTestMany(t2, Dok.class, null, lt); | |
491 System.out.println(" Error input 2nd time"); | |
492 invokeTestMany(t2, d2, expected, lt); | |
493 System.out.println(" Good input (instance of Dok)"); | |
494 invokeTestMany(t2, Dok.class, null, lt); | |
142 } | 495 } |
143 } | 496 } |