blob: 1aa15da8af2000894141349e46d6c6ba5f95b3e6 [file] [log] [blame]
rfield099afec2013-09-03 21:42:56 -07001/*
2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26/*
27 * @test
28 * @summary verify Lookup.revealDirect on a variety of input handles
29 * @compile -XDignore.symbol.file RevealDirectTest.java
30 * @run junit/othervm -ea -esa test.java.lang.invoke.RevealDirectTest
31 *
32 * @test
33 * @summary verify Lookup.revealDirect on a variety of input handles, with security manager
34 * @run main/othervm/policy=jtreg.security.policy/secure=java.lang.SecurityManager -ea -esa test.java.lang.invoke.RevealDirectTest
35 */
36
37/* To run manually:
38 * $ $JAVA8X_HOME/bin/javac -cp $JUNIT4_JAR -d ../../../.. -XDignore.symbol.file RevealDirectTest.java
39 * $ $JAVA8X_HOME/bin/java -cp $JUNIT4_JAR:../../../.. -ea -esa org.junit.runner.JUnitCore test.java.lang.invoke.RevealDirectTest
40 * $ $JAVA8X_HOME/bin/java -cp $JUNIT4_JAR:../../../.. -ea -esa -Djava.security.manager test.java.lang.invoke.RevealDirectTest
41 */
42
43package test.java.lang.invoke;
44
45import java.lang.reflect.*;
46import java.lang.invoke.*;
47import static java.lang.invoke.MethodHandles.*;
48import static java.lang.invoke.MethodType.*;
49import static java.lang.invoke.MethodHandleInfo.*;
50import java.util.*;
51import static org.junit.Assert.*;
52import org.junit.*;
53
54public class RevealDirectTest {
55 public static void main(String... av) throws Throwable {
56 // Run the @Test methods explicitly, in case we don't want to use the JUnitCore driver.
57 // This appears to be necessary when running with a security manager.
58 Throwable fail = null;
59 for (Method test : RevealDirectTest.class.getDeclaredMethods()) {
60 if (!test.isAnnotationPresent(Test.class)) continue;
61 try {
62 test.invoke(new RevealDirectTest());
63 } catch (Throwable ex) {
64 if (ex instanceof InvocationTargetException)
65 ex = ex.getCause();
66 if (fail == null) fail = ex;
67 System.out.println("Testcase: "+test.getName()
68 +"("+test.getDeclaringClass().getName()
69 +"):\tCaused an ERROR");
70 System.out.println(ex);
71 ex.printStackTrace(System.out);
72 }
73 }
74 if (fail != null) throw fail;
75 }
76
77 public interface SimpleSuperInterface {
78 public abstract int getInt();
79 public static void printAll(String... args) {
80 System.out.println(Arrays.toString(args));
81 }
82 public int NICE_CONSTANT = 42;
83 }
84 public interface SimpleInterface extends SimpleSuperInterface {
85 default float getFloat() { return getInt(); }
86 public static void printAll(String[] args) {
87 System.out.println(Arrays.toString(args));
88 }
89 }
90 public static class Simple implements SimpleInterface, Cloneable {
91 public int intField;
92 public final int finalField;
93 private static String stringField;
94 public int getInt() { return NICE_CONSTANT; }
95 private static Number getNum() { return 804; }
96 public Simple clone() {
97 try {
98 return (Simple) super.clone();
99 } catch (CloneNotSupportedException ex) {
100 throw new RuntimeException(ex);
101 }
102 }
103 Simple() { finalField = -NICE_CONSTANT; }
104 private static Lookup localLookup() { return lookup(); }
105 private static List<Member> members() { return getMembers(lookup().lookupClass()); };
106 }
jrose8347af82013-10-05 05:30:40 -0700107 static class Nestmate {
108 private static Lookup localLookup() { return lookup(); }
109 }
rfield099afec2013-09-03 21:42:56 -0700110
111 static boolean VERBOSE = false;
112
113 @Test public void testSimple() throws Throwable {
114 if (VERBOSE) System.out.println("@Test testSimple");
115 testOnMembers("testSimple", Simple.members(), Simple.localLookup());
116 }
117 @Test public void testPublicLookup() throws Throwable {
118 if (VERBOSE) System.out.println("@Test testPublicLookup");
119 List<Member> mems = publicOnly(Simple.members());
120 Lookup pubLookup = publicLookup(), privLookup = Simple.localLookup();
121 testOnMembers("testPublicLookup/1", mems, pubLookup);
122 // reveal using publicLookup:
123 testOnMembers("testPublicLookup/2", mems, privLookup, pubLookup);
124 // lookup using publicLookup, but reveal using private:
125 testOnMembers("testPublicLookup/3", mems, pubLookup, privLookup);
126 }
127 @Test public void testPublicLookupNegative() throws Throwable {
128 if (VERBOSE) System.out.println("@Test testPublicLookupNegative");
129 List<Member> mems = nonPublicOnly(Simple.members());
130 Lookup pubLookup = publicLookup(), privLookup = Simple.localLookup();
131 testOnMembersNoLookup("testPublicLookupNegative/1", mems, pubLookup);
132 testOnMembersNoReveal("testPublicLookupNegative/2", mems, privLookup, pubLookup);
133 testOnMembersNoReflect("testPublicLookupNegative/3", mems, privLookup, pubLookup);
134 }
135 @Test public void testJavaLangClass() throws Throwable {
136 if (VERBOSE) System.out.println("@Test testJavaLangClass");
137 List<Member> mems = callerSensitive(false, publicOnly(getMembers(Class.class)));
138 mems = limit(20, mems);
139 testOnMembers("testJavaLangClass", mems, Simple.localLookup());
140 }
141 @Test public void testCallerSensitive() throws Throwable {
142 if (VERBOSE) System.out.println("@Test testCallerSensitive");
143 List<Member> mems = union(getMembers(MethodHandles.class, "lookup"),
144 getMembers(Method.class, "invoke"),
145 getMembers(Field.class, "get", "set", "getLong"),
146 getMembers(Class.class));
147 mems = callerSensitive(true, publicOnly(mems));
148 mems = limit(10, mems);
149 testOnMembers("testCallerSensitive", mems, Simple.localLookup());
150 }
151 @Test public void testCallerSensitiveNegative() throws Throwable {
152 if (VERBOSE) System.out.println("@Test testCallerSensitiveNegative");
153 List<Member> mems = union(getMembers(MethodHandles.class, "lookup"),
154 getMembers(Class.class, "forName"),
155 getMembers(Method.class, "invoke"));
156 mems = callerSensitive(true, publicOnly(mems));
157 // CS methods cannot be looked up with publicLookup
jrose8347af82013-10-05 05:30:40 -0700158 testOnMembersNoLookup("testCallerSensitiveNegative/1", mems, publicLookup());
159 // CS methods have to be revealed with a matching lookupClass
160 testOnMembersNoReveal("testCallerSensitiveNegative/2", mems, Simple.localLookup(), publicLookup());
161 testOnMembersNoReveal("testCallerSensitiveNegative/3", mems, Simple.localLookup(), Nestmate.localLookup());
rfield099afec2013-09-03 21:42:56 -0700162 }
163 @Test public void testMethodHandleNatives() throws Throwable {
164 if (VERBOSE) System.out.println("@Test testMethodHandleNatives");
165 List<Member> mems = getMembers(MethodHandle.class, "invoke", "invokeExact");
166 testOnMembers("testMethodHandleNatives", mems, Simple.localLookup());
167 }
168 @Test public void testMethodHandleInvokes() throws Throwable {
169 if (VERBOSE) System.out.println("@Test testMethodHandleInvokes");
170 List<MethodType> types = new ArrayList<>();
171 Class<?>[] someParamTypes = { void.class, int.class, Object.class, Object[].class };
172 for (Class<?> rt : someParamTypes) {
173 for (Class<?> p0 : someParamTypes) {
174 if (p0 == void.class) { types.add(methodType(rt)); continue; }
175 for (Class<?> p1 : someParamTypes) {
176 if (p1 == void.class) { types.add(methodType(rt, p0)); continue; }
177 for (Class<?> p2 : someParamTypes) {
178 if (p2 == void.class) { types.add(methodType(rt, p0, p1)); continue; }
179 types.add(methodType(rt, p0, p1, p2));
180 }
181 }
182 }
183 }
184 List<Member> mems = union(getPolyMembers(MethodHandle.class, "invoke", types),
185 getPolyMembers(MethodHandle.class, "invokeExact", types));
186 testOnMembers("testMethodHandleInvokes/1", mems, Simple.localLookup());
187 testOnMembers("testMethodHandleInvokes/2", mems, publicLookup());
188 }
189
190 static List<Member> getPolyMembers(Class<?> cls, String name, List<MethodType> types) {
191 assert(cls == MethodHandle.class);
192 ArrayList<Member> mems = new ArrayList<>();
193 for (MethodType type : types) {
194 mems.add(new SignaturePolymorphicMethod(name, type));
195 }
196 return mems;
197 }
198 static List<Member> getMembers(Class<?> cls) {
199 return getMembers(cls, (String[]) null);
200 }
201 static List<Member> getMembers(Class<?> cls, String... onlyNames) {
202 List<String> names = (onlyNames == null || onlyNames.length == 0 ? null : Arrays.asList(onlyNames));
203 ArrayList<Member> res = new ArrayList<>();
204 for (Class<?> sup : getSupers(cls)) {
205 res.addAll(getDeclaredMembers(sup, "getDeclaredFields"));
206 res.addAll(getDeclaredMembers(sup, "getDeclaredMethods"));
207 res.addAll(getDeclaredMembers(sup, "getDeclaredConstructors"));
208 }
209 res = new ArrayList<>(new LinkedHashSet<>(res));
210 for (int i = 0; i < res.size(); i++) {
211 Member mem = res.get(i);
212 if (!canBeReached(mem, cls) ||
213 res.indexOf(mem) != i ||
214 mem.isSynthetic() ||
215 (names != null && !names.contains(mem.getName()))
216 ) {
217 res.remove(i--);
218 }
219 }
220 return res;
221 }
222 static List<Class<?>> getSupers(Class<?> cls) {
223 ArrayList<Class<?>> res = new ArrayList<>();
224 ArrayList<Class<?>> intfs = new ArrayList<>();
225 for (Class<?> sup = cls; sup != null; sup = sup.getSuperclass()) {
226 res.add(sup);
227 for (Class<?> intf : cls.getInterfaces()) {
228 if (!intfs.contains(intf))
229 intfs.add(intf);
230 }
231 }
232 for (int i = 0; i < intfs.size(); i++) {
233 for (Class<?> intf : intfs.get(i).getInterfaces()) {
234 if (!intfs.contains(intf))
235 intfs.add(intf);
236 }
237 }
238 res.addAll(intfs);
239 //System.out.println("getSupers => "+res);
240 return res;
241 }
242 static boolean hasSM() {
243 return (System.getSecurityManager() != null);
244 }
245 static List<Member> getDeclaredMembers(Class<?> cls, String accessor) {
246 Member[] mems = {};
247 Method getter = getMethod(Class.class, accessor);
248 if (hasSM()) {
249 try {
250 mems = (Member[]) invokeMethod(getter, cls);
251 } catch (SecurityException ex) {
252 //if (VERBOSE) ex.printStackTrace();
253 accessor = accessor.replace("Declared", "");
254 getter = getMethod(Class.class, accessor);
255 if (VERBOSE) System.out.println("replaced accessor: "+getter);
256 }
257 }
258 if (mems.length == 0) {
259 try {
260 mems = (Member[]) invokeMethod(getter, cls);
261 } catch (SecurityException ex) {
262 ex.printStackTrace();
263 }
264 }
265 if (VERBOSE) System.out.println(accessor+" "+cls.getName()+" => "+mems.length+" members");
266 return Arrays.asList(mems);
267 }
268 static Method getMethod(Class<?> cls, String name) {
269 try {
270 return cls.getMethod(name);
271 } catch (ReflectiveOperationException ex) {
272 throw new AssertionError(ex);
273 }
274 }
275 static Object invokeMethod(Method m, Object recv, Object... args) {
276 try {
277 return m.invoke(recv, args);
278 } catch (InvocationTargetException ex) {
279 Throwable ex2 = ex.getCause();
280 if (ex2 instanceof RuntimeException) throw (RuntimeException) ex2;
281 if (ex2 instanceof Error) throw (Error) ex2;
282 throw new AssertionError(ex);
283 } catch (ReflectiveOperationException ex) {
284 throw new AssertionError(ex);
285 }
286 }
287
288 static List<Member> limit(int len, List<Member> mems) {
289 if (mems.size() <= len) return mems;
290 return mems.subList(0, len);
291 }
292 @SafeVarargs
293 static List<Member> union(List<Member> mems, List<Member>... mem2s) {
294 for (List<Member> mem2 : mem2s) {
295 for (Member m : mem2) {
296 if (!mems.contains(m))
297 mems.add(m);
298 }
299 }
300 return mems;
301 }
302 static List<Member> callerSensitive(boolean cond, List<Member> members) {
303 for (Iterator<Member> i = members.iterator(); i.hasNext(); ) {
304 Member mem = i.next();
305 if (isCallerSensitive(mem) != cond)
306 i.remove();
307 }
308 if (members.isEmpty()) throw new AssertionError("trivial result");
309 return members;
310 }
311 static boolean isCallerSensitive(Member mem) {
312 if (!(mem instanceof AnnotatedElement)) return false;
313 AnnotatedElement ae = (AnnotatedElement) mem;
314 if (CS_CLASS != null)
315 return ae.isAnnotationPresent(sun.reflect.CallerSensitive.class);
316 for (java.lang.annotation.Annotation a : ae.getDeclaredAnnotations()) {
317 if (a.toString().contains(".CallerSensitive"))
318 return true;
319 }
320 return false;
321 }
322 static final Class<?> CS_CLASS;
323 static {
324 Class<?> c = null;
325 try {
326 c = sun.reflect.CallerSensitive.class;
327 } catch (SecurityException | LinkageError ex) {
328 }
329 CS_CLASS = c;
330 }
331 static List<Member> publicOnly(List<Member> members) {
332 return removeMods(members, Modifier.PUBLIC, 0);
333 }
334 static List<Member> nonPublicOnly(List<Member> members) {
335 return removeMods(members, Modifier.PUBLIC, -1);
336 }
337 static List<Member> removeMods(List<Member> members, int mask, int bits) {
338 int publicMods = (mask & Modifier.PUBLIC);
339 members = new ArrayList<>(members);
340 for (Iterator<Member> i = members.iterator(); i.hasNext(); ) {
341 Member mem = i.next();
342 int mods = mem.getModifiers();
343 if ((publicMods & mods) != 0 &&
344 (publicMods & mem.getDeclaringClass().getModifiers()) == 0)
345 mods -= publicMods;
346 if ((mods & mask) == (bits & mask))
347 i.remove();
348 }
349 return members;
350 }
351
352 void testOnMembers(String tname, List<Member> mems, Lookup lookup, Lookup... lookups) throws Throwable {
353 if (VERBOSE) System.out.println("testOnMembers "+mems);
354 Lookup revLookup = (lookups.length > 0) ? lookups[0] : null;
355 if (revLookup == null) revLookup = lookup;
356 Lookup refLookup = (lookups.length > 1) ? lookups[1] : null;
357 if (refLookup == null) refLookup = lookup;
358 assert(lookups.length <= 2);
359 testOnMembersImpl(tname, mems, lookup, revLookup, refLookup, NO_FAIL);
360 }
361 void testOnMembersNoLookup(String tname, List<Member> mems, Lookup lookup) throws Throwable {
362 if (VERBOSE) System.out.println("testOnMembersNoLookup "+mems);
363 testOnMembersImpl(tname, mems, lookup, null, null, FAIL_LOOKUP);
364 }
365 void testOnMembersNoReveal(String tname, List<Member> mems,
366 Lookup lookup, Lookup negLookup) throws Throwable {
367 if (VERBOSE) System.out.println("testOnMembersNoReveal "+mems);
368 testOnMembersImpl(tname, mems, lookup, negLookup, null, FAIL_REVEAL);
369 }
370 void testOnMembersNoReflect(String tname, List<Member> mems,
371 Lookup lookup, Lookup negLookup) throws Throwable {
372 if (VERBOSE) System.out.println("testOnMembersNoReflect "+mems);
373 testOnMembersImpl(tname, mems, lookup, lookup, negLookup, FAIL_REFLECT);
374 }
375 void testOnMembersImpl(String tname, List<Member> mems,
376 Lookup lookup,
377 Lookup revLookup,
378 Lookup refLookup,
379 int failureMode) throws Throwable {
380 Throwable fail = null;
381 int failCount = 0;
382 failureModeCounts = new int[FAIL_MODE_COUNT];
383 long tm0 = System.currentTimeMillis();
384 for (Member mem : mems) {
385 try {
386 testWithMember(mem, lookup, revLookup, refLookup, failureMode);
387 } catch (Throwable ex) {
388 if (fail == null) fail = ex;
389 if (++failCount > 10) { System.out.println("*** FAIL: too many failures"); break; }
390 System.out.println("*** FAIL: "+mem+" => "+ex);
391 if (VERBOSE) ex.printStackTrace(System.out);
392 }
393 }
394 long tm1 = System.currentTimeMillis();
395 System.out.printf("@Test %s executed %s tests in %d ms",
396 tname, testKinds(failureModeCounts), (tm1-tm0)).println();
397 if (fail != null) throw fail;
398 }
399 static String testKinds(int[] modes) {
400 int pos = modes[0], neg = -pos;
401 for (int n : modes) neg += n;
402 if (neg == 0) return pos + " positive";
403 String negs = "";
404 for (int n : modes) negs += "/"+n;
405 negs = negs.replaceFirst("/"+pos+"/", "");
406 negs += " negative";
407 if (pos == 0) return negs;
408 return pos + " positive, " + negs;
409 }
410 static class SignaturePolymorphicMethod implements Member { // non-reflected instance of MH.invoke*
411 final String name;
412 final MethodType type;
413 SignaturePolymorphicMethod(String name, MethodType type) {
414 this.name = name;
415 this.type = type;
416 }
417 public String toString() {
418 String typeStr = type.toString();
419 if (isVarArgs()) typeStr = typeStr.replaceFirst("\\[\\])$", "...)");
420 return (Modifier.toString(getModifiers())
421 +typeStr.substring(0, typeStr.indexOf('('))+" "
422 +getDeclaringClass().getTypeName()+"."
423 +getName()+typeStr.substring(typeStr.indexOf('(')));
424 }
425 public boolean equals(Object x) {
426 return (x instanceof SignaturePolymorphicMethod && equals((SignaturePolymorphicMethod)x));
427 }
428 public boolean equals(SignaturePolymorphicMethod that) {
429 return this.name.equals(that.name) && this.type.equals(that.type);
430 }
431 public int hashCode() {
432 return name.hashCode() * 31 + type.hashCode();
433 }
434 public Class<?> getDeclaringClass() { return MethodHandle.class; }
435 public String getName() { return name; }
436 public MethodType getMethodType() { return type; }
437 public int getModifiers() { return Modifier.PUBLIC | Modifier.FINAL | Modifier.NATIVE | SYNTHETIC; }
438 public boolean isVarArgs() { return Modifier.isTransient(getModifiers()); }
439 public boolean isSynthetic() { return true; }
440 public Class<?> getReturnType() { return type.returnType(); }
441 public Class<?>[] getParameterTypes() { return type.parameterArray(); }
442 static final int SYNTHETIC = 0x00001000;
443 }
444 static class UnreflectResult { // a tuple
445 final MethodHandle mh;
446 final Throwable ex;
447 final byte kind;
448 final Member mem;
449 final int var;
450 UnreflectResult(MethodHandle mh, byte kind, Member mem, int var) {
451 this.mh = mh;
452 this.ex = null;
453 this.kind = kind;
454 this.mem = mem;
455 this.var = var;
456 }
457 UnreflectResult(Throwable ex, byte kind, Member mem, int var) {
458 this.mh = null;
459 this.ex = ex;
460 this.kind = kind;
461 this.mem = mem;
462 this.var = var;
463 }
464 public String toString() {
465 return toInfoString()+"/v"+var;
466 }
467 public String toInfoString() {
468 return String.format("%s %s.%s:%s", MethodHandleInfo.referenceKindToString(kind),
469 mem.getDeclaringClass().getName(), name(mem), type(mem, kind));
470 }
471 static String name(Member mem) {
472 if (mem instanceof Constructor) return "<init>";
473 return mem.getName();
474 }
475 static MethodType type(Member mem, byte kind) {
476 if (mem instanceof Field) {
477 Class<?> type = ((Field)mem).getType();
478 if (kind == REF_putStatic || kind == REF_putField)
479 return methodType(void.class, type);
480 return methodType(type);
481 } else if (mem instanceof SignaturePolymorphicMethod) {
482 return ((SignaturePolymorphicMethod)mem).getMethodType();
483 }
484 Class<?>[] params = ((Executable)mem).getParameterTypes();
485 if (mem instanceof Constructor)
486 return methodType(void.class, params);
487 Class<?> type = ((Method)mem).getReturnType();
488 return methodType(type, params);
489 }
490 }
491 static UnreflectResult unreflectMember(Lookup lookup, Member mem, int variation) {
492 byte[] refKind = {0};
493 try {
494 return unreflectMemberOrThrow(lookup, mem, variation, refKind);
495 } catch (ReflectiveOperationException|SecurityException ex) {
496 return new UnreflectResult(ex, refKind[0], mem, variation);
497 }
498 }
499 static UnreflectResult unreflectMemberOrThrow(Lookup lookup, Member mem, int variation,
500 byte[] refKind) throws ReflectiveOperationException {
501 Class<?> cls = lookup.lookupClass();
502 Class<?> defc = mem.getDeclaringClass();
503 String name = mem.getName();
504 int mods = mem.getModifiers();
505 boolean isStatic = Modifier.isStatic(mods);
506 MethodHandle mh = null;
507 byte kind = 0;
508 if (mem instanceof Method) {
509 Method m = (Method) mem;
510 MethodType type = methodType(m.getReturnType(), m.getParameterTypes());
511 boolean canBeSpecial = (!isStatic &&
512 (lookup.lookupModes() & Modifier.PRIVATE) != 0 &&
513 defc.isAssignableFrom(cls) &&
514 (!defc.isInterface() || Arrays.asList(cls.getInterfaces()).contains(defc)));
515 if (variation >= 2)
516 kind = REF_invokeSpecial;
517 else if (isStatic)
518 kind = REF_invokeStatic;
519 else if (defc.isInterface())
520 kind = REF_invokeInterface;
521 else
522 kind = REF_invokeVirtual;
523 refKind[0] = kind;
524 switch (variation) {
525 case 0:
526 mh = lookup.unreflect(m);
527 break;
528 case 1:
529 if (defc == MethodHandle.class &&
530 !isStatic &&
531 m.isVarArgs() &&
532 Modifier.isFinal(mods) &&
533 Modifier.isNative(mods)) {
534 break;
535 }
536 if (isStatic)
537 mh = lookup.findStatic(defc, name, type);
538 else
539 mh = lookup.findVirtual(defc, name, type);
540 break;
541 case 2:
542 if (!canBeSpecial)
543 break;
544 mh = lookup.unreflectSpecial(m, lookup.lookupClass());
545 break;
546 case 3:
547 if (!canBeSpecial)
548 break;
549 mh = lookup.findSpecial(defc, name, type, lookup.lookupClass());
550 break;
551 }
552 } else if (mem instanceof SignaturePolymorphicMethod) {
553 SignaturePolymorphicMethod m = (SignaturePolymorphicMethod) mem;
554 MethodType type = methodType(m.getReturnType(), m.getParameterTypes());
555 kind = REF_invokeVirtual;
556 refKind[0] = kind;
557 switch (variation) {
558 case 0:
559 mh = lookup.findVirtual(defc, name, type);
560 break;
561 }
562 } else if (mem instanceof Constructor) {
563 name = "<init>"; // not used
564 Constructor<?> m = (Constructor<?>) mem;
565 MethodType type = methodType(void.class, m.getParameterTypes());
566 kind = REF_newInvokeSpecial;
567 refKind[0] = kind;
568 switch (variation) {
569 case 0:
570 mh = lookup.unreflectConstructor(m);
571 break;
572 case 1:
573 mh = lookup.findConstructor(defc, type);
574 break;
575 }
576 } else if (mem instanceof Field) {
577 Field m = (Field) mem;
578 Class<?> type = m.getType();
579 boolean canHaveSetter = !Modifier.isFinal(mods);
580 if (variation >= 2)
581 kind = (byte)(isStatic ? REF_putStatic : REF_putField);
582 else
583 kind = (byte)(isStatic ? REF_getStatic : REF_getField);
584 refKind[0] = kind;
585 switch (variation) {
586 case 0:
587 mh = lookup.unreflectGetter(m);
588 break;
589 case 1:
590 if (isStatic)
591 mh = lookup.findStaticGetter(defc, name, type);
592 else
593 mh = lookup.findGetter(defc, name, type);
594 break;
595 case 3:
596 if (!canHaveSetter)
597 break;
598 mh = lookup.unreflectSetter(m);
599 break;
600 case 2:
601 if (!canHaveSetter)
602 break;
603 if (isStatic)
604 mh = lookup.findStaticSetter(defc, name, type);
605 else
606 mh = lookup.findSetter(defc, name, type);
607 break;
608 }
609 } else {
610 throw new IllegalArgumentException(String.valueOf(mem));
611 }
612 if (mh == null)
613 // ran out of valid variations; return null to caller
614 return null;
615 return new UnreflectResult(mh, kind, mem, variation);
616 }
617 static boolean canBeReached(Member mem, Class<?> cls) {
618 Class<?> defc = mem.getDeclaringClass();
619 String name = mem.getName();
620 int mods = mem.getModifiers();
621 if (mem instanceof Constructor) {
622 name = "<init>"; // according to 292 spec.
623 }
624 if (defc == cls)
625 return true;
626 if (name.startsWith("<"))
627 return false; // only my own constructors
628 if (Modifier.isPrivate(mods))
629 return false; // only my own constructors
630 if (defc.getPackage() == cls.getPackage())
631 return true; // package access or greater OK
632 if (Modifier.isPublic(mods))
633 return true; // publics always OK
634 if (Modifier.isProtected(mods) && defc.isAssignableFrom(cls))
635 return true; // protected OK
636 return false;
637 }
638 static boolean consistent(UnreflectResult res, MethodHandleInfo info) {
639 assert(res.mh != null);
640 assertEquals(res.kind, info.getReferenceKind());
641 assertEquals(res.mem.getModifiers(), info.getModifiers());
642 assertEquals(res.mem.getDeclaringClass(), info.getDeclaringClass());
643 String expectName = res.mem.getName();
644 if (res.kind == REF_newInvokeSpecial)
645 expectName = "<init>";
646 assertEquals(expectName, info.getName());
647 MethodType expectType = res.mh.type();
648 if ((res.kind & 1) == (REF_getField & 1))
649 expectType = expectType.dropParameterTypes(0, 1);
650 if (res.kind == REF_newInvokeSpecial)
651 expectType = expectType.changeReturnType(void.class);
652 assertEquals(expectType, info.getMethodType());
653 assertEquals(res.mh.isVarargsCollector(), isVarArgs(info));
654 assertEquals(res.toInfoString(), info.toString());
655 assertEquals(res.toInfoString(), MethodHandleInfo.toString(info.getReferenceKind(), info.getDeclaringClass(), info.getName(), info.getMethodType()));
656 return true;
657 }
658 static boolean isVarArgs(MethodHandleInfo info) {
659 return info.isVarArgs();
660 }
661 static boolean consistent(Member mem, Member mem2) {
662 assertEquals(mem, mem2);
663 return true;
664 }
665 static boolean consistent(MethodHandleInfo info, MethodHandleInfo info2) {
666 assertEquals(info.getReferenceKind(), info2.getReferenceKind());
667 assertEquals(info.getModifiers(), info2.getModifiers());
668 assertEquals(info.getDeclaringClass(), info2.getDeclaringClass());
669 assertEquals(info.getName(), info2.getName());
670 assertEquals(info.getMethodType(), info2.getMethodType());
671 assertEquals(isVarArgs(info), isVarArgs(info));
672 return true;
673 }
674 static boolean consistent(MethodHandle mh, MethodHandle mh2) {
675 assertEquals(mh.type(), mh2.type());
676 assertEquals(mh.isVarargsCollector(), mh2.isVarargsCollector());
677 return true;
678 }
679 int[] failureModeCounts;
680 static final int NO_FAIL=0, FAIL_LOOKUP=1, FAIL_REVEAL=2, FAIL_REFLECT=3, FAIL_MODE_COUNT=4;
681 void testWithMember(Member mem,
682 Lookup lookup, // initial lookup of member => MH
683 Lookup revLookup, // reveal MH => info
684 Lookup refLookup, // reflect info => member
685 int failureMode) throws Throwable {
686 boolean expectEx1 = (failureMode == FAIL_LOOKUP); // testOnMembersNoLookup
687 boolean expectEx2 = (failureMode == FAIL_REVEAL); // testOnMembersNoReveal
688 boolean expectEx3 = (failureMode == FAIL_REFLECT); // testOnMembersNoReflect
689 for (int variation = 0; ; variation++) {
690 UnreflectResult res = unreflectMember(lookup, mem, variation);
691 failureModeCounts[failureMode] += 1;
692 if (variation == 0) assert(res != null);
693 if (res == null) break;
694 if (VERBOSE && variation == 0)
695 System.out.println("from "+mem.getDeclaringClass().getSimpleName());
696 MethodHandle mh = res.mh;
697 Throwable ex1 = res.ex;
698 if (VERBOSE) System.out.println(" "+variation+": "+res+" << "+(mh != null ? mh : ex1));
699 if (expectEx1 && ex1 != null)
700 continue; // this is OK; we expected that lookup to fail
701 if (expectEx1)
702 throw new AssertionError("unexpected lookup for negative test");
703 if (ex1 != null && !expectEx1) {
704 if (failureMode != NO_FAIL)
705 throw new AssertionError("unexpected lookup failure for negative test", ex1);
706 throw ex1;
707 }
708 MethodHandleInfo info;
709 try {
710 info = revLookup.revealDirect(mh);
711 if (expectEx2) throw new AssertionError("unexpected revelation for negative test");
jrose8347af82013-10-05 05:30:40 -0700712 } catch (IllegalArgumentException|SecurityException ex2) {
rfield099afec2013-09-03 21:42:56 -0700713 if (VERBOSE) System.out.println(" "+variation+": "+res+" => "+mh.getClass().getName()+" => (EX2)"+ex2);
714 if (expectEx2)
715 continue; // this is OK; we expected the reflect to fail
716 if (failureMode != NO_FAIL)
717 throw new AssertionError("unexpected revelation failure for negative test", ex2);
718 throw ex2;
719 }
720 assert(consistent(res, info));
721 Member mem2;
722 try {
723 mem2 = info.reflectAs(Member.class, refLookup);
724 if (expectEx3) throw new AssertionError("unexpected reflection for negative test");
725 assert(!(mem instanceof SignaturePolymorphicMethod));
726 } catch (IllegalArgumentException ex3) {
727 if (VERBOSE) System.out.println(" "+variation+": "+info+" => (EX3)"+ex3);
728 if (expectEx3)
729 continue; // this is OK; we expected the reflect to fail
730 if (mem instanceof SignaturePolymorphicMethod)
731 continue; // this is OK; we cannot reflect MH.invokeExact(a,b,c)
732 if (failureMode != NO_FAIL)
733 throw new AssertionError("unexpected reflection failure for negative test", ex3);
734 throw ex3;
735 }
736 assert(consistent(mem, mem2));
737 UnreflectResult res2 = unreflectMember(lookup, mem2, variation);
738 MethodHandle mh2 = res2.mh;
739 assert(consistent(mh, mh2));
740 MethodHandleInfo info2 = lookup.revealDirect(mh2);
741 assert(consistent(info, info2));
742 assert(consistent(res, info2));
743 Member mem3;
744 if (hasSM())
745 mem3 = info2.reflectAs(Member.class, lookup);
746 else
747 mem3 = MethodHandles.reflectAs(Member.class, mh2);
748 assert(consistent(mem2, mem3));
749 if (hasSM()) {
750 try {
751 MethodHandles.reflectAs(Member.class, mh2);
752 throw new AssertionError("failed to throw on "+mem3);
753 } catch (SecurityException ex3) {
754 // OK...
755 }
756 }
757 }
758 }
759}