• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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