blob: f05b19077c112aa5792634c20c92e9642a8cf889 [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 }
107
108 static boolean VERBOSE = false;
109
110 @Test public void testSimple() throws Throwable {
111 if (VERBOSE) System.out.println("@Test testSimple");
112 testOnMembers("testSimple", Simple.members(), Simple.localLookup());
113 }
114 @Test public void testPublicLookup() throws Throwable {
115 if (VERBOSE) System.out.println("@Test testPublicLookup");
116 List<Member> mems = publicOnly(Simple.members());
117 Lookup pubLookup = publicLookup(), privLookup = Simple.localLookup();
118 testOnMembers("testPublicLookup/1", mems, pubLookup);
119 // reveal using publicLookup:
120 testOnMembers("testPublicLookup/2", mems, privLookup, pubLookup);
121 // lookup using publicLookup, but reveal using private:
122 testOnMembers("testPublicLookup/3", mems, pubLookup, privLookup);
123 }
124 @Test public void testPublicLookupNegative() throws Throwable {
125 if (VERBOSE) System.out.println("@Test testPublicLookupNegative");
126 List<Member> mems = nonPublicOnly(Simple.members());
127 Lookup pubLookup = publicLookup(), privLookup = Simple.localLookup();
128 testOnMembersNoLookup("testPublicLookupNegative/1", mems, pubLookup);
129 testOnMembersNoReveal("testPublicLookupNegative/2", mems, privLookup, pubLookup);
130 testOnMembersNoReflect("testPublicLookupNegative/3", mems, privLookup, pubLookup);
131 }
132 @Test public void testJavaLangClass() throws Throwable {
133 if (VERBOSE) System.out.println("@Test testJavaLangClass");
134 List<Member> mems = callerSensitive(false, publicOnly(getMembers(Class.class)));
135 mems = limit(20, mems);
136 testOnMembers("testJavaLangClass", mems, Simple.localLookup());
137 }
138 @Test public void testCallerSensitive() throws Throwable {
139 if (VERBOSE) System.out.println("@Test testCallerSensitive");
140 List<Member> mems = union(getMembers(MethodHandles.class, "lookup"),
141 getMembers(Method.class, "invoke"),
142 getMembers(Field.class, "get", "set", "getLong"),
143 getMembers(Class.class));
144 mems = callerSensitive(true, publicOnly(mems));
145 mems = limit(10, mems);
146 testOnMembers("testCallerSensitive", mems, Simple.localLookup());
147 }
148 @Test public void testCallerSensitiveNegative() throws Throwable {
149 if (VERBOSE) System.out.println("@Test testCallerSensitiveNegative");
150 List<Member> mems = union(getMembers(MethodHandles.class, "lookup"),
151 getMembers(Class.class, "forName"),
152 getMembers(Method.class, "invoke"));
153 mems = callerSensitive(true, publicOnly(mems));
154 // CS methods cannot be looked up with publicLookup
155 testOnMembersNoLookup("testCallerSensitiveNegative", mems, publicLookup());
156 }
157 @Test public void testMethodHandleNatives() throws Throwable {
158 if (VERBOSE) System.out.println("@Test testMethodHandleNatives");
159 List<Member> mems = getMembers(MethodHandle.class, "invoke", "invokeExact");
160 testOnMembers("testMethodHandleNatives", mems, Simple.localLookup());
161 }
162 @Test public void testMethodHandleInvokes() throws Throwable {
163 if (VERBOSE) System.out.println("@Test testMethodHandleInvokes");
164 List<MethodType> types = new ArrayList<>();
165 Class<?>[] someParamTypes = { void.class, int.class, Object.class, Object[].class };
166 for (Class<?> rt : someParamTypes) {
167 for (Class<?> p0 : someParamTypes) {
168 if (p0 == void.class) { types.add(methodType(rt)); continue; }
169 for (Class<?> p1 : someParamTypes) {
170 if (p1 == void.class) { types.add(methodType(rt, p0)); continue; }
171 for (Class<?> p2 : someParamTypes) {
172 if (p2 == void.class) { types.add(methodType(rt, p0, p1)); continue; }
173 types.add(methodType(rt, p0, p1, p2));
174 }
175 }
176 }
177 }
178 List<Member> mems = union(getPolyMembers(MethodHandle.class, "invoke", types),
179 getPolyMembers(MethodHandle.class, "invokeExact", types));
180 testOnMembers("testMethodHandleInvokes/1", mems, Simple.localLookup());
181 testOnMembers("testMethodHandleInvokes/2", mems, publicLookup());
182 }
183
184 static List<Member> getPolyMembers(Class<?> cls, String name, List<MethodType> types) {
185 assert(cls == MethodHandle.class);
186 ArrayList<Member> mems = new ArrayList<>();
187 for (MethodType type : types) {
188 mems.add(new SignaturePolymorphicMethod(name, type));
189 }
190 return mems;
191 }
192 static List<Member> getMembers(Class<?> cls) {
193 return getMembers(cls, (String[]) null);
194 }
195 static List<Member> getMembers(Class<?> cls, String... onlyNames) {
196 List<String> names = (onlyNames == null || onlyNames.length == 0 ? null : Arrays.asList(onlyNames));
197 ArrayList<Member> res = new ArrayList<>();
198 for (Class<?> sup : getSupers(cls)) {
199 res.addAll(getDeclaredMembers(sup, "getDeclaredFields"));
200 res.addAll(getDeclaredMembers(sup, "getDeclaredMethods"));
201 res.addAll(getDeclaredMembers(sup, "getDeclaredConstructors"));
202 }
203 res = new ArrayList<>(new LinkedHashSet<>(res));
204 for (int i = 0; i < res.size(); i++) {
205 Member mem = res.get(i);
206 if (!canBeReached(mem, cls) ||
207 res.indexOf(mem) != i ||
208 mem.isSynthetic() ||
209 (names != null && !names.contains(mem.getName()))
210 ) {
211 res.remove(i--);
212 }
213 }
214 return res;
215 }
216 static List<Class<?>> getSupers(Class<?> cls) {
217 ArrayList<Class<?>> res = new ArrayList<>();
218 ArrayList<Class<?>> intfs = new ArrayList<>();
219 for (Class<?> sup = cls; sup != null; sup = sup.getSuperclass()) {
220 res.add(sup);
221 for (Class<?> intf : cls.getInterfaces()) {
222 if (!intfs.contains(intf))
223 intfs.add(intf);
224 }
225 }
226 for (int i = 0; i < intfs.size(); i++) {
227 for (Class<?> intf : intfs.get(i).getInterfaces()) {
228 if (!intfs.contains(intf))
229 intfs.add(intf);
230 }
231 }
232 res.addAll(intfs);
233 //System.out.println("getSupers => "+res);
234 return res;
235 }
236 static boolean hasSM() {
237 return (System.getSecurityManager() != null);
238 }
239 static List<Member> getDeclaredMembers(Class<?> cls, String accessor) {
240 Member[] mems = {};
241 Method getter = getMethod(Class.class, accessor);
242 if (hasSM()) {
243 try {
244 mems = (Member[]) invokeMethod(getter, cls);
245 } catch (SecurityException ex) {
246 //if (VERBOSE) ex.printStackTrace();
247 accessor = accessor.replace("Declared", "");
248 getter = getMethod(Class.class, accessor);
249 if (VERBOSE) System.out.println("replaced accessor: "+getter);
250 }
251 }
252 if (mems.length == 0) {
253 try {
254 mems = (Member[]) invokeMethod(getter, cls);
255 } catch (SecurityException ex) {
256 ex.printStackTrace();
257 }
258 }
259 if (VERBOSE) System.out.println(accessor+" "+cls.getName()+" => "+mems.length+" members");
260 return Arrays.asList(mems);
261 }
262 static Method getMethod(Class<?> cls, String name) {
263 try {
264 return cls.getMethod(name);
265 } catch (ReflectiveOperationException ex) {
266 throw new AssertionError(ex);
267 }
268 }
269 static Object invokeMethod(Method m, Object recv, Object... args) {
270 try {
271 return m.invoke(recv, args);
272 } catch (InvocationTargetException ex) {
273 Throwable ex2 = ex.getCause();
274 if (ex2 instanceof RuntimeException) throw (RuntimeException) ex2;
275 if (ex2 instanceof Error) throw (Error) ex2;
276 throw new AssertionError(ex);
277 } catch (ReflectiveOperationException ex) {
278 throw new AssertionError(ex);
279 }
280 }
281
282 static List<Member> limit(int len, List<Member> mems) {
283 if (mems.size() <= len) return mems;
284 return mems.subList(0, len);
285 }
286 @SafeVarargs
287 static List<Member> union(List<Member> mems, List<Member>... mem2s) {
288 for (List<Member> mem2 : mem2s) {
289 for (Member m : mem2) {
290 if (!mems.contains(m))
291 mems.add(m);
292 }
293 }
294 return mems;
295 }
296 static List<Member> callerSensitive(boolean cond, List<Member> members) {
297 for (Iterator<Member> i = members.iterator(); i.hasNext(); ) {
298 Member mem = i.next();
299 if (isCallerSensitive(mem) != cond)
300 i.remove();
301 }
302 if (members.isEmpty()) throw new AssertionError("trivial result");
303 return members;
304 }
305 static boolean isCallerSensitive(Member mem) {
306 if (!(mem instanceof AnnotatedElement)) return false;
307 AnnotatedElement ae = (AnnotatedElement) mem;
308 if (CS_CLASS != null)
309 return ae.isAnnotationPresent(sun.reflect.CallerSensitive.class);
310 for (java.lang.annotation.Annotation a : ae.getDeclaredAnnotations()) {
311 if (a.toString().contains(".CallerSensitive"))
312 return true;
313 }
314 return false;
315 }
316 static final Class<?> CS_CLASS;
317 static {
318 Class<?> c = null;
319 try {
320 c = sun.reflect.CallerSensitive.class;
321 } catch (SecurityException | LinkageError ex) {
322 }
323 CS_CLASS = c;
324 }
325 static List<Member> publicOnly(List<Member> members) {
326 return removeMods(members, Modifier.PUBLIC, 0);
327 }
328 static List<Member> nonPublicOnly(List<Member> members) {
329 return removeMods(members, Modifier.PUBLIC, -1);
330 }
331 static List<Member> removeMods(List<Member> members, int mask, int bits) {
332 int publicMods = (mask & Modifier.PUBLIC);
333 members = new ArrayList<>(members);
334 for (Iterator<Member> i = members.iterator(); i.hasNext(); ) {
335 Member mem = i.next();
336 int mods = mem.getModifiers();
337 if ((publicMods & mods) != 0 &&
338 (publicMods & mem.getDeclaringClass().getModifiers()) == 0)
339 mods -= publicMods;
340 if ((mods & mask) == (bits & mask))
341 i.remove();
342 }
343 return members;
344 }
345
346 void testOnMembers(String tname, List<Member> mems, Lookup lookup, Lookup... lookups) throws Throwable {
347 if (VERBOSE) System.out.println("testOnMembers "+mems);
348 Lookup revLookup = (lookups.length > 0) ? lookups[0] : null;
349 if (revLookup == null) revLookup = lookup;
350 Lookup refLookup = (lookups.length > 1) ? lookups[1] : null;
351 if (refLookup == null) refLookup = lookup;
352 assert(lookups.length <= 2);
353 testOnMembersImpl(tname, mems, lookup, revLookup, refLookup, NO_FAIL);
354 }
355 void testOnMembersNoLookup(String tname, List<Member> mems, Lookup lookup) throws Throwable {
356 if (VERBOSE) System.out.println("testOnMembersNoLookup "+mems);
357 testOnMembersImpl(tname, mems, lookup, null, null, FAIL_LOOKUP);
358 }
359 void testOnMembersNoReveal(String tname, List<Member> mems,
360 Lookup lookup, Lookup negLookup) throws Throwable {
361 if (VERBOSE) System.out.println("testOnMembersNoReveal "+mems);
362 testOnMembersImpl(tname, mems, lookup, negLookup, null, FAIL_REVEAL);
363 }
364 void testOnMembersNoReflect(String tname, List<Member> mems,
365 Lookup lookup, Lookup negLookup) throws Throwable {
366 if (VERBOSE) System.out.println("testOnMembersNoReflect "+mems);
367 testOnMembersImpl(tname, mems, lookup, lookup, negLookup, FAIL_REFLECT);
368 }
369 void testOnMembersImpl(String tname, List<Member> mems,
370 Lookup lookup,
371 Lookup revLookup,
372 Lookup refLookup,
373 int failureMode) throws Throwable {
374 Throwable fail = null;
375 int failCount = 0;
376 failureModeCounts = new int[FAIL_MODE_COUNT];
377 long tm0 = System.currentTimeMillis();
378 for (Member mem : mems) {
379 try {
380 testWithMember(mem, lookup, revLookup, refLookup, failureMode);
381 } catch (Throwable ex) {
382 if (fail == null) fail = ex;
383 if (++failCount > 10) { System.out.println("*** FAIL: too many failures"); break; }
384 System.out.println("*** FAIL: "+mem+" => "+ex);
385 if (VERBOSE) ex.printStackTrace(System.out);
386 }
387 }
388 long tm1 = System.currentTimeMillis();
389 System.out.printf("@Test %s executed %s tests in %d ms",
390 tname, testKinds(failureModeCounts), (tm1-tm0)).println();
391 if (fail != null) throw fail;
392 }
393 static String testKinds(int[] modes) {
394 int pos = modes[0], neg = -pos;
395 for (int n : modes) neg += n;
396 if (neg == 0) return pos + " positive";
397 String negs = "";
398 for (int n : modes) negs += "/"+n;
399 negs = negs.replaceFirst("/"+pos+"/", "");
400 negs += " negative";
401 if (pos == 0) return negs;
402 return pos + " positive, " + negs;
403 }
404 static class SignaturePolymorphicMethod implements Member { // non-reflected instance of MH.invoke*
405 final String name;
406 final MethodType type;
407 SignaturePolymorphicMethod(String name, MethodType type) {
408 this.name = name;
409 this.type = type;
410 }
411 public String toString() {
412 String typeStr = type.toString();
413 if (isVarArgs()) typeStr = typeStr.replaceFirst("\\[\\])$", "...)");
414 return (Modifier.toString(getModifiers())
415 +typeStr.substring(0, typeStr.indexOf('('))+" "
416 +getDeclaringClass().getTypeName()+"."
417 +getName()+typeStr.substring(typeStr.indexOf('(')));
418 }
419 public boolean equals(Object x) {
420 return (x instanceof SignaturePolymorphicMethod && equals((SignaturePolymorphicMethod)x));
421 }
422 public boolean equals(SignaturePolymorphicMethod that) {
423 return this.name.equals(that.name) && this.type.equals(that.type);
424 }
425 public int hashCode() {
426 return name.hashCode() * 31 + type.hashCode();
427 }
428 public Class<?> getDeclaringClass() { return MethodHandle.class; }
429 public String getName() { return name; }
430 public MethodType getMethodType() { return type; }
431 public int getModifiers() { return Modifier.PUBLIC | Modifier.FINAL | Modifier.NATIVE | SYNTHETIC; }
432 public boolean isVarArgs() { return Modifier.isTransient(getModifiers()); }
433 public boolean isSynthetic() { return true; }
434 public Class<?> getReturnType() { return type.returnType(); }
435 public Class<?>[] getParameterTypes() { return type.parameterArray(); }
436 static final int SYNTHETIC = 0x00001000;
437 }
438 static class UnreflectResult { // a tuple
439 final MethodHandle mh;
440 final Throwable ex;
441 final byte kind;
442 final Member mem;
443 final int var;
444 UnreflectResult(MethodHandle mh, byte kind, Member mem, int var) {
445 this.mh = mh;
446 this.ex = null;
447 this.kind = kind;
448 this.mem = mem;
449 this.var = var;
450 }
451 UnreflectResult(Throwable ex, byte kind, Member mem, int var) {
452 this.mh = null;
453 this.ex = ex;
454 this.kind = kind;
455 this.mem = mem;
456 this.var = var;
457 }
458 public String toString() {
459 return toInfoString()+"/v"+var;
460 }
461 public String toInfoString() {
462 return String.format("%s %s.%s:%s", MethodHandleInfo.referenceKindToString(kind),
463 mem.getDeclaringClass().getName(), name(mem), type(mem, kind));
464 }
465 static String name(Member mem) {
466 if (mem instanceof Constructor) return "<init>";
467 return mem.getName();
468 }
469 static MethodType type(Member mem, byte kind) {
470 if (mem instanceof Field) {
471 Class<?> type = ((Field)mem).getType();
472 if (kind == REF_putStatic || kind == REF_putField)
473 return methodType(void.class, type);
474 return methodType(type);
475 } else if (mem instanceof SignaturePolymorphicMethod) {
476 return ((SignaturePolymorphicMethod)mem).getMethodType();
477 }
478 Class<?>[] params = ((Executable)mem).getParameterTypes();
479 if (mem instanceof Constructor)
480 return methodType(void.class, params);
481 Class<?> type = ((Method)mem).getReturnType();
482 return methodType(type, params);
483 }
484 }
485 static UnreflectResult unreflectMember(Lookup lookup, Member mem, int variation) {
486 byte[] refKind = {0};
487 try {
488 return unreflectMemberOrThrow(lookup, mem, variation, refKind);
489 } catch (ReflectiveOperationException|SecurityException ex) {
490 return new UnreflectResult(ex, refKind[0], mem, variation);
491 }
492 }
493 static UnreflectResult unreflectMemberOrThrow(Lookup lookup, Member mem, int variation,
494 byte[] refKind) throws ReflectiveOperationException {
495 Class<?> cls = lookup.lookupClass();
496 Class<?> defc = mem.getDeclaringClass();
497 String name = mem.getName();
498 int mods = mem.getModifiers();
499 boolean isStatic = Modifier.isStatic(mods);
500 MethodHandle mh = null;
501 byte kind = 0;
502 if (mem instanceof Method) {
503 Method m = (Method) mem;
504 MethodType type = methodType(m.getReturnType(), m.getParameterTypes());
505 boolean canBeSpecial = (!isStatic &&
506 (lookup.lookupModes() & Modifier.PRIVATE) != 0 &&
507 defc.isAssignableFrom(cls) &&
508 (!defc.isInterface() || Arrays.asList(cls.getInterfaces()).contains(defc)));
509 if (variation >= 2)
510 kind = REF_invokeSpecial;
511 else if (isStatic)
512 kind = REF_invokeStatic;
513 else if (defc.isInterface())
514 kind = REF_invokeInterface;
515 else
516 kind = REF_invokeVirtual;
517 refKind[0] = kind;
518 switch (variation) {
519 case 0:
520 mh = lookup.unreflect(m);
521 break;
522 case 1:
523 if (defc == MethodHandle.class &&
524 !isStatic &&
525 m.isVarArgs() &&
526 Modifier.isFinal(mods) &&
527 Modifier.isNative(mods)) {
528 break;
529 }
530 if (isStatic)
531 mh = lookup.findStatic(defc, name, type);
532 else
533 mh = lookup.findVirtual(defc, name, type);
534 break;
535 case 2:
536 if (!canBeSpecial)
537 break;
538 mh = lookup.unreflectSpecial(m, lookup.lookupClass());
539 break;
540 case 3:
541 if (!canBeSpecial)
542 break;
543 mh = lookup.findSpecial(defc, name, type, lookup.lookupClass());
544 break;
545 }
546 } else if (mem instanceof SignaturePolymorphicMethod) {
547 SignaturePolymorphicMethod m = (SignaturePolymorphicMethod) mem;
548 MethodType type = methodType(m.getReturnType(), m.getParameterTypes());
549 kind = REF_invokeVirtual;
550 refKind[0] = kind;
551 switch (variation) {
552 case 0:
553 mh = lookup.findVirtual(defc, name, type);
554 break;
555 }
556 } else if (mem instanceof Constructor) {
557 name = "<init>"; // not used
558 Constructor<?> m = (Constructor<?>) mem;
559 MethodType type = methodType(void.class, m.getParameterTypes());
560 kind = REF_newInvokeSpecial;
561 refKind[0] = kind;
562 switch (variation) {
563 case 0:
564 mh = lookup.unreflectConstructor(m);
565 break;
566 case 1:
567 mh = lookup.findConstructor(defc, type);
568 break;
569 }
570 } else if (mem instanceof Field) {
571 Field m = (Field) mem;
572 Class<?> type = m.getType();
573 boolean canHaveSetter = !Modifier.isFinal(mods);
574 if (variation >= 2)
575 kind = (byte)(isStatic ? REF_putStatic : REF_putField);
576 else
577 kind = (byte)(isStatic ? REF_getStatic : REF_getField);
578 refKind[0] = kind;
579 switch (variation) {
580 case 0:
581 mh = lookup.unreflectGetter(m);
582 break;
583 case 1:
584 if (isStatic)
585 mh = lookup.findStaticGetter(defc, name, type);
586 else
587 mh = lookup.findGetter(defc, name, type);
588 break;
589 case 3:
590 if (!canHaveSetter)
591 break;
592 mh = lookup.unreflectSetter(m);
593 break;
594 case 2:
595 if (!canHaveSetter)
596 break;
597 if (isStatic)
598 mh = lookup.findStaticSetter(defc, name, type);
599 else
600 mh = lookup.findSetter(defc, name, type);
601 break;
602 }
603 } else {
604 throw new IllegalArgumentException(String.valueOf(mem));
605 }
606 if (mh == null)
607 // ran out of valid variations; return null to caller
608 return null;
609 return new UnreflectResult(mh, kind, mem, variation);
610 }
611 static boolean canBeReached(Member mem, Class<?> cls) {
612 Class<?> defc = mem.getDeclaringClass();
613 String name = mem.getName();
614 int mods = mem.getModifiers();
615 if (mem instanceof Constructor) {
616 name = "<init>"; // according to 292 spec.
617 }
618 if (defc == cls)
619 return true;
620 if (name.startsWith("<"))
621 return false; // only my own constructors
622 if (Modifier.isPrivate(mods))
623 return false; // only my own constructors
624 if (defc.getPackage() == cls.getPackage())
625 return true; // package access or greater OK
626 if (Modifier.isPublic(mods))
627 return true; // publics always OK
628 if (Modifier.isProtected(mods) && defc.isAssignableFrom(cls))
629 return true; // protected OK
630 return false;
631 }
632 static boolean consistent(UnreflectResult res, MethodHandleInfo info) {
633 assert(res.mh != null);
634 assertEquals(res.kind, info.getReferenceKind());
635 assertEquals(res.mem.getModifiers(), info.getModifiers());
636 assertEquals(res.mem.getDeclaringClass(), info.getDeclaringClass());
637 String expectName = res.mem.getName();
638 if (res.kind == REF_newInvokeSpecial)
639 expectName = "<init>";
640 assertEquals(expectName, info.getName());
641 MethodType expectType = res.mh.type();
642 if ((res.kind & 1) == (REF_getField & 1))
643 expectType = expectType.dropParameterTypes(0, 1);
644 if (res.kind == REF_newInvokeSpecial)
645 expectType = expectType.changeReturnType(void.class);
646 assertEquals(expectType, info.getMethodType());
647 assertEquals(res.mh.isVarargsCollector(), isVarArgs(info));
648 assertEquals(res.toInfoString(), info.toString());
649 assertEquals(res.toInfoString(), MethodHandleInfo.toString(info.getReferenceKind(), info.getDeclaringClass(), info.getName(), info.getMethodType()));
650 return true;
651 }
652 static boolean isVarArgs(MethodHandleInfo info) {
653 return info.isVarArgs();
654 }
655 static boolean consistent(Member mem, Member mem2) {
656 assertEquals(mem, mem2);
657 return true;
658 }
659 static boolean consistent(MethodHandleInfo info, MethodHandleInfo info2) {
660 assertEquals(info.getReferenceKind(), info2.getReferenceKind());
661 assertEquals(info.getModifiers(), info2.getModifiers());
662 assertEquals(info.getDeclaringClass(), info2.getDeclaringClass());
663 assertEquals(info.getName(), info2.getName());
664 assertEquals(info.getMethodType(), info2.getMethodType());
665 assertEquals(isVarArgs(info), isVarArgs(info));
666 return true;
667 }
668 static boolean consistent(MethodHandle mh, MethodHandle mh2) {
669 assertEquals(mh.type(), mh2.type());
670 assertEquals(mh.isVarargsCollector(), mh2.isVarargsCollector());
671 return true;
672 }
673 int[] failureModeCounts;
674 static final int NO_FAIL=0, FAIL_LOOKUP=1, FAIL_REVEAL=2, FAIL_REFLECT=3, FAIL_MODE_COUNT=4;
675 void testWithMember(Member mem,
676 Lookup lookup, // initial lookup of member => MH
677 Lookup revLookup, // reveal MH => info
678 Lookup refLookup, // reflect info => member
679 int failureMode) throws Throwable {
680 boolean expectEx1 = (failureMode == FAIL_LOOKUP); // testOnMembersNoLookup
681 boolean expectEx2 = (failureMode == FAIL_REVEAL); // testOnMembersNoReveal
682 boolean expectEx3 = (failureMode == FAIL_REFLECT); // testOnMembersNoReflect
683 for (int variation = 0; ; variation++) {
684 UnreflectResult res = unreflectMember(lookup, mem, variation);
685 failureModeCounts[failureMode] += 1;
686 if (variation == 0) assert(res != null);
687 if (res == null) break;
688 if (VERBOSE && variation == 0)
689 System.out.println("from "+mem.getDeclaringClass().getSimpleName());
690 MethodHandle mh = res.mh;
691 Throwable ex1 = res.ex;
692 if (VERBOSE) System.out.println(" "+variation+": "+res+" << "+(mh != null ? mh : ex1));
693 if (expectEx1 && ex1 != null)
694 continue; // this is OK; we expected that lookup to fail
695 if (expectEx1)
696 throw new AssertionError("unexpected lookup for negative test");
697 if (ex1 != null && !expectEx1) {
698 if (failureMode != NO_FAIL)
699 throw new AssertionError("unexpected lookup failure for negative test", ex1);
700 throw ex1;
701 }
702 MethodHandleInfo info;
703 try {
704 info = revLookup.revealDirect(mh);
705 if (expectEx2) throw new AssertionError("unexpected revelation for negative test");
706 } catch (Throwable ex2) {
707 if (VERBOSE) System.out.println(" "+variation+": "+res+" => "+mh.getClass().getName()+" => (EX2)"+ex2);
708 if (expectEx2)
709 continue; // this is OK; we expected the reflect to fail
710 if (failureMode != NO_FAIL)
711 throw new AssertionError("unexpected revelation failure for negative test", ex2);
712 throw ex2;
713 }
714 assert(consistent(res, info));
715 Member mem2;
716 try {
717 mem2 = info.reflectAs(Member.class, refLookup);
718 if (expectEx3) throw new AssertionError("unexpected reflection for negative test");
719 assert(!(mem instanceof SignaturePolymorphicMethod));
720 } catch (IllegalArgumentException ex3) {
721 if (VERBOSE) System.out.println(" "+variation+": "+info+" => (EX3)"+ex3);
722 if (expectEx3)
723 continue; // this is OK; we expected the reflect to fail
724 if (mem instanceof SignaturePolymorphicMethod)
725 continue; // this is OK; we cannot reflect MH.invokeExact(a,b,c)
726 if (failureMode != NO_FAIL)
727 throw new AssertionError("unexpected reflection failure for negative test", ex3);
728 throw ex3;
729 }
730 assert(consistent(mem, mem2));
731 UnreflectResult res2 = unreflectMember(lookup, mem2, variation);
732 MethodHandle mh2 = res2.mh;
733 assert(consistent(mh, mh2));
734 MethodHandleInfo info2 = lookup.revealDirect(mh2);
735 assert(consistent(info, info2));
736 assert(consistent(res, info2));
737 Member mem3;
738 if (hasSM())
739 mem3 = info2.reflectAs(Member.class, lookup);
740 else
741 mem3 = MethodHandles.reflectAs(Member.class, mh2);
742 assert(consistent(mem2, mem3));
743 if (hasSM()) {
744 try {
745 MethodHandles.reflectAs(Member.class, mh2);
746 throw new AssertionError("failed to throw on "+mem3);
747 } catch (SecurityException ex3) {
748 // OK...
749 }
750 }
751 }
752 }
753}