1 /*
   2  * Copyright (c) 2009, 2012, 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 /* @test
  25  * @summary unit tests for java.lang.invoke.MethodHandles
  26  * @compile MethodHandlesTest.java remote/RemoteExample.java
  27  * @run junit/othervm/timeout=2500 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies -esa test.java.lang.invoke.MethodHandlesTest
  28  */
  29 
  30 package test.java.lang.invoke;
  31 
  32 import test.java.lang.invoke.remote.RemoteExample;
  33 import java.lang.invoke.*;
  34 import java.lang.invoke.MethodHandles.Lookup;
  35 import java.lang.reflect.*;
  36 import java.util.*;
  37 import org.junit.*;
  38 import static org.junit.Assert.*;
  39 
  40 
  41 /**
  42  *
  43  * @author jrose
  44  */
  45 public class MethodHandlesTest {
  46     static final Class<?> THIS_CLASS = MethodHandlesTest.class;
  47     // How much output?
  48     static int verbosity = 0;
  49     static {
  50         String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".verbosity");
  51         if (vstr == null)
  52             vstr = System.getProperty(THIS_CLASS.getName()+".verbosity");
  53         if (vstr != null)  verbosity = Integer.parseInt(vstr);
  54     }
  55 
  56     // Set this true during development if you want to fast-forward to
  57     // a particular new, non-working test.  Tests which are known to
  58     // work (or have recently worked) test this flag and return on true.
  59     static final boolean CAN_SKIP_WORKING;
  60     static {
  61         String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".CAN_SKIP_WORKING");
  62         if (vstr == null)
  63             vstr = System.getProperty(THIS_CLASS.getName()+".CAN_SKIP_WORKING");
  64         CAN_SKIP_WORKING = Boolean.parseBoolean(vstr);
  65     }
  66 
  67     // Set 'true' to do about 15x fewer tests, especially those redundant with RicochetTest.
  68     // This might be useful with -Xcomp stress tests that compile all method handles.
  69     static boolean CAN_TEST_LIGHTLY = Boolean.getBoolean(THIS_CLASS.getName()+".CAN_TEST_LIGHTLY");
  70 
  71     @Test
  72     public void testFirst() throws Throwable {
  73         verbosity += 9; try {
  74             // left blank for debugging
  75         } finally { printCounts(); verbosity -= 9; }
  76     }
  77 
  78     static final int MAX_ARG_INCREASE = 3;
  79 
  80     public MethodHandlesTest() {
  81     }
  82 
  83     String testName;
  84     static int allPosTests, allNegTests;
  85     int posTests, negTests;
  86     @After
  87     public void printCounts() {
  88         if (verbosity >= 2 && (posTests | negTests) != 0) {
  89             System.out.println();
  90             if (posTests != 0)  System.out.println("=== "+testName+": "+posTests+" positive test cases run");
  91             if (negTests != 0)  System.out.println("=== "+testName+": "+negTests+" negative test cases run");
  92             allPosTests += posTests;
  93             allNegTests += negTests;
  94             posTests = negTests = 0;
  95         }
  96     }
  97     void countTest(boolean positive) {
  98         if (positive) ++posTests;
  99         else          ++negTests;
 100     }
 101     void countTest() { countTest(true); }
 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
 111     public static void setUpClass() throws Exception {
 112         calledLog.clear();
 113         calledLog.add(null);
 114         nextArgVal = INITIAL_ARG_VAL;
 115     }
 116 
 117     @AfterClass
 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     static Object logEntry(String name, Object... args) {
 129         return Arrays.asList(name, Arrays.asList(args));
 130     }
 131     public static Object called(String name, Object... args) {
 132         Object entry = logEntry(name, args);
 133         calledLog.add(entry);
 134         return entry;
 135     }
 136     static void assertCalled(String name, Object... args) {
 137         Object expected = logEntry(name, args);
 138         Object actual   = calledLog.get(calledLog.size() - 1);
 139         if (expected.equals(actual) && verbosity < 9)  return;
 140         System.out.println("assertCalled "+name+":");
 141         System.out.println("expected:   "+deepToString(expected));
 142         System.out.println("actual:     "+actual);
 143         System.out.println("ex. types:  "+getClasses(expected));
 144         System.out.println("act. types: "+getClasses(actual));
 145         assertEquals("previous method call", expected, actual);
 146     }
 147     static void printCalled(MethodHandle target, String name, Object... args) {
 148         if (verbosity >= 3)
 149             System.out.println("calling MH="+target+" to "+name+deepToString(args));
 150     }
 151     static String deepToString(Object x) {
 152         if (x == null)  return "null";
 153         if (x instanceof Collection)
 154             x = ((Collection)x).toArray();
 155         if (x instanceof Object[]) {
 156             Object[] ax = (Object[]) x;
 157             ax = Arrays.copyOf(ax, ax.length, Object[].class);
 158             for (int i = 0; i < ax.length; i++)
 159                 ax[i] = deepToString(ax[i]);
 160             x = Arrays.deepToString(ax);
 161         }
 162         if (x.getClass().isArray())
 163             try {
 164                 x = Arrays.class.getMethod("toString", x.getClass()).invoke(null, x);
 165             } catch (ReflectiveOperationException ex) { throw new Error(ex); }
 166         assert(!(x instanceof Object[]));
 167         return x.toString();
 168     }
 169 
 170     static Object castToWrapper(Object value, Class<?> dst) {
 171         Object wrap = null;
 172         if (value instanceof Number)
 173             wrap = castToWrapperOrNull(((Number)value).longValue(), dst);
 174         if (value instanceof Character)
 175             wrap = castToWrapperOrNull((char)(Character)value, dst);
 176         if (wrap != null)  return wrap;
 177         return dst.cast(value);
 178     }
 179 
 180     @SuppressWarnings("cast")  // primitive cast to (long) is part of the pattern
 181     static Object castToWrapperOrNull(long value, Class<?> dst) {
 182         if (dst == int.class || dst == Integer.class)
 183             return (int)(value);
 184         if (dst == long.class || dst == Long.class)
 185             return (long)(value);
 186         if (dst == char.class || dst == Character.class)
 187             return (char)(value);
 188         if (dst == short.class || dst == Short.class)
 189             return (short)(value);
 190         if (dst == float.class || dst == Float.class)
 191             return (float)(value);
 192         if (dst == double.class || dst == Double.class)
 193             return (double)(value);
 194         if (dst == byte.class || dst == Byte.class)
 195             return (byte)(value);
 196         if (dst == boolean.class || dst == boolean.class)
 197             return ((value % 29) & 1) == 0;
 198         return null;
 199     }
 200 
 201     static final int ONE_MILLION = (1000*1000),  // first int value
 202                      TEN_BILLION = (10*1000*1000*1000),  // scale factor to reach upper 32 bits
 203                      INITIAL_ARG_VAL = ONE_MILLION << 1;  // <<1 makes space for sign bit;
 204     static long nextArgVal;
 205     static long nextArg(boolean moreBits) {
 206         long val = nextArgVal++;
 207         long sign = -(val & 1); // alternate signs
 208         val >>= 1;
 209         if (moreBits)
 210             // Guarantee some bits in the high word.
 211             // In any case keep the decimal representation simple-looking,
 212             // with lots of zeroes, so as not to make the printed decimal
 213             // strings unnecessarily noisy.
 214             val += (val % ONE_MILLION) * TEN_BILLION;
 215         return val ^ sign;
 216     }
 217     static int nextArg() {
 218         // Produce a 32-bit result something like ONE_MILLION+(smallint).
 219         // Example: 1_000_042.
 220         return (int) nextArg(false);
 221     }
 222     static long nextArg(Class<?> kind) {
 223         if (kind == long.class   || kind == Long.class ||
 224             kind == double.class || kind == Double.class)
 225             // produce a 64-bit result something like
 226             // ((TEN_BILLION+1) * (ONE_MILLION+(smallint)))
 227             // Example: 10_000_420_001_000_042.
 228             return nextArg(true);
 229         return (long) nextArg();
 230     }
 231 
 232     static Object randomArg(Class<?> param) {
 233         Object wrap = castToWrapperOrNull(nextArg(param), param);
 234         if (wrap != null) {
 235             return wrap;
 236         }
 237 //        import sun.invoke.util.Wrapper;
 238 //        Wrapper wrap = Wrapper.forBasicType(dst);
 239 //        if (wrap == Wrapper.OBJECT && Wrapper.isWrapperType(dst))
 240 //            wrap = Wrapper.forWrapperType(dst);
 241 //        if (wrap != Wrapper.OBJECT)
 242 //            return wrap.wrap(nextArg++);
 243         if (param.isInterface()) {
 244             for (Class<?> c : param.getClasses()) {
 245                 if (param.isAssignableFrom(c) && !c.isInterface())
 246                     { param = c; break; }
 247             }
 248         }
 249         if (param.isArray()) {
 250             Class<?> ctype = param.getComponentType();
 251             Object arg = Array.newInstance(ctype, 2);
 252             Array.set(arg, 0, randomArg(ctype));
 253             return arg;
 254         }
 255         if (param.isInterface() && param.isAssignableFrom(List.class))
 256             return Arrays.asList("#"+nextArg());
 257         if (param.isInterface() || param.isAssignableFrom(String.class))
 258             return "#"+nextArg();
 259         else
 260             try {
 261                 return param.newInstance();
 262             } catch (InstantiationException | IllegalAccessException ex) {
 263             }
 264         return null;  // random class not Object, String, Integer, etc.
 265     }
 266     static Object[] randomArgs(Class<?>... params) {
 267         Object[] args = new Object[params.length];
 268         for (int i = 0; i < args.length; i++)
 269             args[i] = randomArg(params[i]);
 270         return args;
 271     }
 272     static Object[] randomArgs(int nargs, Class<?> param) {
 273         Object[] args = new Object[nargs];
 274         for (int i = 0; i < args.length; i++)
 275             args[i] = randomArg(param);
 276         return args;
 277     }
 278     static Object[] randomArgs(List<Class<?>> params) {
 279         return randomArgs(params.toArray(new Class<?>[params.size()]));
 280     }
 281 
 282     @SafeVarargs @SuppressWarnings("varargs")
 283     static <T, E extends T> T[] array(Class<T[]> atype, E... a) {
 284         return Arrays.copyOf(a, a.length, atype);
 285     }
 286     @SafeVarargs @SuppressWarnings("varargs")
 287     static <T> T[] cat(T[] a, T... b) {
 288         int alen = a.length, blen = b.length;
 289         if (blen == 0)  return a;
 290         T[] c = Arrays.copyOf(a, alen + blen);
 291         System.arraycopy(b, 0, c, alen, blen);
 292         return c;
 293     }
 294     static Integer[] boxAll(int... vx) {
 295         Integer[] res = new Integer[vx.length];
 296         for (int i = 0; i < res.length; i++) {
 297             res[i] = vx[i];
 298         }
 299         return res;
 300     }
 301     static Object getClasses(Object x) {
 302         if (x == null)  return x;
 303         if (x instanceof String)  return x;  // keep the name
 304         if (x instanceof List) {
 305             // recursively report classes of the list elements
 306             Object[] xa = ((List)x).toArray();
 307             for (int i = 0; i < xa.length; i++)
 308                 xa[i] = getClasses(xa[i]);
 309             return Arrays.asList(xa);
 310         }
 311         return x.getClass().getSimpleName();
 312     }
 313 
 314     /** Return lambda(arg...[arity]) { new Object[]{ arg... } } */
 315     static MethodHandle varargsList(int arity) {
 316         return ValueConversions.varargsList(arity);
 317     }
 318     /** Return lambda(arg...[arity]) { Arrays.asList(arg...) } */
 319     static MethodHandle varargsArray(int arity) {
 320         return ValueConversions.varargsArray(arity);
 321     }
 322     static MethodHandle varargsArray(Class<?> arrayType, int arity) {
 323         return ValueConversions.varargsArray(arrayType, arity);
 324     }
 325     /** Variation of varargsList, but with the given rtype. */
 326     static MethodHandle varargsList(int arity, Class<?> rtype) {
 327         MethodHandle list = varargsList(arity);
 328         MethodType listType = list.type().changeReturnType(rtype);
 329         if (List.class.isAssignableFrom(rtype) || rtype == void.class || rtype == Object.class) {
 330             // OK
 331         } else if (rtype.isAssignableFrom(String.class)) {
 332             if (LIST_TO_STRING == null)
 333                 try {
 334                     LIST_TO_STRING = PRIVATE.findStatic(PRIVATE.lookupClass(), "listToString",
 335                                                         MethodType.methodType(String.class, List.class));
 336                 } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); }
 337             list = MethodHandles.filterReturnValue(list, LIST_TO_STRING);
 338         } else if (rtype.isPrimitive()) {
 339             if (LIST_TO_INT == null)
 340                 try {
 341                     LIST_TO_INT = PRIVATE.findStatic(PRIVATE.lookupClass(), "listToInt",
 342                                                      MethodType.methodType(int.class, List.class));
 343                 } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); }
 344             list = MethodHandles.filterReturnValue(list, LIST_TO_INT);
 345             list = MethodHandles.explicitCastArguments(list, listType);
 346         } else {
 347             throw new RuntimeException("varargsList: "+rtype);
 348         }
 349         return list.asType(listType);
 350     }
 351     /** Variation of varargsList, but with the given ptypes and rtype. */
 352     static MethodHandle varargsList(List<Class<?>> ptypes, Class<?> rtype) {
 353         MethodHandle list = varargsList(ptypes.size(), rtype);
 354         return list.asType(MethodType.methodType(rtype, ptypes));
 355     }
 356     private static MethodHandle LIST_TO_STRING, LIST_TO_INT;
 357     private static String listToString(List<?> x) { return x.toString(); }
 358     private static int listToInt(List<?> x) { return x.toString().hashCode(); }
 359 
 360     static MethodHandle changeArgTypes(MethodHandle target, Class<?> argType) {
 361         return changeArgTypes(target, 0, 999, argType);
 362     }
 363     static MethodHandle changeArgTypes(MethodHandle target,
 364             int beg, int end, Class<?> argType) {
 365         MethodType targetType = target.type();
 366         end = Math.min(end, targetType.parameterCount());
 367         ArrayList<Class<?>> argTypes = new ArrayList<>(targetType.parameterList());
 368         Collections.fill(argTypes.subList(beg, end), argType);
 369         MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes);
 370         return target.asType(ttype2);
 371     }
 372     static MethodHandle addTrailingArgs(MethodHandle target, int nargs, Class<?> argClass) {
 373         int targetLen = target.type().parameterCount();
 374         int extra = (nargs - targetLen);
 375         if (extra <= 0)  return target;
 376         List<Class<?>> fakeArgs = Collections.<Class<?>>nCopies(extra, argClass);
 377         return MethodHandles.dropArguments(target, targetLen, fakeArgs);
 378     }
 379 
 380     // This lookup is good for all members in and under MethodHandlesTest.
 381     static final Lookup PRIVATE = MethodHandles.lookup();
 382     // This lookup is good for package-private members but not private ones.
 383     static final Lookup PACKAGE = PackageSibling.lookup();
 384     // This lookup is good for public members and protected members of PubExample
 385     static final Lookup SUBCLASS = RemoteExample.lookup();
 386     // This lookup is good only for public members.
 387     static final Lookup PUBLIC  = MethodHandles.publicLookup();
 388 
 389     // Subject methods...
 390     static class Example implements IntExample {
 391         final String name;
 392         public Example() { name = "Example#"+nextArg(); }
 393         protected Example(String name) { this.name = name; }
 394         @SuppressWarnings("LeakingThisInConstructor")
 395         protected Example(int x) { this(); called("protected <init>", this, x); }
 396         //Example(Void x) { does not exist; lookup elicts NoSuchMethodException }
 397         @Override public String toString() { return name; }
 398 
 399         public void            v0()     { called("v0", this); }
 400         protected void         pro_v0() { called("pro_v0", this); }
 401         void                   pkg_v0() { called("pkg_v0", this); }
 402         private void           pri_v0() { called("pri_v0", this); }
 403         public static void     s0()     { called("s0"); }
 404         protected static void  pro_s0() { called("pro_s0"); }
 405         static void            pkg_s0() { called("pkg_s0"); }
 406         private static void    pri_s0() { called("pri_s0"); }
 407 
 408         public Object          v1(Object x) { return called("v1", this, x); }
 409         public Object          v2(Object x, Object y) { return called("v2", this, x, y); }
 410         public Object          v2(Object x, int    y) { return called("v2", this, x, y); }
 411         public Object          v2(int    x, Object y) { return called("v2", this, x, y); }
 412         public Object          v2(int    x, int    y) { return called("v2", this, x, y); }
 413         public static Object   s1(Object x) { return called("s1", x); }
 414         public static Object   s2(int x)    { return called("s2", x); }
 415         public static Object   s3(long x)   { return called("s3", x); }
 416         public static Object   s4(int x, int y) { return called("s4", x, y); }
 417         public static Object   s5(long x, int y) { return called("s5", x, y); }
 418         public static Object   s6(int x, long y) { return called("s6", x, y); }
 419         public static Object   s7(float x, double y) { return called("s7", x, y); }
 420 
 421         // for testing findConstructor:
 422         public Example(String x, int y) { this.name = x+y; called("Example.<init>", x, y); }
 423         public Example(int x, String y) { this.name = x+y; called("Example.<init>", x, y); }
 424         public Example(int x, int    y) { this.name = x+""+y; called("Example.<init>", x, y); }
 425         public Example(int x, long   y) { this.name = x+""+y; called("Example.<init>", x, y); }
 426         public Example(int x, float  y) { this.name = x+""+y; called("Example.<init>", x, y); }
 427         public Example(int x, double y) { this.name = x+""+y; called("Example.<init>", x, y); }
 428         public Example(int x, int    y, int z) { this.name = x+""+y+""+z; called("Example.<init>", x, y, z); }
 429         public Example(int x, int    y, int z, int a) { this.name = x+""+y+""+z+""+a; called("Example.<init>", x, y, z, a); }
 430 
 431         static final Lookup EXAMPLE = MethodHandles.lookup();  // for testing findSpecial
 432     }
 433     static final Lookup EXAMPLE = Example.EXAMPLE;
 434     public static class PubExample extends Example {
 435         public PubExample() { this("PubExample"); }
 436         protected PubExample(String prefix) { super(prefix+"#"+nextArg()); }
 437         protected void         pro_v0() { called("Pub/pro_v0", this); }
 438         protected static void  pro_s0() { called("Pub/pro_s0"); }
 439     }
 440     static class SubExample extends Example {
 441         @Override public void  v0()     { called("Sub/v0", this); }
 442         @Override void         pkg_v0() { called("Sub/pkg_v0", this); }
 443         @SuppressWarnings("LeakingThisInConstructor")
 444         private      SubExample(int x)  { called("<init>", this, x); }
 445         public SubExample() { super("SubExample#"+nextArg()); }
 446     }
 447     public static interface IntExample {
 448         public void            v0();
 449         public static class Impl implements IntExample {
 450             public void        v0()     { called("Int/v0", this); }
 451             final String name;
 452             public Impl() { name = "Impl#"+nextArg(); }
 453             @Override public String toString() { return name; }
 454         }
 455     }
 456     static interface SubIntExample extends IntExample { }
 457 
 458     static final Object[][][] ACCESS_CASES = {
 459         { { false, PUBLIC }, { false, SUBCLASS }, { false, PACKAGE }, { false, PRIVATE }, { false, EXAMPLE } }, //[0]: all false
 460         { { false, PUBLIC }, { false, SUBCLASS }, { false, PACKAGE }, { true,  PRIVATE }, { true,  EXAMPLE } }, //[1]: only PRIVATE
 461         { { false, PUBLIC }, { false, SUBCLASS }, { true,  PACKAGE }, { true,  PRIVATE }, { true,  EXAMPLE } }, //[2]: PUBLIC false
 462         { { false, PUBLIC }, { true,  SUBCLASS }, { true,  PACKAGE }, { true,  PRIVATE }, { true,  EXAMPLE } }, //[3]: subclass OK
 463         { { true,  PUBLIC }, { true,  SUBCLASS }, { true,  PACKAGE }, { true,  PRIVATE }, { true,  EXAMPLE } }, //[4]: all true
 464     };
 465 
 466     static Object[][] accessCases(Class<?> defc, String name, boolean isSpecial) {
 467         Object[][] cases;
 468         if (name.contains("pri_") || isSpecial) {
 469             cases = ACCESS_CASES[1]; // PRIVATE only
 470         } else if (name.contains("pkg_") || !Modifier.isPublic(defc.getModifiers())) {
 471             cases = ACCESS_CASES[2]; // not PUBLIC
 472         } else if (name.contains("pro_")) {
 473             cases = ACCESS_CASES[3]; // PUBLIC class, protected member
 474         } else {
 475             assertTrue(name.indexOf('_') < 0 || name.contains("fin_"));
 476             boolean pubc = Modifier.isPublic(defc.getModifiers());
 477             if (pubc)
 478                 cases = ACCESS_CASES[4]; // all access levels
 479             else
 480                 cases = ACCESS_CASES[2]; // PACKAGE but not PUBLIC
 481         }
 482         if (defc != Example.class && cases[cases.length-1][1] == EXAMPLE)
 483             cases = Arrays.copyOfRange(cases, 0, cases.length-1);
 484         return cases;
 485     }
 486     static Object[][] accessCases(Class<?> defc, String name) {
 487         return accessCases(defc, name, false);
 488     }
 489 
 490     static Lookup maybeMoveIn(Lookup lookup, Class<?> defc) {
 491         if (lookup == PUBLIC || lookup == SUBCLASS || lookup == PACKAGE)
 492             // external views stay external
 493             return lookup;
 494         return lookup.in(defc);
 495     }
 496 
 497     /** Is findVirtual (etc.) of "&lt;init&lt;" supposed to elicit a NoSuchMethodException? */
 498     final static boolean INIT_REF_CAUSES_NSME = true;
 499 
 500     @Test
 501     public void testFindStatic() throws Throwable {
 502         if (CAN_SKIP_WORKING)  return;
 503         startTest("findStatic");
 504         testFindStatic(PubExample.class, void.class, "s0");
 505         testFindStatic(Example.class, void.class, "s0");
 506         testFindStatic(Example.class, void.class, "pkg_s0");
 507         testFindStatic(Example.class, void.class, "pri_s0");
 508         testFindStatic(Example.class, void.class, "pro_s0");
 509         testFindStatic(PubExample.class, void.class, "Pub/pro_s0");
 510 
 511         testFindStatic(Example.class, Object.class, "s1", Object.class);
 512         testFindStatic(Example.class, Object.class, "s2", int.class);
 513         testFindStatic(Example.class, Object.class, "s3", long.class);
 514         testFindStatic(Example.class, Object.class, "s4", int.class, int.class);
 515         testFindStatic(Example.class, Object.class, "s5", long.class, int.class);
 516         testFindStatic(Example.class, Object.class, "s6", int.class, long.class);
 517         testFindStatic(Example.class, Object.class, "s7", float.class, double.class);
 518 
 519         testFindStatic(false, PRIVATE, Example.class, void.class, "bogus");
 520         testFindStatic(false, PRIVATE, Example.class, void.class, "<init>", int.class);
 521         testFindStatic(false, PRIVATE, Example.class, void.class, "<init>", Void.class);
 522         testFindStatic(false, PRIVATE, Example.class, void.class, "v0");
 523     }
 524 
 525     void testFindStatic(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
 526         for (Object[] ac : accessCases(defc, name)) {
 527             testFindStatic((Boolean)ac[0], (Lookup)ac[1], defc, ret, name, params);
 528         }
 529     }
 530     void testFindStatic(Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
 531         testFindStatic(true, lookup, defc, ret, name, params);
 532     }
 533     void testFindStatic(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
 534         countTest(positive);
 535         String methodName = name.substring(1 + name.indexOf('/'));  // foo/bar => foo
 536         MethodType type = MethodType.methodType(ret, params);
 537         MethodHandle target = null;
 538         Exception noAccess = null;
 539         try {
 540             if (verbosity >= 4)  System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
 541             target = maybeMoveIn(lookup, defc).findStatic(defc, methodName, type);
 542         } catch (ReflectiveOperationException ex) {
 543             noAccess = ex;
 544             assertExceptionClass(
 545                 (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>"))
 546                 ?   NoSuchMethodException.class
 547                 :   IllegalAccessException.class,
 548                 noAccess);
 549             if (verbosity >= 5)  ex.printStackTrace(System.out);
 550         }
 551         if (verbosity >= 3)
 552             System.out.println("findStatic "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target
 553                     +(noAccess == null ? "" : " !! "+noAccess));
 554         if (positive && noAccess != null)  throw noAccess;
 555         assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
 556         if (!positive)  return; // negative test failed as expected
 557         assertEquals(type, target.type());
 558         assertNameStringContains(target, methodName);
 559         Object[] args = randomArgs(params);
 560         printCalled(target, name, args);
 561         target.invokeWithArguments(args);
 562         assertCalled(name, args);
 563         if (verbosity >= 1)
 564             System.out.print(':');
 565     }
 566 
 567     static void assertExceptionClass(Class<? extends Throwable> expected,
 568                                      Throwable actual) {
 569         if (expected.isInstance(actual))  return;
 570         actual.printStackTrace();
 571         assertEquals(expected, actual.getClass());
 572     }
 573 
 574     static final boolean DEBUG_METHOD_HANDLE_NAMES = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
 575 
 576     // rough check of name string
 577     static void assertNameStringContains(MethodHandle x, String s) {
 578         if (!DEBUG_METHOD_HANDLE_NAMES) {
 579             // ignore s
 580             assertEquals("MethodHandle"+x.type(), x.toString());
 581             return;
 582         }
 583         if (x.toString().contains(s))  return;
 584         assertEquals(s, x);
 585     }
 586 
 587     @Test
 588     public void testFindVirtual() throws Throwable {
 589         if (CAN_SKIP_WORKING)  return;
 590         startTest("findVirtual");
 591         testFindVirtual(Example.class, void.class, "v0");
 592         testFindVirtual(Example.class, void.class, "pkg_v0");
 593         testFindVirtual(Example.class, void.class, "pri_v0");
 594         testFindVirtual(Example.class, Object.class, "v1", Object.class);
 595         testFindVirtual(Example.class, Object.class, "v2", Object.class, Object.class);
 596         testFindVirtual(Example.class, Object.class, "v2", Object.class, int.class);
 597         testFindVirtual(Example.class, Object.class, "v2", int.class, Object.class);
 598         testFindVirtual(Example.class, Object.class, "v2", int.class, int.class);
 599         testFindVirtual(Example.class, void.class, "pro_v0");
 600         testFindVirtual(PubExample.class, void.class, "Pub/pro_v0");
 601 
 602         testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "bogus");
 603         testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "<init>", int.class);
 604         testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "<init>", Void.class);
 605         testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "s0");
 606 
 607         // test dispatch
 608         testFindVirtual(SubExample.class,      SubExample.class, void.class, "Sub/v0");
 609         testFindVirtual(SubExample.class,         Example.class, void.class, "Sub/v0");
 610         testFindVirtual(SubExample.class,      IntExample.class, void.class, "Sub/v0");
 611         testFindVirtual(SubExample.class,      SubExample.class, void.class, "Sub/pkg_v0");
 612         testFindVirtual(SubExample.class,         Example.class, void.class, "Sub/pkg_v0");
 613         testFindVirtual(Example.class,         IntExample.class, void.class, "v0");
 614         testFindVirtual(IntExample.Impl.class, IntExample.class, void.class, "Int/v0");
 615     }
 616 
 617     @Test
 618     public void testFindVirtualClone() throws Throwable {
 619         // test some ad hoc system methods
 620         testFindVirtual(false, PUBLIC, Object.class, Object.class, "clone");
 621         testFindVirtual(true, PUBLIC, Object[].class, Object.class, "clone");
 622         testFindVirtual(true, PUBLIC, int[].class, Object.class, "clone");
 623         for (Class<?> cls : new Class<?>[]{ boolean[].class, long[].class, float[].class, char[].class })
 624             testFindVirtual(true, PUBLIC, cls, Object.class, "clone");
 625     }
 626 
 627     void testFindVirtual(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
 628         Class<?> rcvc = defc;
 629         testFindVirtual(rcvc, defc, ret, name, params);
 630     }
 631     void testFindVirtual(Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
 632         for (Object[] ac : accessCases(defc, name)) {
 633             testFindVirtual((Boolean)ac[0], (Lookup)ac[1], rcvc, defc, ret, name, params);
 634         }
 635     }
 636     void testFindVirtual(Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
 637         testFindVirtual(true, lookup, rcvc, defc, ret, name, params);
 638     }
 639     void testFindVirtual(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
 640         testFindVirtual(positive, lookup, defc, defc, ret, name, params);
 641     }
 642     void testFindVirtual(boolean positive, Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
 643         countTest(positive);
 644         String methodName = name.substring(1 + name.indexOf('/'));  // foo/bar => foo
 645         MethodType type = MethodType.methodType(ret, params);
 646         MethodHandle target = null;
 647         Exception noAccess = null;
 648         try {
 649             if (verbosity >= 4)  System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
 650             target = maybeMoveIn(lookup, defc).findVirtual(defc, methodName, type);
 651         } catch (ReflectiveOperationException ex) {
 652             noAccess = ex;
 653             assertExceptionClass(
 654                 (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>"))
 655                 ?   NoSuchMethodException.class
 656                 :   IllegalAccessException.class,
 657                 noAccess);
 658             if (verbosity >= 5)  ex.printStackTrace(System.out);
 659         }
 660         if (verbosity >= 3)
 661             System.out.println("findVirtual "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target
 662                     +(noAccess == null ? "" : " !! "+noAccess));
 663         if (positive && noAccess != null)  throw noAccess;
 664         assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
 665         if (!positive)  return; // negative test failed as expected
 666         Class<?> selfc = defc;
 667         // predict receiver type narrowing:
 668         if (lookup == SUBCLASS &&
 669                 name.contains("pro_") &&
 670                 selfc.isAssignableFrom(lookup.lookupClass())) {
 671             selfc = lookup.lookupClass();
 672             if (name.startsWith("Pub/"))  name = "Rem/"+name.substring(4);
 673         }
 674         Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)selfc), params);
 675         MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf);
 676         assertEquals(typeWithSelf, target.type());
 677         assertNameStringContains(target, methodName);
 678         Object[] argsWithSelf = randomArgs(paramsWithSelf);
 679         if (selfc.isAssignableFrom(rcvc) && rcvc != selfc)  argsWithSelf[0] = randomArg(rcvc);
 680         printCalled(target, name, argsWithSelf);
 681         Object res = target.invokeWithArguments(argsWithSelf);
 682         if (Example.class.isAssignableFrom(defc) || IntExample.class.isAssignableFrom(defc)) {
 683             assertCalled(name, argsWithSelf);
 684         } else if (name.equals("clone")) {
 685             // Ad hoc method call outside Example.  For Object[].clone.
 686             printCalled(target, name, argsWithSelf);
 687             assertEquals(MethodType.methodType(Object.class, rcvc), target.type());
 688             Object orig = argsWithSelf[0];
 689             assertEquals(orig.getClass(), res.getClass());
 690             if (res instanceof Object[])
 691                 assertArrayEquals((Object[])res, (Object[])argsWithSelf[0]);
 692             assert(Arrays.deepEquals(new Object[]{res}, new Object[]{argsWithSelf[0]}));
 693         } else {
 694             assert(false) : Arrays.asList(positive, lookup, rcvc, defc, ret, name, deepToString(params));
 695         }
 696         if (verbosity >= 1)
 697             System.out.print(':');
 698     }
 699 
 700     @Test
 701     public void testFindSpecial() throws Throwable {
 702         if (CAN_SKIP_WORKING)  return;
 703         startTest("findSpecial");
 704         testFindSpecial(SubExample.class, Example.class, void.class, "v0");
 705         testFindSpecial(SubExample.class, Example.class, void.class, "pkg_v0");
 706         testFindSpecial(RemoteExample.class, PubExample.class, void.class, "Pub/pro_v0");
 707         // Do some negative testing:
 708         for (Lookup lookup : new Lookup[]{ PRIVATE, EXAMPLE, PACKAGE, PUBLIC }) {
 709             testFindSpecial(false, lookup, Object.class, Example.class, void.class, "v0");
 710             testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "bogus");
 711             testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", int.class);
 712             testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", Void.class);
 713             testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "s0");
 714         }
 715     }
 716 
 717     void testFindSpecial(Class<?> specialCaller,
 718                          Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
 719         if (specialCaller == RemoteExample.class) {
 720             testFindSpecial(false, EXAMPLE,  specialCaller, defc, ret, name, params);
 721             testFindSpecial(false, PRIVATE,  specialCaller, defc, ret, name, params);
 722             testFindSpecial(false, PACKAGE,  specialCaller, defc, ret, name, params);
 723             testFindSpecial(true,  SUBCLASS, specialCaller, defc, ret, name, params);
 724             testFindSpecial(false, PUBLIC,   specialCaller, defc, ret, name, params);
 725             return;
 726         }
 727         testFindSpecial(true,  EXAMPLE,  specialCaller, defc, ret, name, params);
 728         testFindSpecial(true,  PRIVATE,  specialCaller, defc, ret, name, params);
 729         testFindSpecial(false, PACKAGE,  specialCaller, defc, ret, name, params);
 730         testFindSpecial(false, SUBCLASS, specialCaller, defc, ret, name, params);
 731         testFindSpecial(false, PUBLIC,   specialCaller, defc, ret, name, params);
 732     }
 733     void testFindSpecial(boolean positive, Lookup lookup, Class<?> specialCaller,
 734                          Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
 735         countTest(positive);
 736         String methodName = name.substring(1 + name.indexOf('/'));  // foo/bar => foo
 737         MethodType type = MethodType.methodType(ret, params);
 738         Lookup specialLookup = maybeMoveIn(lookup, specialCaller);
 739         boolean specialAccessOK = (specialLookup.lookupClass() == specialCaller &&
 740                                    (specialLookup.lookupModes() & Lookup.PRIVATE) != 0);
 741         MethodHandle target = null;
 742         Exception noAccess = null;
 743         try {
 744             if (verbosity >= 4)  System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
 745             if (verbosity >= 5)  System.out.println("  lookup => "+specialLookup);
 746             target = specialLookup.findSpecial(defc, methodName, type, specialCaller);
 747         } catch (ReflectiveOperationException ex) {
 748             noAccess = ex;
 749             assertExceptionClass(
 750                 (!specialAccessOK)  // this check should happen first
 751                 ?   IllegalAccessException.class
 752                 : (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>"))
 753                 ?   NoSuchMethodException.class
 754                 : IllegalAccessException.class,
 755                 noAccess);
 756             if (verbosity >= 5)  ex.printStackTrace(System.out);
 757         }
 758         if (verbosity >= 3)
 759             System.out.println("findSpecial from "+specialCaller.getName()+" to "+defc.getName()+"."+name+"/"+type+" => "+target
 760                                +(target == null ? "" : target.type())
 761                                +(noAccess == null ? "" : " !! "+noAccess));
 762         if (positive && noAccess != null)  throw noAccess;
 763         assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
 764         if (!positive)  return; // negative test failed as expected
 765         assertEquals(specialCaller, target.type().parameterType(0));
 766         assertEquals(type,          target.type().dropParameterTypes(0,1));
 767         Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)specialCaller), params);
 768         MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf);
 769         assertNameStringContains(target, methodName);
 770         Object[] args = randomArgs(paramsWithSelf);
 771         printCalled(target, name, args);
 772         target.invokeWithArguments(args);
 773         assertCalled(name, args);
 774     }
 775 
 776     @Test
 777     public void testFindConstructor() throws Throwable {
 778         if (CAN_SKIP_WORKING)  return;
 779         startTest("findConstructor");
 780         testFindConstructor(true, EXAMPLE, Example.class);
 781         testFindConstructor(true, EXAMPLE, Example.class, int.class);
 782         testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class);
 783         testFindConstructor(true, EXAMPLE, Example.class, int.class, long.class);
 784         testFindConstructor(true, EXAMPLE, Example.class, int.class, float.class);
 785         testFindConstructor(true, EXAMPLE, Example.class, int.class, double.class);
 786         testFindConstructor(true, EXAMPLE, Example.class, String.class);
 787         testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class, int.class);
 788         testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class, int.class, int.class);
 789     }
 790     void testFindConstructor(boolean positive, Lookup lookup,
 791                              Class<?> defc, Class<?>... params) throws Throwable {
 792         countTest(positive);
 793         MethodType type = MethodType.methodType(void.class, params);
 794         MethodHandle target = null;
 795         Exception noAccess = null;
 796         try {
 797             if (verbosity >= 4)  System.out.println("lookup via "+lookup+" of "+defc+" <init>"+type);
 798             target = lookup.findConstructor(defc, type);
 799         } catch (ReflectiveOperationException ex) {
 800             noAccess = ex;
 801             assertTrue(noAccess.getClass().getName(), noAccess instanceof IllegalAccessException);
 802         }
 803         if (verbosity >= 3)
 804             System.out.println("findConstructor "+defc.getName()+".<init>/"+type+" => "+target
 805                                +(target == null ? "" : target.type())
 806                                +(noAccess == null ? "" : " !! "+noAccess));
 807         if (positive && noAccess != null)  throw noAccess;
 808         assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
 809         if (!positive)  return; // negative test failed as expected
 810         assertEquals(type.changeReturnType(defc), target.type());
 811         Object[] args = randomArgs(params);
 812         printCalled(target, defc.getSimpleName(), args);
 813         Object obj = target.invokeWithArguments(args);
 814         if (!(defc == Example.class && params.length < 2))
 815             assertCalled(defc.getSimpleName()+".<init>", args);
 816         assertTrue("instance of "+defc.getName(), defc.isInstance(obj));
 817     }
 818 
 819     @Test
 820     public void testBind() throws Throwable {
 821         if (CAN_SKIP_WORKING)  return;
 822         startTest("bind");
 823         testBind(Example.class, void.class, "v0");
 824         testBind(Example.class, void.class, "pkg_v0");
 825         testBind(Example.class, void.class, "pri_v0");
 826         testBind(Example.class, Object.class, "v1", Object.class);
 827         testBind(Example.class, Object.class, "v2", Object.class, Object.class);
 828         testBind(Example.class, Object.class, "v2", Object.class, int.class);
 829         testBind(Example.class, Object.class, "v2", int.class, Object.class);
 830         testBind(Example.class, Object.class, "v2", int.class, int.class);
 831         testBind(false, PRIVATE, Example.class, void.class, "bogus");
 832         testBind(false, PRIVATE, Example.class, void.class, "<init>", int.class);
 833         testBind(false, PRIVATE, Example.class, void.class, "<init>", Void.class);
 834         testBind(SubExample.class, void.class, "Sub/v0");
 835         testBind(SubExample.class, void.class, "Sub/pkg_v0");
 836         testBind(IntExample.Impl.class, void.class, "Int/v0");
 837     }
 838 
 839     void testBind(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
 840         for (Object[] ac : accessCases(defc, name)) {
 841             testBind((Boolean)ac[0], (Lookup)ac[1], defc, ret, name, params);
 842         }
 843     }
 844 
 845     void testBind(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
 846         countTest(positive);
 847         String methodName = name.substring(1 + name.indexOf('/'));  // foo/bar => foo
 848         MethodType type = MethodType.methodType(ret, params);
 849         Object receiver = randomArg(defc);
 850         MethodHandle target = null;
 851         Exception noAccess = null;
 852         try {
 853             if (verbosity >= 4)  System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
 854             target = maybeMoveIn(lookup, defc).bind(receiver, methodName, type);
 855         } catch (ReflectiveOperationException ex) {
 856             noAccess = ex;
 857             assertExceptionClass(
 858                 (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>"))
 859                 ?   NoSuchMethodException.class
 860                 :   IllegalAccessException.class,
 861                 noAccess);
 862             if (verbosity >= 5)  ex.printStackTrace(System.out);
 863         }
 864         if (verbosity >= 3)
 865             System.out.println("bind "+receiver+"."+name+"/"+type+" => "+target
 866                     +(noAccess == null ? "" : " !! "+noAccess));
 867         if (positive && noAccess != null)  throw noAccess;
 868         assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
 869         if (!positive)  return; // negative test failed as expected
 870         assertEquals(type, target.type());
 871         Object[] args = randomArgs(params);
 872         printCalled(target, name, args);
 873         target.invokeWithArguments(args);
 874         Object[] argsWithReceiver = cat(array(Object[].class, receiver), args);
 875         assertCalled(name, argsWithReceiver);
 876         if (verbosity >= 1)
 877             System.out.print(':');
 878     }
 879 
 880     @Test
 881     public void testUnreflect() throws Throwable {
 882         if (CAN_SKIP_WORKING)  return;
 883         startTest("unreflect");
 884         testUnreflect(Example.class, true, void.class, "s0");
 885         testUnreflect(Example.class, true, void.class, "pro_s0");
 886         testUnreflect(Example.class, true, void.class, "pkg_s0");
 887         testUnreflect(Example.class, true, void.class, "pri_s0");
 888 
 889         testUnreflect(Example.class, true, Object.class, "s1", Object.class);
 890         testUnreflect(Example.class, true, Object.class, "s2", int.class);
 891         testUnreflect(Example.class, true, Object.class, "s3", long.class);
 892         testUnreflect(Example.class, true, Object.class, "s4", int.class, int.class);
 893         testUnreflect(Example.class, true, Object.class, "s5", long.class, int.class);
 894         testUnreflect(Example.class, true, Object.class, "s6", int.class, long.class);
 895 
 896         testUnreflect(Example.class, false, void.class, "v0");
 897         testUnreflect(Example.class, false, void.class, "pkg_v0");
 898         testUnreflect(Example.class, false, void.class, "pri_v0");
 899         testUnreflect(Example.class, false, Object.class, "v1", Object.class);
 900         testUnreflect(Example.class, false, Object.class, "v2", Object.class, Object.class);
 901         testUnreflect(Example.class, false, Object.class, "v2", Object.class, int.class);
 902         testUnreflect(Example.class, false, Object.class, "v2", int.class, Object.class);
 903         testUnreflect(Example.class, false, Object.class, "v2", int.class, int.class);
 904 
 905         // Test a public final member in another package:
 906         testUnreflect(RemoteExample.class, false, void.class, "Rem/fin_v0");
 907     }
 908 
 909     void testUnreflect(Class<?> defc, boolean isStatic, Class<?> ret, String name, Class<?>... params) throws Throwable {
 910         for (Object[] ac : accessCases(defc, name)) {
 911             testUnreflectMaybeSpecial(null, (Boolean)ac[0], (Lookup)ac[1], defc, (isStatic ? null : defc), ret, name, params);
 912         }
 913     }
 914     void testUnreflect(Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable {
 915         for (Object[] ac : accessCases(defc, name)) {
 916             testUnreflectMaybeSpecial(null, (Boolean)ac[0], (Lookup)ac[1], defc, rcvc, ret, name, params);
 917         }
 918     }
 919     void testUnreflectMaybeSpecial(Class<?> specialCaller,
 920                                    boolean positive, Lookup lookup,
 921                                    Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable {
 922         countTest(positive);
 923         String methodName = name.substring(1 + name.indexOf('/'));  // foo/bar => foo
 924         MethodType type = MethodType.methodType(ret, params);
 925         Lookup specialLookup = (specialCaller != null ? maybeMoveIn(lookup, specialCaller) : null);
 926         boolean specialAccessOK = (specialCaller != null &&
 927                                    specialLookup.lookupClass() == specialCaller &&
 928                                    (specialLookup.lookupModes() & Lookup.PRIVATE) != 0);
 929         Method rmethod = defc.getDeclaredMethod(methodName, params);
 930         MethodHandle target = null;
 931         Exception noAccess = null;
 932         boolean isStatic = (rcvc == null);
 933         boolean isSpecial = (specialCaller != null);
 934         try {
 935             if (verbosity >= 4)  System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
 936             if (isSpecial)
 937                 target = specialLookup.unreflectSpecial(rmethod, specialCaller);
 938             else
 939                 target = maybeMoveIn(lookup, defc).unreflect(rmethod);
 940         } catch (ReflectiveOperationException ex) {
 941             noAccess = ex;
 942             assertExceptionClass(
 943                 IllegalAccessException.class,  // NSME is impossible, since it was already reflected
 944                 noAccess);
 945             if (verbosity >= 5)  ex.printStackTrace(System.out);
 946         }
 947         if (verbosity >= 3)
 948             System.out.println("unreflect"+(isSpecial?"Special":"")+" "+defc.getName()+"."+name+"/"+type
 949                                +(!isSpecial ? "" : " specialCaller="+specialCaller)
 950                                +( isStatic  ? "" : " receiver="+rcvc)
 951                                +" => "+target
 952                                +(noAccess == null ? "" : " !! "+noAccess));
 953         if (positive && noAccess != null)  throw noAccess;
 954         assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
 955         if (!positive)  return; // negative test failed as expected
 956         assertEquals(isStatic, Modifier.isStatic(rmethod.getModifiers()));
 957         Class<?>[] paramsMaybeWithSelf = params;
 958         if (!isStatic) {
 959             paramsMaybeWithSelf = cat(array(Class[].class, (Class)rcvc), params);
 960         }
 961         MethodType typeMaybeWithSelf = MethodType.methodType(ret, paramsMaybeWithSelf);
 962         if (isStatic) {
 963             assertEquals(typeMaybeWithSelf, target.type());
 964         } else {
 965             if (isSpecial)
 966                 assertEquals(specialCaller, target.type().parameterType(0));
 967             else
 968                 assertEquals(defc, target.type().parameterType(0));
 969             assertEquals(typeMaybeWithSelf, target.type().changeParameterType(0, rcvc));
 970         }
 971         Object[] argsMaybeWithSelf = randomArgs(paramsMaybeWithSelf);
 972         printCalled(target, name, argsMaybeWithSelf);
 973         target.invokeWithArguments(argsMaybeWithSelf);
 974         assertCalled(name, argsMaybeWithSelf);
 975         if (verbosity >= 1)
 976             System.out.print(':');
 977     }
 978 
 979     void testUnreflectSpecial(Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable {
 980         for (Object[] ac : accessCases(defc, name, true)) {
 981             Class<?> specialCaller = rcvc;
 982             testUnreflectMaybeSpecial(specialCaller, (Boolean)ac[0], (Lookup)ac[1], defc, rcvc, ret, name, params);
 983         }
 984     }
 985 
 986     @Test
 987     public void testUnreflectSpecial() throws Throwable {
 988         if (CAN_SKIP_WORKING)  return;
 989         startTest("unreflectSpecial");
 990         testUnreflectSpecial(Example.class,    Example.class, void.class, "v0");
 991         testUnreflectSpecial(Example.class, SubExample.class, void.class, "v0");
 992         testUnreflectSpecial(Example.class,    Example.class, void.class, "pkg_v0");
 993         testUnreflectSpecial(Example.class, SubExample.class, void.class, "pkg_v0");
 994         testUnreflectSpecial(Example.class,    Example.class, Object.class, "v2", int.class, int.class);
 995         testUnreflectSpecial(Example.class, SubExample.class, Object.class, "v2", int.class, int.class);
 996         testUnreflectMaybeSpecial(Example.class, false, PRIVATE, Example.class, Example.class, void.class, "s0");
 997     }
 998 
 999     public static class HasFields {
1000         boolean fZ = false;
1001         byte fB = (byte)'B';
1002         short fS = (short)'S';
1003         char fC = 'C';
1004         int fI = 'I';
1005         long fJ = 'J';
1006         float fF = 'F';
1007         double fD = 'D';
1008         static boolean sZ = true;
1009         static byte sB = 1+(byte)'B';
1010         static short sS = 1+(short)'S';
1011         static char sC = 1+'C';
1012         static int sI = 1+'I';
1013         static long sJ = 1+'J';
1014         static float sF = 1+'F';
1015         static double sD = 1+'D';
1016 
1017         Object fL = 'L';
1018         String fR = "R";
1019         static Object sL = 'M';
1020         static String sR = "S";
1021 
1022         static final Object[][] CASES;
1023         static {
1024             ArrayList<Object[]> cases = new ArrayList<>();
1025             Object types[][] = {
1026                 {'L',Object.class}, {'R',String.class},
1027                 {'I',int.class}, {'J',long.class},
1028                 {'F',float.class}, {'D',double.class},
1029                 {'Z',boolean.class}, {'B',byte.class},
1030                 {'S',short.class}, {'C',char.class},
1031             };
1032             HasFields fields = new HasFields();
1033             for (Object[] t : types) {
1034                 for (int kind = 0; kind <= 1; kind++) {
1035                     boolean isStatic = (kind != 0);
1036                     char btc = (Character)t[0];
1037                     String name = (isStatic ? "s" : "f") + btc;
1038                     Class<?> type = (Class<?>) t[1];
1039                     Object value;
1040                     Field field;
1041                         try {
1042                         field = HasFields.class.getDeclaredField(name);
1043                     } catch (NoSuchFieldException | SecurityException ex) {
1044                         throw new InternalError("no field HasFields."+name);
1045                     }
1046                     try {
1047                         value = field.get(fields);
1048                     } catch (IllegalArgumentException | IllegalAccessException ex) {
1049                         throw new InternalError("cannot fetch field HasFields."+name);
1050                     }
1051                     if (type == float.class) {
1052                         float v = 'F';
1053                         if (isStatic)  v++;
1054                         assertTrue(value.equals(v));
1055                     }
1056                     assertTrue(name.equals(field.getName()));
1057                     assertTrue(type.equals(field.getType()));
1058                     assertTrue(isStatic == (Modifier.isStatic(field.getModifiers())));
1059                     cases.add(new Object[]{ field, value });
1060                 }
1061             }
1062             cases.add(new Object[]{ new Object[]{ false, HasFields.class, "bogus_fD", double.class }, Error.class });
1063             cases.add(new Object[]{ new Object[]{ true,  HasFields.class, "bogus_sL", Object.class }, Error.class });
1064             CASES = cases.toArray(new Object[0][]);
1065         }
1066     }
1067 
1068     static final int TEST_UNREFLECT = 1, TEST_FIND_FIELD = 2, TEST_FIND_STATIC = 3, TEST_SETTER = 0x10, TEST_BOUND = 0x20, TEST_NPE = 0x40;
1069     static boolean testModeMatches(int testMode, boolean isStatic) {
1070         switch (testMode) {
1071         case TEST_FIND_STATIC:          return isStatic;
1072         case TEST_FIND_FIELD:           return !isStatic;
1073         case TEST_UNREFLECT:            return true;  // unreflect matches both
1074         }
1075         throw new InternalError("testMode="+testMode);
1076     }
1077 
1078     @Test
1079     public void testUnreflectGetter() throws Throwable {
1080         if (CAN_SKIP_WORKING)  return;
1081         startTest("unreflectGetter");
1082         testGetter(TEST_UNREFLECT);
1083     }
1084     @Test
1085     public void testFindGetter() throws Throwable {
1086         if (CAN_SKIP_WORKING)  return;
1087         startTest("findGetter");
1088         testGetter(TEST_FIND_FIELD);
1089         testGetter(TEST_FIND_FIELD | TEST_BOUND);
1090     }
1091     @Test
1092     public void testFindStaticGetter() throws Throwable {
1093         if (CAN_SKIP_WORKING)  return;
1094         startTest("findStaticGetter");
1095         testGetter(TEST_FIND_STATIC);
1096     }
1097     public void testGetter(int testMode) throws Throwable {
1098         Lookup lookup = PRIVATE;  // FIXME: test more lookups than this one
1099         for (Object[] c : HasFields.CASES) {
1100             boolean positive = (c[1] != Error.class);
1101             testGetter(positive, lookup, c[0], c[1], testMode);
1102             if (positive)
1103                 testGetter(positive, lookup, c[0], c[1], testMode | TEST_NPE);
1104         }
1105         testGetter(true, lookup,
1106                    new Object[]{ true,  System.class, "out", java.io.PrintStream.class },
1107                    System.out, testMode);
1108         for (int isStaticN = 0; isStaticN <= 1; isStaticN++) {
1109             testGetter(false, lookup,
1110                        new Object[]{ (isStaticN != 0), System.class, "bogus", char.class },
1111                        null, testMode);
1112         }
1113     }
1114     public void testGetter(boolean positive, MethodHandles.Lookup lookup,
1115                            Object fieldRef, Object value, int testMode) throws Throwable {
1116         testAccessor(positive, lookup, fieldRef, value, testMode);
1117     }
1118 
1119     public void testAccessor(boolean positive0, MethodHandles.Lookup lookup,
1120                              Object fieldRef, Object value, int testMode0) throws Throwable {
1121         if (verbosity >= 4)
1122             System.out.println("testAccessor"+Arrays.deepToString(new Object[]{positive0, lookup, fieldRef, value, testMode0}));
1123         boolean isGetter = ((testMode0 & TEST_SETTER) == 0);
1124         boolean doBound  = ((testMode0 & TEST_BOUND) != 0);
1125         boolean testNPE  = ((testMode0 & TEST_NPE) != 0);
1126         int testMode = testMode0 & ~(TEST_SETTER | TEST_BOUND | TEST_NPE);
1127         boolean positive = positive0 && !testNPE;
1128         boolean isStatic;
1129         Class<?> fclass;
1130         String   fname;
1131         Class<?> ftype;
1132         Field f = (fieldRef instanceof Field ? (Field)fieldRef : null);
1133         if (f != null) {
1134             isStatic = Modifier.isStatic(f.getModifiers());
1135             fclass   = f.getDeclaringClass();
1136             fname    = f.getName();
1137             ftype    = f.getType();
1138         } else {
1139             Object[] scnt = (Object[]) fieldRef;
1140             isStatic = (Boolean)  scnt[0];
1141             fclass   = (Class<?>) scnt[1];
1142             fname    = (String)   scnt[2];
1143             ftype    = (Class<?>) scnt[3];
1144             try {
1145                 f = fclass.getDeclaredField(fname);
1146             } catch (ReflectiveOperationException ex) {
1147                 f = null;
1148             }
1149         }
1150         if (!testModeMatches(testMode, isStatic))  return;
1151         if (f == null && testMode == TEST_UNREFLECT)  return;
1152         if (testNPE && isStatic)  return;
1153         countTest(positive);
1154         MethodType expType;
1155         if (isGetter)
1156             expType = MethodType.methodType(ftype, HasFields.class);
1157         else
1158             expType = MethodType.methodType(void.class, HasFields.class, ftype);
1159         if (isStatic)  expType = expType.dropParameterTypes(0, 1);
1160         Exception noAccess = null;
1161         MethodHandle mh;
1162         try {
1163             switch (testMode0 & ~(TEST_BOUND | TEST_NPE)) {
1164             case TEST_UNREFLECT:   mh = lookup.unreflectGetter(f);                      break;
1165             case TEST_FIND_FIELD:  mh = lookup.findGetter(fclass, fname, ftype);        break;
1166             case TEST_FIND_STATIC: mh = lookup.findStaticGetter(fclass, fname, ftype);  break;
1167             case TEST_SETTER|
1168                  TEST_UNREFLECT:   mh = lookup.unreflectSetter(f);                      break;
1169             case TEST_SETTER|
1170                  TEST_FIND_FIELD:  mh = lookup.findSetter(fclass, fname, ftype);        break;
1171             case TEST_SETTER|
1172                  TEST_FIND_STATIC: mh = lookup.findStaticSetter(fclass, fname, ftype);  break;
1173             default:
1174                 throw new InternalError("testMode="+testMode);
1175             }
1176         } catch (ReflectiveOperationException ex) {
1177             mh = null;
1178             noAccess = ex;
1179             assertExceptionClass(
1180                 (fname.contains("bogus"))
1181                 ?   NoSuchFieldException.class
1182                 :   IllegalAccessException.class,
1183                 noAccess);
1184             if (verbosity >= 5)  ex.printStackTrace(System.out);
1185         }
1186         if (verbosity >= 3)
1187             System.out.println("find"+(isStatic?"Static":"")+(isGetter?"Getter":"Setter")+" "+fclass.getName()+"."+fname+"/"+ftype
1188                                +" => "+mh
1189                                +(noAccess == null ? "" : " !! "+noAccess));
1190         if (positive && !testNPE && noAccess != null)  throw new RuntimeException(noAccess);
1191         assertEquals(positive0 ? "positive test" : "negative test erroneously passed", positive0, mh != null);
1192         if (!positive && !testNPE)  return; // negative access test failed as expected
1193         assertEquals((isStatic ? 0 : 1)+(isGetter ? 0 : 1), mh.type().parameterCount());
1194 
1195 
1196         assertSame(mh.type(), expType);
1197         //assertNameStringContains(mh, fname);  // This does not hold anymore with LFs
1198         HasFields fields = new HasFields();
1199         HasFields fieldsForMH = fields;
1200         if (testNPE)  fieldsForMH = null;  // perturb MH argument to elicit expected error
1201         if (doBound)
1202             mh = mh.bindTo(fieldsForMH);
1203         Object sawValue;
1204         Class<?> vtype = ftype;
1205         if (ftype != int.class)  vtype = Object.class;
1206         if (isGetter) {
1207             mh = mh.asType(mh.type().generic()
1208                            .changeReturnType(vtype));
1209         } else {
1210             int last = mh.type().parameterCount() - 1;
1211             mh = mh.asType(mh.type().generic()
1212                            .changeReturnType(void.class)
1213                            .changeParameterType(last, vtype));
1214         }
1215         if (f != null && f.getDeclaringClass() == HasFields.class) {
1216             assertEquals(f.get(fields), value);  // clean to start with
1217         }
1218         Throwable caughtEx = null;
1219         if (isGetter) {
1220             Object expValue = value;
1221             for (int i = 0; i <= 1; i++) {
1222                 sawValue = null;  // make DA rules happy under try/catch
1223                 try {
1224                     if (isStatic || doBound) {
1225                         if (ftype == int.class)
1226                             sawValue = (int) mh.invokeExact();  // do these exactly
1227                         else
1228                             sawValue = mh.invokeExact();
1229                     } else {
1230                         if (ftype == int.class)
1231                             sawValue = (int) mh.invokeExact((Object) fieldsForMH);
1232                         else
1233                             sawValue = mh.invokeExact((Object) fieldsForMH);
1234                     }
1235                 } catch (RuntimeException ex) {
1236                     if (ex instanceof NullPointerException && testNPE) {
1237                         caughtEx = ex;
1238                         break;
1239                     }
1240                 }
1241                 assertEquals(sawValue, expValue);
1242                 if (f != null && f.getDeclaringClass() == HasFields.class
1243                     && !Modifier.isFinal(f.getModifiers())) {
1244                     Object random = randomArg(ftype);
1245                     f.set(fields, random);
1246                     expValue = random;
1247                 } else {
1248                     break;
1249                 }
1250             }
1251         } else {
1252             for (int i = 0; i <= 1; i++) {
1253                 Object putValue = randomArg(ftype);
1254                 try {
1255                     if (isStatic || doBound) {
1256                         if (ftype == int.class)
1257                             mh.invokeExact((int)putValue);  // do these exactly
1258                         else
1259                             mh.invokeExact(putValue);
1260                     } else {
1261                         if (ftype == int.class)
1262                             mh.invokeExact((Object) fieldsForMH, (int)putValue);
1263                         else
1264                             mh.invokeExact((Object) fieldsForMH, putValue);
1265                     }
1266                 } catch (RuntimeException ex) {
1267                     if (ex instanceof NullPointerException && testNPE) {
1268                         caughtEx = ex;
1269                         break;
1270                     }
1271                 }
1272                 if (f != null && f.getDeclaringClass() == HasFields.class) {
1273                     assertEquals(f.get(fields), putValue);
1274                 }
1275             }
1276         }
1277         if (f != null && f.getDeclaringClass() == HasFields.class) {
1278             f.set(fields, value);  // put it back
1279         }
1280         if (testNPE) {
1281             if (caughtEx == null || !(caughtEx instanceof NullPointerException))
1282                 throw new RuntimeException("failed to catch NPE exception"+(caughtEx == null ? " (caughtEx=null)" : ""), caughtEx);
1283             caughtEx = null;  // nullify expected exception
1284         }
1285         if (caughtEx != null) {
1286             throw new RuntimeException("unexpected exception", caughtEx);
1287         }
1288     }
1289 
1290 
1291     @Test
1292     public void testUnreflectSetter() throws Throwable {
1293         if (CAN_SKIP_WORKING)  return;
1294         startTest("unreflectSetter");
1295         testSetter(TEST_UNREFLECT);
1296     }
1297     @Test
1298     public void testFindSetter() throws Throwable {
1299         if (CAN_SKIP_WORKING)  return;
1300         startTest("findSetter");
1301         testSetter(TEST_FIND_FIELD);
1302         testSetter(TEST_FIND_FIELD | TEST_BOUND);
1303     }
1304     @Test
1305     public void testFindStaticSetter() throws Throwable {
1306         if (CAN_SKIP_WORKING)  return;
1307         startTest("findStaticSetter");
1308         testSetter(TEST_FIND_STATIC);
1309     }
1310     public void testSetter(int testMode) throws Throwable {
1311         Lookup lookup = PRIVATE;  // FIXME: test more lookups than this one
1312         startTest("unreflectSetter");
1313         for (Object[] c : HasFields.CASES) {
1314             boolean positive = (c[1] != Error.class);
1315             testSetter(positive, lookup, c[0], c[1], testMode);
1316             if (positive)
1317                 testSetter(positive, lookup, c[0], c[1], testMode | TEST_NPE);
1318         }
1319         for (int isStaticN = 0; isStaticN <= 1; isStaticN++) {
1320             testSetter(false, lookup,
1321                        new Object[]{ (isStaticN != 0), System.class, "bogus", char.class },
1322                        null, testMode);
1323         }
1324     }
1325     public void testSetter(boolean positive, MethodHandles.Lookup lookup,
1326                            Object fieldRef, Object value, int testMode) throws Throwable {
1327         testAccessor(positive, lookup, fieldRef, value, testMode | TEST_SETTER);
1328     }
1329 
1330     @Test
1331     public void testArrayElementGetter() throws Throwable {
1332         if (CAN_SKIP_WORKING)  return;
1333         startTest("arrayElementGetter");
1334         testArrayElementGetterSetter(false);
1335     }
1336 
1337     @Test
1338     public void testArrayElementSetter() throws Throwable {
1339         if (CAN_SKIP_WORKING)  return;
1340         startTest("arrayElementSetter");
1341         testArrayElementGetterSetter(true);
1342     }
1343 
1344     private static final int TEST_ARRAY_NONE = 0, TEST_ARRAY_NPE = 1, TEST_ARRAY_OOB = 2, TEST_ARRAY_ASE = 3;
1345 
1346     public void testArrayElementGetterSetter(boolean testSetter) throws Throwable {
1347         testArrayElementGetterSetter(testSetter, TEST_ARRAY_NONE);
1348     }
1349 
1350     @Test
1351     public void testArrayElementErrors() throws Throwable {
1352         if (CAN_SKIP_WORKING)  return;
1353         startTest("arrayElementErrors");
1354         testArrayElementGetterSetter(false, TEST_ARRAY_NPE);
1355         testArrayElementGetterSetter(true, TEST_ARRAY_NPE);
1356         testArrayElementGetterSetter(false, TEST_ARRAY_OOB);
1357         testArrayElementGetterSetter(true, TEST_ARRAY_OOB);
1358         testArrayElementGetterSetter(new Object[10], true, TEST_ARRAY_ASE);
1359         testArrayElementGetterSetter(new Example[10], true, TEST_ARRAY_ASE);
1360         testArrayElementGetterSetter(new IntExample[10], true, TEST_ARRAY_ASE);
1361     }
1362 
1363     public void testArrayElementGetterSetter(boolean testSetter, int negTest) throws Throwable {
1364         testArrayElementGetterSetter(new String[10], testSetter, negTest);
1365         testArrayElementGetterSetter(new Iterable<?>[10], testSetter, negTest);
1366         testArrayElementGetterSetter(new Example[10], testSetter, negTest);
1367         testArrayElementGetterSetter(new IntExample[10], testSetter, negTest);
1368         testArrayElementGetterSetter(new Object[10], testSetter, negTest);
1369         testArrayElementGetterSetter(new boolean[10], testSetter, negTest);
1370         testArrayElementGetterSetter(new byte[10], testSetter, negTest);
1371         testArrayElementGetterSetter(new char[10], testSetter, negTest);
1372         testArrayElementGetterSetter(new short[10], testSetter, negTest);
1373         testArrayElementGetterSetter(new int[10], testSetter, negTest);
1374         testArrayElementGetterSetter(new float[10], testSetter, negTest);
1375         testArrayElementGetterSetter(new long[10], testSetter, negTest);
1376         testArrayElementGetterSetter(new double[10], testSetter, negTest);
1377     }
1378 
1379     public void testArrayElementGetterSetter(Object array, boolean testSetter, int negTest) throws Throwable {
1380         boolean positive = (negTest == TEST_ARRAY_NONE);
1381         int length = java.lang.reflect.Array.getLength(array);
1382         Class<?> arrayType = array.getClass();
1383         Class<?> elemType = arrayType.getComponentType();
1384         Object arrayToMH = array;
1385         // this stanza allows negative tests to make argument perturbations:
1386         switch (negTest) {
1387         case TEST_ARRAY_NPE:
1388             arrayToMH = null;
1389             break;
1390         case TEST_ARRAY_OOB:
1391             assert(length > 0);
1392             arrayToMH = java.lang.reflect.Array.newInstance(elemType, 0);
1393             break;
1394         case TEST_ARRAY_ASE:
1395             assert(testSetter && !elemType.isPrimitive());
1396             if (elemType == Object.class)
1397                 arrayToMH = new StringBuffer[length];  // very random subclass of Object!
1398             else if (elemType == Example.class)
1399                 arrayToMH = new SubExample[length];
1400             else if (elemType == IntExample.class)
1401                 arrayToMH = new SubIntExample[length];
1402             else
1403                 return;  // can't make an ArrayStoreException test
1404             assert(arrayType.isInstance(arrayToMH))
1405                 : Arrays.asList(arrayType, arrayToMH.getClass(), testSetter, negTest);
1406             break;
1407         }
1408         countTest(positive);
1409         if (verbosity > 2)  System.out.println("array type = "+array.getClass().getComponentType().getName()+"["+length+"]"+(positive ? "" : " negative test #"+negTest+" using "+Arrays.deepToString(new Object[]{arrayToMH})));
1410         MethodType expType = !testSetter
1411                 ? MethodType.methodType(elemType,   arrayType, int.class)
1412                 : MethodType.methodType(void.class, arrayType, int.class, elemType);
1413         MethodHandle mh = !testSetter
1414                 ? MethodHandles.arrayElementGetter(arrayType)
1415                 : MethodHandles.arrayElementSetter(arrayType);
1416         assertSame(mh.type(), expType);
1417         if (elemType != int.class && elemType != boolean.class) {
1418             MethodType gtype = mh.type().generic().changeParameterType(1, int.class);
1419             if (testSetter)  gtype = gtype.changeReturnType(void.class);
1420             mh = mh.asType(gtype);
1421         }
1422         Object sawValue, expValue;
1423         List<Object> model = array2list(array);
1424         Throwable caughtEx = null;
1425         for (int i = 0; i < length; i++) {
1426             // update array element
1427             Object random = randomArg(elemType);
1428             model.set(i, random);
1429             if (testSetter) {
1430                 try {
1431                     if (elemType == int.class)
1432                         mh.invokeExact((int[]) arrayToMH, i, (int)random);
1433                     else if (elemType == boolean.class)
1434                         mh.invokeExact((boolean[]) arrayToMH, i, (boolean)random);
1435                     else
1436                         mh.invokeExact(arrayToMH, i, random);
1437                 } catch (RuntimeException ex) {
1438                     caughtEx = ex;
1439                     break;
1440                 }
1441                 assertEquals(model, array2list(array));
1442             } else {
1443                 Array.set(array, i, random);
1444             }
1445             if (verbosity >= 5) {
1446                 List<Object> array2list = array2list(array);
1447                 System.out.println("a["+i+"]="+random+" => "+array2list);
1448                 if (!array2list.equals(model))
1449                     System.out.println("***   != "+model);
1450             }
1451             // observe array element
1452             sawValue = Array.get(array, i);
1453             if (!testSetter) {
1454                 expValue = sawValue;
1455                 try {
1456                     if (elemType == int.class)
1457                         sawValue = (int) mh.invokeExact((int[]) arrayToMH, i);
1458                     else if (elemType == boolean.class)
1459                         sawValue = (boolean) mh.invokeExact((boolean[]) arrayToMH, i);
1460                     else
1461                         sawValue = mh.invokeExact(arrayToMH, i);
1462                 } catch (RuntimeException ex) {
1463                     caughtEx = ex;
1464                     break;
1465                 }
1466                 assertEquals(sawValue, expValue);
1467                 assertEquals(model, array2list(array));
1468             }
1469         }
1470         if (!positive) {
1471             if (caughtEx == null)
1472                 throw new RuntimeException("failed to catch exception for negTest="+negTest);
1473             // test the kind of exception
1474             Class<?> reqType = null;
1475             switch (negTest) {
1476             case TEST_ARRAY_ASE:  reqType = ArrayStoreException.class; break;
1477             case TEST_ARRAY_OOB:  reqType = ArrayIndexOutOfBoundsException.class; break;
1478             case TEST_ARRAY_NPE:  reqType = NullPointerException.class; break;
1479             default:              assert(false);
1480             }
1481             if (reqType.isInstance(caughtEx)) {
1482                 caughtEx = null;  // nullify expected exception
1483             }
1484         }
1485         if (caughtEx != null) {
1486             throw new RuntimeException("unexpected exception", caughtEx);
1487         }
1488     }
1489 
1490     List<Object> array2list(Object array) {
1491         int length = Array.getLength(array);
1492         ArrayList<Object> model = new ArrayList<>(length);
1493         for (int i = 0; i < length; i++)
1494             model.add(Array.get(array, i));
1495         return model;
1496     }
1497 
1498     static class Callee {
1499         static Object id() { return called("id"); }
1500         static Object id(Object x) { return called("id", x); }
1501         static Object id(Object x, Object y) { return called("id", x, y); }
1502         static Object id(Object x, Object y, Object z) { return called("id", x, y, z); }
1503         static Object id(Object... vx) { return called("id", vx); }
1504         static MethodHandle ofType(int n) {
1505             return ofType(Object.class, n);
1506         }
1507         static MethodHandle ofType(Class<?> rtype, int n) {
1508             if (n == -1)
1509                 return ofType(MethodType.methodType(rtype, Object[].class));
1510             return ofType(MethodType.genericMethodType(n).changeReturnType(rtype));
1511         }
1512         static MethodHandle ofType(Class<?> rtype, Class<?>... ptypes) {
1513             return ofType(MethodType.methodType(rtype, ptypes));
1514         }
1515         static MethodHandle ofType(MethodType type) {
1516             Class<?> rtype = type.returnType();
1517             String pfx = "";
1518             if (rtype != Object.class)
1519                 pfx = rtype.getSimpleName().substring(0, 1).toLowerCase();
1520             String name = pfx+"id";
1521             try {
1522                 return PRIVATE.findStatic(Callee.class, name, type);
1523             } catch (NoSuchMethodException | IllegalAccessException ex) {
1524                 throw new RuntimeException(ex);
1525             }
1526         }
1527     }
1528 
1529     @Test
1530     public void testConvertArguments() throws Throwable {
1531         if (CAN_SKIP_WORKING)  return;
1532         startTest("convertArguments");
1533         testConvert(Callee.ofType(1), null, "id", int.class);
1534         testConvert(Callee.ofType(1), null, "id", String.class);
1535         testConvert(Callee.ofType(1), null, "id", Integer.class);
1536         testConvert(Callee.ofType(1), null, "id", short.class);
1537         testConvert(Callee.ofType(1), null, "id", char.class);
1538         testConvert(Callee.ofType(1), null, "id", byte.class);
1539     }
1540 
1541     void testConvert(MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {
1542         testConvert(true, id, rtype, name, params);
1543     }
1544 
1545     void testConvert(boolean positive,
1546                      MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {
1547         countTest(positive);
1548         MethodType idType = id.type();
1549         if (rtype == null)  rtype = idType.returnType();
1550         for (int i = 0; i < params.length; i++) {
1551             if (params[i] == null)  params[i] = idType.parameterType(i);
1552         }
1553         // simulate the pairwise conversion
1554         MethodType newType = MethodType.methodType(rtype, params);
1555         Object[] args = randomArgs(newType.parameterArray());
1556         Object[] convArgs = args.clone();
1557         for (int i = 0; i < args.length; i++) {
1558             Class<?> src = newType.parameterType(i);
1559             Class<?> dst = idType.parameterType(i);
1560             if (src != dst)
1561                 convArgs[i] = castToWrapper(convArgs[i], dst);
1562         }
1563         Object convResult = id.invokeWithArguments(convArgs);
1564         {
1565             Class<?> dst = newType.returnType();
1566             Class<?> src = idType.returnType();
1567             if (src != dst)
1568                 convResult = castToWrapper(convResult, dst);
1569         }
1570         MethodHandle target = null;
1571         RuntimeException error = null;
1572         try {
1573             target = id.asType(newType);
1574         } catch (WrongMethodTypeException ex) {
1575             error = ex;
1576         }
1577         if (verbosity >= 3)
1578             System.out.println("convert "+id+ " to "+newType+" => "+target
1579                     +(error == null ? "" : " !! "+error));
1580         if (positive && error != null)  throw error;
1581         assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
1582         if (!positive)  return; // negative test failed as expected
1583         assertEquals(newType, target.type());
1584         printCalled(target, id.toString(), args);
1585         Object result = target.invokeWithArguments(args);
1586         assertCalled(name, convArgs);
1587         assertEquals(convResult, result);
1588         if (verbosity >= 1)
1589             System.out.print(':');
1590     }
1591 
1592     @Test
1593     public void testVarargsCollector() throws Throwable {
1594         if (CAN_SKIP_WORKING)  return;
1595         startTest("varargsCollector");
1596         MethodHandle vac0 = PRIVATE.findStatic(MethodHandlesTest.class, "called",
1597                                MethodType.methodType(Object.class, String.class, Object[].class));
1598         vac0 = vac0.bindTo("vac");
1599         MethodHandle vac = vac0.asVarargsCollector(Object[].class);
1600         testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac");
1601         testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac");
1602         for (Class<?> at : new Class<?>[] { Object.class, String.class, Integer.class }) {
1603             testConvert(true, vac.asType(MethodType.genericMethodType(1)), null, "vac", at);
1604             testConvert(true, vac.asType(MethodType.genericMethodType(2)), null, "vac", at, at);
1605         }
1606     }
1607 
1608     @Test  // SLOW
1609     public void testPermuteArguments() throws Throwable {
1610         if (CAN_SKIP_WORKING)  return;
1611         startTest("permuteArguments");
1612         testPermuteArguments(4, Integer.class,  2, long.class,    6);
1613         if (CAN_TEST_LIGHTLY)  return;
1614         testPermuteArguments(4, Integer.class,  2, String.class,  0);
1615         testPermuteArguments(6, Integer.class,  0, null,         30);
1616     }
1617     public void testPermuteArguments(int max, Class<?> type1, int t2c, Class<?> type2, int dilution) throws Throwable {
1618         if (verbosity >= 2)
1619             System.out.println("permuteArguments "+max+"*"+type1.getName()
1620                     +(t2c==0?"":"/"+t2c+"*"+type2.getName())
1621                     +(dilution > 0 ? " with dilution "+dilution : ""));
1622         int t2pos = t2c == 0 ? 0 : 1;
1623         for (int inargs = t2pos+1; inargs <= max; inargs++) {
1624             Class<?>[] types = new Class<?>[inargs];
1625             Arrays.fill(types, type1);
1626             if (t2c != 0) {
1627                 // Fill in a middle range with type2:
1628                 Arrays.fill(types, t2pos, Math.min(t2pos+t2c, inargs), type2);
1629             }
1630             Object[] args = randomArgs(types);
1631             int numcases = 1;
1632             for (int outargs = 0; outargs <= max; outargs++) {
1633                 if (outargs - inargs >= MAX_ARG_INCREASE)  continue;
1634                 int casStep = dilution + 1;
1635                 // Avoid some common factors:
1636                 while ((casStep > 2 && casStep % 2 == 0 && inargs % 2 == 0) ||
1637                        (casStep > 3 && casStep % 3 == 0 && inargs % 3 == 0))
1638                     casStep++;
1639                 testPermuteArguments(args, types, outargs, numcases, casStep);
1640                 numcases *= inargs;
1641                 if (CAN_TEST_LIGHTLY && outargs < max-2)  continue;
1642                 if (dilution > 10 && outargs >= 4) {
1643                     if (CAN_TEST_LIGHTLY)  continue;
1644                     int[] reorder = new int[outargs];
1645                     // Do some special patterns, which we probably missed.
1646                     // Replication of a single argument or argument pair.
1647                     for (int i = 0; i < inargs; i++) {
1648                         Arrays.fill(reorder, i);
1649                         testPermuteArguments(args, types, reorder);
1650                         for (int d = 1; d <= 2; d++) {
1651                             if (i + d >= inargs)  continue;
1652                             for (int j = 1; j < outargs; j += 2)
1653                                 reorder[j] += 1;
1654                             testPermuteArguments(args, types, reorder);
1655                             testPermuteArguments(args, types, reverse(reorder));
1656                         }
1657                     }
1658                     // Repetition of a sequence of 3 or more arguments.
1659                     for (int i = 1; i < inargs; i++) {
1660                         for (int len = 3; len <= inargs; len++) {
1661                             for (int j = 0; j < outargs; j++)
1662                                 reorder[j] = (i + (j % len)) % inargs;
1663                             testPermuteArguments(args, types, reorder);
1664                             testPermuteArguments(args, types, reverse(reorder));
1665                         }
1666                     }
1667                 }
1668             }
1669         }
1670     }
1671 
1672     public void testPermuteArguments(Object[] args, Class<?>[] types,
1673                                      int outargs, int numcases, int casStep) throws Throwable {
1674         int inargs = args.length;
1675         int[] reorder = new int[outargs];
1676         for (int cas = 0; cas < numcases; cas += casStep) {
1677             for (int i = 0, c = cas; i < outargs; i++) {
1678                 reorder[i] = c % inargs;
1679                 c /= inargs;
1680             }
1681             if (CAN_TEST_LIGHTLY && outargs >= 3 && (reorder[0] == reorder[1] || reorder[1] == reorder[2]))  continue;
1682             testPermuteArguments(args, types, reorder);
1683         }
1684     }
1685 
1686     static int[] reverse(int[] reorder) {
1687         reorder = reorder.clone();
1688         for (int i = 0, imax = reorder.length / 2; i < imax; i++) {
1689             int j = reorder.length - 1 - i;
1690             int tem = reorder[i];
1691             reorder[i] = reorder[j];
1692             reorder[j] = tem;
1693         }
1694         return reorder;
1695     }
1696 
1697     void testPermuteArguments(Object[] args, Class<?>[] types, int[] reorder) throws Throwable {
1698         countTest();
1699         if (args == null && types == null) {
1700             int max = 0;
1701             for (int j : reorder) {
1702                 if (max < j)  max = j;
1703             }
1704             args = randomArgs(max+1, Integer.class);
1705         }
1706         if (args == null) {
1707             args = randomArgs(types);
1708         }
1709         if (types == null) {
1710             types = new Class<?>[args.length];
1711             for (int i = 0; i < args.length; i++)
1712                 types[i] = args[i].getClass();
1713         }
1714         int inargs = args.length, outargs = reorder.length;
1715         assertTrue(inargs == types.length);
1716         if (verbosity >= 3)
1717             System.out.println("permuteArguments "+Arrays.toString(reorder));
1718         Object[] permArgs = new Object[outargs];
1719         Class<?>[] permTypes = new Class<?>[outargs];
1720         for (int i = 0; i < outargs; i++) {
1721             permArgs[i] = args[reorder[i]];
1722             permTypes[i] = types[reorder[i]];
1723         }
1724         if (verbosity >= 4) {
1725             System.out.println("in args:   "+Arrays.asList(args));
1726             System.out.println("out args:  "+Arrays.asList(permArgs));
1727             System.out.println("in types:  "+Arrays.asList(types));
1728             System.out.println("out types: "+Arrays.asList(permTypes));
1729         }
1730         MethodType inType  = MethodType.methodType(Object.class, types);
1731         MethodType outType = MethodType.methodType(Object.class, permTypes);
1732         MethodHandle target = varargsList(outargs).asType(outType);
1733         MethodHandle newTarget = MethodHandles.permuteArguments(target, inType, reorder);
1734         if (verbosity >= 5)  System.out.println("newTarget = "+newTarget);
1735         Object result = newTarget.invokeWithArguments(args);
1736         Object expected = Arrays.asList(permArgs);
1737         if (!expected.equals(result)) {
1738             System.out.println("*** failed permuteArguments "+Arrays.toString(reorder)+" types="+Arrays.asList(types));
1739             System.out.println("in args:   "+Arrays.asList(args));
1740             System.out.println("out args:  "+expected);
1741             System.out.println("bad args:  "+result);
1742         }
1743         assertEquals(expected, result);
1744     }
1745 
1746 
1747     @Test  // SLOW
1748     public void testSpreadArguments() throws Throwable {
1749         if (CAN_SKIP_WORKING)  return;
1750         startTest("spreadArguments");
1751         for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
1752             if (verbosity >= 3)
1753                 System.out.println("spreadArguments "+argType);
1754             for (int nargs = 0; nargs < 50; nargs++) {
1755                 if (CAN_TEST_LIGHTLY && nargs > 11)  break;
1756                 for (int pos = 0; pos <= nargs; pos++) {
1757                     if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2)  continue;
1758                     if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
1759                         continue;
1760                     testSpreadArguments(argType, pos, nargs);
1761                 }
1762             }
1763         }
1764     }
1765     public void testSpreadArguments(Class<?> argType, int pos, int nargs) throws Throwable {
1766         countTest();
1767         Class<?> arrayType = java.lang.reflect.Array.newInstance(argType, 0).getClass();
1768         MethodHandle target2 = varargsArray(arrayType, nargs);
1769         MethodHandle target = target2.asType(target2.type().generic());
1770         if (verbosity >= 3)
1771             System.out.println("spread into "+target2+" ["+pos+".."+nargs+"]");
1772         Object[] args = randomArgs(target2.type().parameterArray());
1773         // make sure the target does what we think it does:
1774         if (pos == 0 && nargs < 5 && !argType.isPrimitive()) {
1775             Object[] check = (Object[]) target.invokeWithArguments(args);
1776             assertArrayEquals(args, check);
1777             switch (nargs) {
1778                 case 0:
1779                     check = (Object[]) (Object) target.invokeExact();
1780                     assertArrayEquals(args, check);
1781                     break;
1782                 case 1:
1783                     check = (Object[]) (Object) target.invokeExact(args[0]);
1784                     assertArrayEquals(args, check);
1785                     break;
1786                 case 2:
1787                     check = (Object[]) (Object) target.invokeExact(args[0], args[1]);
1788                     assertArrayEquals(args, check);
1789                     break;
1790             }
1791         }
1792         List<Class<?>> newParams = new ArrayList<>(target2.type().parameterList());
1793         {   // modify newParams in place
1794             List<Class<?>> spreadParams = newParams.subList(pos, nargs);
1795             spreadParams.clear(); spreadParams.add(arrayType);
1796         }
1797         MethodType newType = MethodType.methodType(arrayType, newParams);
1798         MethodHandle result = target2.asSpreader(arrayType, nargs-pos);
1799         assert(result.type() == newType) : Arrays.asList(result, newType);
1800         result = result.asType(newType.generic());
1801         Object returnValue;
1802         if (pos == 0) {
1803             Object args2 = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length));
1804             returnValue = result.invokeExact(args2);
1805         } else {
1806             Object[] args1 = Arrays.copyOfRange(args, 0, pos+1);
1807             args1[pos] = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length));
1808             returnValue = result.invokeWithArguments(args1);
1809         }
1810         String argstr = Arrays.toString(args);
1811         if (!argType.isPrimitive()) {
1812             Object[] rv = (Object[]) returnValue;
1813             String rvs = Arrays.toString(rv);
1814             if (!Arrays.equals(args, rv)) {
1815                 System.out.println("method:   "+result);
1816                 System.out.println("expected: "+argstr);
1817                 System.out.println("returned: "+rvs);
1818                 assertArrayEquals(args, rv);
1819             }
1820         } else if (argType == int.class) {
1821             String rvs = Arrays.toString((int[]) returnValue);
1822             if (!argstr.equals(rvs)) {
1823                 System.out.println("method:   "+result);
1824                 System.out.println("expected: "+argstr);
1825                 System.out.println("returned: "+rvs);
1826                 assertEquals(argstr, rvs);
1827             }
1828         } else if (argType == long.class) {
1829             String rvs = Arrays.toString((long[]) returnValue);
1830             if (!argstr.equals(rvs)) {
1831                 System.out.println("method:   "+result);
1832                 System.out.println("expected: "+argstr);
1833                 System.out.println("returned: "+rvs);
1834                 assertEquals(argstr, rvs);
1835             }
1836         } else {
1837             // cannot test...
1838         }
1839     }
1840 
1841     @Test  // SLOW
1842     public void testAsCollector() throws Throwable {
1843         if (CAN_SKIP_WORKING)  return;
1844         startTest("asCollector");
1845         for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
1846             if (verbosity >= 3)
1847                 System.out.println("asCollector "+argType);
1848             for (int nargs = 0; nargs < 50; nargs++) {
1849                 if (CAN_TEST_LIGHTLY && nargs > 11)  break;
1850                 for (int pos = 0; pos <= nargs; pos++) {
1851                     if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2)  continue;
1852                     if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
1853                         continue;
1854                     testAsCollector(argType, pos, nargs);
1855                 }
1856             }
1857         }
1858     }
1859     public void testAsCollector(Class<?> argType, int pos, int nargs) throws Throwable {
1860         countTest();
1861         // fake up a MH with the same type as the desired adapter:
1862         MethodHandle fake = varargsArray(nargs);
1863         fake = changeArgTypes(fake, argType);
1864         MethodType newType = fake.type();
1865         Object[] args = randomArgs(newType.parameterArray());
1866         // here is what should happen:
1867         Object[] collectedArgs = Arrays.copyOfRange(args, 0, pos+1);
1868         collectedArgs[pos] = Arrays.copyOfRange(args, pos, args.length);
1869         // here is the MH which will witness the collected argument tail:
1870         MethodHandle target = varargsArray(pos+1);
1871         target = changeArgTypes(target, 0, pos, argType);
1872         target = changeArgTypes(target, pos, pos+1, Object[].class);
1873         if (verbosity >= 3)
1874             System.out.println("collect from "+Arrays.asList(args)+" ["+pos+".."+nargs+"]");
1875         MethodHandle result = target.asCollector(Object[].class, nargs-pos).asType(newType);
1876         Object[] returnValue = (Object[]) result.invokeWithArguments(args);
1877 //        assertTrue(returnValue.length == pos+1 && returnValue[pos] instanceof Object[]);
1878 //        returnValue[pos] = Arrays.asList((Object[]) returnValue[pos]);
1879 //        collectedArgs[pos] = Arrays.asList((Object[]) collectedArgs[pos]);
1880         assertArrayEquals(collectedArgs, returnValue);
1881     }
1882 
1883     @Test  // SLOW
1884     public void testInsertArguments() throws Throwable {
1885         if (CAN_SKIP_WORKING)  return;
1886         startTest("insertArguments");
1887         for (int nargs = 0; nargs < 50; nargs++) {
1888             if (CAN_TEST_LIGHTLY && nargs > 11)  break;
1889             for (int ins = 0; ins <= nargs; ins++) {
1890                 if (nargs > 10 && ins > 4 && ins < nargs-4 && ins % 10 != 3)
1891                     continue;
1892                 for (int pos = 0; pos <= nargs; pos++) {
1893                     if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
1894                         continue;
1895                     if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2)  continue;
1896                     testInsertArguments(nargs, pos, ins);
1897                 }
1898             }
1899         }
1900     }
1901 
1902     void testInsertArguments(int nargs, int pos, int ins) throws Throwable {
1903         countTest();
1904         MethodHandle target = varargsArray(nargs + ins);
1905         Object[] args = randomArgs(target.type().parameterArray());
1906         List<Object> resList = Arrays.asList(args);
1907         List<Object> argsToPass = new ArrayList<>(resList);
1908         List<Object> argsToInsert = argsToPass.subList(pos, pos + ins);
1909         if (verbosity >= 3)
1910             System.out.println("insert: "+argsToInsert+" @"+pos+" into "+target);
1911         @SuppressWarnings("cast")  // cast to spread Object... is helpful
1912         MethodHandle target2 = MethodHandles.insertArguments(target, pos,
1913                 (Object[]/*...*/) argsToInsert.toArray());
1914         argsToInsert.clear();  // remove from argsToInsert
1915         Object res2 = target2.invokeWithArguments(argsToPass);
1916         Object res2List = Arrays.asList((Object[])res2);
1917         if (verbosity >= 3)
1918             System.out.println("result: "+res2List);
1919         //if (!resList.equals(res2List))
1920         //    System.out.println("*** fail at n/p/i = "+nargs+"/"+pos+"/"+ins+": "+resList+" => "+res2List);
1921         assertEquals(resList, res2List);
1922     }
1923 
1924     @Test
1925     public void testFilterReturnValue() throws Throwable {
1926         if (CAN_SKIP_WORKING)  return;
1927         startTest("filterReturnValue");
1928         Class<?> classOfVCList = varargsList(1).invokeWithArguments(0).getClass();
1929         assertTrue(List.class.isAssignableFrom(classOfVCList));
1930         for (int nargs = 0; nargs <= 3; nargs++) {
1931             for (Class<?> rtype : new Class<?>[] { Object.class,
1932                                                 List.class,
1933                                                 int.class,
1934                                                 byte.class,
1935                                                 long.class,
1936                                                 CharSequence.class,
1937                                                 String.class }) {
1938                 testFilterReturnValue(nargs, rtype);
1939             }
1940         }
1941     }
1942 
1943     void testFilterReturnValue(int nargs, Class<?> rtype) throws Throwable {
1944         countTest();
1945         MethodHandle target = varargsList(nargs, rtype);
1946         MethodHandle filter;
1947         if (List.class.isAssignableFrom(rtype) || rtype.isAssignableFrom(List.class))
1948             filter = varargsList(1);  // add another layer of list-ness
1949         else
1950             filter = MethodHandles.identity(rtype);
1951         filter = filter.asType(MethodType.methodType(target.type().returnType(), rtype));
1952         Object[] argsToPass = randomArgs(nargs, Object.class);
1953         if (verbosity >= 3)
1954             System.out.println("filter "+target+" to "+rtype.getSimpleName()+" with "+filter);
1955         MethodHandle target2 = MethodHandles.filterReturnValue(target, filter);
1956         if (verbosity >= 4)
1957             System.out.println("filtered target: "+target2);
1958         // Simulate expected effect of filter on return value:
1959         Object unfiltered = target.invokeWithArguments(argsToPass);
1960         Object expected = filter.invokeWithArguments(unfiltered);
1961         if (verbosity >= 4)
1962             System.out.println("unfiltered: "+unfiltered+" : "+unfiltered.getClass().getSimpleName());
1963         if (verbosity >= 4)
1964             System.out.println("expected: "+expected+" : "+expected.getClass().getSimpleName());
1965         Object result = target2.invokeWithArguments(argsToPass);
1966         if (verbosity >= 3)
1967             System.out.println("result: "+result+" : "+result.getClass().getSimpleName());
1968         if (!expected.equals(result))
1969             System.out.println("*** fail at n/rt = "+nargs+"/"+rtype.getSimpleName()+": "+Arrays.asList(argsToPass)+" => "+result+" != "+expected);
1970         assertEquals(expected, result);
1971     }
1972 
1973     @Test
1974     public void testFilterArguments() throws Throwable {
1975         if (CAN_SKIP_WORKING)  return;
1976         startTest("filterArguments");
1977         for (int nargs = 1; nargs <= 6; nargs++) {
1978             for (int pos = 0; pos < nargs; pos++) {
1979                 testFilterArguments(nargs, pos);
1980             }
1981         }
1982     }
1983 
1984     void testFilterArguments(int nargs, int pos) throws Throwable {
1985         countTest();
1986         MethodHandle target = varargsList(nargs);
1987         MethodHandle filter = varargsList(1);
1988         filter = filter.asType(filter.type().generic());
1989         Object[] argsToPass = randomArgs(nargs, Object.class);
1990         if (verbosity >= 3)
1991             System.out.println("filter "+target+" at "+pos+" with "+filter);
1992         MethodHandle target2 = MethodHandles.filterArguments(target, pos, filter);
1993         // Simulate expected effect of filter on arglist:
1994         Object[] filteredArgs = argsToPass.clone();
1995         filteredArgs[pos] = filter.invokeExact(filteredArgs[pos]);
1996         List<Object> expected = Arrays.asList(filteredArgs);
1997         Object result = target2.invokeWithArguments(argsToPass);
1998         if (verbosity >= 3)
1999             System.out.println("result: "+result);
2000         if (!expected.equals(result))
2001             System.out.println("*** fail at n/p = "+nargs+"/"+pos+": "+Arrays.asList(argsToPass)+" => "+result+" != "+expected);
2002         assertEquals(expected, result);
2003     }
2004 
2005     @Test
2006     public void testCollectArguments() throws Throwable {
2007         if (CAN_SKIP_WORKING)  return;
2008         startTest("collectArguments");
2009         testFoldOrCollectArguments(true);
2010     }
2011 
2012     @Test
2013     public void testFoldArguments() throws Throwable {
2014         if (CAN_SKIP_WORKING)  return;
2015         startTest("foldArguments");
2016         testFoldOrCollectArguments(false);
2017     }
2018 
2019     void testFoldOrCollectArguments(boolean isCollect) throws Throwable {
2020         for (Class<?> lastType : new Class<?>[]{ Object.class, String.class, int.class }) {
2021             for (Class<?> collectType : new Class<?>[]{ Object.class, String.class, int.class, void.class }) {
2022                 int maxArity = 10;
2023                 if (collectType != String.class)  maxArity = 5;
2024                 if (lastType != Object.class)  maxArity = 4;
2025                 for (int nargs = 0; nargs <= maxArity; nargs++) {
2026                     ArrayList<Class<?>> argTypes = new ArrayList<>(Collections.nCopies(nargs, Object.class));
2027                     int maxMix = 20;
2028                     if (collectType != Object.class)  maxMix = 0;
2029                     Map<Object,Integer> argTypesSeen = new HashMap<>();
2030                     for (int mix = 0; mix <= maxMix; mix++) {
2031                         if (!mixArgs(argTypes, mix, argTypesSeen))  continue;
2032                         for (int collect = 0; collect <= nargs; collect++) {
2033                             for (int pos = 0; pos <= nargs - collect; pos++) {
2034                                 testFoldOrCollectArguments(argTypes, pos, collect, collectType, lastType, isCollect);
2035                             }
2036                         }
2037                     }
2038                 }
2039             }
2040         }
2041     }
2042 
2043     boolean mixArgs(List<Class<?>> argTypes, int mix, Map<Object,Integer> argTypesSeen) {
2044         assert(mix >= 0);
2045         if (mix == 0)  return true;  // no change
2046         if ((mix >>> argTypes.size()) != 0)  return false;
2047         for (int i = 0; i < argTypes.size(); i++) {
2048             if (i >= 31)  break;
2049             boolean bit = (mix & (1 << i)) != 0;
2050             if (bit) {
2051                 Class<?> type = argTypes.get(i);
2052                 if (type == Object.class)
2053                     type = String.class;
2054                 else if (type == String.class)
2055                     type = int.class;
2056                 else
2057                     type = Object.class;
2058                 argTypes.set(i, type);
2059             }
2060         }
2061         Integer prev = argTypesSeen.put(new ArrayList<>(argTypes), mix);
2062         if (prev != null) {
2063             if (verbosity >= 4)  System.out.println("mix "+prev+" repeated "+mix+": "+argTypes);
2064             return false;
2065         }
2066         if (verbosity >= 3)  System.out.println("mix "+mix+" = "+argTypes);
2067         return true;
2068     }
2069 
2070     void testFoldOrCollectArguments(List<Class<?>> argTypes,  // argument types minus the inserted combineType
2071                                     int pos, int fold, // position and length of the folded arguments
2072                                     Class<?> combineType, // type returned from the combiner
2073                                     Class<?> lastType,  // type returned from the target
2074                                     boolean isCollect) throws Throwable {
2075         int nargs = argTypes.size();
2076         if (pos != 0 && !isCollect)  return;  // can fold only at pos=0 for now
2077         countTest();
2078         List<Class<?>> combineArgTypes = argTypes.subList(pos, pos + fold);
2079         List<Class<?>> targetArgTypes = new ArrayList<>(argTypes);
2080         if (isCollect)  // does targret see arg[pos..pos+cc-1]?
2081             targetArgTypes.subList(pos, pos + fold).clear();
2082         if (combineType != void.class)
2083             targetArgTypes.add(pos, combineType);
2084         MethodHandle target = varargsList(targetArgTypes, lastType);
2085         MethodHandle combine = varargsList(combineArgTypes, combineType);
2086         List<Object> argsToPass = Arrays.asList(randomArgs(argTypes));
2087         if (verbosity >= 3)
2088             System.out.println((isCollect ? "collect" : "fold")+" "+target+" with "+combine);
2089         MethodHandle target2;
2090         if (isCollect)
2091             target2 = MethodHandles.collectArguments(target, pos, combine);
2092         else
2093             target2 = MethodHandles.foldArguments(target, combine);
2094         // Simulate expected effect of combiner on arglist:
2095         List<Object> expectedList = new ArrayList<>(argsToPass);
2096         List<Object> argsToFold = expectedList.subList(pos, pos + fold);
2097         if (verbosity >= 3)
2098             System.out.println((isCollect ? "collect" : "fold")+": "+argsToFold+" into "+target2);
2099         Object foldedArgs = combine.invokeWithArguments(argsToFold);
2100         if (isCollect)
2101             argsToFold.clear();
2102         if (combineType != void.class)
2103             argsToFold.add(0, foldedArgs);
2104         Object result = target2.invokeWithArguments(argsToPass);
2105         if (verbosity >= 3)
2106             System.out.println("result: "+result);
2107         Object expected = target.invokeWithArguments(expectedList);
2108         if (!expected.equals(result))
2109             System.out.println("*** fail at n/p/f = "+nargs+"/"+pos+"/"+fold+": "+argsToPass+" => "+result+" != "+expected);
2110         assertEquals(expected, result);
2111     }
2112 
2113     @Test
2114     public void testDropArguments() throws Throwable {
2115         if (CAN_SKIP_WORKING)  return;
2116         startTest("dropArguments");
2117         for (int nargs = 0; nargs <= 4; nargs++) {
2118             for (int drop = 1; drop <= 4; drop++) {
2119                 for (int pos = 0; pos <= nargs; pos++) {
2120                     testDropArguments(nargs, pos, drop);
2121                 }
2122             }
2123         }
2124     }
2125 
2126     void testDropArguments(int nargs, int pos, int drop) throws Throwable {
2127         countTest();
2128         MethodHandle target = varargsArray(nargs);
2129         Object[] args = randomArgs(target.type().parameterArray());
2130         MethodHandle target2 = MethodHandles.dropArguments(target, pos,
2131                 Collections.nCopies(drop, Object.class).toArray(new Class<?>[0]));
2132         List<Object> resList = Arrays.asList(args);
2133         List<Object> argsToDrop = new ArrayList<>(resList);
2134         for (int i = drop; i > 0; i--) {
2135             argsToDrop.add(pos, "blort#"+i);
2136         }
2137         Object res2 = target2.invokeWithArguments(argsToDrop);
2138         Object res2List = Arrays.asList((Object[])res2);
2139         //if (!resList.equals(res2List))
2140         //    System.out.println("*** fail at n/p/d = "+nargs+"/"+pos+"/"+drop+": "+argsToDrop+" => "+res2List);
2141         assertEquals(resList, res2List);
2142     }
2143 
2144     @Test  // SLOW
2145     public void testInvokers() throws Throwable {
2146         if (CAN_SKIP_WORKING)  return;
2147         startTest("exactInvoker, genericInvoker, varargsInvoker, dynamicInvoker");
2148         // exactInvoker, genericInvoker, varargsInvoker[0..N], dynamicInvoker
2149         Set<MethodType> done = new HashSet<>();
2150         for (int i = 0; i <= 6; i++) {
2151             if (CAN_TEST_LIGHTLY && i > 3)  break;
2152             MethodType gtype = MethodType.genericMethodType(i);
2153             for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
2154                 for (int j = -1; j < i; j++) {
2155                     MethodType type = gtype;
2156                     if (j < 0)
2157                         type = type.changeReturnType(argType);
2158                     else if (argType == void.class)
2159                         continue;
2160                     else
2161                         type = type.changeParameterType(j, argType);
2162                     if (done.add(type))
2163                         testInvokers(type);
2164                     MethodType vtype = type.changeReturnType(void.class);
2165                     if (done.add(vtype))
2166                         testInvokers(vtype);
2167                 }
2168             }
2169         }
2170     }
2171 
2172     public void testInvokers(MethodType type) throws Throwable {
2173         if (verbosity >= 3)
2174             System.out.println("test invokers for "+type);
2175         int nargs = type.parameterCount();
2176         boolean testRetCode = type.returnType() != void.class;
2177         MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "invokee",
2178                                 MethodType.genericMethodType(0, true));
2179         assertTrue(target.isVarargsCollector());
2180         target = target.asType(type);
2181         Object[] args = randomArgs(type.parameterArray());
2182         List<Object> targetPlusArgs = new ArrayList<>(Arrays.asList(args));
2183         targetPlusArgs.add(0, target);
2184         int code = (Integer) invokee(args);
2185         Object log = logEntry("invokee", args);
2186         assertEquals(log.hashCode(), code);
2187         assertCalled("invokee", args);
2188         MethodHandle inv;
2189         Object result;
2190         // exact invoker
2191         countTest();
2192         calledLog.clear();
2193         inv = MethodHandles.exactInvoker(type);
2194         result = inv.invokeWithArguments(targetPlusArgs);
2195         if (testRetCode)  assertEquals(code, result);
2196         assertCalled("invokee", args);
2197         // generic invoker
2198         countTest();
2199         inv = MethodHandles.invoker(type);
2200         if (nargs <= 3 && type == type.generic()) {
2201             calledLog.clear();
2202             switch (nargs) {
2203             case 0:
2204                 result = inv.invokeExact(target);
2205                 break;
2206             case 1:
2207                 result = inv.invokeExact(target, args[0]);
2208                 break;
2209             case 2:
2210                 result = inv.invokeExact(target, args[0], args[1]);
2211                 break;
2212             case 3:
2213                 result = inv.invokeExact(target, args[0], args[1], args[2]);
2214                 break;
2215             }
2216             if (testRetCode)  assertEquals(code, result);
2217             assertCalled("invokee", args);
2218         }
2219         calledLog.clear();
2220         result = inv.invokeWithArguments(targetPlusArgs);
2221         if (testRetCode)  assertEquals(code, result);
2222         assertCalled("invokee", args);
2223         // varargs invoker #0
2224         calledLog.clear();
2225         inv = MethodHandles.spreadInvoker(type, 0);
2226         if (type.returnType() == Object.class) {
2227             result = inv.invokeExact(target, args);
2228         } else if (type.returnType() == void.class) {
2229             result = null; inv.invokeExact(target, args);
2230         } else {
2231             result = inv.invokeWithArguments(target, (Object) args);
2232         }
2233         if (testRetCode)  assertEquals(code, result);
2234         assertCalled("invokee", args);
2235         if (nargs >= 1 && type == type.generic()) {
2236             // varargs invoker #1
2237             calledLog.clear();
2238             inv = MethodHandles.spreadInvoker(type, 1);
2239             result = inv.invokeExact(target, args[0], Arrays.copyOfRange(args, 1, nargs));
2240             if (testRetCode)  assertEquals(code, result);
2241             assertCalled("invokee", args);
2242         }
2243         if (nargs >= 2 && type == type.generic()) {
2244             // varargs invoker #2
2245             calledLog.clear();
2246             inv = MethodHandles.spreadInvoker(type, 2);
2247             result = inv.invokeExact(target, args[0], args[1], Arrays.copyOfRange(args, 2, nargs));
2248             if (testRetCode)  assertEquals(code, result);
2249             assertCalled("invokee", args);
2250         }
2251         if (nargs >= 3 && type == type.generic()) {
2252             // varargs invoker #3
2253             calledLog.clear();
2254             inv = MethodHandles.spreadInvoker(type, 3);
2255             result = inv.invokeExact(target, args[0], args[1], args[2], Arrays.copyOfRange(args, 3, nargs));
2256             if (testRetCode)  assertEquals(code, result);
2257             assertCalled("invokee", args);
2258         }
2259         for (int k = 0; k <= nargs; k++) {
2260             // varargs invoker #0..N
2261             if (CAN_TEST_LIGHTLY && (k > 1 || k < nargs - 1))  continue;
2262             countTest();
2263             calledLog.clear();
2264             inv = MethodHandles.spreadInvoker(type, k);
2265             MethodType expType = (type.dropParameterTypes(k, nargs)
2266                                   .appendParameterTypes(Object[].class)
2267                                   .insertParameterTypes(0, MethodHandle.class));
2268             assertEquals(expType, inv.type());
2269             List<Object> targetPlusVarArgs = new ArrayList<>(targetPlusArgs);
2270             List<Object> tailList = targetPlusVarArgs.subList(1+k, 1+nargs);
2271             Object[] tail = tailList.toArray();
2272             tailList.clear(); tailList.add(tail);
2273             result = inv.invokeWithArguments(targetPlusVarArgs);
2274             if (testRetCode)  assertEquals(code, result);
2275             assertCalled("invokee", args);
2276         }
2277 
2278         // dynamic invoker
2279         countTest();
2280         CallSite site = new MutableCallSite(type);
2281         inv = site.dynamicInvoker();
2282 
2283         // see if we get the result of the original target:
2284         try {
2285             result = inv.invokeWithArguments(args);
2286             assertTrue("should not reach here", false);
2287         } catch (IllegalStateException ex) {
2288             String msg = ex.getMessage();
2289             assertTrue(msg, msg.contains("site"));
2290         }
2291 
2292         // set new target after invoker is created, to make sure we track target
2293         site.setTarget(target);
2294         calledLog.clear();
2295         result = inv.invokeWithArguments(args);
2296         if (testRetCode)  assertEquals(code, result);
2297         assertCalled("invokee", args);
2298     }
2299 
2300     static Object invokee(Object... args) {
2301         return called("invokee", args).hashCode();
2302     }
2303 
2304     private static final String MISSING_ARG = "missingArg";
2305     private static final String MISSING_ARG_2 = "missingArg#2";
2306     static Object targetIfEquals() {
2307         return called("targetIfEquals");
2308     }
2309     static Object fallbackIfNotEquals() {
2310         return called("fallbackIfNotEquals");
2311     }
2312     static Object targetIfEquals(Object x) {
2313         assertEquals(x, MISSING_ARG);
2314         return called("targetIfEquals", x);
2315     }
2316     static Object fallbackIfNotEquals(Object x) {
2317         assertFalse(x.toString(), x.equals(MISSING_ARG));
2318         return called("fallbackIfNotEquals", x);
2319     }
2320     static Object targetIfEquals(Object x, Object y) {
2321         assertEquals(x, y);
2322         return called("targetIfEquals", x, y);
2323     }
2324     static Object fallbackIfNotEquals(Object x, Object y) {
2325         assertFalse(x.toString(), x.equals(y));
2326         return called("fallbackIfNotEquals", x, y);
2327     }
2328     static Object targetIfEquals(Object x, Object y, Object z) {
2329         assertEquals(x, y);
2330         return called("targetIfEquals", x, y, z);
2331     }
2332     static Object fallbackIfNotEquals(Object x, Object y, Object z) {
2333         assertFalse(x.toString(), x.equals(y));
2334         return called("fallbackIfNotEquals", x, y, z);
2335     }
2336 
2337     @Test
2338     public void testGuardWithTest() throws Throwable {
2339         if (CAN_SKIP_WORKING)  return;
2340         startTest("guardWithTest");
2341         for (int nargs = 0; nargs <= 50; nargs++) {
2342             if (CAN_TEST_LIGHTLY && nargs > 7)  break;
2343             testGuardWithTest(nargs, Object.class);
2344             testGuardWithTest(nargs, String.class);
2345         }
2346     }
2347     void testGuardWithTest(int nargs, Class<?> argClass) throws Throwable {
2348         testGuardWithTest(nargs, 0, argClass);
2349         if (nargs <= 5 || nargs % 10 == 3) {
2350             for (int testDrops = 1; testDrops <= nargs; testDrops++)
2351                 testGuardWithTest(nargs, testDrops, argClass);
2352         }
2353     }
2354     void testGuardWithTest(int nargs, int testDrops, Class<?> argClass) throws Throwable {
2355         countTest();
2356         int nargs1 = Math.min(3, nargs);
2357         MethodHandle test = PRIVATE.findVirtual(Object.class, "equals", MethodType.methodType(boolean.class, Object.class));
2358         MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "targetIfEquals", MethodType.genericMethodType(nargs1));
2359         MethodHandle fallback = PRIVATE.findStatic(MethodHandlesTest.class, "fallbackIfNotEquals", MethodType.genericMethodType(nargs1));
2360         while (test.type().parameterCount() > nargs)
2361             // 0: test = constant(MISSING_ARG.equals(MISSING_ARG))
2362             // 1: test = lambda (_) MISSING_ARG.equals(_)
2363             test = MethodHandles.insertArguments(test, 0, MISSING_ARG);
2364         if (argClass != Object.class) {
2365             test = changeArgTypes(test, argClass);
2366             target = changeArgTypes(target, argClass);
2367             fallback = changeArgTypes(fallback, argClass);
2368         }
2369         int testArgs = nargs - testDrops;
2370         assert(testArgs >= 0);
2371         test = addTrailingArgs(test, Math.min(testArgs, nargs), argClass);
2372         target = addTrailingArgs(target, nargs, argClass);
2373         fallback = addTrailingArgs(fallback, nargs, argClass);
2374         Object[][] argLists = {
2375             { },
2376             { "foo" }, { MISSING_ARG },
2377             { "foo", "foo" }, { "foo", "bar" },
2378             { "foo", "foo", "baz" }, { "foo", "bar", "baz" }
2379         };
2380         for (Object[] argList : argLists) {
2381             Object[] argList1 = argList;
2382             if (argList.length != nargs) {
2383                 if (argList.length != nargs1)  continue;
2384                 argList1 = Arrays.copyOf(argList, nargs);
2385                 Arrays.fill(argList1, nargs1, nargs, MISSING_ARG_2);
2386             }
2387             MethodHandle test1 = test;
2388             if (test1.type().parameterCount() > testArgs) {
2389                 int pc = test1.type().parameterCount();
2390                 test1 = MethodHandles.insertArguments(test, testArgs, Arrays.copyOfRange(argList1, testArgs, pc));
2391             }
2392             MethodHandle mh = MethodHandles.guardWithTest(test1, target, fallback);
2393             assertEquals(target.type(), mh.type());
2394             boolean equals;
2395             switch (nargs) {
2396             case 0:   equals = true; break;
2397             case 1:   equals = MISSING_ARG.equals(argList[0]); break;
2398             default:  equals = argList[0].equals(argList[1]); break;
2399             }
2400             String willCall = (equals ? "targetIfEquals" : "fallbackIfNotEquals");
2401             if (verbosity >= 3)
2402                 System.out.println(logEntry(willCall, argList));
2403             Object result = mh.invokeWithArguments(argList1);
2404             assertCalled(willCall, argList);
2405         }
2406     }
2407 
2408     @Test
2409     public void testCatchException() throws Throwable {
2410         if (CAN_SKIP_WORKING)  return;
2411         startTest("catchException");
2412         for (int nargs = 0; nargs < 40; nargs++) {
2413             if (CAN_TEST_LIGHTLY && nargs > 11)  break;
2414             for (int throwMode = 0; throwMode < THROW_MODE_LIMIT; throwMode++) {
2415                 testCatchException(int.class, new ClassCastException("testing"), throwMode, nargs);
2416                 if (CAN_TEST_LIGHTLY && nargs > 3)  continue;
2417                 testCatchException(void.class, new java.io.IOException("testing"), throwMode, nargs);
2418                 testCatchException(String.class, new LinkageError("testing"), throwMode, nargs);
2419             }
2420         }
2421     }
2422 
2423     static final int THROW_NOTHING = 0, THROW_CAUGHT = 1, THROW_UNCAUGHT = 2, THROW_THROUGH_ADAPTER = 3, THROW_MODE_LIMIT = 4;
2424 
2425     void testCatchException(Class<?> returnType, Throwable thrown, int throwMode, int nargs) throws Throwable {
2426         testCatchException(returnType, thrown, throwMode, nargs, 0);
2427         if (nargs <= 5 || nargs % 10 == 3) {
2428             for (int catchDrops = 1; catchDrops <= nargs; catchDrops++)
2429                 testCatchException(returnType, thrown, throwMode, nargs, catchDrops);
2430         }
2431     }
2432 
2433     private static <T extends Throwable>
2434     Object throwOrReturn(Object normal, T exception) throws T {
2435         if (exception != null) {
2436             called("throwOrReturn/throw", normal, exception);
2437             throw exception;
2438         }
2439         called("throwOrReturn/normal", normal, exception);
2440         return normal;
2441     }
2442     private int fakeIdentityCount;
2443     private Object fakeIdentity(Object x) {
2444         System.out.println("should throw through this!");
2445         fakeIdentityCount++;
2446         return x;
2447     }
2448 
2449     void testCatchException(Class<?> returnType, Throwable thrown, int throwMode, int nargs, int catchDrops) throws Throwable {
2450         countTest();
2451         if (verbosity >= 3)
2452             System.out.println("catchException rt="+returnType+" throw="+throwMode+" nargs="+nargs+" drops="+catchDrops);
2453         Class<? extends Throwable> exType = thrown.getClass();
2454         if (throwMode > THROW_CAUGHT)  thrown = new UnsupportedOperationException("do not catch this");
2455         MethodHandle throwOrReturn
2456                 = PRIVATE.findStatic(MethodHandlesTest.class, "throwOrReturn",
2457                     MethodType.methodType(Object.class, Object.class, Throwable.class));
2458         if (throwMode == THROW_THROUGH_ADAPTER) {
2459             MethodHandle fakeIdentity
2460                 = PRIVATE.findVirtual(MethodHandlesTest.class, "fakeIdentity",
2461                     MethodType.methodType(Object.class, Object.class)).bindTo(this);
2462             for (int i = 0; i < 10; i++)
2463                 throwOrReturn = MethodHandles.filterReturnValue(throwOrReturn, fakeIdentity);
2464         }
2465         int nargs1 = Math.max(2, nargs);
2466         MethodHandle thrower = throwOrReturn.asType(MethodType.genericMethodType(2));
2467         thrower = addTrailingArgs(thrower, nargs, Object.class);
2468         int catchArgc = 1 + nargs - catchDrops;
2469         MethodHandle catcher = varargsList(catchArgc).asType(MethodType.genericMethodType(catchArgc));
2470         Object[] args = randomArgs(nargs, Object.class);
2471         Object arg0 = MISSING_ARG;
2472         Object arg1 = (throwMode == THROW_NOTHING) ? (Throwable) null : thrown;
2473         if (nargs > 0)  arg0 = args[0];
2474         if (nargs > 1)  args[1] = arg1;
2475         assertEquals(nargs1, thrower.type().parameterCount());
2476         if (nargs < nargs1) {
2477             Object[] appendArgs = { arg0, arg1 };
2478             appendArgs = Arrays.copyOfRange(appendArgs, nargs, nargs1);
2479             thrower = MethodHandles.insertArguments(thrower, nargs, appendArgs);
2480         }
2481         assertEquals(nargs, thrower.type().parameterCount());
2482         MethodHandle target = MethodHandles.catchException(thrower, exType, catcher);
2483         assertEquals(thrower.type(), target.type());
2484         assertEquals(nargs, target.type().parameterCount());
2485         //System.out.println("catching with "+target+" : "+throwOrReturn);
2486         Object returned;
2487         try {
2488             returned = target.invokeWithArguments(args);
2489         } catch (Throwable ex) {
2490             assertSame("must get the out-of-band exception", thrown, ex);
2491             if (throwMode <= THROW_CAUGHT)
2492                 assertEquals(THROW_UNCAUGHT, throwMode);
2493             returned = ex;
2494         }
2495         assertCalled("throwOrReturn/"+(throwMode == THROW_NOTHING ? "normal" : "throw"), arg0, arg1);
2496         //System.out.println("return from "+target+" : "+returned);
2497         if (throwMode == THROW_NOTHING) {
2498             assertSame(arg0, returned);
2499         } else if (throwMode == THROW_CAUGHT) {
2500             List<Object> catchArgs = new ArrayList<>(Arrays.asList(args));
2501             // catcher receives an initial subsequence of target arguments:
2502             catchArgs.subList(nargs - catchDrops, nargs).clear();
2503             // catcher also receives the exception, prepended:
2504             catchArgs.add(0, thrown);
2505             assertEquals(catchArgs, returned);
2506         }
2507         assertEquals(0, fakeIdentityCount);
2508     }
2509 
2510     @Test
2511     public void testThrowException() throws Throwable {
2512         if (CAN_SKIP_WORKING)  return;
2513         startTest("throwException");
2514         testThrowException(int.class, new ClassCastException("testing"));
2515         testThrowException(void.class, new java.io.IOException("testing"));
2516         testThrowException(String.class, new LinkageError("testing"));
2517     }
2518 
2519     void testThrowException(Class<?> returnType, Throwable thrown) throws Throwable {
2520         countTest();
2521         Class<? extends Throwable> exType = thrown.getClass();
2522         MethodHandle target = MethodHandles.throwException(returnType, exType);
2523         //System.out.println("throwing with "+target+" : "+thrown);
2524         MethodType expectedType = MethodType.methodType(returnType, exType);
2525         assertEquals(expectedType, target.type());
2526         target = target.asType(target.type().generic());
2527         Throwable caught = null;
2528         try {
2529             Object res = target.invokeExact((Object) thrown);
2530             fail("got "+res+" instead of throwing "+thrown);
2531         } catch (Throwable ex) {
2532             if (ex != thrown) {
2533                 if (ex instanceof Error)  throw (Error)ex;
2534                 if (ex instanceof RuntimeException)  throw (RuntimeException)ex;
2535             }
2536             caught = ex;
2537         }
2538         assertSame(thrown, caught);
2539     }
2540 
2541     @Test
2542     public void testInterfaceCast() throws Throwable {
2543         //if (CAN_SKIP_WORKING)  return;
2544         startTest("interfaceCast");
2545         assert( (((Object)"foo") instanceof CharSequence));
2546         assert(!(((Object)"foo") instanceof Iterable));
2547         for (MethodHandle mh : new MethodHandle[]{
2548             MethodHandles.identity(String.class),
2549             MethodHandles.identity(CharSequence.class),
2550             MethodHandles.identity(Iterable.class)
2551         }) {
2552             if (verbosity > 0)  System.out.println("-- mh = "+mh);
2553             for (Class<?> ctype : new Class<?>[]{
2554                 Object.class, String.class, CharSequence.class,
2555                 Number.class, Iterable.class
2556             }) {
2557                 if (verbosity > 0)  System.out.println("---- ctype = "+ctype.getName());
2558                 //                           doret  docast
2559                 testInterfaceCast(mh, ctype, false, false);
2560                 testInterfaceCast(mh, ctype, true,  false);
2561                 testInterfaceCast(mh, ctype, false, true);
2562                 testInterfaceCast(mh, ctype, true,  true);
2563             }
2564         }
2565     }
2566     private static Class<?> i2o(Class<?> c) {
2567         return (c.isInterface() ? Object.class : c);
2568     }
2569     public void testInterfaceCast(MethodHandle mh, Class<?> ctype,
2570                                                    boolean doret, boolean docast) throws Throwable {
2571         MethodHandle mh0 = mh;
2572         if (verbosity > 1)
2573             System.out.println("mh="+mh+", ctype="+ctype.getName()+", doret="+doret+", docast="+docast);
2574         String normalRetVal = "normal return value";
2575         MethodType mt = mh.type();
2576         MethodType mt0 = mt;
2577         if (doret)  mt = mt.changeReturnType(ctype);
2578         else        mt = mt.changeParameterType(0, ctype);
2579         if (docast) mh = MethodHandles.explicitCastArguments(mh, mt);
2580         else        mh = mh.asType(mt);
2581         assertEquals(mt, mh.type());
2582         MethodType mt1 = mt;
2583         // this bit is needed to make the interface types disappear for invokeWithArguments:
2584         mh = MethodHandles.explicitCastArguments(mh, mt.generic());
2585         Class<?>[] step = {
2586             mt1.parameterType(0),  // param as passed to mh at first
2587             mt0.parameterType(0),  // param after incoming cast
2588             mt0.returnType(),      // return value before cast
2589             mt1.returnType(),      // return value after outgoing cast
2590         };
2591         // where might a checkCast occur?
2592         boolean[] checkCast = new boolean[step.length];
2593         // the string value must pass each step without causing an exception
2594         if (!docast) {
2595             if (!doret) {
2596                 if (step[0] != step[1])
2597                     checkCast[1] = true;  // incoming value is cast
2598             } else {
2599                 if (step[2] != step[3])
2600                     checkCast[3] = true;  // outgoing value is cast
2601             }
2602         }
2603         boolean expectFail = false;
2604         for (int i = 0; i < step.length; i++) {
2605             Class<?> c = step[i];
2606             if (!checkCast[i])  c = i2o(c);
2607             if (!c.isInstance(normalRetVal)) {
2608                 if (verbosity > 3)
2609                     System.out.println("expect failure at step "+i+" in "+Arrays.toString(step)+Arrays.toString(checkCast));
2610                 expectFail = true;
2611                 break;
2612             }
2613         }
2614         countTest(!expectFail);
2615         if (verbosity > 2)
2616             System.out.println("expectFail="+expectFail+", mt="+mt);
2617         Object res;
2618         try {
2619             res = mh.invokeWithArguments(normalRetVal);
2620         } catch (Exception ex) {
2621             res = ex;
2622         }
2623         boolean sawFail = !(res instanceof String);
2624         if (sawFail != expectFail) {
2625             System.out.println("*** testInterfaceCast: mh0 = "+mh0);
2626             System.out.println("  retype using "+(docast ? "explicitCastArguments" : "asType")+" to "+mt+" => "+mh);
2627             System.out.println("  call returned "+res);
2628             System.out.println("  expected "+(expectFail ? "an exception" : normalRetVal));
2629         }
2630         if (!expectFail) {
2631             assertFalse(res.toString(), sawFail);
2632             assertEquals(normalRetVal, res);
2633         } else {
2634             assertTrue(res.toString(), sawFail);
2635         }
2636     }
2637 
2638     @Test  // SLOW
2639     public void testCastFailure() throws Throwable {
2640         if (CAN_SKIP_WORKING)  return;
2641         startTest("testCastFailure");
2642         testCastFailure("cast/argument", 11000);
2643         if (CAN_TEST_LIGHTLY)  return;
2644         testCastFailure("unbox/argument", 11000);
2645         testCastFailure("cast/return", 11000);
2646         testCastFailure("unbox/return", 11000);
2647     }
2648 
2649     static class Surprise {
2650         public MethodHandle asMethodHandle() {
2651             return VALUE.bindTo(this);
2652         }
2653         Object value(Object x) {
2654             trace("value", x);
2655             if (boo != null)  return boo;
2656             return x;
2657         }
2658         Object boo;
2659         void boo(Object x) { boo = x; }
2660 
2661         static void trace(String x, Object y) {
2662             if (verbosity > 8) System.out.println(x+"="+y);
2663         }
2664         static Object  refIdentity(Object x)  { trace("ref.x", x); return x; }
2665         static Integer boxIdentity(Integer x) { trace("box.x", x); return x; }
2666         static int     intIdentity(int x)     { trace("int.x", x); return x; }
2667         static MethodHandle VALUE, REF_IDENTITY, BOX_IDENTITY, INT_IDENTITY;
2668         static {
2669             try {
2670                 VALUE = PRIVATE.findVirtual(
2671                     Surprise.class, "value",
2672                         MethodType.methodType(Object.class, Object.class));
2673                 REF_IDENTITY = PRIVATE.findStatic(
2674                     Surprise.class, "refIdentity",
2675                         MethodType.methodType(Object.class, Object.class));
2676                 BOX_IDENTITY = PRIVATE.findStatic(
2677                     Surprise.class, "boxIdentity",
2678                         MethodType.methodType(Integer.class, Integer.class));
2679                 INT_IDENTITY = PRIVATE.findStatic(
2680                     Surprise.class, "intIdentity",
2681                         MethodType.methodType(int.class, int.class));
2682             } catch (NoSuchMethodException | IllegalAccessException ex) {
2683                 throw new RuntimeException(ex);
2684             }
2685         }
2686     }
2687 
2688     @SuppressWarnings("ConvertToStringSwitch")
2689     void testCastFailure(String mode, int okCount) throws Throwable {
2690         countTest(false);
2691         if (verbosity > 2)  System.out.println("mode="+mode);
2692         Surprise boo = new Surprise();
2693         MethodHandle identity = Surprise.REF_IDENTITY, surprise0 = boo.asMethodHandle(), surprise = surprise0;
2694         if (mode.endsWith("/return")) {
2695             if (mode.equals("unbox/return")) {
2696                 // fail on return to ((Integer)surprise).intValue
2697                 surprise = surprise.asType(MethodType.methodType(int.class, Object.class));
2698                 identity = identity.asType(MethodType.methodType(int.class, Object.class));
2699             } else if (mode.equals("cast/return")) {
2700                 // fail on return to (Integer)surprise
2701                 surprise = surprise.asType(MethodType.methodType(Integer.class, Object.class));
2702                 identity = identity.asType(MethodType.methodType(Integer.class, Object.class));
2703             }
2704         } else if (mode.endsWith("/argument")) {
2705             MethodHandle callee = null;
2706             if (mode.equals("unbox/argument")) {
2707                 // fail on handing surprise to int argument
2708                 callee = Surprise.INT_IDENTITY;
2709             } else if (mode.equals("cast/argument")) {
2710                 // fail on handing surprise to Integer argument
2711                 callee = Surprise.BOX_IDENTITY;
2712             }
2713             if (callee != null) {
2714                 callee = callee.asType(MethodType.genericMethodType(1));
2715                 surprise = MethodHandles.filterArguments(callee, 0, surprise);
2716                 identity = MethodHandles.filterArguments(callee, 0, identity);
2717             }
2718         }
2719         assertNotSame(mode, surprise, surprise0);
2720         identity = identity.asType(MethodType.genericMethodType(1));
2721         surprise = surprise.asType(MethodType.genericMethodType(1));
2722         Object x = 42;
2723         for (int i = 0; i < okCount; i++) {
2724             Object y = identity.invokeExact(x);
2725             assertEquals(x, y);
2726             Object z = surprise.invokeExact(x);
2727             assertEquals(x, z);
2728         }
2729         boo.boo("Boo!");
2730         Object y = identity.invokeExact(x);
2731         assertEquals(x, y);
2732         try {
2733             Object z = surprise.invokeExact(x);
2734             System.out.println("Failed to throw; got z="+z);
2735             assertTrue(false);
2736         } catch (ClassCastException ex) {
2737             if (verbosity > 2)
2738                 System.out.println("caught "+ex);
2739             if (verbosity > 3)
2740                 ex.printStackTrace(System.out);
2741             assertTrue(true);  // all is well
2742         }
2743     }
2744 
2745     static Example userMethod(Object o, String s, int i) {
2746         called("userMethod", o, s, i);
2747         return null;
2748     }
2749 
2750     @Test
2751     public void testUserClassInSignature() throws Throwable {
2752         if (CAN_SKIP_WORKING)  return;
2753         startTest("testUserClassInSignature");
2754         Lookup lookup = MethodHandles.lookup();
2755         String name; MethodType mt; MethodHandle mh;
2756         Object[] args;
2757 
2758         // Try a static method.
2759         name = "userMethod";
2760         mt = MethodType.methodType(Example.class, Object.class, String.class, int.class);
2761         mh = lookup.findStatic(lookup.lookupClass(), name, mt);
2762         assertEquals(mt, mh.type());
2763         assertEquals(Example.class, mh.type().returnType());
2764         args = randomArgs(mh.type().parameterArray());
2765         mh.invokeWithArguments(args);
2766         assertCalled(name, args);
2767 
2768         // Try a virtual method.
2769         name = "v2";
2770         mt = MethodType.methodType(Object.class, Object.class, int.class);
2771         mh = lookup.findVirtual(Example.class, name, mt);
2772         assertEquals(mt, mh.type().dropParameterTypes(0,1));
2773         assertTrue(mh.type().parameterList().contains(Example.class));
2774         args = randomArgs(mh.type().parameterArray());
2775         mh.invokeWithArguments(args);
2776         assertCalled(name, args);
2777     }
2778 
2779     static void runForRunnable() {
2780         called("runForRunnable");
2781     }
2782     public interface Fooable {
2783         // overloads:
2784         Object  foo(Object x, String y);
2785         List<?> foo(String x, int y);
2786         Object  foo(String x);
2787     }
2788     static Object fooForFooable(String x, Object... y) {
2789         return called("fooForFooable/"+x, y);
2790     }
2791     @SuppressWarnings("serial")  // not really a public API, just a test case
2792     public static class MyCheckedException extends Exception {
2793     }
2794     public interface WillThrow {
2795         void willThrow() throws MyCheckedException;
2796     }
2797     /*non-public*/ interface PrivateRunnable {
2798         public void run();
2799     }
2800 
2801     @Test
2802     public void testAsInterfaceInstance() throws Throwable {
2803         if (CAN_SKIP_WORKING)  return;
2804         startTest("asInterfaceInstance");
2805         Lookup lookup = MethodHandles.lookup();
2806         // test typical case:  Runnable.run
2807         {
2808             countTest();
2809             if (verbosity >= 2)  System.out.println("Runnable");
2810             MethodType mt = MethodType.methodType(void.class);
2811             MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "runForRunnable", mt);
2812             Runnable proxy = MethodHandleProxies.asInterfaceInstance(Runnable.class, mh);
2813             proxy.run();
2814             assertCalled("runForRunnable");
2815         }
2816         // well known single-name overloaded interface:  Appendable.append
2817         {
2818             countTest();
2819             if (verbosity >= 2)  System.out.println("Appendable");
2820             ArrayList<List<?>> appendResults = new ArrayList<>();
2821             MethodHandle append = lookup.bind(appendResults, "add", MethodType.methodType(boolean.class, Object.class));
2822             append = append.asType(MethodType.methodType(void.class, List.class)); // specialize the type
2823             MethodHandle asList = lookup.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class));
2824             MethodHandle mh = MethodHandles.filterReturnValue(asList, append).asVarargsCollector(Object[].class);
2825             Appendable proxy = MethodHandleProxies.asInterfaceInstance(Appendable.class, mh);
2826             proxy.append("one");
2827             proxy.append("two", 3, 4);
2828             proxy.append('5');
2829             assertEquals(Arrays.asList(Arrays.asList("one"),
2830                                        Arrays.asList("two", 3, 4),
2831                                        Arrays.asList('5')),
2832                          appendResults);
2833             if (verbosity >= 3)  System.out.println("appendResults="+appendResults);
2834             appendResults.clear();
2835             Formatter formatter = new Formatter(proxy);
2836             String fmt = "foo str=%s char='%c' num=%d";
2837             Object[] fmtArgs = { "str!", 'C', 42 };
2838             String expect = String.format(fmt, fmtArgs);
2839             formatter.format(fmt, fmtArgs);
2840             String actual = "";
2841             if (verbosity >= 3)  System.out.println("appendResults="+appendResults);
2842             for (List<?> l : appendResults) {
2843                 Object x = l.get(0);
2844                 switch (l.size()) {
2845                 case 1:  actual += x; continue;
2846                 case 3:  actual += ((String)x).substring((int)(Object)l.get(1), (int)(Object)l.get(2)); continue;
2847                 }
2848                 actual += l;
2849             }
2850             if (verbosity >= 3)  System.out.println("expect="+expect);
2851             if (verbosity >= 3)  System.out.println("actual="+actual);
2852             assertEquals(expect, actual);
2853         }
2854         // test case of an single name which is overloaded:  Fooable.foo(...)
2855         {
2856             if (verbosity >= 2)  System.out.println("Fooable");
2857             MethodHandle mh = lookup.findStatic(MethodHandlesTest.class, "fooForFooable",
2858                                                 MethodType.methodType(Object.class, String.class, Object[].class));
2859             Fooable proxy = MethodHandleProxies.asInterfaceInstance(Fooable.class, mh);
2860             for (Method m : Fooable.class.getDeclaredMethods()) {
2861                 countTest();
2862                 assertSame("foo", m.getName());
2863                 if (verbosity > 3)
2864                     System.out.println("calling "+m);
2865                 MethodHandle invoker = lookup.unreflect(m);
2866                 MethodType mt = invoker.type();
2867                 Class<?>[] types = mt.parameterArray();
2868                 types[0] = int.class;  // placeholder
2869                 Object[] args = randomArgs(types);
2870                 args[0] = proxy;
2871                 if (verbosity > 3)
2872                     System.out.println("calling "+m+" on "+Arrays.asList(args));
2873                 Object result = invoker.invokeWithArguments(args);
2874                 if (verbosity > 4)
2875                     System.out.println("result = "+result);
2876                 String name = "fooForFooable/"+args[1];
2877                 Object[] argTail = Arrays.copyOfRange(args, 2, args.length);
2878                 assertCalled(name, argTail);
2879                 assertEquals(result, logEntry(name, argTail));
2880             }
2881         }
2882         // test processing of thrown exceptions:
2883         for (Throwable ex : new Throwable[] { new NullPointerException("ok"),
2884                                               new InternalError("ok"),
2885                                               new Throwable("fail"),
2886                                               new Exception("fail"),
2887                                               new MyCheckedException()
2888                                             }) {
2889             MethodHandle mh = MethodHandles.throwException(void.class, Throwable.class);
2890             mh = MethodHandles.insertArguments(mh, 0, ex);
2891             WillThrow proxy = MethodHandleProxies.asInterfaceInstance(WillThrow.class, mh);
2892             try {
2893                 countTest();
2894                 proxy.willThrow();
2895                 System.out.println("Failed to throw: "+ex);
2896                 assertTrue(false);
2897             } catch (Throwable ex1) {
2898                 if (verbosity > 3) {
2899                     System.out.println("throw "+ex);
2900                     System.out.println("catch "+(ex == ex1 ? "UNWRAPPED" : ex1));
2901                 }
2902                 if (ex instanceof RuntimeException ||
2903                     ex instanceof Error) {
2904                     assertSame("must pass unchecked exception out without wrapping", ex, ex1);
2905                 } else if (ex instanceof MyCheckedException) {
2906                     assertSame("must pass declared exception out without wrapping", ex, ex1);
2907                 } else {
2908                     assertNotSame("must pass undeclared checked exception with wrapping", ex, ex1);
2909                     if (!(ex1 instanceof UndeclaredThrowableException) || ex1.getCause() != ex) {
2910                         ex1.printStackTrace(System.out);
2911                     }
2912                     assertSame(ex, ex1.getCause());
2913                     UndeclaredThrowableException utex = (UndeclaredThrowableException) ex1;
2914                 }
2915             }
2916         }
2917         // Test error checking on bad interfaces:
2918         for (Class<?> nonSMI : new Class<?>[] { Object.class,
2919                                              String.class,
2920                                              CharSequence.class,
2921                                              java.io.Serializable.class,
2922                                              PrivateRunnable.class,
2923                                              Example.class }) {
2924             if (verbosity > 2)  System.out.println(nonSMI.getName());
2925             try {
2926                 countTest(false);
2927                 MethodHandleProxies.asInterfaceInstance(nonSMI, varargsArray(0));
2928                 assertTrue("Failed to throw on "+nonSMI.getName(), false);
2929             } catch (IllegalArgumentException ex) {
2930                 if (verbosity > 2)  System.out.println(nonSMI.getSimpleName()+": "+ex);
2931                 // Object: java.lang.IllegalArgumentException:
2932                 //     not a public interface: java.lang.Object
2933                 // String: java.lang.IllegalArgumentException:
2934                 //     not a public interface: java.lang.String
2935                 // CharSequence: java.lang.IllegalArgumentException:
2936                 //     not a single-method interface: java.lang.CharSequence
2937                 // Serializable: java.lang.IllegalArgumentException:
2938                 //     not a single-method interface: java.io.Serializable
2939                 // PrivateRunnable: java.lang.IllegalArgumentException:
2940                 //     not a public interface: test.java.lang.invoke.MethodHandlesTest$PrivateRunnable
2941                 // Example: java.lang.IllegalArgumentException:
2942                 //     not a public interface: test.java.lang.invoke.MethodHandlesTest$Example
2943             }
2944         }
2945         // Test error checking on interfaces with the wrong method type:
2946         for (Class<?> intfc : new Class<?>[] { Runnable.class /*arity 0*/,
2947                                             Fooable.class /*arity 1 & 2*/ }) {
2948             int badArity = 1;  // known to be incompatible
2949             if (verbosity > 2)  System.out.println(intfc.getName());
2950             try {
2951                 countTest(false);
2952                 MethodHandleProxies.asInterfaceInstance(intfc, varargsArray(badArity));
2953                 assertTrue("Failed to throw on "+intfc.getName(), false);
2954             } catch (WrongMethodTypeException ex) {
2955                 if (verbosity > 2)  System.out.println(intfc.getSimpleName()+": "+ex);
2956                 // Runnable: java.lang.invoke.WrongMethodTypeException:
2957                 //     cannot convert MethodHandle(Object)Object[] to ()void
2958                 // Fooable: java.lang.invoke.WrongMethodTypeException:
2959                 //     cannot convert MethodHandle(Object)Object[] to (Object,String)Object
2960             }
2961         }
2962     }
2963 
2964     @Test
2965     public void testRunnableProxy() throws Throwable {
2966         if (CAN_SKIP_WORKING)  return;
2967         startTest("testRunnableProxy");
2968         MethodHandles.Lookup lookup = MethodHandles.lookup();
2969         MethodHandle run = lookup.findStatic(lookup.lookupClass(), "runForRunnable", MethodType.methodType(void.class));
2970         Runnable r = MethodHandleProxies.asInterfaceInstance(Runnable.class, run);
2971         testRunnableProxy(r);
2972         assertCalled("runForRunnable");
2973     }
2974     private static void testRunnableProxy(Runnable r) {
2975         //7058630: JSR 292 method handle proxy violates contract for Object methods
2976         r.run();
2977         Object o = r;
2978         r = null;
2979         boolean eq = (o == o);
2980         int     hc = System.identityHashCode(o);
2981         String  st = o.getClass().getName() + "@" + Integer.toHexString(hc);
2982         Object expect = Arrays.asList(st, eq, hc);
2983         if (verbosity >= 2)  System.out.println("expect st/eq/hc = "+expect);
2984         Object actual = Arrays.asList(o.toString(), o.equals(o), o.hashCode());
2985         if (verbosity >= 2)  System.out.println("actual st/eq/hc = "+actual);
2986         assertEquals(expect, actual);
2987     }
2988 }
2989 // Local abbreviated copy of sun.invoke.util.ValueConversions
2990 // This guy tests access from outside the same package member, but inside
2991 // the package itself.
2992 class ValueConversions {
2993     private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
2994     private static final Object[] NO_ARGS_ARRAY = {};
2995     private static Object[] makeArray(Object... args) { return args; }
2996     private static Object[] array() { return NO_ARGS_ARRAY; }
2997     private static Object[] array(Object a0)
2998                 { return makeArray(a0); }
2999     private static Object[] array(Object a0, Object a1)
3000                 { return makeArray(a0, a1); }
3001     private static Object[] array(Object a0, Object a1, Object a2)
3002                 { return makeArray(a0, a1, a2); }
3003     private static Object[] array(Object a0, Object a1, Object a2, Object a3)
3004                 { return makeArray(a0, a1, a2, a3); }
3005     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
3006                                   Object a4)
3007                 { return makeArray(a0, a1, a2, a3, a4); }
3008     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
3009                                   Object a4, Object a5)
3010                 { return makeArray(a0, a1, a2, a3, a4, a5); }
3011     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
3012                                   Object a4, Object a5, Object a6)
3013                 { return makeArray(a0, a1, a2, a3, a4, a5, a6); }
3014     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
3015                                   Object a4, Object a5, Object a6, Object a7)
3016                 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); }
3017     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
3018                                   Object a4, Object a5, Object a6, Object a7,
3019                                   Object a8)
3020                 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
3021     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
3022                                   Object a4, Object a5, Object a6, Object a7,
3023                                   Object a8, Object a9)
3024                 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
3025     static MethodHandle[] makeArrays() {
3026         ArrayList<MethodHandle> arrays = new ArrayList<>();
3027         MethodHandles.Lookup lookup = IMPL_LOOKUP;
3028         for (;;) {
3029             int nargs = arrays.size();
3030             MethodType type = MethodType.genericMethodType(nargs).changeReturnType(Object[].class);
3031             String name = "array";
3032             MethodHandle array = null;
3033             try {
3034                 array = lookup.findStatic(ValueConversions.class, name, type);
3035             } catch (ReflectiveOperationException ex) {
3036                 // break from loop!
3037             }
3038             if (array == null)  break;
3039             arrays.add(array);
3040         }
3041         assertTrue(arrays.size() == 11);  // current number of methods
3042         return arrays.toArray(new MethodHandle[0]);
3043     }
3044     static final MethodHandle[] ARRAYS = makeArrays();
3045 
3046     /** Return a method handle that takes the indicated number of Object
3047      *  arguments and returns an Object array of them, as if for varargs.
3048      */
3049     public static MethodHandle varargsArray(int nargs) {
3050         if (nargs < ARRAYS.length)
3051             return ARRAYS[nargs];
3052         return MethodHandles.identity(Object[].class).asCollector(Object[].class, nargs);
3053     }
3054     public static MethodHandle varargsArray(Class<?> arrayType, int nargs) {
3055         Class<?> elemType = arrayType.getComponentType();
3056         MethodType vaType = MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType));
3057         MethodHandle mh = varargsArray(nargs);
3058         if (arrayType != Object[].class)
3059             mh = MethodHandles.filterReturnValue(mh, CHANGE_ARRAY_TYPE.bindTo(arrayType));
3060         return mh.asType(vaType);
3061     }
3062     static Object changeArrayType(Class<?> arrayType, Object[] a) {
3063         Class<?> elemType = arrayType.getComponentType();
3064         if (!elemType.isPrimitive())
3065             return Arrays.copyOf(a, a.length, arrayType.asSubclass(Object[].class));
3066         Object b = java.lang.reflect.Array.newInstance(elemType, a.length);
3067         for (int i = 0; i < a.length; i++)
3068             java.lang.reflect.Array.set(b, i, a[i]);
3069         return b;
3070     }
3071     private static final MethodHandle CHANGE_ARRAY_TYPE;
3072     static {
3073         try {
3074             CHANGE_ARRAY_TYPE = IMPL_LOOKUP.findStatic(ValueConversions.class, "changeArrayType",
3075                                                        MethodType.methodType(Object.class, Class.class, Object[].class));
3076         } catch (NoSuchMethodException | IllegalAccessException ex) {
3077             Error err = new InternalError("uncaught exception");
3078             err.initCause(ex);
3079             throw err;
3080         }
3081     }
3082 
3083     private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY);
3084     private static List<Object> makeList(Object... args) { return Arrays.asList(args); }
3085     private static List<Object> list() { return NO_ARGS_LIST; }
3086     private static List<Object> list(Object a0)
3087                 { return makeList(a0); }
3088     private static List<Object> list(Object a0, Object a1)
3089                 { return makeList(a0, a1); }
3090     private static List<Object> list(Object a0, Object a1, Object a2)
3091                 { return makeList(a0, a1, a2); }
3092     private static List<Object> list(Object a0, Object a1, Object a2, Object a3)
3093                 { return makeList(a0, a1, a2, a3); }
3094     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
3095                                      Object a4)
3096                 { return makeList(a0, a1, a2, a3, a4); }
3097     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
3098                                      Object a4, Object a5)
3099                 { return makeList(a0, a1, a2, a3, a4, a5); }
3100     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
3101                                      Object a4, Object a5, Object a6)
3102                 { return makeList(a0, a1, a2, a3, a4, a5, a6); }
3103     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
3104                                      Object a4, Object a5, Object a6, Object a7)
3105                 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); }
3106     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
3107                                      Object a4, Object a5, Object a6, Object a7,
3108                                      Object a8)
3109                 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
3110     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
3111                                      Object a4, Object a5, Object a6, Object a7,
3112                                      Object a8, Object a9)
3113                 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
3114     static MethodHandle[] makeLists() {
3115         ArrayList<MethodHandle> lists = new ArrayList<>();
3116         MethodHandles.Lookup lookup = IMPL_LOOKUP;
3117         for (;;) {
3118             int nargs = lists.size();
3119             MethodType type = MethodType.genericMethodType(nargs).changeReturnType(List.class);
3120             String name = "list";
3121             MethodHandle list = null;
3122             try {
3123                 list = lookup.findStatic(ValueConversions.class, name, type);
3124             } catch (ReflectiveOperationException ex) {
3125                 // break from loop!
3126             }
3127             if (list == null)  break;
3128             lists.add(list);
3129         }
3130         assertTrue(lists.size() == 11);  // current number of methods
3131         return lists.toArray(new MethodHandle[0]);
3132     }
3133     static final MethodHandle[] LISTS = makeLists();
3134     static final MethodHandle AS_LIST;
3135     static {
3136         try {
3137             AS_LIST = IMPL_LOOKUP.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class));
3138         } catch (NoSuchMethodException | IllegalAccessException ex) { throw new RuntimeException(ex); }
3139     }
3140 
3141     /** Return a method handle that takes the indicated number of Object
3142      *  arguments and returns List.
3143      */
3144     public static MethodHandle varargsList(int nargs) {
3145         if (nargs < LISTS.length)
3146             return LISTS[nargs];
3147         return AS_LIST.asCollector(Object[].class, nargs);
3148     }
3149 }
3150 // This guy tests access from outside the same package member, but inside
3151 // the package itself.
3152 class PackageSibling {
3153     static Lookup lookup() {
3154         return MethodHandles.lookup();
3155     }
3156 }