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