1 /*
2  * Copyright (c) 2009, 2018, 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.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
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
21  * questions.
22  */
23 
24 package test.java.lang.invoke;
25 
26 import org.junit.*;
27 import test.java.lang.invoke.remote.RemoteExample;
28 
29 import java.lang.invoke.MethodHandle;
30 import java.lang.invoke.MethodHandles;
31 import java.lang.invoke.MethodHandles.Lookup;
32 import java.lang.invoke.MethodType;
33 import java.lang.reflect.Array;
34 import java.lang.reflect.Field;
35 import java.lang.reflect.Modifier;
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.Collection;
39 import java.util.Collections;
40 import java.util.List;
41 
42 import static org.junit.Assert.*;
43 
44 /**
45  *
46  * @author jrose
47  */
48 public abstract class MethodHandlesTest {
49 
50     static final Class<?> THIS_CLASS = MethodHandlesTest.class;
51     // How much output?
52     static int verbosity = 0;
53 
54     static {
55         String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".verbosity");
56         if (vstr == null)
57             vstr = System.getProperty(THIS_CLASS.getName()+".verbosity");
58         if (vstr != null)  verbosity = Integer.parseInt(vstr);
59     }
60 
61     // Set this true during development if you want to fast-forward to
62     // a particular new, non-working test.  Tests which are known to
63     // work (or have recently worked) test this flag and return on true.
64     static final boolean CAN_SKIP_WORKING;
65 
66     static {
67         String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".CAN_SKIP_WORKING");
68         if (vstr == null)
69             vstr = System.getProperty(THIS_CLASS.getName()+".CAN_SKIP_WORKING");
70         CAN_SKIP_WORKING = Boolean.parseBoolean(vstr);
71     }
72 
73     // Set 'true' to do about 15x fewer tests, especially those redundant with RicochetTest.
74     // This might be useful with -Xcomp stress tests that compile all method handles.
75     static boolean CAN_TEST_LIGHTLY = Boolean.getBoolean(THIS_CLASS.getName()+".CAN_TEST_LIGHTLY");
76 
77     static final int MAX_ARG_INCREASE = 3;
78 
79     String testName;
80     static int allPosTests, allNegTests;
81     int posTests, negTests;
82 
83     @After
printCounts()84     public void printCounts() {
85         if (verbosity >= 2 && (posTests | negTests) != 0) {
86             System.out.println();
87             if (posTests != 0)  System.out.println("=== "+testName+": "+posTests+" positive test cases run");
88             if (negTests != 0)  System.out.println("=== "+testName+": "+negTests+" negative test cases run");
89             allPosTests += posTests;
90             allNegTests += negTests;
91             posTests = negTests = 0;
92         }
93     }
94 
countTest(boolean positive)95     void countTest(boolean positive) {
96         if (positive) ++posTests;
97         else          ++negTests;
98     }
99 
countTest()100     void countTest() { countTest(true); }
101 
startTest(String name)102     void startTest(String name) {
103         if (testName != null)  printCounts();
104         if (verbosity >= 1)
105             System.out.println(name);
106         posTests = negTests = 0;
107         testName = name;
108     }
109 
110     @BeforeClass
setUpClass()111     public static void setUpClass() throws Exception {
112         calledLog.clear();
113         calledLog.add(null);
114         nextArgVal = INITIAL_ARG_VAL;
115     }
116 
117     @AfterClass
tearDownClass()118     public static void tearDownClass() throws Exception {
119         int posTests = allPosTests, negTests = allNegTests;
120         if (verbosity >= 0 && (posTests | negTests) != 0) {
121             System.out.println();
122             if (posTests != 0)  System.out.println("=== "+posTests+" total positive test cases");
123             if (negTests != 0)  System.out.println("=== "+negTests+" total negative test cases");
124         }
125     }
126 
127     static List<Object> calledLog = new ArrayList<>();
128 
logEntry(String name, Object... args)129     static Object logEntry(String name, Object... args) {
130         return Arrays.asList(name, Arrays.asList(args));
131     }
132 
called(String name, Object... args)133     public static Object called(String name, Object... args) {
134         Object entry = logEntry(name, args);
135         calledLog.add(entry);
136         return entry;
137     }
138 
assertCalled(String name, Object... args)139     static void assertCalled(String name, Object... args) {
140         Object expected = logEntry(name, args);
141         Object actual   = calledLog.get(calledLog.size() - 1);
142         if (expected.equals(actual) && verbosity < 9)  return;
143         System.out.println("assertCalled "+name+":");
144         System.out.println("expected:   "+deepToString(expected));
145         System.out.println("actual:     "+actual);
146         System.out.println("ex. types:  "+getClasses(expected));
147         System.out.println("act. types: "+getClasses(actual));
148         assertEquals("previous method call", expected, actual);
149     }
150 
printCalled(MethodHandle target, String name, Object... args)151     static void printCalled(MethodHandle target, String name, Object... args) {
152         if (verbosity >= 3)
153             System.out.println("calling MH="+target+" to "+name+deepToString(args));
154     }
155 
deepToString(Object x)156     static String deepToString(Object x) {
157         if (x == null)  return "null";
158         if (x instanceof Collection)
159             x = ((Collection)x).toArray();
160         if (x instanceof Object[]) {
161             Object[] ax = (Object[]) x;
162             ax = Arrays.copyOf(ax, ax.length, Object[].class);
163             for (int i = 0; i < ax.length; i++)
164                 ax[i] = deepToString(ax[i]);
165             x = Arrays.deepToString(ax);
166         }
167         if (x.getClass().isArray())
168             try {
169                 x = Arrays.class.getMethod("toString", x.getClass()).invoke(null, x);
170             } catch (ReflectiveOperationException ex) { throw new Error(ex); }
171         assert(!(x instanceof Object[]));
172         return x.toString();
173     }
174 
castToWrapper(Object value, Class<?> dst)175     static Object castToWrapper(Object value, Class<?> dst) {
176         Object wrap = null;
177         if (value instanceof Number)
178             wrap = castToWrapperOrNull(((Number)value).longValue(), dst);
179         if (value instanceof Character)
180             wrap = castToWrapperOrNull((char)(Character)value, dst);
181         if (wrap != null)  return wrap;
182         return dst.cast(value);
183     }
184 
185     @SuppressWarnings("cast")  // primitive cast to (long) is part of the pattern
castToWrapperOrNull(long value, Class<?> dst)186     static Object castToWrapperOrNull(long value, Class<?> dst) {
187         if (dst == int.class || dst == Integer.class)
188             return (int)(value);
189         if (dst == long.class || dst == Long.class)
190             return (long)(value);
191         if (dst == char.class || dst == Character.class)
192             return (char)(value);
193         if (dst == short.class || dst == Short.class)
194             return (short)(value);
195         if (dst == float.class || dst == Float.class)
196             return (float)(value);
197         if (dst == double.class || dst == Double.class)
198             return (double)(value);
199         if (dst == byte.class || dst == Byte.class)
200             return (byte)(value);
201         if (dst == boolean.class || dst == boolean.class)
202             return ((value % 29) & 1) == 0;
203         return null;
204     }
205 
206     static final int ONE_MILLION = (1000*1000),  // first int value
207                      TEN_BILLION = (10*1000*1000*1000),  // scale factor to reach upper 32 bits
208                      INITIAL_ARG_VAL = ONE_MILLION << 1;  // <<1 makes space for sign bit;
209     static long nextArgVal;
210 
nextArg(boolean moreBits)211     static long nextArg(boolean moreBits) {
212         long val = nextArgVal++;
213         long sign = -(val & 1); // alternate signs
214         val >>= 1;
215         if (moreBits)
216             // Guarantee some bits in the high word.
217             // In any case keep the decimal representation simple-looking,
218             // with lots of zeroes, so as not to make the printed decimal
219             // strings unnecessarily noisy.
220             val += (val % ONE_MILLION) * TEN_BILLION;
221         return val ^ sign;
222     }
223 
nextArg()224     static int nextArg() {
225         // Produce a 32-bit result something like ONE_MILLION+(smallint).
226         // Example: 1_000_042.
227         return (int) nextArg(false);
228     }
229 
nextArg(Class<?> kind)230     static long nextArg(Class<?> kind) {
231         if (kind == long.class   || kind == Long.class ||
232             kind == double.class || kind == Double.class)
233             // produce a 64-bit result something like
234             // ((TEN_BILLION+1) * (ONE_MILLION+(smallint)))
235             // Example: 10_000_420_001_000_042.
236             return nextArg(true);
237         return (long) nextArg();
238     }
239 
randomArg(Class<?> param)240     static Object randomArg(Class<?> param) {
241         Object wrap = castToWrapperOrNull(nextArg(param), param);
242         if (wrap != null) {
243             return wrap;
244         }
245         //import sun.invoke.util.Wrapper;
246         //Wrapper wrap = Wrapper.forBasicType(dst);
247         //if (wrap == Wrapper.OBJECT && Wrapper.isWrapperType(dst))
248         //   wrap = Wrapper.forWrapperType(dst);
249         //   if (wrap != Wrapper.OBJECT)
250         //       return wrap.wrap(nextArg++);
251         if (param.isInterface()) {
252             for (Class<?> c : param.getClasses()) {
253                 if (param.isAssignableFrom(c) && !c.isInterface())
254                     { param = c; break; }
255             }
256         }
257         if (param.isArray()) {
258             Class<?> ctype = param.getComponentType();
259             Object arg = Array.newInstance(ctype, 2);
260             Array.set(arg, 0, randomArg(ctype));
261             return arg;
262         }
263         if (param.isInterface() && param.isAssignableFrom(List.class))
264             return Arrays.asList("#"+nextArg());
265         if (param.isInterface() || param.isAssignableFrom(String.class))
266             return "#"+nextArg();
267         else
268             try {
269                 return param.newInstance();
270             } catch (InstantiationException | IllegalAccessException ex) {
271             }
272         return null;  // random class not Object, String, Integer, etc.
273     }
274 
randomArgs(Class<?>.... params)275     static Object[] randomArgs(Class<?>... params) {
276         Object[] args = new Object[params.length];
277         for (int i = 0; i < args.length; i++)
278             args[i] = randomArg(params[i]);
279         return args;
280     }
281 
randomArgs(int nargs, Class<?> param)282     static Object[] randomArgs(int nargs, Class<?> param) {
283         Object[] args = new Object[nargs];
284         for (int i = 0; i < args.length; i++)
285             args[i] = randomArg(param);
286         return args;
287     }
288 
randomArgs(List<Class<?>> params)289     static Object[] randomArgs(List<Class<?>> params) {
290         return randomArgs(params.toArray(new Class<?>[params.size()]));
291     }
292 
293     @SafeVarargs @SuppressWarnings("varargs")
array(Class<T[]> atype, E... a)294     static <T, E extends T> T[] array(Class<T[]> atype, E... a) {
295         return Arrays.copyOf(a, a.length, atype);
296     }
297 
298     @SafeVarargs @SuppressWarnings("varargs")
cat(T[] a, T... b)299     static <T> T[] cat(T[] a, T... b) {
300         int alen = a.length, blen = b.length;
301         if (blen == 0)  return a;
302         T[] c = Arrays.copyOf(a, alen + blen);
303         System.arraycopy(b, 0, c, alen, blen);
304         return c;
305     }
306 
boxAll(int... vx)307     static Integer[] boxAll(int... vx) {
308         Integer[] res = new Integer[vx.length];
309         for (int i = 0; i < res.length; i++) {
310             res[i] = vx[i];
311         }
312         return res;
313     }
314 
getClasses(Object x)315     static Object getClasses(Object x) {
316         if (x == null)  return x;
317         if (x instanceof String)  return x;  // keep the name
318         if (x instanceof List) {
319             // recursively report classes of the list elements
320             Object[] xa = ((List)x).toArray();
321             for (int i = 0; i < xa.length; i++)
322                 xa[i] = getClasses(xa[i]);
323             return Arrays.asList(xa);
324         }
325         return x.getClass().getSimpleName();
326     }
327 
328     /** Return lambda(arg...[arity]) { new Object[]{ arg... } } */
varargsList(int arity)329     static MethodHandle varargsList(int arity) {
330         return ValueConversions.varargsList(arity);
331     }
332 
333     /** Return lambda(arg...[arity]) { Arrays.asList(arg...) } */
varargsArray(int arity)334     static MethodHandle varargsArray(int arity) {
335         return ValueConversions.varargsArray(arity);
336     }
337 
varargsArray(Class<?> arrayType, int arity)338     static MethodHandle varargsArray(Class<?> arrayType, int arity) {
339         return ValueConversions.varargsArray(arrayType, arity);
340     }
341 
342     /** Variation of varargsList, but with the given rtype. */
varargsList(int arity, Class<?> rtype)343     static MethodHandle varargsList(int arity, Class<?> rtype) {
344         MethodHandle list = varargsList(arity);
345         MethodType listType = list.type().changeReturnType(rtype);
346         if (List.class.isAssignableFrom(rtype) || rtype == void.class || rtype == Object.class) {
347             // OK
348         } else if (rtype.isAssignableFrom(String.class)) {
349             if (LIST_TO_STRING == null)
350                 try {
351                     LIST_TO_STRING = PRIVATE.findStatic(PRIVATE.lookupClass(), "listToString",
352                                                         MethodType.methodType(String.class, List.class));
353                 } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); }
354             list = MethodHandles.filterReturnValue(list, LIST_TO_STRING);
355         } else if (rtype.isPrimitive()) {
356             if (LIST_TO_INT == null)
357                 try {
358                     LIST_TO_INT = PRIVATE.findStatic(PRIVATE.lookupClass(), "listToInt",
359                                                      MethodType.methodType(int.class, List.class));
360                 } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); }
361             list = MethodHandles.filterReturnValue(list, LIST_TO_INT);
362             list = MethodHandles.explicitCastArguments(list, listType);
363         } else {
364             throw new RuntimeException("varargsList: "+rtype);
365         }
366         return list.asType(listType);
367     }
368 
369     /** Variation of varargsList, but with the given ptypes and rtype. */
varargsList(List<Class<?>> ptypes, Class<?> rtype)370     static MethodHandle varargsList(List<Class<?>> ptypes, Class<?> rtype) {
371         MethodHandle list = varargsList(ptypes.size(), rtype);
372         return list.asType(MethodType.methodType(rtype, ptypes));
373     }
374 
375     private static MethodHandle LIST_TO_STRING, LIST_TO_INT;
listToString(List<?> x)376     private static String listToString(List<?> x) { return x.toString(); }
listToInt(List<?> x)377     private static int listToInt(List<?> x) { return x.toString().hashCode(); }
378 
changeArgTypes(MethodHandle target, Class<?> argType)379     static MethodHandle changeArgTypes(MethodHandle target, Class<?> argType) {
380         return changeArgTypes(target, 0, 999, argType);
381     }
382 
changeArgTypes(MethodHandle target, int beg, int end, Class<?> argType)383     static MethodHandle changeArgTypes(MethodHandle target,
384             int beg, int end, Class<?> argType) {
385         MethodType targetType = target.type();
386         end = Math.min(end, targetType.parameterCount());
387         ArrayList<Class<?>> argTypes = new ArrayList<>(targetType.parameterList());
388         Collections.fill(argTypes.subList(beg, end), argType);
389         MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes);
390         return target.asType(ttype2);
391     }
392 
addTrailingArgs(MethodHandle target, int nargs, Class<?> argClass)393     static MethodHandle addTrailingArgs(MethodHandle target, int nargs, Class<?> argClass) {
394         int targetLen = target.type().parameterCount();
395         int extra = (nargs - targetLen);
396         if (extra <= 0)  return target;
397         List<Class<?>> fakeArgs = Collections.<Class<?>>nCopies(extra, argClass);
398         return MethodHandles.dropArguments(target, targetLen, fakeArgs);
399     }
400 
401     // This lookup is good for all members in and under MethodHandlesTest.
402     static final Lookup PRIVATE = MethodHandles.lookup();
403     // This lookup is good for package-private members but not private ones.
404     static final Lookup PACKAGE = PackageSibling.lookup();
405     // This lookup is good for public members and protected members of PubExample
406     static final Lookup SUBCLASS = RemoteExample.lookup();
407     // This lookup is good only for public members in exported packages.
408     static final Lookup PUBLIC  = MethodHandles.publicLookup();
409 
410     // Subject methods...
411     static class Example implements IntExample {
412         final String name;
Example()413         public Example() { name = "Example#"+nextArg(); }
Example(String name)414         protected Example(String name) { this.name = name; }
415         @SuppressWarnings("LeakingThisInConstructor")
Example(int x)416         protected Example(int x) { this(); called("protected <init>", this, x); }
417         //Example(Void x) { does not exist; lookup elicts NoSuchMethodException }
toString()418         @Override public String toString() { return name; }
419 
v0()420         public void            v0()     { called("v0", this); }
pro_v0()421         protected void         pro_v0() { called("pro_v0", this); }
pkg_v0()422         void                   pkg_v0() { called("pkg_v0", this); }
pri_v0()423         private void           pri_v0() { called("pri_v0", this); }
s0()424         public static void     s0()     { called("s0"); }
pro_s0()425         protected static void  pro_s0() { called("pro_s0"); }
pkg_s0()426         static void            pkg_s0() { called("pkg_s0"); }
pri_s0()427         private static void    pri_s0() { called("pri_s0"); }
428 
v1(Object x)429         public Object          v1(Object x) { return called("v1", this, x); }
v2(Object x, Object y)430         public Object          v2(Object x, Object y) { return called("v2", this, x, y); }
v2(Object x, int y)431         public Object          v2(Object x, int    y) { return called("v2", this, x, y); }
v2(int x, Object y)432         public Object          v2(int    x, Object y) { return called("v2", this, x, y); }
v2(int x, int y)433         public Object          v2(int    x, int    y) { return called("v2", this, x, y); }
s1(Object x)434         public static Object   s1(Object x) { return called("s1", x); }
s2(int x)435         public static Object   s2(int x)    { return called("s2", x); }
s3(long x)436         public static Object   s3(long x)   { return called("s3", x); }
s4(int x, int y)437         public static Object   s4(int x, int y) { return called("s4", x, y); }
s5(long x, int y)438         public static Object   s5(long x, int y) { return called("s5", x, y); }
s6(int x, long y)439         public static Object   s6(int x, long y) { return called("s6", x, y); }
s7(float x, double y)440         public static Object   s7(float x, double y) { return called("s7", x, y); }
441 
442         // for testing findConstructor:
Example(String x, int y)443         public Example(String x, int y) { this.name = x+y; called("Example.<init>", x, y); }
Example(int x, String y)444         public Example(int x, String y) { this.name = x+y; called("Example.<init>", x, y); }
Example(int x, int y)445         public Example(int x, int    y) { this.name = x+""+y; called("Example.<init>", x, y); }
Example(int x, long y)446         public Example(int x, long   y) { this.name = x+""+y; called("Example.<init>", x, y); }
Example(int x, float y)447         public Example(int x, float  y) { this.name = x+""+y; called("Example.<init>", x, y); }
Example(int x, double y)448         public Example(int x, double y) { this.name = x+""+y; called("Example.<init>", x, y); }
Example(int x, int y, int z)449         public Example(int x, int    y, int z) { this.name = x+""+y+""+z; called("Example.<init>", x, y, z); }
Example(int x, int y, int z, int a)450         public Example(int x, int    y, int z, int a) { this.name = x+""+y+""+z+""+a; called("Example.<init>", x, y, z, a); }
451 
452         static final Lookup EXAMPLE = MethodHandles.lookup();  // for testing findSpecial
453     }
454 
455     static final Lookup EXAMPLE = Example.EXAMPLE;
456     public static class PubExample extends Example {
PubExample()457         public PubExample() { this("PubExample"); }
PubExample(String prefix)458         protected PubExample(String prefix) { super(prefix+"#"+nextArg()); }
pro_v0()459         protected void         pro_v0() { called("Pub/pro_v0", this); }
pro_s0()460         protected static void  pro_s0() { called("Pub/pro_s0"); }
461     }
462 
463     static class SubExample extends Example {
v0()464         @Override public void  v0()     { called("Sub/v0", this); }
pkg_v0()465         @Override void         pkg_v0() { called("Sub/pkg_v0", this); }
466         @SuppressWarnings("LeakingThisInConstructor")
SubExample(int x)467         private      SubExample(int x)  { called("<init>", this, x); }
SubExample()468         public SubExample() { super("SubExample#"+nextArg()); }
469     }
470 
471     public static interface IntExample {
v0()472         public void            v0();
vd()473         public default void    vd() { called("vd", this); }
474         public static class Impl implements IntExample {
v0()475             public void        v0()     { called("Int/v0", this); }
476             final String name;
Impl()477             public Impl() { name = "Impl#"+nextArg(); }
toString()478             @Override public String toString() { return name; }
479         }
480     }
481 
482     static interface SubIntExample extends IntExample { }
483 
484     static final Object[][][] ACCESS_CASES = {
485         { { false, PUBLIC }, { false, SUBCLASS }, { false, PACKAGE }, { false, PRIVATE }, { false, EXAMPLE } }, //[0]: all false
486         { { false, PUBLIC }, { false, SUBCLASS }, { false, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[1]: only PRIVATE
487         { { false, PUBLIC }, { false, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[2]: PUBLIC false
488         { { false, PUBLIC }, { true, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[3]: subclass OK
489         { { true, PUBLIC }, { true, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[4]: all true
490     };
491 
accessCases(Class<?> defc, String name, boolean isSpecial)492     static Object[][] accessCases(Class<?> defc, String name, boolean isSpecial) {
493         Object[][] cases;
494         if (name.contains("pri_") || isSpecial) {
495             cases = ACCESS_CASES[1]; // PRIVATE only
496         } else if (name.contains("pkg_") || !Modifier.isPublic(defc.getModifiers())) {
497             cases = ACCESS_CASES[2]; // not PUBLIC
498         } else if (name.contains("pro_")) {
499             cases = ACCESS_CASES[3]; // PUBLIC class, protected member
500         } else {
501             assertTrue(name.indexOf('_') < 0 || name.contains("fin_"));
502             boolean pubc = Modifier.isPublic(defc.getModifiers());
503             if (pubc)
504                 cases = ACCESS_CASES[4]; // all access levels
505             else
506                 cases = ACCESS_CASES[2]; // PACKAGE but not PUBLIC
507         }
508         if (defc != Example.class && cases[cases.length-1][1] == EXAMPLE)
509             cases = Arrays.copyOfRange(cases, 0, cases.length-1);
510         return cases;
511     }
512 
513     static Object[][] accessCases(Class<?> defc, String name) {
514         return accessCases(defc, name, false);
515     }
516 
517     static Lookup maybeMoveIn(Lookup lookup, Class<?> defc) {
518         if (lookup == PUBLIC || lookup == SUBCLASS || lookup == PACKAGE)
519             // external views stay external
520             return lookup;
521         return lookup.in(defc);
522     }
523 
524     /** Is findVirtual (etc.) of "&lt;init&lt;" supposed to elicit a NoSuchMethodException? */
525     static final boolean INIT_REF_CAUSES_NSME = true;
526 
527     static void assertExceptionClass(Class<? extends Throwable> expected,
528                                      Throwable actual) {
529         if (expected.isInstance(actual))  return;
530         actual.printStackTrace();
531         assertEquals(expected, actual.getClass());
532     }
533 
534     static final boolean DEBUG_METHOD_HANDLE_NAMES = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
535 
536     // rough check of name string
537     static void assertNameStringContains(MethodHandle x, String s) {
538         if (!DEBUG_METHOD_HANDLE_NAMES) {
539             // ignore s
540             assertEquals("MethodHandle"+x.type(), x.toString());
541             return;
542         }
543         if (x.toString().contains(s))  return;
544         assertEquals(s, x);
545     }
546 
547     public static class HasFields {
548         boolean fZ = false;
549         byte fB = (byte)'B';
550         short fS = (short)'S';
551         char fC = 'C';
552         int fI = 'I';
553         long fJ = 'J';
554         float fF = 'F';
555         double fD = 'D';
556         static boolean sZ = true;
557         static byte sB = 1+(byte)'B';
558         static short sS = 1+(short)'S';
559         static char sC = 1+'C';
560         static int sI = 1+'I';
561         static long sJ = 1+'J';
562         static float sF = 1+'F';
563         static double sD = 1+'D';
564 
565         Object fL = 'L';
566         String fR = "R";
567         static Object sL = 'M';
568         static String sR = "S";
569 
570         static final Object[][] CASES;
571         static {
572             ArrayList<Object[]> cases = new ArrayList<>();
573             Object types[][] = {
574                 {'L',Object.class}, {'R',String.class},
575                 {'I',int.class}, {'J',long.class},
576                 {'F',float.class}, {'D',double.class},
577                 {'Z',boolean.class}, {'B',byte.class},
578                 {'S',short.class}, {'C',char.class},
579             };
580             HasFields fields = new HasFields();
581             for (Object[] t : types) {
582                 for (int kind = 0; kind <= 1; kind++) {
583                     boolean isStatic = (kind != 0);
584                     char btc = (Character)t[0];
585                     String name = (isStatic ? "s" : "f") + btc;
586                     Class<?> type = (Class<?>) t[1];
587                     Object value;
588                     Field field;
589                         try {
590                         field = HasFields.class.getDeclaredField(name);
591                     } catch (NoSuchFieldException | SecurityException ex) {
592                         throw new InternalError("no field HasFields."+name);
593                     }
594                     try {
595                         value = field.get(fields);
596                     } catch (IllegalArgumentException | IllegalAccessException ex) {
597                         throw new InternalError("cannot fetch field HasFields."+name);
598                     }
599                     if (type == float.class) {
600                         float v = 'F';
601                         if (isStatic)  v++;
602                         assertTrue(value.equals(v));
603                     }
604                     assertTrue(name.equals(field.getName()));
605                     assertTrue(type.equals(field.getType()));
606                     assertTrue(isStatic == (Modifier.isStatic(field.getModifiers())));
607                     cases.add(new Object[]{ field, value });
608                 }
609             }
610             cases.add(new Object[]{ new Object[]{ false, HasFields.class, "bogus_fD", double.class }, Error.class });
611             cases.add(new Object[]{ new Object[]{ true,  HasFields.class, "bogus_sL", Object.class }, Error.class });
612             CASES = cases.toArray(new Object[0][]);
613         }
614     }
615 
616     static final int TEST_UNREFLECT = 1, TEST_FIND_FIELD = 2, TEST_FIND_STATIC = 3, TEST_SETTER = 0x10, TEST_BOUND = 0x20, TEST_NPE = 0x40;
617 
618     static boolean testModeMatches(int testMode, boolean isStatic) {
619         switch (testMode) {
620         case TEST_FIND_STATIC:          return isStatic;
621         case TEST_FIND_FIELD:           return !isStatic;
622         case TEST_UNREFLECT:            return true;  // unreflect matches both
623         }
624         throw new InternalError("testMode="+testMode);
625     }
626 
627     static class Callee {
628         static Object id() { return called("id"); }
629         static Object id(Object x) { return called("id", x); }
630         static Object id(Object x, Object y) { return called("id", x, y); }
631         static Object id(Object x, Object y, Object z) { return called("id", x, y, z); }
632         static Object id(Object... vx) { return called("id", vx); }
633         static MethodHandle ofType(int n) {
634             return ofType(Object.class, n);
635         }
636         static MethodHandle ofType(Class<?> rtype, int n) {
637             if (n == -1)
638                 return ofType(MethodType.methodType(rtype, Object[].class));
639             return ofType(MethodType.genericMethodType(n).changeReturnType(rtype));
640         }
641         static MethodHandle ofType(Class<?> rtype, Class<?>... ptypes) {
642             return ofType(MethodType.methodType(rtype, ptypes));
643         }
644         static MethodHandle ofType(MethodType type) {
645             Class<?> rtype = type.returnType();
646             String pfx = "";
647             if (rtype != Object.class)
648                 pfx = rtype.getSimpleName().substring(0, 1).toLowerCase();
649             String name = pfx+"id";
650             try {
651                 return PRIVATE.findStatic(Callee.class, name, type);
652             } catch (NoSuchMethodException | IllegalAccessException ex) {
653                 throw new RuntimeException(ex);
654             }
655         }
656     }
657 
658     static Object invokee(Object... args) {
659         return called("invokee", args).hashCode();
660     }
661 
662     protected static final String MISSING_ARG = "missingArg";
663     protected static final String MISSING_ARG_2 = "missingArg#2";
664 
665     static Object targetIfEquals() {
666         return called("targetIfEquals");
667     }
668 
669     static Object fallbackIfNotEquals() {
670         return called("fallbackIfNotEquals");
671     }
672 
673     static Object targetIfEquals(Object x) {
674         assertEquals(x, MISSING_ARG);
675         return called("targetIfEquals", x);
676     }
677 
678     static Object fallbackIfNotEquals(Object x) {
679         assertFalse(x.toString(), x.equals(MISSING_ARG));
680         return called("fallbackIfNotEquals", x);
681     }
682 
683     static Object targetIfEquals(Object x, Object y) {
684         assertEquals(x, y);
685         return called("targetIfEquals", x, y);
686     }
687 
688     static Object fallbackIfNotEquals(Object x, Object y) {
689         assertFalse(x.toString(), x.equals(y));
690         return called("fallbackIfNotEquals", x, y);
691     }
692 
693     static Object targetIfEquals(Object x, Object y, Object z) {
694         assertEquals(x, y);
695         return called("targetIfEquals", x, y, z);
696     }
697 
698     static Object fallbackIfNotEquals(Object x, Object y, Object z) {
699         assertFalse(x.toString(), x.equals(y));
700         return called("fallbackIfNotEquals", x, y, z);
701     }
702 
703     static boolean loopIntPred(int a) {
704         if (verbosity >= 5) {
705             System.out.println("int pred " + a + " -> " + (a < 7));
706         }
707         return a < 7;
708     }
709 
710     static boolean loopDoublePred(int a, double b) {
711         if (verbosity >= 5) {
712             System.out.println("double pred (a=" + a + ") " + b + " -> " + (b > 0.5));
713         }
714         return b > 0.5;
715     }
716 
loopStringPred(int a, double b, String c)717     static boolean loopStringPred(int a, double b, String c) {
718         if (verbosity >= 5) {
719             System.out.println("String pred (a=" + a + ",b=" + b + ") " + c + " -> " + (c.length() <= 9));
720         }
721         return c.length() <= 9;
722     }
723 
loopIntStep(int a)724     static int loopIntStep(int a) {
725         if (verbosity >= 5) {
726             System.out.println("int step " + a + " -> " + (a + 1));
727         }
728         return a + 1;
729     }
730 
loopDoubleStep(int a, double b)731     static double loopDoubleStep(int a, double b) {
732         if (verbosity >= 5) {
733             System.out.println("double step (a=" + a + ") " + b + " -> " + (b / 2.0));
734         }
735         return b / 2.0;
736     }
737 
loopStringStep(int a, double b, String c)738     static String loopStringStep(int a, double b, String c) {
739         if (verbosity >= 5) {
740             System.out.println("String step (a=" + a + ",b=" + b + ") " + c + " -> " + (c + a));
741         }
742         return c + a;
743     }
744 
vtarget(String[] a)745     static void vtarget(String[] a) {
746         // naught, akin to identity
747     }
748 
vtargetThrow(String[] a)749     static void vtargetThrow(String[] a) throws Exception {
750         throw new Exception("thrown");
751     }
752 
vcleanupPassThrough(Throwable t, String[] a)753     static void vcleanupPassThrough(Throwable t, String[] a) {
754         assertNull(t);
755         // naught, akin to identity
756     }
757 
vcleanupAugment(Throwable t, String[] a)758     static void vcleanupAugment(Throwable t, String[] a) {
759         assertNull(t);
760         a[0] = "augmented";
761     }
762 
vcleanupCatch(Throwable t, String[] a)763     static void vcleanupCatch(Throwable t, String[] a) {
764         assertNotNull(t);
765         a[0] = "caught";
766     }
767 
vcleanupThrow(Throwable t, String[] a)768     static void vcleanupThrow(Throwable t, String[] a) throws Exception {
769         assertNotNull(t);
770         throw new Exception("rethrown");
771     }
772 }
773 // Local abbreviated copy of sun.invoke.util.ValueConversions
774 // This guy tests access from outside the same package member, but inside
775 // the package itself.
776 class ValueConversions {
777     private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
778     private static final Object[] NO_ARGS_ARRAY = {};
makeArray(Object... args)779     private static Object[] makeArray(Object... args) { return args; }
array()780     private static Object[] array() { return NO_ARGS_ARRAY; }
array(Object a0)781     private static Object[] array(Object a0)
782                 { return makeArray(a0); }
array(Object a0, Object a1)783     private static Object[] array(Object a0, Object a1)
784                 { return makeArray(a0, a1); }
array(Object a0, Object a1, Object a2)785     private static Object[] array(Object a0, Object a1, Object a2)
786                 { return makeArray(a0, a1, a2); }
array(Object a0, Object a1, Object a2, Object a3)787     private static Object[] array(Object a0, Object a1, Object a2, Object a3)
788                 { return makeArray(a0, a1, a2, a3); }
array(Object a0, Object a1, Object a2, Object a3, Object a4)789     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
790                                   Object a4)
791                 { return makeArray(a0, a1, a2, a3, a4); }
array(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5)792     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
793                                   Object a4, Object a5)
794                 { return makeArray(a0, a1, a2, a3, a4, a5); }
array(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6)795     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
796                                   Object a4, Object a5, Object a6)
797                 { return makeArray(a0, a1, a2, a3, a4, a5, a6); }
array(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7)798     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
799                                   Object a4, Object a5, Object a6, Object a7)
800                 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); }
array(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8)801     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
802                                   Object a4, Object a5, Object a6, Object a7,
803                                   Object a8)
804                 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
array(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9)805     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
806                                   Object a4, Object a5, Object a6, Object a7,
807                                   Object a8, Object a9)
808                 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
809 
makeArrays()810     static MethodHandle[] makeArrays() {
811         ArrayList<MethodHandle> arrays = new ArrayList<>();
812         MethodHandles.Lookup lookup = IMPL_LOOKUP;
813         for (;;) {
814             int nargs = arrays.size();
815             MethodType type = MethodType.genericMethodType(nargs).changeReturnType(Object[].class);
816             String name = "array";
817             MethodHandle array = null;
818             try {
819                 array = lookup.findStatic(ValueConversions.class, name, type);
820             } catch (ReflectiveOperationException ex) {
821                 // break from loop!
822             }
823             if (array == null)  break;
824             arrays.add(array);
825         }
826         assertTrue(arrays.size() == 11);  // current number of methods
827         return arrays.toArray(new MethodHandle[0]);
828     }
829 
830     static final MethodHandle[] ARRAYS = makeArrays();
831 
832     /** Return a method handle that takes the indicated number of Object
833      *  arguments and returns an Object array of them, as if for varargs.
834      */
varargsArray(int nargs)835     public static MethodHandle varargsArray(int nargs) {
836         if (nargs < ARRAYS.length)
837             return ARRAYS[nargs];
838         return MethodHandles.identity(Object[].class).asCollector(Object[].class, nargs);
839     }
840 
varargsArray(Class<?> arrayType, int nargs)841     public static MethodHandle varargsArray(Class<?> arrayType, int nargs) {
842         Class<?> elemType = arrayType.getComponentType();
843         MethodType vaType = MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType));
844         MethodHandle mh = varargsArray(nargs);
845         if (arrayType != Object[].class)
846             mh = MethodHandles.filterReturnValue(mh, CHANGE_ARRAY_TYPE.bindTo(arrayType));
847         return mh.asType(vaType);
848     }
849 
changeArrayType(Class<?> arrayType, Object[] a)850     static Object changeArrayType(Class<?> arrayType, Object[] a) {
851         Class<?> elemType = arrayType.getComponentType();
852         if (!elemType.isPrimitive())
853             return Arrays.copyOf(a, a.length, arrayType.asSubclass(Object[].class));
854         Object b = java.lang.reflect.Array.newInstance(elemType, a.length);
855         for (int i = 0; i < a.length; i++)
856             java.lang.reflect.Array.set(b, i, a[i]);
857         return b;
858     }
859 
860     private static final MethodHandle CHANGE_ARRAY_TYPE;
861     static {
862         try {
863             CHANGE_ARRAY_TYPE = IMPL_LOOKUP.findStatic(ValueConversions.class, "changeArrayType",
864                                                        MethodType.methodType(Object.class, Class.class, Object[].class));
865         } catch (NoSuchMethodException | IllegalAccessException ex) {
866             Error err = new InternalError("uncaught exception");
867             err.initCause(ex);
868             throw err;
869         }
870     }
871 
872     private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY);
makeList(Object... args)873     private static List<Object> makeList(Object... args) { return Arrays.asList(args); }
list()874     private static List<Object> list() { return NO_ARGS_LIST; }
list(Object a0)875     private static List<Object> list(Object a0)
876                 { return makeList(a0); }
list(Object a0, Object a1)877     private static List<Object> list(Object a0, Object a1)
878                 { return makeList(a0, a1); }
list(Object a0, Object a1, Object a2)879     private static List<Object> list(Object a0, Object a1, Object a2)
880                 { return makeList(a0, a1, a2); }
list(Object a0, Object a1, Object a2, Object a3)881     private static List<Object> list(Object a0, Object a1, Object a2, Object a3)
882                 { return makeList(a0, a1, a2, a3); }
list(Object a0, Object a1, Object a2, Object a3, Object a4)883     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
884                                      Object a4)
885                 { return makeList(a0, a1, a2, a3, a4); }
list(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5)886     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
887                                      Object a4, Object a5)
888                 { return makeList(a0, a1, a2, a3, a4, a5); }
list(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6)889     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
890                                      Object a4, Object a5, Object a6)
891                 { return makeList(a0, a1, a2, a3, a4, a5, a6); }
list(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7)892     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
893                                      Object a4, Object a5, Object a6, Object a7)
894                 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); }
list(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8)895     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
896                                      Object a4, Object a5, Object a6, Object a7,
897                                      Object a8)
898                 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
list(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7, Object a8, Object a9)899     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
900                                      Object a4, Object a5, Object a6, Object a7,
901                                      Object a8, Object a9)
902                 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
903 
makeLists()904     static MethodHandle[] makeLists() {
905         ArrayList<MethodHandle> lists = new ArrayList<>();
906         MethodHandles.Lookup lookup = IMPL_LOOKUP;
907         for (;;) {
908             int nargs = lists.size();
909             MethodType type = MethodType.genericMethodType(nargs).changeReturnType(List.class);
910             String name = "list";
911             MethodHandle list = null;
912             try {
913                 list = lookup.findStatic(ValueConversions.class, name, type);
914             } catch (ReflectiveOperationException ex) {
915                 // break from loop!
916             }
917             if (list == null)  break;
918             lists.add(list);
919         }
920         assertTrue(lists.size() == 11);  // current number of methods
921         return lists.toArray(new MethodHandle[0]);
922     }
923 
924     static final MethodHandle[] LISTS = makeLists();
925     static final MethodHandle AS_LIST;
926 
927     static {
928         try {
929             AS_LIST = IMPL_LOOKUP.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class));
930         } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); }
931     }
932 
933     /** Return a method handle that takes the indicated number of Object
934      *  arguments and returns List.
935      */
varargsList(int nargs)936     public static MethodHandle varargsList(int nargs) {
937         if (nargs < LISTS.length)
938             return LISTS[nargs];
939         return AS_LIST.asCollector(Object[].class, nargs);
940     }
941 }
942 // This guy tests access from outside the same package member, but inside
943 // the package itself.
944 class PackageSibling {
lookup()945     static Lookup lookup() {
946         return MethodHandles.lookup();
947     }
948 }
949