test/java/dyn/MethodHandlesTest.java
author jrose
Thu Jan 07 16:16:45 2010 -0800 (2 years ago)
changeset 2040 dbcf6cafa65c
parent 20389c352f7ed4a3
child 236200cd9dc3c2b5
child 24310cd764a1c809
permissions -rw-r--r--
6914665: update jdk code for JSR 292 (post 6858164)
Summary: Fill in missing API implementations, fix numerous bugs, adjust APIs towards EG design.
Reviewed-by: twisti
        1 /*
        2  * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
        8  * particular file as subject to the "Classpath" exception as provided
        9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       22  * CA 95054 USA or visit www.sun.com if you need additional information or
       23  * have any questions.
       24  */
       25 
       26 /* @test
       27  * @summary unit tests for java.dyn.MethodHandles
       28  * @compile -XDinvokedynamic MethodHandlesTest.java
       29  * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic jdk.java.dyn.MethodHandlesTest
       30  */
       31 
       32 package jdk.java.dyn;
       33 
       34 import java.dyn.*;
       35 import java.dyn.MethodHandles.Lookup;
       36 import java.lang.reflect.*;
       37 import java.util.*;
       38 import java.util.logging.Level;
       39 import java.util.logging.Logger;
       40 import org.junit.*;
       41 import static org.junit.Assert.*;
       42 
       43 
       44 /**
       45  *
       46  * @author jrose
       47  */
       48 public class MethodHandlesTest {
       49     // How much output?
       50     static int verbosity = 1;
       51 
       52     // Set this true during development if you want to fast-forward to
       53     // a particular new, non-working test.  Tests which are known to
       54     // work (or have recently worked) test this flag and return on true.
       55     static boolean CAN_SKIP_WORKING = false;
       56     //static { CAN_SKIP_WORKING = true; }
       57 
       58     // Set true to test more calls.  If false, some tests are just
       59     // lookups, without exercising the actual method handle.
       60     static boolean DO_MORE_CALLS = false;
       61 
       62 
       63     @Test
       64     public void testFirst() throws Throwable {
       65         verbosity += 9; try {
       66             // left blank for debugging
       67         } finally { verbosity -= 9; }
       68     }
       69 
       70     // current failures
       71     @Test @Ignore("failure in call to makeRawRetypeOnly in ToGeneric")
       72     public void testFail_1() throws Throwable {
       73         testSpreadArguments(int.class, 0, 6);
       74     }
       75     @Test @Ignore("failure in JVM when expanding the stack")
       76     public void testFail_2() throws Throwable {
       77         // if CONV_OP_IMPLEMENTED_MASK includes OP_SPREAD_ARGS, this crashes:
       78         testSpreadArguments(Object.class, 0, 2);
       79     }
       80     @Test @Ignore("IllArgEx failure in call to ToGeneric.make")
       81     public void testFail_3() throws Throwable {
       82         testSpreadArguments(int.class, 1, 2);
       83     }
       84     @Test @Ignore("IllArgEx failure in call to ToGeneric.make")
       85     public void testFail_4() throws Throwable {
       86         testCollectArguments(int.class, 1, 2);
       87     }
       88     @Test @Ignore("cannot collect leading primitive types")
       89     public void testFail_5() throws Throwable {
       90         testInvokers(MethodType.genericMethodType(2).changeParameterType(0, int.class));
       91     }
       92     @Test @Ignore("should not insert arguments beyond MethodHandlePushLimit")
       93     public void testFail_6() throws Throwable {
       94         testInsertArguments(0, 0, MAX_ARG_INCREASE+1);
       95     }
       96     static final int MAX_ARG_INCREASE = 3;
       97 
       98     public MethodHandlesTest() {
       99     }
      100 
      101     String testName;
      102     int posTests, negTests;
      103     @After
      104     public void printCounts() {
      105         if (verbosity >= 1 && (posTests | negTests) != 0) {
      106             System.out.println();
      107             if (posTests != 0)  System.out.println("=== "+testName+": "+posTests+" positive test cases run");
      108             if (negTests != 0)  System.out.println("=== "+testName+": "+negTests+" negative test cases run");
      109         }
      110     }
      111     void countTest(boolean positive) {
      112         if (positive) ++posTests;
      113         else          ++negTests;
      114     }
      115     void countTest() { countTest(true); }
      116     void startTest(String name) {
      117         if (testName != null)  printCounts();
      118         if (verbosity >= 0)
      119             System.out.println(name);
      120         posTests = negTests = 0;
      121         testName = name;
      122     }
      123 
      124     @BeforeClass
      125     public static void setUpClass() throws Exception {
      126         calledLog.clear();
      127         calledLog.add(null);
      128         nextArg = 1000000;
      129     }
      130 
      131     @AfterClass
      132     public static void tearDownClass() throws Exception {
      133     }
      134 
      135     static List<Object> calledLog = new ArrayList<Object>();
      136     static Object logEntry(String name, Object... args) {
      137         return Arrays.asList(name, Arrays.asList(args));
      138     }
      139     static Object called(String name, Object... args) {
      140         Object entry = logEntry(name, args);
      141         calledLog.add(entry);
      142         return entry;
      143     }
      144     static void assertCalled(String name, Object... args) {
      145         Object expected = logEntry(name, args);
      146         Object actual   = calledLog.get(calledLog.size() - 1);
      147         if (expected.equals(actual))  return;
      148         System.out.println("assertCalled "+name+":");
      149         System.out.println("expected:   "+expected);
      150         System.out.println("actual:     "+actual);
      151         System.out.println("ex. types:  "+getClasses(expected));
      152         System.out.println("act. types: "+getClasses(actual));
      153         assertEquals("previous method call types", expected, actual);
      154         assertEquals("previous method call", expected, actual);
      155     }
      156     static void printCalled(MethodHandle target, String name, Object... args) {
      157         if (verbosity >= 2)
      158             System.out.println("calling "+logEntry(name, args)+" on "+target);
      159     }
      160 
      161     static Object castToWrapper(Object value, Class<?> dst) {
      162         Object wrap = null;
      163         if (value instanceof Number)
      164             wrap = castToWrapperOrNull(((Number)value).longValue(), dst);
      165         if (value instanceof Character)
      166             wrap = castToWrapperOrNull((char)(Character)value, dst);
      167         if (wrap != null)  return wrap;
      168         return dst.cast(value);
      169     }
      170 
      171     static Object castToWrapperOrNull(long value, Class<?> dst) {
      172         if (dst == int.class || dst == Integer.class)
      173             return (int)(value);
      174         if (dst == long.class || dst == Long.class)
      175             return (long)(value);
      176         if (dst == char.class || dst == Character.class)
      177             return (char)(value);
      178         if (dst == short.class || dst == Short.class)
      179             return (short)(value);
      180         if (dst == float.class || dst == Float.class)
      181             return (float)(value);
      182         if (dst == double.class || dst == Double.class)
      183             return (double)(value);
      184         if (dst == byte.class || dst == Byte.class)
      185             return (byte)(value);
      186         if (dst == boolean.class || dst == boolean.class)
      187             return ((value % 29) & 1) == 0;
      188         return null;
      189     }
      190 
      191     static int nextArg;
      192     static Object randomArg(Class<?> param) {
      193         Object wrap = castToWrapperOrNull(nextArg, param);
      194         if (wrap != null) {
      195             nextArg++;
      196             return wrap;
      197         }
      198 //        import sun.dyn.util.Wrapper;
      199 //        Wrapper wrap = Wrapper.forBasicType(dst);
      200 //        if (wrap == Wrapper.OBJECT && Wrapper.isWrapperType(dst))
      201 //            wrap = Wrapper.forWrapperType(dst);
      202 //        if (wrap != Wrapper.OBJECT)
      203 //            return wrap.wrap(nextArg++);
      204         if (param.isInterface() || param.isAssignableFrom(String.class))
      205             return "#"+(nextArg++);
      206         else
      207             try {
      208                 return param.newInstance();
      209             } catch (InstantiationException ex) {
      210             } catch (IllegalAccessException ex) {
      211             }
      212         return null;  // random class not Object, String, Integer, etc.
      213     }
      214     static Object[] randomArgs(Class<?>... params) {
      215         Object[] args = new Object[params.length];
      216         for (int i = 0; i < args.length; i++)
      217             args[i] = randomArg(params[i]);
      218         return args;
      219     }
      220     static Object[] randomArgs(int nargs, Class<?> param) {
      221         Object[] args = new Object[nargs];
      222         for (int i = 0; i < args.length; i++)
      223             args[i] = randomArg(param);
      224         return args;
      225     }
      226 
      227     static <T, E extends T> T[] array(Class<T[]> atype, E... a) {
      228         return Arrays.copyOf(a, a.length, atype);
      229     }
      230     static <T> T[] cat(T[] a, T... b) {
      231         int alen = a.length, blen = b.length;
      232         if (blen == 0)  return a;
      233         T[] c = Arrays.copyOf(a, alen + blen);
      234         System.arraycopy(b, 0, c, alen, blen);
      235         return c;
      236     }
      237     static Integer[] boxAll(int... vx) {
      238         Integer[] res = new Integer[vx.length];
      239         for (int i = 0; i < res.length; i++) {
      240             res[i] = vx[i];
      241         }
      242         return res;
      243     }
      244     static Object getClasses(Object x) {
      245         if (x == null)  return x;
      246         if (x instanceof String)  return x;  // keep the name
      247         if (x instanceof List) {
      248             // recursively report classes of the list elements
      249             Object[] xa = ((List)x).toArray();
      250             for (int i = 0; i < xa.length; i++)
      251                 xa[i] = getClasses(xa[i]);
      252             return Arrays.asList(xa);
      253         }
      254         return x.getClass().getSimpleName();
      255     }
      256 
      257     static MethodHandle changeArgTypes(MethodHandle target, Class<?> argType) {
      258         return changeArgTypes(target, 0, 999, argType);
      259     }
      260     static MethodHandle changeArgTypes(MethodHandle target,
      261             int beg, int end, Class<?> argType) {
      262         MethodType targetType = target.type();
      263         end = Math.min(end, targetType.parameterCount());
      264         ArrayList<Class<?>> argTypes = new ArrayList<Class<?>>(targetType.parameterList());
      265         Collections.fill(argTypes.subList(beg, end), argType);
      266         MethodType ttype2 = MethodType.methodType(targetType.returnType(), argTypes);
      267         return MethodHandles.convertArguments(target, ttype2);
      268     }
      269 
      270     // This lookup is good for all members in and under MethodHandlesTest.
      271     static final Lookup PRIVATE = MethodHandles.lookup();
      272     // This lookup is good for package-private members but not private ones.
      273     static final Lookup PACKAGE = PackageSibling.lookup();
      274     // This lookup is good only for public members.
      275     static final Lookup PUBLIC  = MethodHandles.publicLookup();
      276 
      277     // Subject methods...
      278     static class Example implements IntExample {
      279         final String name;
      280         public Example() { name = "Example#"+(nextArg++); }
      281         protected Example(String name) { this.name = name; }
      282         protected Example(int x) { this(); called("protected <init>", this, x); }
      283         @Override public String toString() { return name; }
      284 
      285         public void            v0()     { called("v0", this); }
      286         void                   pkg_v0() { called("pkg_v0", this); }
      287         private void           pri_v0() { called("pri_v0", this); }
      288         public static void     s0()     { called("s0"); }
      289         static void            pkg_s0() { called("pkg_s0"); }
      290         private static void    pri_s0() { called("pri_s0"); }
      291 
      292         public Object          v1(Object x) { return called("v1", this, x); }
      293         public Object          v2(Object x, Object y) { return called("v2", this, x, y); }
      294         public Object          v2(Object x, int    y) { return called("v2", this, x, y); }
      295         public Object          v2(int    x, Object y) { return called("v2", this, x, y); }
      296         public Object          v2(int    x, int    y) { return called("v2", this, x, y); }
      297         public static Object   s1(Object x) { return called("s1", x); }
      298         public static Object   s2(int x)    { return called("s2", x); }
      299         public static Object   s3(long x)   { return called("s3", x); }
      300         public static Object   s4(int x, int y) { return called("s4", x, y); }
      301         public static Object   s5(long x, int y) { return called("s5", x, y); }
      302         public static Object   s6(int x, long y) { return called("s6", x, y); }
      303         public static Object   s7(float x, double y) { return called("s7", x, y); }
      304     }
      305     public static class PubExample extends Example {
      306     }
      307     static class SubExample extends Example {
      308         @Override public void  v0()     { called("Sub/v0", this); }
      309         @Override void         pkg_v0() { called("Sub/pkg_v0", this); }
      310         private      SubExample(int x)  { called("<init>", this, x); }
      311         public SubExample() { super("SubExample#"+(nextArg++)); }
      312     }
      313     public static interface IntExample {
      314         public void            v0();
      315         static class Impl implements IntExample {
      316             public void        v0()     { called("Int/v0", this); }
      317             final String name;
      318             public Impl() { name = "Example#"+(nextArg++); }
      319         }
      320     }
      321 
      322     static final Object[][][] ACCESS_CASES = {
      323         { { false, PUBLIC }, { false, PACKAGE }, { false, PRIVATE } },
      324         { { false, PUBLIC }, { false, PACKAGE }, { true,  PRIVATE } },
      325         { { false, PUBLIC }, { true,  PACKAGE }, { true,  PRIVATE } },
      326         { { true,  PUBLIC }, { true,  PACKAGE }, { true,  PRIVATE } },
      327     };
      328 
      329     static Object[][] accessCases(Class<?> defc, String name) {
      330         if (name.contains("pri_")) {
      331             return ACCESS_CASES[1]; // PRIVATE only
      332         } else if (name.contains("pkg_")) {
      333             return ACCESS_CASES[2]; // not PUBLIC
      334         } else {
      335             assertTrue(name.indexOf('_') < 0);
      336             boolean pubc = Modifier.isPublic(defc.getModifiers());
      337             if (pubc)
      338                 return ACCESS_CASES[3]; // all access levels
      339             return ACCESS_CASES[2]; // PACKAGE but not PUBLIC
      340         }
      341     }
      342 
      343     @Test
      344     public void testFindStatic() throws Throwable {
      345         if (CAN_SKIP_WORKING)  return;
      346         startTest("findStatic");
      347         testFindStatic(PubExample.class, void.class, "s0");
      348         testFindStatic(Example.class, void.class, "s0");
      349         testFindStatic(Example.class, void.class, "pkg_s0");
      350         testFindStatic(Example.class, void.class, "pri_s0");
      351 
      352         testFindStatic(Example.class, Object.class, "s1", Object.class);
      353         testFindStatic(Example.class, Object.class, "s2", int.class);
      354         testFindStatic(Example.class, Object.class, "s3", long.class);
      355         testFindStatic(Example.class, Object.class, "s4", int.class, int.class);
      356         testFindStatic(Example.class, Object.class, "s5", long.class, int.class);
      357         testFindStatic(Example.class, Object.class, "s6", int.class, long.class);
      358         testFindStatic(Example.class, Object.class, "s7", float.class, double.class);
      359 
      360         testFindStatic(false, PRIVATE, Example.class, void.class, "bogus");
      361     }
      362 
      363     void testFindStatic(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
      364         for (Object[] ac : accessCases(defc, name)) {
      365             testFindStatic((Boolean)ac[0], (Lookup)ac[1], defc, ret, name, params);
      366         }
      367     }
      368     void testFindStatic(Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
      369         testFindStatic(true, lookup, defc, ret, name, params);
      370     }
      371     void testFindStatic(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
      372         countTest(positive);
      373         MethodType type = MethodType.methodType(ret, params);
      374         MethodHandle target = null;
      375         RuntimeException noAccess = null;
      376         try {
      377             target = lookup.findStatic(defc, name, type);
      378         } catch (NoAccessException ex) {
      379             noAccess = ex;
      380         }
      381         if (verbosity >= 2)
      382             System.out.println("findStatic "+lookup+": "+defc+"."+name+"/"+type+" => "+target
      383                     +(noAccess == null ? "" : " !! "+noAccess));
      384         if (positive && noAccess != null)  throw noAccess;
      385         assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
      386         if (!positive)  return; // negative test failed as expected
      387         assertEquals(type, target.type());
      388         assertTrue(target.toString().contains(name));  // rough check
      389         if (!DO_MORE_CALLS && lookup != PRIVATE)  return;
      390         Object[] args = randomArgs(params);
      391         printCalled(target, name, args);
      392         target.invokeVarargs(args);
      393         assertCalled(name, args);
      394         System.out.print(':');
      395     }
      396 
      397     @Test
      398     public void testFindVirtual() throws Throwable {
      399         if (CAN_SKIP_WORKING)  return;
      400         startTest("findVirtual");
      401         testFindVirtual(Example.class, void.class, "v0");
      402         testFindVirtual(Example.class, void.class, "pkg_v0");
      403         testFindVirtual(Example.class, void.class, "pri_v0");
      404         testFindVirtual(Example.class, Object.class, "v1", Object.class);
      405         testFindVirtual(Example.class, Object.class, "v2", Object.class, Object.class);
      406         testFindVirtual(Example.class, Object.class, "v2", Object.class, int.class);
      407         testFindVirtual(Example.class, Object.class, "v2", int.class, Object.class);
      408         testFindVirtual(Example.class, Object.class, "v2", int.class, int.class);
      409         testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "bogus");
      410         // test dispatch
      411         testFindVirtual(SubExample.class,      SubExample.class, void.class, "Sub/v0");
      412         testFindVirtual(SubExample.class,         Example.class, void.class, "Sub/v0");
      413         testFindVirtual(SubExample.class,      IntExample.class, void.class, "Sub/v0");
      414         testFindVirtual(SubExample.class,      SubExample.class, void.class, "Sub/pkg_v0");
      415         testFindVirtual(SubExample.class,         Example.class, void.class, "Sub/pkg_v0");
      416         testFindVirtual(Example.class,         IntExample.class, void.class, "v0");
      417         testFindVirtual(IntExample.Impl.class, IntExample.class, void.class, "Int/v0");
      418     }
      419 
      420     void testFindVirtual(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
      421         Class<?> rcvc = defc;
      422         testFindVirtual(rcvc, defc, ret, name, params);
      423     }
      424     void testFindVirtual(Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
      425         for (Object[] ac : accessCases(defc, name)) {
      426             testFindVirtual((Boolean)ac[0], (Lookup)ac[1], rcvc, defc, ret, name, params);
      427         }
      428     }
      429     void testFindVirtual(Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
      430         testFindVirtual(true, lookup, rcvc, defc, ret, name, params);
      431     }
      432     void testFindVirtual(boolean positive, Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
      433         countTest(positive);
      434         String methodName = name.substring(1 + name.indexOf('/'));  // foo/bar => foo
      435         MethodType type = MethodType.methodType(ret, params);
      436         MethodHandle target = null;
      437         RuntimeException noAccess = null;
      438         try {
      439             target = lookup.findVirtual(defc, methodName, type);
      440         } catch (NoAccessException ex) {
      441             noAccess = ex;
      442         }
      443         if (verbosity >= 2)
      444             System.out.println("findVirtual "+lookup+": "+defc+"."+name+"/"+type+" => "+target
      445                     +(noAccess == null ? "" : " !! "+noAccess));
      446         if (positive && noAccess != null)  throw noAccess;
      447         assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
      448         if (!positive)  return; // negative test failed as expected
      449         Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)defc), params);
      450         MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf);
      451         MethodType ttype = target.type();
      452         ttype = ttype.changeParameterType(0, defc); // FIXME: test this
      453         assertEquals(typeWithSelf, ttype);
      454         assertTrue(target.toString().contains(methodName));  // rough check
      455         if (!DO_MORE_CALLS && lookup != PRIVATE)  return;
      456         Object[] argsWithSelf = randomArgs(paramsWithSelf);
      457         if (rcvc != defc)  argsWithSelf[0] = randomArg(rcvc);
      458         printCalled(target, name, argsWithSelf);
      459         target.invokeVarargs(argsWithSelf);
      460         assertCalled(name, argsWithSelf);
      461         System.out.print(':');
      462     }
      463 
      464     @Test
      465     public void testFindSpecial() throws Throwable {
      466         if (CAN_SKIP_WORKING)  return;
      467         startTest("findSpecial");
      468         testFindSpecial(Example.class, void.class, "v0");
      469         testFindSpecial(Example.class, void.class, "pkg_v0");
      470         testFindSpecial(false, PRIVATE, Example.class, void.class, "<init>", int.class);
      471         testFindSpecial(false, PRIVATE, Example.class, void.class, "bogus");
      472     }
      473 
      474     void testFindSpecial(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
      475         testFindSpecial(true,  PRIVATE, defc, ret, name, params);
      476         testFindSpecial(false, PACKAGE, defc, ret, name, params);
      477         testFindSpecial(false, PUBLIC,  defc, ret, name, params);
      478     }
      479     void testFindSpecial(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
      480         countTest(positive);
      481         MethodType type = MethodType.methodType(ret, params);
      482         MethodHandle target = null;
      483         RuntimeException noAccess = null;
      484         try {
      485             target = lookup.findSpecial(defc, name, type, defc);
      486         } catch (NoAccessException ex) {
      487             noAccess = ex;
      488         }
      489         if (verbosity >= 2)
      490             System.out.println("findSpecial "+defc+"."+name+"/"+type+" => "+target
      491                     +(noAccess == null ? "" : " !! "+noAccess));
      492         if (positive && noAccess != null)  throw noAccess;
      493         assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
      494         if (!positive)  return; // negative test failed as expected
      495         Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)defc), params);
      496         MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf);
      497         MethodType ttype = target.type();
      498         ttype = ttype.changeParameterType(0, defc); // FIXME: test this
      499         assertEquals(typeWithSelf, ttype);
      500         assertTrue(target.toString().contains(name));  // rough check
      501         if (!DO_MORE_CALLS && lookup != PRIVATE)  return;
      502         Object[] args = randomArgs(paramsWithSelf);
      503         printCalled(target, name, args);
      504         target.invokeVarargs(args);
      505         assertCalled(name, args);
      506         System.out.print(':');
      507     }
      508 
      509     @Test
      510     public void testBind() throws Throwable {
      511         if (CAN_SKIP_WORKING)  return;
      512         startTest("bind");
      513         testBind(Example.class, void.class, "v0");
      514         testBind(Example.class, void.class, "pkg_v0");
      515         testBind(Example.class, void.class, "pri_v0");
      516         testBind(Example.class, Object.class, "v1", Object.class);
      517         testBind(Example.class, Object.class, "v2", Object.class, Object.class);
      518         testBind(Example.class, Object.class, "v2", Object.class, int.class);
      519         testBind(Example.class, Object.class, "v2", int.class, Object.class);
      520         testBind(Example.class, Object.class, "v2", int.class, int.class);
      521         testBind(false, PRIVATE, Example.class, void.class, "bogus");
      522         testBind(SubExample.class, void.class, "Sub/v0");
      523         testBind(SubExample.class, void.class, "Sub/pkg_v0");
      524         testBind(IntExample.Impl.class, void.class, "Int/v0");
      525     }
      526 
      527     void testBind(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
      528         for (Object[] ac : accessCases(defc, name)) {
      529             testBind((Boolean)ac[0], (Lookup)ac[1], defc, ret, name, params);
      530         }
      531     }
      532 
      533     void testBind(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
      534         countTest(positive);
      535         String methodName = name.substring(1 + name.indexOf('/'));  // foo/bar => foo
      536         MethodType type = MethodType.methodType(ret, params);
      537         Object receiver = randomArg(defc);
      538         MethodHandle target = null;
      539         RuntimeException noAccess = null;
      540         try {
      541             target = lookup.bind(receiver, methodName, type);
      542         } catch (NoAccessException ex) {
      543             noAccess = ex;
      544         }
      545         if (verbosity >= 2)
      546             System.out.println("bind "+receiver+"."+name+"/"+type+" => "+target
      547                     +(noAccess == null ? "" : " !! "+noAccess));
      548         if (positive && noAccess != null)  throw noAccess;
      549         assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
      550         if (!positive)  return; // negative test failed as expected
      551         assertEquals(type, target.type());
      552         Object[] args = randomArgs(params);
      553         printCalled(target, name, args);
      554         target.invokeVarargs(args);
      555         Object[] argsWithReceiver = cat(array(Object[].class, receiver), args);
      556         assertCalled(name, argsWithReceiver);
      557         System.out.print(':');
      558     }
      559 
      560     @Test
      561     public void testUnreflect() throws Throwable {
      562         if (CAN_SKIP_WORKING)  return;
      563         startTest("unreflect");
      564         testUnreflect(Example.class, true, void.class, "s0");
      565         testUnreflect(Example.class, true, void.class, "pkg_s0");
      566         testUnreflect(Example.class, true, void.class, "pri_s0");
      567 
      568         testUnreflect(Example.class, true, Object.class, "s1", Object.class);
      569         testUnreflect(Example.class, true, Object.class, "s2", int.class);
      570         //testUnreflect(Example.class, true, Object.class, "s3", long.class);
      571         //testUnreflect(Example.class, true, Object.class, "s4", int.class, int.class);
      572         //testUnreflect(Example.class, true, Object.class, "s5", long.class, int.class);
      573         //testUnreflect(Example.class, true, Object.class, "s6", int.class, long.class);
      574 
      575         testUnreflect(Example.class, false, void.class, "v0");
      576         testUnreflect(Example.class, false, void.class, "pkg_v0");
      577         testUnreflect(Example.class, false, void.class, "pri_v0");
      578         testUnreflect(Example.class, false, Object.class, "v1", Object.class);
      579         testUnreflect(Example.class, false, Object.class, "v2", Object.class, Object.class);
      580         testUnreflect(Example.class, false, Object.class, "v2", Object.class, int.class);
      581         testUnreflect(Example.class, false, Object.class, "v2", int.class, Object.class);
      582         testUnreflect(Example.class, false, Object.class, "v2", int.class, int.class);
      583     }
      584 
      585     void testUnreflect(Class<?> defc, boolean isStatic, Class<?> ret, String name, Class<?>... params) throws Throwable {
      586         for (Object[] ac : accessCases(defc, name)) {
      587             testUnreflect((Boolean)ac[0], (Lookup)ac[1], defc, isStatic, ret, name, params);
      588         }
      589     }
      590     void testUnreflect(boolean positive, Lookup lookup, Class<?> defc, boolean isStatic, Class<?> ret, String name, Class<?>... params) throws Throwable {
      591         countTest(positive);
      592         MethodType type = MethodType.methodType(ret, params);
      593         Method rmethod = null;
      594         MethodHandle target = null;
      595         RuntimeException noAccess = null;
      596         try {
      597             rmethod = defc.getDeclaredMethod(name, params);
      598         } catch (NoSuchMethodException ex) {
      599             throw new NoAccessException(ex);
      600         }
      601         assertEquals(isStatic, Modifier.isStatic(rmethod.getModifiers()));
      602         try {
      603             target = lookup.unreflect(rmethod);
      604         } catch (NoAccessException ex) {
      605             noAccess = ex;
      606         }
      607         if (verbosity >= 2)
      608             System.out.println("unreflect "+defc+"."+name+"/"+type+" => "+target
      609                     +(noAccess == null ? "" : " !! "+noAccess));
      610         if (positive && noAccess != null)  throw noAccess;
      611         assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
      612         if (!positive)  return; // negative test failed as expected
      613         Class<?>[] paramsMaybeWithSelf = params;
      614         if (!isStatic) {
      615             paramsMaybeWithSelf = cat(array(Class[].class, (Class)defc), params);
      616         }
      617         MethodType typeMaybeWithSelf = MethodType.methodType(ret, paramsMaybeWithSelf);
      618         MethodType ttype = target.type();
      619         if (!isStatic)
      620             ttype = ttype.changeParameterType(0, defc); // FIXME: test this
      621         assertEquals(typeMaybeWithSelf, ttype);
      622         Object[] argsMaybeWithSelf = randomArgs(paramsMaybeWithSelf);
      623         printCalled(target, name, argsMaybeWithSelf);
      624         target.invokeVarargs(argsMaybeWithSelf);
      625         assertCalled(name, argsMaybeWithSelf);
      626         System.out.print(':');
      627     }
      628 
      629     @Test @Ignore("unimplemented")
      630     public void testUnreflectSpecial() throws Throwable {
      631         Lookup lookup = PRIVATE;  // FIXME: test more lookups than this one
      632         startTest("unreflectSpecial");
      633         Method m = null;
      634         MethodHandle expResult = null;
      635         MethodHandle result = lookup.unreflectSpecial(m, Example.class);
      636         assertEquals(expResult, result);
      637         fail("The test case is a prototype.");
      638     }
      639 
      640     public static class HasFields {
      641         boolean fZ = false;
      642         byte fB = (byte)'B';
      643         short fS = (short)'S';
      644         char fC = 'C';
      645         int fI = 'I';
      646         long fJ = 'J';
      647         float fF = 'F';
      648         double fD = 'D';
      649         static boolean sZ = true;
      650         static byte sB = 1+(byte)'B';
      651         static short sS = 1+(short)'S';
      652         static char sC = 1+'C';
      653         static int sI = 1+'I';
      654         static long sJ = 1+'J';
      655         static float sF = 1+'F';
      656         static double sD = 1+'D';
      657 
      658         Object fL = 'L';
      659         String fR = "R";
      660         static Object sL = 'M';
      661         static String sR = "S";
      662 
      663         static final Object[][] CASES;
      664         static {
      665             ArrayList<Object[]> cases = new ArrayList<Object[]>();
      666             Object types[][] = {
      667                 {'L',Object.class}, {'R',String.class},
      668                 {'I',int.class}, {'J',long.class},
      669                 {'F',float.class}, {'D',double.class},
      670                 {'Z',boolean.class}, {'B',byte.class},
      671                 {'S',short.class}, {'C',char.class},
      672             };
      673             HasFields fields = new HasFields();
      674             for (Object[] t : types) {
      675                 for (int kind = 0; kind <= 1; kind++) {
      676                     boolean isStatic = (kind != 0);
      677                     char btc = (Character)t[0];
      678                     String name = (isStatic ? "s" : "f") + btc;
      679                     Class<?> type = (Class<?>) t[1];
      680                     Object value;
      681                     Field field;
      682                     try {
      683                         field = HasFields.class.getDeclaredField(name);
      684                     } catch (Exception ex) {
      685                         throw new InternalError("no field HasFields."+name);
      686                     }
      687                     try {
      688                         value = field.get(fields);
      689                     } catch (Exception ex) {
      690                         throw new InternalError("cannot fetch field HasFields."+name);
      691                     }
      692                     if (type == float.class) {
      693                         float v = 'F';
      694                         if (isStatic)  v++;
      695                         assert(value.equals(v));
      696                     }
      697                     assert(name.equals(field.getName()));
      698                     assert(type.equals(field.getType()));
      699                     assert(isStatic == (Modifier.isStatic(field.getModifiers())));
      700                     cases.add(new Object[]{ field, value });
      701                 }
      702             }
      703             CASES = cases.toArray(new Object[0][]);
      704         }
      705     }
      706 
      707     @Test
      708     public void testUnreflectGetter() throws Throwable {
      709         Lookup lookup = PRIVATE;  // FIXME: test more lookups than this one
      710         startTest("unreflectGetter");
      711         for (Object[] c : HasFields.CASES) {
      712             Field f = (Field)c[0];
      713             Object value = c[1];
      714             Class<?> type = f.getType();
      715             if (type.isPrimitive() && type != int.class)
      716                 continue;  //FIXME
      717             testUnreflectGetter(lookup, f, type, value);
      718         }
      719     }
      720     public void testUnreflectGetter(MethodHandles.Lookup lookup,
      721             Field f, Class<?> type, Object value) throws Throwable {
      722         countTest(true);
      723         boolean isStatic = Modifier.isStatic(f.getModifiers());
      724         MethodType expType = MethodType.methodType(type, HasFields.class);
      725         if (isStatic)  expType = expType.dropParameterTypes(0, 1);
      726         MethodHandle mh = lookup.unreflectGetter(f);
      727         assertSame(mh.type(), expType);
      728         assertEquals(mh.toString(), f.getName());
      729         HasFields fields = new HasFields();
      730         Object sawValue;
      731         Class<?> rtype = type;
      732         if (type != int.class)  rtype = Object.class;
      733         mh = MethodHandles.convertArguments(mh, mh.type().generic().changeReturnType(rtype));
      734         Object expValue = value;
      735         for (int i = 0; i <= 1; i++) {
      736             if (isStatic) {
      737                 if (type == int.class)
      738                     sawValue = mh.<int>invoke();  // do these exactly
      739                 else
      740                     sawValue = mh.invoke();
      741             } else {
      742                 if (type == int.class)
      743                     sawValue = mh.<int>invoke((Object) fields);
      744                 else
      745                     sawValue = mh.invoke((Object) fields);
      746             }
      747             assertEquals(sawValue, expValue);
      748             Object random = randomArg(type);
      749             f.set(fields, random);
      750             expValue = random;
      751         }
      752         f.set(fields, value);  // put it back
      753     }
      754 
      755 
      756     @Test
      757     public void testUnreflectSetter() throws Throwable {
      758         Lookup lookup = PRIVATE;  // FIXME: test more lookups than this one
      759         startTest("unreflectSetter");
      760         for (Object[] c : HasFields.CASES) {
      761             Field f = (Field)c[0];
      762             Object value = c[1];
      763             Class<?> type = f.getType();
      764             if (type.isPrimitive() && type != int.class)
      765                 continue;  //FIXME
      766             testUnreflectSetter(lookup, f, type, value);
      767         }
      768     }
      769     public void testUnreflectSetter(MethodHandles.Lookup lookup,
      770             Field f, Class<?> type, Object value) throws Throwable {
      771         countTest(true);
      772         boolean isStatic = Modifier.isStatic(f.getModifiers());
      773         MethodType expType = MethodType.methodType(void.class, HasFields.class, type);
      774         if (isStatic)  expType = expType.dropParameterTypes(0, 1);
      775         MethodHandle mh = lookup.unreflectSetter(f);
      776         assertSame(mh.type(), expType);
      777         assertEquals(mh.toString(), f.getName());
      778         HasFields fields = new HasFields();
      779         Object sawValue;
      780         Class<?> vtype = type;
      781         if (type != int.class)  vtype = Object.class;
      782         int last = mh.type().parameterCount() - 1;
      783         mh = MethodHandles.convertArguments(mh, mh.type().generic().changeReturnType(void.class).changeParameterType(last, vtype));
      784         assertEquals(f.get(fields), value);  // clean to start with
      785         for (int i = 0; i <= 1; i++) {
      786             Object putValue = randomArg(type);
      787             if (isStatic) {
      788                 if (type == int.class)
      789                     mh.<void>invoke((int)(Integer)putValue);  // do these exactly
      790                 else
      791                     mh.<void>invoke(putValue);
      792             } else {
      793                 if (type == int.class)
      794                     mh.<void>invoke((Object) fields, (int)(Integer)putValue);
      795                 else
      796                     mh.<void>invoke((Object) fields, putValue);
      797             }
      798             assertEquals(f.get(fields), putValue);
      799         }
      800         f.set(fields, value);  // put it back
      801     }
      802 
      803     @Test
      804     public void testArrayElementGetter() throws Throwable {
      805         startTest("arrayElementGetter");
      806         testArrayElementGetterSetter(new Object[10], false);
      807         testArrayElementGetterSetter(new String[10], false);
      808         testArrayElementGetterSetter(new int[10], false);
      809         // FIXME: Do the other primitive types.
      810         //testArrayElementGetterSetter(new float[10], false);
      811     }
      812 
      813     @Test
      814     public void testArrayElementSetter() throws Throwable {
      815         startTest("arrayElementSetter");
      816         testArrayElementGetterSetter(new Object[10], true);
      817         testArrayElementGetterSetter(new String[10], true);
      818         testArrayElementGetterSetter(new int[10], true);
      819         // FIXME: Do the other primitive types.
      820         //testArrayElementGetterSetter(new float[10], true);
      821     }
      822 
      823     public void testArrayElementGetterSetter(Object array, boolean testSetter) throws Throwable {
      824         countTest(true);
      825         Class<?> arrayType = array.getClass();
      826         Class<?> elemType = arrayType.getComponentType();
      827         MethodType expType = !testSetter
      828                 ? MethodType.methodType(elemType,   arrayType, int.class)
      829                 : MethodType.methodType(void.class, arrayType, int.class, elemType);
      830         MethodHandle mh = !testSetter
      831                 ? MethodHandles.arrayElementGetter(arrayType)
      832                 : MethodHandles.arrayElementSetter(arrayType);
      833         assertSame(mh.type(), expType);
      834         //assertEquals(mh.toString(), f.getName());
      835         Object sawValue, expValue;
      836         List<Object> model = array2list(array);
      837         int length = Array.getLength(array);
      838         for (int i = 0; i < length; i++) {
      839             // update array element
      840             Object random = randomArg(elemType);
      841             model.set(i, random);
      842             if (testSetter) {
      843                 if (elemType == int.class)
      844                     mh.<void>invoke((int[]) array, i, (int)(Integer)random);
      845                 else
      846                     mh.invokeGeneric(array, i, random);
      847                 assertEquals(model, array2list(array));
      848             } else {
      849                 Array.set(array, i, random);
      850 
      851             }
      852             // observe array element
      853             sawValue = Array.get(array, i);
      854             if (!testSetter) {
      855                 expValue = sawValue;
      856                 if (elemType == int.class)
      857                     sawValue = mh.<int>invoke((int[]) array, i);
      858                 else
      859                     sawValue = mh.invokeGeneric(array, i);
      860                 assertEquals(sawValue, expValue);
      861                 assertEquals(model, array2list(array));
      862             }
      863         }
      864     }
      865 
      866     List<Object> array2list(Object array) {
      867         int length = Array.getLength(array);
      868         ArrayList<Object> model = new ArrayList<Object>(length);
      869         for (int i = 0; i < length; i++)
      870             model.add(Array.get(array, i));
      871         return model;
      872     }
      873 
      874     static class Callee {
      875         static Object id() { return called("id"); }
      876         static Object id(Object x) { return called("id", x); }
      877         static Object id(Object x, Object y) { return called("id", x, y); }
      878         static Object id(Object x, Object y, Object z) { return called("id", x, y, z); }
      879         static Object id(Object... vx) { return called("id", vx); }
      880         static MethodHandle ofType(int n) {
      881             return ofType(Object.class, n);
      882         }
      883         static MethodHandle ofType(Class<?> rtype, int n) {
      884             if (n == -1)
      885                 return ofType(MethodType.methodType(rtype, Object[].class));
      886             return ofType(MethodType.genericMethodType(n).changeReturnType(rtype));
      887         }
      888         static MethodHandle ofType(Class<?> rtype, Class<?>... ptypes) {
      889             return ofType(MethodType.methodType(rtype, ptypes));
      890         }
      891         static MethodHandle ofType(MethodType type) {
      892             Class<?> rtype = type.returnType();
      893             String pfx = "";
      894             if (rtype != Object.class)
      895                 pfx = rtype.getSimpleName().substring(0, 1).toLowerCase();
      896             String name = pfx+"id";
      897             return PRIVATE.findStatic(Callee.class, name, type);
      898         }
      899     }
      900 
      901     @Test
      902     public void testConvertArguments() throws Throwable {
      903         if (CAN_SKIP_WORKING)  return;
      904         startTest("convertArguments");
      905         testConvert(Callee.ofType(1), null, "id", int.class);
      906         testConvert(Callee.ofType(1), null, "id", String.class);
      907         testConvert(Callee.ofType(1), null, "id", Integer.class);
      908         testConvert(Callee.ofType(1), null, "id", short.class);
      909     }
      910 
      911     void testConvert(MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {
      912         testConvert(true, id, rtype, name, params);
      913     }
      914 
      915     void testConvert(boolean positive, MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable {
      916         countTest(positive);
      917         MethodType idType = id.type();
      918         if (rtype == null)  rtype = idType.returnType();
      919         for (int i = 0; i < params.length; i++) {
      920             if (params[i] == null)  params[i] = idType.parameterType(i);
      921         }
      922         // simulate the pairwise conversion
      923         MethodType newType = MethodType.methodType(rtype, params);
      924         Object[] args = randomArgs(newType.parameterArray());
      925         Object[] convArgs = args.clone();
      926         for (int i = 0; i < args.length; i++) {
      927             Class<?> src = newType.parameterType(i);
      928             Class<?> dst = idType.parameterType(i);
      929             if (src != dst)
      930                 convArgs[i] = castToWrapper(convArgs[i], dst);
      931         }
      932         Object convResult = id.invokeVarargs(convArgs);
      933         {
      934             Class<?> dst = newType.returnType();
      935             Class<?> src = idType.returnType();
      936             if (src != dst)
      937                 convResult = castToWrapper(convResult, dst);
      938         }
      939         MethodHandle target = null;
      940         RuntimeException error = null;
      941         try {
      942             target = MethodHandles.convertArguments(id, newType);
      943         } catch (RuntimeException ex) {
      944             error = ex;
      945         }
      946         if (verbosity >= 2)
      947             System.out.println("convert "+id+ " to "+newType+" => "+target
      948                     +(error == null ? "" : " !! "+error));
      949         if (positive && error != null)  throw error;
      950         assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
      951         if (!positive)  return; // negative test failed as expected
      952         assertEquals(newType, target.type());
      953         printCalled(target, id.toString(), args);
      954         Object result = target.invokeVarargs(args);
      955         assertCalled(name, convArgs);
      956         assertEquals(convResult, result);
      957         System.out.print(':');
      958     }
      959 
      960     @Test
      961     public void testPermuteArguments() throws Throwable {
      962         if (CAN_SKIP_WORKING)  return;
      963         startTest("permuteArguments");
      964         testPermuteArguments(4, Integer.class,  2, String.class,  0);
      965         //testPermuteArguments(6, Integer.class,  0, null,         30);
      966         //testPermuteArguments(4, Integer.class,  1, int.class,     6);
      967     }
      968     public void testPermuteArguments(int max, Class<?> type1, int t2c, Class<?> type2, int dilution) throws Throwable {
      969         if (verbosity >= 1)
      970             System.out.println("permuteArguments "+max+"*"+type1.getName()
      971                     +(t2c==0?"":"/"+t2c+"*"+type2.getName())
      972                     +(dilution > 0 ? " with dilution "+dilution : ""));
      973         int t2pos = t2c == 0 ? 0 : 1;
      974         for (int inargs = t2pos+1; inargs <= max; inargs++) {
      975             Class<?>[] types = new Class<?>[inargs];
      976             Arrays.fill(types, type1);
      977             if (t2c != 0) {
      978                 // Fill in a middle range with type2:
      979                 Arrays.fill(types, t2pos, Math.min(t2pos+t2c, inargs), type2);
      980             }
      981             Object[] args = randomArgs(types);
      982             int numcases = 1;
      983             for (int outargs = 0; outargs <= max; outargs++) {
      984                 if (outargs - inargs >= MAX_ARG_INCREASE)  continue;
      985                 int[] reorder = new int[outargs];
      986                 int casStep = dilution + 1;
      987                 // Avoid some common factors:
      988                 while ((casStep > 2 && casStep % 2 == 0 && inargs % 2 == 0) ||
      989                        (casStep > 3 && casStep % 3 == 0 && inargs % 3 == 0))
      990                     casStep++;
      991                 for (int cas = 0; cas < numcases; cas += casStep) {
      992                     for (int i = 0, c = cas; i < outargs; i++) {
      993                         reorder[i] = c % inargs;
      994                         c /= inargs;
      995                     }
      996                     testPermuteArguments(args, types, reorder);
      997                 }
      998                 numcases *= inargs;
      999                 if (dilution > 10 && outargs >= 4) {
     1000                     // Do some special patterns, which we probably missed.
     1001                     // Replication of a single argument or argument pair.
     1002                     for (int i = 0; i < inargs; i++) {
     1003                         Arrays.fill(reorder, i);
     1004                         testPermuteArguments(args, types, reorder);
     1005                         for (int d = 1; d <= 2; d++) {
     1006                             if (i + d >= inargs)  continue;
     1007                             for (int j = 1; j < outargs; j += 2)
     1008                                 reorder[j] += 1;
     1009                             testPermuteArguments(args, types, reorder);
     1010                             testPermuteArguments(args, types, reverse(reorder));
     1011                         }
     1012                     }
     1013                     // Repetition of a sequence of 3 or more arguments.
     1014                     for (int i = 1; i < inargs; i++) {
     1015                         for (int len = 3; len <= inargs; len++) {
     1016                             for (int j = 0; j < outargs; j++)
     1017                                 reorder[j] = (i + (j % len)) % inargs;
     1018                             testPermuteArguments(args, types, reorder);
     1019                             testPermuteArguments(args, types, reverse(reorder));
     1020                         }
     1021                     }
     1022                 }
     1023             }
     1024         }
     1025     }
     1026 
     1027     static int[] reverse(int[] reorder) {
     1028         reorder = reorder.clone();
     1029         for (int i = 0, imax = reorder.length / 2; i < imax; i++) {
     1030             int j = reorder.length - 1 - i;
     1031             int tem = reorder[i];
     1032             reorder[i] = reorder[j];
     1033             reorder[j] = tem;
     1034         }
     1035         return reorder;
     1036     }
     1037 
     1038     void testPermuteArguments(Object[] args, Class<?>[] types, int[] reorder) throws Throwable {
     1039         countTest();
     1040         if (args == null && types == null) {
     1041             int max = 0;
     1042             for (int j : reorder) {
     1043                 if (max < j)  max = j;
     1044             }
     1045             args = randomArgs(max+1, Integer.class);
     1046         }
     1047         if (args == null) {
     1048             args = randomArgs(types);
     1049         }
     1050         if (types == null) {
     1051             types = new Class<?>[args.length];
     1052             for (int i = 0; i < args.length; i++)
     1053                 types[i] = args[i].getClass();
     1054         }
     1055         int inargs = args.length, outargs = reorder.length;
     1056         assert(inargs == types.length);
     1057         if (verbosity >= 2)
     1058             System.out.println("permuteArguments "+Arrays.toString(reorder));
     1059         Object[] permArgs = new Object[outargs];
     1060         Class<?>[] permTypes = new Class<?>[outargs];
     1061         for (int i = 0; i < outargs; i++) {
     1062             permArgs[i] = args[reorder[i]];
     1063             permTypes[i] = types[reorder[i]];
     1064         }
     1065         if (verbosity >= 3) {
     1066             System.out.println("in args:   "+Arrays.asList(args));
     1067             System.out.println("out args:  "+Arrays.asList(permArgs));
     1068             System.out.println("in types:  "+Arrays.asList(types));
     1069             System.out.println("out types: "+Arrays.asList(permTypes));
     1070         }
     1071         MethodType inType  = MethodType.methodType(Object.class, types);
     1072         MethodType outType = MethodType.methodType(Object.class, permTypes);
     1073         MethodHandle target = MethodHandles.convertArguments(ValueConversions.varargsList(outargs), outType);
     1074         MethodHandle newTarget = MethodHandles.permuteArguments(target, inType, reorder);
     1075         Object result = newTarget.invokeVarargs(args);
     1076         Object expected = Arrays.asList(permArgs);
     1077         assertEquals(expected, result);
     1078     }
     1079 
     1080 
     1081     @Test
     1082     public void testSpreadArguments() throws Throwable {
     1083         if (CAN_SKIP_WORKING)  return;
     1084         startTest("spreadArguments");
     1085         for (Class<?> argType : new Class[]{Object.class, Integer.class, int.class}) {
     1086             if (verbosity >= 2)
     1087                 System.out.println("spreadArguments "+argType);
     1088             for (int nargs = 0; nargs < 10; nargs++) {
     1089                 if (argType == int.class && nargs >= 6)  continue; // FIXME Fail_1
     1090                 for (int pos = 0; pos < nargs; pos++) {
     1091                     if (argType == int.class && pos > 0)  continue; // FIXME Fail_3
     1092                     testSpreadArguments(argType, pos, nargs);
     1093                 }
     1094             }
     1095         }
     1096     }
     1097     public void testSpreadArguments(Class<?> argType, int pos, int nargs) throws Throwable {
     1098         countTest();
     1099         MethodHandle target = ValueConversions.varargsArray(nargs);
     1100         MethodHandle target2 = changeArgTypes(target, argType);
     1101         if (verbosity >= 2)
     1102             System.out.println("spread into "+target2+" ["+pos+".."+nargs+"]");
     1103         Object[] args = randomArgs(target2.type().parameterArray());
     1104         // make sure the target does what we think it does:
     1105         if (pos == 0 && nargs < 5) {
     1106             Object[] check = (Object[]) target.invokeVarargs(args);
     1107             assertArrayEquals(args, check);
     1108             switch (nargs) {
     1109                 case 0:
     1110                     check = target.<Object[]>invoke();
     1111                     assertArrayEquals(args, check);
     1112                     break;
     1113                 case 1:
     1114                     check = target.<Object[]>invoke(args[0]);
     1115                     assertArrayEquals(args, check);
     1116                     break;
     1117                 case 2:
     1118                     check = target.<Object[]>invoke(args[0], args[1]);
     1119                     assertArrayEquals(args, check);
     1120                     break;
     1121             }
     1122         }
     1123         List<Class<?>> newParams = new ArrayList<Class<?>>(target2.type().parameterList());
     1124         {   // modify newParams in place
     1125             List<Class<?>> spreadParams = newParams.subList(pos, nargs);
     1126             spreadParams.clear(); spreadParams.add(Object[].class);
     1127         }
     1128         MethodType newType = MethodType.methodType(Object.class, newParams);
     1129         MethodHandle result = MethodHandles.spreadArguments(target2, newType);
     1130         Object[] returnValue;
     1131         if (pos == 0) {
     1132             returnValue = (Object[]) result.invoke(args);
     1133         } else {
     1134             Object[] args1 = Arrays.copyOfRange(args, 0, pos+1);
     1135             args1[pos] = Arrays.copyOfRange(args, pos, args.length);
     1136             returnValue = (Object[]) result.invokeVarargs(args1);
     1137         }
     1138         assertArrayEquals(args, returnValue);
     1139     }
     1140 
     1141     @Test
     1142     public void testCollectArguments() throws Throwable {
     1143         if (CAN_SKIP_WORKING)  return;
     1144         startTest("collectArguments");
     1145         for (Class<?> argType : new Class[]{Object.class, Integer.class, int.class}) {
     1146             if (verbosity >= 2)
     1147                 System.out.println("collectArguments "+argType);
     1148             for (int nargs = 0; nargs < 10; nargs++) {
     1149                 for (int pos = 0; pos < nargs; pos++) {
     1150                     if (argType == int.class)  continue; // FIXME Fail_4
     1151                     testCollectArguments(argType, pos, nargs);
     1152                 }
     1153             }
     1154         }
     1155     }
     1156     public void testCollectArguments(Class<?> argType, int pos, int nargs) throws Throwable {
     1157         countTest();
     1158         // fake up a MH with the same type as the desired adapter:
     1159         MethodHandle fake = ValueConversions.varargsArray(nargs);
     1160         fake = changeArgTypes(fake, argType);
     1161         MethodType newType = fake.type();
     1162         Object[] args = randomArgs(newType.parameterArray());
     1163         // here is what should happen:
     1164         Object[] collectedArgs = Arrays.copyOfRange(args, 0, pos+1);
     1165         collectedArgs[pos] = Arrays.copyOfRange(args, pos, args.length);
     1166         // here is the MH which will witness the collected argument tail:
     1167         MethodHandle target = ValueConversions.varargsArray(pos+1);
     1168         target = changeArgTypes(target, 0, pos, argType);
     1169         target = changeArgTypes(target, pos, pos+1, Object[].class);
     1170         if (verbosity >= 2)
     1171             System.out.println("collect from "+Arrays.asList(args)+" ["+pos+".."+nargs+"]");
     1172         MethodHandle result = MethodHandles.collectArguments(target, newType);
     1173         Object[] returnValue = (Object[]) result.invokeVarargs(args);
     1174 //        assertTrue(returnValue.length == pos+1 && returnValue[pos] instanceof Object[]);
     1175 //        returnValue[pos] = Arrays.asList((Object[]) returnValue[pos]);
     1176 //        collectedArgs[pos] = Arrays.asList((Object[]) collectedArgs[pos]);
     1177         assertArrayEquals(collectedArgs, returnValue);
     1178     }
     1179 
     1180     @Test
     1181     public void testInsertArguments() throws Throwable {
     1182         if (CAN_SKIP_WORKING)  return;
     1183         startTest("insertArguments");
     1184         for (int nargs = 0; nargs <= 4; nargs++) {
     1185             for (int ins = 0; ins <= 4; ins++) {
     1186                 if (ins > MAX_ARG_INCREASE)  continue;  // FIXME Fail_6
     1187                 for (int pos = 0; pos <= nargs; pos++) {
     1188                     testInsertArguments(nargs, pos, ins);
     1189                 }
     1190             }
     1191         }
     1192     }
     1193 
     1194     void testInsertArguments(int nargs, int pos, int ins) throws Throwable {
     1195         countTest();
     1196         MethodHandle target = ValueConversions.varargsArray(nargs + ins);
     1197         Object[] args = randomArgs(target.type().parameterArray());
     1198         List<Object> resList = Arrays.asList(args);
     1199         List<Object> argsToPass = new ArrayList<Object>(resList);
     1200         List<Object> argsToInsert = argsToPass.subList(pos, pos + ins);
     1201         if (verbosity >= 2)
     1202             System.out.println("insert: "+argsToInsert+" into "+target);
     1203         MethodHandle target2 = MethodHandles.insertArguments(target, pos,
     1204                 (Object[]) argsToInsert.toArray());
     1205         argsToInsert.clear();  // remove from argsToInsert
     1206         Object res2 = target2.invokeVarargs(argsToPass);
     1207         Object res2List = Arrays.asList((Object[])res2);
     1208         if (verbosity >= 2)
     1209             System.out.println("result: "+res2List);
     1210         //if (!resList.equals(res2List))
     1211         //    System.out.println("*** fail at n/p/i = "+nargs+"/"+pos+"/"+ins+": "+resList+" => "+res2List);
     1212         assertEquals(resList, res2List);
     1213     }
     1214 
     1215     @Test
     1216     public void testFilterArguments() throws Throwable {
     1217         if (CAN_SKIP_WORKING)  return;
     1218         startTest("filterArguments");
     1219         for (int nargs = 1; nargs <= 6; nargs++) {
     1220             for (int pos = 0; pos < nargs; pos++) {
     1221                 testFilterArguments(nargs, pos);
     1222             }
     1223         }
     1224     }
     1225 
     1226     void testFilterArguments(int nargs, int pos) throws Throwable {
     1227         countTest();
     1228         MethodHandle target = ValueConversions.varargsList(nargs);
     1229         MethodHandle filter = ValueConversions.varargsList(1);
     1230         filter = MethodHandles.convertArguments(filter, filter.type().generic());
     1231         Object[] argsToPass = randomArgs(nargs, Object.class);
     1232         if (verbosity >= 2)
     1233             System.out.println("filter "+target+" at "+pos+" with "+filter);
     1234         MethodHandle[] filters = new MethodHandle[pos*2+1];
     1235         filters[pos] = filter;
     1236         MethodHandle target2 = MethodHandles.filterArguments(target, filters);
     1237         // Simulate expected effect of filter on arglist:
     1238         Object[] filteredArgs = argsToPass.clone();
     1239         filteredArgs[pos] = filter.invoke(filteredArgs[pos]);
     1240         List<Object> expected = Arrays.asList(filteredArgs);
     1241         Object result = target2.invokeVarargs(argsToPass);
     1242         if (verbosity >= 2)
     1243             System.out.println("result: "+result);
     1244         if (!expected.equals(result))
     1245             System.out.println("*** fail at n/p = "+nargs+"/"+pos+": "+argsToPass+" => "+result);
     1246         assertEquals(expected, result);
     1247     }
     1248 
     1249     @Test
     1250     public void testFoldArguments() throws Throwable {
     1251         if (CAN_SKIP_WORKING)  return;
     1252         startTest("foldArguments");
     1253         for (int nargs = 0; nargs <= 4; nargs++) {
     1254             for (int fold = 0; fold <= nargs; fold++) {
     1255                 for (int pos = 0; pos <= nargs; pos++) {
     1256                     testFoldArguments(nargs, pos, fold);
     1257                 }
     1258             }
     1259         }
     1260     }
     1261 
     1262     void testFoldArguments(int nargs, int pos, int fold) throws Throwable {
     1263         if (pos != 0)  return;  // can fold only at pos=0 for now
     1264         countTest();
     1265         MethodHandle target = ValueConversions.varargsList(1 + nargs);
     1266         MethodHandle combine = ValueConversions.varargsList(fold);
     1267         List<Object> argsToPass = Arrays.asList(randomArgs(nargs, Object.class));
     1268         if (verbosity >= 2)
     1269             System.out.println("fold "+target+" with "+combine);
     1270         MethodHandle target2 = MethodHandles.foldArguments(target, combine);
     1271         // Simulate expected effect of combiner on arglist:
     1272         List<Object> expected = new ArrayList<Object>(argsToPass);
     1273         List<Object> argsToFold = expected.subList(pos, pos + fold);
     1274         if (verbosity >= 2)
     1275             System.out.println("fold: "+argsToFold+" into "+target2);
     1276         Object foldedArgs = combine.invokeVarargs(argsToFold);
     1277         argsToFold.add(0, foldedArgs);
     1278         Object result = target2.invokeVarargs(argsToPass);
     1279         if (verbosity >= 2)
     1280             System.out.println("result: "+result);
     1281         if (!expected.equals(result))
     1282             System.out.println("*** fail at n/p/f = "+nargs+"/"+pos+"/"+fold+": "+argsToPass+" => "+result);
     1283         assertEquals(expected, result);
     1284     }
     1285 
     1286     @Test
     1287     public void testDropArguments() throws Throwable {
     1288         if (CAN_SKIP_WORKING)  return;
     1289         startTest("dropArguments");
     1290         for (int nargs = 0; nargs <= 4; nargs++) {
     1291             for (int drop = 1; drop <= 4; drop++) {
     1292                 for (int pos = 0; pos <= nargs; pos++) {
     1293                     testDropArguments(nargs, pos, drop);
     1294                 }
     1295             }
     1296         }
     1297     }
     1298 
     1299     void testDropArguments(int nargs, int pos, int drop) throws Throwable {
     1300         countTest();
     1301         MethodHandle target = ValueConversions.varargsArray(nargs);
     1302         Object[] args = randomArgs(target.type().parameterArray());
     1303         MethodHandle target2 = MethodHandles.dropArguments(target, pos,
     1304                 Collections.nCopies(drop, Object.class).toArray(new Class[0]));
     1305         List<Object> resList = Arrays.asList(args);
     1306         List<Object> argsToDrop = new ArrayList<Object>(resList);
     1307         for (int i = drop; i > 0; i--) {
     1308             argsToDrop.add(pos, "blort#"+i);
     1309         }
     1310         Object res2 = target2.invokeVarargs(argsToDrop);
     1311         Object res2List = Arrays.asList((Object[])res2);
     1312         //if (!resList.equals(res2List))
     1313         //    System.out.println("*** fail at n/p/d = "+nargs+"/"+pos+"/"+drop+": "+argsToDrop+" => "+res2List);
     1314         assertEquals(resList, res2List);
     1315     }
     1316 
     1317     @Test
     1318     public void testInvokers() throws Throwable {
     1319         if (CAN_SKIP_WORKING)  return;
     1320         startTest("exactInvoker, genericInvoker, varargsInvoker, dynamicInvoker");
     1321         // exactInvoker, genericInvoker, varargsInvoker[0..N], dynamicInvoker
     1322         Set<MethodType> done = new HashSet<MethodType>();
     1323         for (int i = 0; i <= 6; i++) {
     1324             MethodType gtype = MethodType.genericMethodType(i);
     1325             for (Class<?> argType : new Class[]{Object.class, Integer.class, int.class}) {
     1326                 for (int j = -1; j < i; j++) {
     1327                     MethodType type = gtype;
     1328                     if (j < 0)
     1329                         type = type.changeReturnType(argType);
     1330                     else if (argType == void.class)
     1331                         continue;
     1332                     else
     1333                         type = type.changeParameterType(j, argType);
     1334                     if (argType.isPrimitive() && j != i-1)  continue; // FIXME Fail_5
     1335                     if (done.add(type))
     1336                         testInvokers(type);
     1337                     MethodType vtype = type.changeReturnType(void.class);
     1338                     if (done.add(vtype))
     1339                         testInvokers(vtype);
     1340                 }
     1341             }
     1342         }
     1343     }
     1344 
     1345     public void testInvokers(MethodType type) throws Throwable {
     1346         if (verbosity >= 2)
     1347             System.out.println("test invokers for "+type);
     1348         int nargs = type.parameterCount();
     1349         boolean testRetCode = type.returnType() != void.class;
     1350         MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "invokee",
     1351                                 MethodType.genericMethodType(0, true));
     1352         target = MethodHandles.collectArguments(target, type);
     1353         Object[] args = randomArgs(type.parameterArray());
     1354         List<Object> targetPlusArgs = new ArrayList<Object>(Arrays.asList(args));
     1355         targetPlusArgs.add(0, target);
     1356         int code = (Integer) invokee(args);
     1357         Object log = logEntry("invokee", args);
     1358         assertEquals(log.hashCode(), code);
     1359         assertCalled("invokee", args);
     1360         MethodHandle inv;
     1361         Object result;
     1362         // exact invoker
     1363         countTest();
     1364         calledLog.clear();
     1365         inv = MethodHandles.exactInvoker(type);
     1366         result = inv.invokeVarargs(targetPlusArgs);
     1367         if (testRetCode)  assertEquals(code, result);
     1368         assertCalled("invokee", args);
     1369         // generic invoker
     1370         countTest();
     1371         inv = MethodHandles.genericInvoker(type);
     1372         if (nargs <= 3) {
     1373             calledLog.clear();
     1374             switch (nargs) {
     1375             case 0:
     1376                 result = inv.invoke(target);
     1377                 break;
     1378             case 1:
     1379                 result = inv.invoke(target, args[0]);
     1380                 break;
     1381             case 2:
     1382                 result = inv.invoke(target, args[0], args[1]);
     1383                 break;
     1384             case 3:
     1385                 result = inv.invoke(target, args[0], args[1], args[2]);
     1386                 break;
     1387             }
     1388             if (testRetCode)  assertEquals(code, result);
     1389             assertCalled("invokee", args);
     1390         }
     1391         calledLog.clear();
     1392         result = inv.invokeVarargs(targetPlusArgs);
     1393         if (testRetCode)  assertEquals(code, result);
     1394         assertCalled("invokee", args);
     1395         // varargs invoker #0
     1396         calledLog.clear();
     1397         inv = MethodHandles.varargsInvoker(type, 0);
     1398         result = inv.invoke(target, args);
     1399         if (testRetCode)  assertEquals(code, result);
     1400         assertCalled("invokee", args);
     1401         if (nargs >= 1) {
     1402             // varargs invoker #1
     1403             calledLog.clear();
     1404             inv = MethodHandles.varargsInvoker(type, 1);
     1405             result = inv.invoke(target, args[0], Arrays.copyOfRange(args, 1, nargs));
     1406             if (testRetCode)  assertEquals(code, result);
     1407             assertCalled("invokee", args);
     1408         }
     1409         if (nargs >= 2) {
     1410             // varargs invoker #2
     1411             calledLog.clear();
     1412             inv = MethodHandles.varargsInvoker(type, 2);
     1413             result = inv.invoke(target, args[0], args[1], Arrays.copyOfRange(args, 2, nargs));
     1414             if (testRetCode)  assertEquals(code, result);
     1415             assertCalled("invokee", args);
     1416         }
     1417         if (nargs >= 3) {
     1418             // varargs invoker #3
     1419             calledLog.clear();
     1420             inv = MethodHandles.varargsInvoker(type, 3);
     1421             result = inv.invoke(target, args[0], args[1], args[2], Arrays.copyOfRange(args, 3, nargs));
     1422             if (testRetCode)  assertEquals(code, result);
     1423             assertCalled("invokee", args);
     1424         }
     1425         for (int k = 0; k <= nargs; k++) {
     1426             // varargs invoker #0..N
     1427             countTest();
     1428             calledLog.clear();
     1429             inv = MethodHandles.varargsInvoker(type, k);
     1430             List<Object> targetPlusVarArgs = new ArrayList<Object>(targetPlusArgs);
     1431             List<Object> tailList = targetPlusVarArgs.subList(1+k, 1+nargs);
     1432             Object[] tail = tailList.toArray();
     1433             tailList.clear(); tailList.add(tail);
     1434             result = inv.invokeVarargs(targetPlusVarArgs);
     1435             if (testRetCode)  assertEquals(code, result);
     1436             assertCalled("invokee", args);
     1437         }
     1438         // dynamic invoker
     1439         countTest();
     1440         CallSite site = new CallSite(MethodHandlesTest.class, "foo", type);
     1441         inv = MethodHandles.dynamicInvoker(site);
     1442         site.setTarget(target);
     1443         calledLog.clear();
     1444         result = inv.invokeVarargs(args);
     1445         if (testRetCode)  assertEquals(code, result);
     1446         assertCalled("invokee", args);
     1447     }
     1448 
     1449     static Object invokee(Object... args) {
     1450         return called("invokee", args).hashCode();
     1451     }
     1452 
     1453     private static final String MISSING_ARG = "missingArg";
     1454     static Object targetIfEquals() {
     1455         return called("targetIfEquals");
     1456     }
     1457     static Object fallbackIfNotEquals() {
     1458         return called("fallbackIfNotEquals");
     1459     }
     1460     static Object targetIfEquals(Object x) {
     1461         assertEquals(x, MISSING_ARG);
     1462         return called("targetIfEquals", x);
     1463     }
     1464     static Object fallbackIfNotEquals(Object x) {
     1465         assertFalse(x.toString(), x.equals(MISSING_ARG));
     1466         return called("fallbackIfNotEquals", x);
     1467     }
     1468     static Object targetIfEquals(Object x, Object y) {
     1469         assertEquals(x, y);
     1470         return called("targetIfEquals", x, y);
     1471     }
     1472     static Object fallbackIfNotEquals(Object x, Object y) {
     1473         assertFalse(x.toString(), x.equals(y));
     1474         return called("fallbackIfNotEquals", x, y);
     1475     }
     1476     static Object targetIfEquals(Object x, Object y, Object z) {
     1477         assertEquals(x, y);
     1478         return called("targetIfEquals", x, y, z);
     1479     }
     1480     static Object fallbackIfNotEquals(Object x, Object y, Object z) {
     1481         assertFalse(x.toString(), x.equals(y));
     1482         return called("fallbackIfNotEquals", x, y, z);
     1483     }
     1484 
     1485     @Test
     1486     public void testGuardWithTest() throws Throwable {
     1487         if (CAN_SKIP_WORKING)  return;
     1488         startTest("guardWithTest");
     1489         for (int nargs = 0; nargs <= 3; nargs++) {
     1490             if (nargs != 2)  continue;  // FIXME: test more later
     1491             testGuardWithTest(nargs, Object.class);
     1492             testGuardWithTest(nargs, String.class);
     1493         }
     1494     }
     1495     void testGuardWithTest(int nargs, Class<?> argClass) throws Throwable {
     1496         countTest();
     1497         MethodHandle test = PRIVATE.findVirtual(Object.class, "equals", MethodType.methodType(boolean.class, Object.class));
     1498         MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "targetIfEquals", MethodType.genericMethodType(nargs));
     1499         MethodHandle fallback = PRIVATE.findStatic(MethodHandlesTest.class, "fallbackIfNotEquals", MethodType.genericMethodType(nargs));
     1500         while (test.type().parameterCount() < nargs)
     1501             test = MethodHandles.dropArguments(test, test.type().parameterCount()-1, Object.class);
     1502         while (test.type().parameterCount() > nargs)
     1503             test = MethodHandles.insertArguments(test, 0, MISSING_ARG);
     1504         if (argClass != Object.class) {
     1505             test = changeArgTypes(test, argClass);
     1506             target = changeArgTypes(target, argClass);
     1507             fallback = changeArgTypes(fallback, argClass);
     1508         }
     1509         MethodHandle mh = MethodHandles.guardWithTest(test, target, fallback);
     1510         assertEquals(target.type(), mh.type());
     1511         Object[][] argLists = {
     1512             { },
     1513             { "foo" }, { MISSING_ARG },
     1514             { "foo", "foo" }, { "foo", "bar" },
     1515             { "foo", "foo", "baz" }, { "foo", "bar", "baz" }
     1516         };
     1517         for (Object[] argList : argLists) {
     1518             if (argList.length != nargs)  continue;
     1519             boolean equals;
     1520             switch (nargs) {
     1521             case 0:   equals = true; break;
     1522             case 1:   equals = MISSING_ARG.equals(argList[0]); break;
     1523             default:  equals = argList[0].equals(argList[1]); break;
     1524             }
     1525             String willCall = (equals ? "targetIfEquals" : "fallbackIfNotEquals");
     1526             if (verbosity >= 2)
     1527                 System.out.println(logEntry(willCall, argList));
     1528             Object result = mh.invokeVarargs(argList);
     1529             assertCalled(willCall, argList);
     1530         }
     1531     }
     1532 
     1533     @Test
     1534     public void testCatchException() throws Throwable {
     1535         if (CAN_SKIP_WORKING)  return;
     1536         startTest("catchException");
     1537         for (int nargs = 2; nargs <= 6; nargs++) {
     1538             for (int ti = 0; ti <= 1; ti++) {
     1539                 boolean throwIt = (ti != 0);
     1540                 testCatchException(int.class, new ClassCastException("testing"), throwIt, nargs);
     1541                 testCatchException(void.class, new java.io.IOException("testing"), throwIt, nargs);
     1542                 testCatchException(String.class, new LinkageError("testing"), throwIt, nargs);
     1543             }
     1544         }
     1545     }
     1546 
     1547     private static <T extends Throwable>
     1548     Object throwOrReturn(Object normal, T exception) throws T {
     1549         if (exception != null)  throw exception;
     1550         return normal;
     1551     }
     1552 
     1553     void testCatchException(Class<?> returnType, Throwable thrown, boolean throwIt, int nargs) throws Throwable {
     1554         countTest();
     1555         if (verbosity >= 2)
     1556             System.out.println("catchException rt="+returnType+" throw="+throwIt+" nargs="+nargs);
     1557         Class<? extends Throwable> exType = thrown.getClass();
     1558         MethodHandle throwOrReturn
     1559                 = PRIVATE.findStatic(MethodHandlesTest.class, "throwOrReturn",
     1560                     MethodType.methodType(Object.class, Object.class, Throwable.class));
     1561         MethodHandle thrower = throwOrReturn;
     1562         while (thrower.type().parameterCount() < nargs)
     1563             thrower = MethodHandles.dropArguments(thrower, thrower.type().parameterCount(), Object.class);
     1564         MethodHandle target = MethodHandles.catchException(thrower,
     1565                 thrown.getClass(), ValueConversions.varargsList(1+nargs));
     1566         assertEquals(thrower.type(), target.type());
     1567         //System.out.println("catching with "+target+" : "+throwOrReturn);
     1568         Object[] args = randomArgs(nargs, Object.class);
     1569         args[1] = (throwIt ? thrown : null);
     1570         Object returned = target.invokeVarargs(args);
     1571         //System.out.println("return from "+target+" : "+returned);
     1572         if (!throwIt) {
     1573             assertSame(args[0], returned);
     1574         } else {
     1575             List<Object> catchArgs = new ArrayList<Object>(Arrays.asList(args));
     1576             catchArgs.add(0, thrown);
     1577             assertEquals(catchArgs, returned);
     1578         }
     1579     }
     1580 
     1581     @Test
     1582     public void testThrowException() throws Throwable {
     1583         if (CAN_SKIP_WORKING)  return;
     1584         startTest("throwException");
     1585         testThrowException(int.class, new ClassCastException("testing"));
     1586         testThrowException(void.class, new java.io.IOException("testing"));
     1587         testThrowException(String.class, new LinkageError("testing"));
     1588     }
     1589 
     1590     void testThrowException(Class<?> returnType, Throwable thrown) throws Throwable {
     1591         countTest();
     1592         Class<? extends Throwable> exType = thrown.getClass();
     1593         MethodHandle target = MethodHandles.throwException(returnType, exType);
     1594         //System.out.println("throwing with "+target+" : "+thrown);
     1595         MethodType expectedType = MethodType.methodType(returnType, exType);
     1596         assertEquals(expectedType, target.type());
     1597         Throwable caught = null;
     1598         try {
     1599             Object res = target.invokeGeneric(thrown);
     1600             fail("got "+res+" instead of throwing "+thrown);
     1601         } catch (Throwable ex) {
     1602             if (ex != thrown) {
     1603                 if (ex instanceof Error)  throw (Error)ex;
     1604                 if (ex instanceof RuntimeException)  throw (RuntimeException)ex;
     1605             }
     1606             caught = ex;
     1607         }
     1608         assertSame(thrown, caught);
     1609     }
     1610 
     1611     @Test
     1612     public void testCastFailure() throws Throwable {
     1613         if (CAN_SKIP_WORKING)  return;
     1614         startTest("testCastFailure");
     1615         testCastFailure("cast/argument", 11000);
     1616         testCastFailure("unbox/argument", 11000);
     1617         testCastFailure("cast/return", 11000);
     1618         testCastFailure("unbox/return", 11000);
     1619     }
     1620 
     1621     static class Surprise extends JavaMethodHandle {
     1622         Surprise() { super("value"); }
     1623         Object value(Object x) {
     1624             trace("value", x);
     1625             if (boo != null)  return boo;
     1626             return x;
     1627         }
     1628         Object boo;
     1629         void boo(Object x) { boo = x; }
     1630 
     1631         static void trace(String x, Object y) {
     1632             if (verbosity > 8) System.out.println(x+"="+y);
     1633         }
     1634         static Object  refIdentity(Object x)  { trace("ref.x", x); return x; }
     1635         static Integer boxIdentity(Integer x) { trace("box.x", x); return x; }
     1636         static int     intIdentity(int x)     { trace("int.x", x); return x; }
     1637         static MethodHandle REF_IDENTITY = PRIVATE.findStatic(
     1638                 Surprise.class, "refIdentity",
     1639                     MethodType.methodType(Object.class, Object.class));
     1640         static MethodHandle BOX_IDENTITY = PRIVATE.findStatic(
     1641                 Surprise.class, "boxIdentity",
     1642                     MethodType.methodType(Integer.class, Integer.class));
     1643         static MethodHandle INT_IDENTITY = PRIVATE.findStatic(
     1644                 Surprise.class, "intIdentity",
     1645                     MethodType.methodType(int.class, int.class));
     1646     }
     1647 
     1648     void testCastFailure(String mode, int okCount) throws Throwable {
     1649         countTest(false);
     1650         if (verbosity > 1)  System.out.println("mode="+mode);
     1651         Surprise boo = new Surprise();
     1652         MethodHandle identity = Surprise.REF_IDENTITY, surprise = boo;
     1653         if (mode.endsWith("/return")) {
     1654             if (mode.equals("unbox/return")) {
     1655                 // fail on return to ((Integer)surprise).intValue
     1656                 surprise = MethodHandles.convertArguments(surprise, MethodType.methodType(int.class, Object.class));
     1657                 identity = MethodHandles.convertArguments(identity, MethodType.methodType(int.class, Object.class));
     1658             } else if (mode.equals("cast/return")) {
     1659                 // fail on return to (Integer)surprise
     1660                 surprise = MethodHandles.convertArguments(surprise, MethodType.methodType(Integer.class, Object.class));
     1661                 identity = MethodHandles.convertArguments(identity, MethodType.methodType(Integer.class, Object.class));
     1662             }
     1663         } else if (mode.endsWith("/argument")) {
     1664             MethodHandle callee = null;
     1665             if (mode.equals("unbox/argument")) {
     1666                 // fail on handing surprise to int argument
     1667                 callee = Surprise.INT_IDENTITY;
     1668             } else if (mode.equals("cast/argument")) {
     1669                 // fail on handing surprise to Integer argument
     1670                 callee = Surprise.BOX_IDENTITY;
     1671             }
     1672             if (callee != null) {
     1673                 callee = MethodHandles.convertArguments(callee, MethodType.genericMethodType(1));
     1674                 surprise = MethodHandles.filterArguments(callee, surprise);
     1675                 identity = MethodHandles.filterArguments(callee, identity);
     1676             }
     1677         }
     1678         assertNotSame(mode, surprise, boo);
     1679         identity = MethodHandles.convertArguments(identity, MethodType.genericMethodType(1));
     1680         surprise = MethodHandles.convertArguments(surprise, MethodType.genericMethodType(1));
     1681         Object x = 42;
     1682         for (int i = 0; i < okCount; i++) {
     1683             Object y = identity.invoke(x);
     1684             assertEquals(x, y);
     1685             Object z = surprise.invoke(x);
     1686             assertEquals(x, z);
     1687         }
     1688         boo.boo("Boo!");
     1689         Object y = identity.invoke(x);
     1690         assertEquals(x, y);
     1691         try {
     1692             Object z = surprise.invoke(x);
     1693             System.out.println("Failed to throw; got z="+z);
     1694             assertTrue(false);
     1695         } catch (Exception ex) {
     1696             if (verbosity > 1)
     1697                 System.out.println("caught "+ex);
     1698             if (verbosity > 2)
     1699                 ex.printStackTrace();
     1700             assertTrue(ex instanceof ClassCastException
     1701                     // FIXME: accept only one of the two for any given unit test
     1702                     || ex instanceof WrongMethodTypeException
     1703                     );
     1704         }
     1705     }
     1706 
     1707 }
     1708 // Local abbreviated copy of sun.dyn.util.ValueConversions
     1709 class ValueConversions {
     1710     private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
     1711     private static final Object[] NO_ARGS_ARRAY = {};
     1712     private static Object[] makeArray(Object... args) { return args; }
     1713     private static Object[] array() { return NO_ARGS_ARRAY; }
     1714     private static Object[] array(Object a0)
     1715                 { return makeArray(a0); }
     1716     private static Object[] array(Object a0, Object a1)
     1717                 { return makeArray(a0, a1); }
     1718     private static Object[] array(Object a0, Object a1, Object a2)
     1719                 { return makeArray(a0, a1, a2); }
     1720     private static Object[] array(Object a0, Object a1, Object a2, Object a3)
     1721                 { return makeArray(a0, a1, a2, a3); }
     1722     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
     1723                                   Object a4)
     1724                 { return makeArray(a0, a1, a2, a3, a4); }
     1725     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
     1726                                   Object a4, Object a5)
     1727                 { return makeArray(a0, a1, a2, a3, a4, a5); }
     1728     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
     1729                                   Object a4, Object a5, Object a6)
     1730                 { return makeArray(a0, a1, a2, a3, a4, a5, a6); }
     1731     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
     1732                                   Object a4, Object a5, Object a6, Object a7)
     1733                 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); }
     1734     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
     1735                                   Object a4, Object a5, Object a6, Object a7,
     1736                                   Object a8)
     1737                 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
     1738     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
     1739                                   Object a4, Object a5, Object a6, Object a7,
     1740                                   Object a8, Object a9)
     1741                 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
     1742     static MethodHandle[] makeArrays() {
     1743         ArrayList<MethodHandle> arrays = new ArrayList<MethodHandle>();
     1744         MethodHandles.Lookup lookup = IMPL_LOOKUP;
     1745         for (;;) {
     1746             int nargs = arrays.size();
     1747             MethodType type = MethodType.genericMethodType(nargs).changeReturnType(Object[].class);
     1748             String name = "array";
     1749             MethodHandle array = null;
     1750             try {
     1751                 array = lookup.findStatic(ValueConversions.class, name, type);
     1752             } catch (NoAccessException ex) {
     1753             }
     1754             if (array == null)  break;
     1755             arrays.add(array);
     1756         }
     1757         assert(arrays.size() == 11);  // current number of methods
     1758         return arrays.toArray(new MethodHandle[0]);
     1759     }
     1760     static final MethodHandle[] ARRAYS = makeArrays();
     1761 
     1762     /** Return a method handle that takes the indicated number of Object
     1763      *  arguments and returns an Object array of them, as if for varargs.
     1764      */
     1765     public static MethodHandle varargsArray(int nargs) {
     1766         if (nargs < ARRAYS.length)
     1767             return ARRAYS[nargs];
     1768         // else need to spin bytecode or do something else fancy
     1769         throw new UnsupportedOperationException("NYI");
     1770     }
     1771 
     1772     private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY);
     1773     private static List<Object> makeList(Object... args) { return Arrays.asList(args); }
     1774     private static List<Object> list() { return NO_ARGS_LIST; }
     1775     private static List<Object> list(Object a0)
     1776                 { return makeList(a0); }
     1777     private static List<Object> list(Object a0, Object a1)
     1778                 { return makeList(a0, a1); }
     1779     private static List<Object> list(Object a0, Object a1, Object a2)
     1780                 { return makeList(a0, a1, a2); }
     1781     private static List<Object> list(Object a0, Object a1, Object a2, Object a3)
     1782                 { return makeList(a0, a1, a2, a3); }
     1783     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
     1784                                      Object a4)
     1785                 { return makeList(a0, a1, a2, a3, a4); }
     1786     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
     1787                                      Object a4, Object a5)
     1788                 { return makeList(a0, a1, a2, a3, a4, a5); }
     1789     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
     1790                                      Object a4, Object a5, Object a6)
     1791                 { return makeList(a0, a1, a2, a3, a4, a5, a6); }
     1792     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
     1793                                      Object a4, Object a5, Object a6, Object a7)
     1794                 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); }
     1795     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
     1796                                      Object a4, Object a5, Object a6, Object a7,
     1797                                      Object a8)
     1798                 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
     1799     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
     1800                                      Object a4, Object a5, Object a6, Object a7,
     1801                                      Object a8, Object a9)
     1802                 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
     1803     static MethodHandle[] makeLists() {
     1804         ArrayList<MethodHandle> arrays = new ArrayList<MethodHandle>();
     1805         MethodHandles.Lookup lookup = IMPL_LOOKUP;
     1806         for (;;) {
     1807             int nargs = arrays.size();
     1808             MethodType type = MethodType.genericMethodType(nargs).changeReturnType(List.class);
     1809             String name = "list";
     1810             MethodHandle array = null;
     1811             try {
     1812                 array = lookup.findStatic(ValueConversions.class, name, type);
     1813             } catch (NoAccessException ex) {
     1814             }
     1815             if (array == null)  break;
     1816             arrays.add(array);
     1817         }
     1818         assert(arrays.size() == 11);  // current number of methods
     1819         return arrays.toArray(new MethodHandle[0]);
     1820     }
     1821     static final MethodHandle[] LISTS = makeLists();
     1822 
     1823     /** Return a method handle that takes the indicated number of Object
     1824      *  arguments and returns List.
     1825      */
     1826     public static MethodHandle varargsList(int nargs) {
     1827         if (nargs < LISTS.length)
     1828             return LISTS[nargs];
     1829         // else need to spin bytecode or do something else fancy
     1830         throw new UnsupportedOperationException("NYI");
     1831     }
     1832 }
     1833 // This guy tests access from outside the same package member, but inside
     1834 // the package itself.
     1835 class PackageSibling {
     1836     static Lookup lookup() {
     1837         return MethodHandles.lookup();
     1838     }
     1839 }