rt/emul/compact/src/main/java/sun/invoke/util/ValueConversions.java
branchjdk8-b132
changeset 1646 c880a8a8803b
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/rt/emul/compact/src/main/java/sun/invoke/util/ValueConversions.java	Sat Aug 09 11:11:13 2014 +0200
     1.3 @@ -0,0 +1,1188 @@
     1.4 +/*
     1.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.  Oracle designates this
    1.11 + * particular file as subject to the "Classpath" exception as provided
    1.12 + * by Oracle in the LICENSE file that accompanied this code.
    1.13 + *
    1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.17 + * version 2 for more details (a copy is included in the LICENSE file that
    1.18 + * accompanied this code).
    1.19 + *
    1.20 + * You should have received a copy of the GNU General Public License version
    1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.23 + *
    1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.25 + * or visit www.oracle.com if you need additional information or have any
    1.26 + * questions.
    1.27 + */
    1.28 +
    1.29 +package sun.invoke.util;
    1.30 +
    1.31 +import java.lang.invoke.MethodHandle;
    1.32 +import java.lang.invoke.MethodHandles;
    1.33 +import java.lang.invoke.MethodHandles.Lookup;
    1.34 +import java.lang.invoke.MethodType;
    1.35 +import java.security.AccessController;
    1.36 +import java.security.PrivilegedAction;
    1.37 +import java.util.ArrayList;
    1.38 +import java.util.Arrays;
    1.39 +import java.util.Collections;
    1.40 +import java.util.EnumMap;
    1.41 +import java.util.List;
    1.42 +
    1.43 +public class ValueConversions {
    1.44 +    private static final Class<?> THIS_CLASS = ValueConversions.class;
    1.45 +    // Do not adjust this except for special platforms:
    1.46 +    private static final int MAX_ARITY;
    1.47 +    static {
    1.48 +        final Object[] values = { 255 };
    1.49 +        AccessController.doPrivileged(new PrivilegedAction<Void>() {
    1.50 +                @Override
    1.51 +                public Void run() {
    1.52 +                    values[0] = Integer.getInteger(THIS_CLASS.getName()+".MAX_ARITY", 255);
    1.53 +                    return null;
    1.54 +                }
    1.55 +            });
    1.56 +        MAX_ARITY = (Integer) values[0];
    1.57 +    }
    1.58 +
    1.59 +    private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
    1.60 +
    1.61 +    private static EnumMap<Wrapper, MethodHandle>[] newWrapperCaches(int n) {
    1.62 +        @SuppressWarnings("unchecked")  // generic array creation
    1.63 +        EnumMap<Wrapper, MethodHandle>[] caches
    1.64 +                = (EnumMap<Wrapper, MethodHandle>[]) new EnumMap<?,?>[n];
    1.65 +        for (int i = 0; i < n; i++)
    1.66 +            caches[i] = new EnumMap<>(Wrapper.class);
    1.67 +        return caches;
    1.68 +    }
    1.69 +
    1.70 +    /// Converting references to values.
    1.71 +
    1.72 +    // There are several levels of this unboxing conversions:
    1.73 +    //   no conversions:  exactly Integer.valueOf, etc.
    1.74 +    //   implicit conversions sanctioned by JLS 5.1.2, etc.
    1.75 +    //   explicit conversions as allowed by explicitCastArguments
    1.76 +
    1.77 +    static int unboxInteger(Object x, boolean cast) {
    1.78 +        if (x instanceof Integer)
    1.79 +            return ((Integer) x).intValue();
    1.80 +        return primitiveConversion(Wrapper.INT, x, cast).intValue();
    1.81 +    }
    1.82 +
    1.83 +    static byte unboxByte(Object x, boolean cast) {
    1.84 +        if (x instanceof Byte)
    1.85 +            return ((Byte) x).byteValue();
    1.86 +        return primitiveConversion(Wrapper.BYTE, x, cast).byteValue();
    1.87 +    }
    1.88 +
    1.89 +    static short unboxShort(Object x, boolean cast) {
    1.90 +        if (x instanceof Short)
    1.91 +            return ((Short) x).shortValue();
    1.92 +        return primitiveConversion(Wrapper.SHORT, x, cast).shortValue();
    1.93 +    }
    1.94 +
    1.95 +    static boolean unboxBoolean(Object x, boolean cast) {
    1.96 +        if (x instanceof Boolean)
    1.97 +            return ((Boolean) x).booleanValue();
    1.98 +        return (primitiveConversion(Wrapper.BOOLEAN, x, cast).intValue() & 1) != 0;
    1.99 +    }
   1.100 +
   1.101 +    static char unboxCharacter(Object x, boolean cast) {
   1.102 +        if (x instanceof Character)
   1.103 +            return ((Character) x).charValue();
   1.104 +        return (char) primitiveConversion(Wrapper.CHAR, x, cast).intValue();
   1.105 +    }
   1.106 +
   1.107 +    static long unboxLong(Object x, boolean cast) {
   1.108 +        if (x instanceof Long)
   1.109 +            return ((Long) x).longValue();
   1.110 +        return primitiveConversion(Wrapper.LONG, x, cast).longValue();
   1.111 +    }
   1.112 +
   1.113 +    static float unboxFloat(Object x, boolean cast) {
   1.114 +        if (x instanceof Float)
   1.115 +            return ((Float) x).floatValue();
   1.116 +        return primitiveConversion(Wrapper.FLOAT, x, cast).floatValue();
   1.117 +    }
   1.118 +
   1.119 +    static double unboxDouble(Object x, boolean cast) {
   1.120 +        if (x instanceof Double)
   1.121 +            return ((Double) x).doubleValue();
   1.122 +        return primitiveConversion(Wrapper.DOUBLE, x, cast).doubleValue();
   1.123 +    }
   1.124 +
   1.125 +    private static MethodType unboxType(Wrapper wrap) {
   1.126 +        return MethodType.methodType(wrap.primitiveType(), Object.class, boolean.class);
   1.127 +    }
   1.128 +
   1.129 +    private static final EnumMap<Wrapper, MethodHandle>[]
   1.130 +            UNBOX_CONVERSIONS = newWrapperCaches(2);
   1.131 +
   1.132 +    private static MethodHandle unbox(Wrapper wrap, boolean cast) {
   1.133 +        EnumMap<Wrapper, MethodHandle> cache = UNBOX_CONVERSIONS[(cast?1:0)];
   1.134 +        MethodHandle mh = cache.get(wrap);
   1.135 +        if (mh != null) {
   1.136 +            return mh;
   1.137 +        }
   1.138 +        // slow path
   1.139 +        switch (wrap) {
   1.140 +            case OBJECT:
   1.141 +                mh = IDENTITY; break;
   1.142 +            case VOID:
   1.143 +                mh = IGNORE; break;
   1.144 +        }
   1.145 +        if (mh != null) {
   1.146 +            cache.put(wrap, mh);
   1.147 +            return mh;
   1.148 +        }
   1.149 +        // look up the method
   1.150 +        String name = "unbox" + wrap.wrapperSimpleName();
   1.151 +        MethodType type = unboxType(wrap);
   1.152 +        try {
   1.153 +            mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
   1.154 +        } catch (ReflectiveOperationException ex) {
   1.155 +            mh = null;
   1.156 +        }
   1.157 +        if (mh != null) {
   1.158 +            mh = MethodHandles.insertArguments(mh, 1, cast);
   1.159 +            cache.put(wrap, mh);
   1.160 +            return mh;
   1.161 +        }
   1.162 +        throw new IllegalArgumentException("cannot find unbox adapter for " + wrap
   1.163 +                + (cast ? " (cast)" : ""));
   1.164 +    }
   1.165 +
   1.166 +    public static MethodHandle unboxCast(Wrapper type) {
   1.167 +        return unbox(type, true);
   1.168 +    }
   1.169 +
   1.170 +    public static MethodHandle unbox(Class<?> type) {
   1.171 +        return unbox(Wrapper.forPrimitiveType(type), false);
   1.172 +    }
   1.173 +
   1.174 +    public static MethodHandle unboxCast(Class<?> type) {
   1.175 +        return unbox(Wrapper.forPrimitiveType(type), true);
   1.176 +    }
   1.177 +
   1.178 +    static private final Integer ZERO_INT = 0, ONE_INT = 1;
   1.179 +
   1.180 +    /// Primitive conversions
   1.181 +    /**
   1.182 +     * Produce a Number which represents the given value {@code x}
   1.183 +     * according to the primitive type of the given wrapper {@code wrap}.
   1.184 +     * Caller must invoke intValue, byteValue, longValue (etc.) on the result
   1.185 +     * to retrieve the desired primitive value.
   1.186 +     */
   1.187 +    public static Number primitiveConversion(Wrapper wrap, Object x, boolean cast) {
   1.188 +        // Maybe merge this code with Wrapper.convert/cast.
   1.189 +        Number res;
   1.190 +        if (x == null) {
   1.191 +            if (!cast)  return null;
   1.192 +            return ZERO_INT;
   1.193 +        }
   1.194 +        if (x instanceof Number) {
   1.195 +            res = (Number) x;
   1.196 +        } else if (x instanceof Boolean) {
   1.197 +            res = ((boolean)x ? ONE_INT : ZERO_INT);
   1.198 +        } else if (x instanceof Character) {
   1.199 +            res = (int)(char)x;
   1.200 +        } else {
   1.201 +            // this will fail with the required ClassCastException:
   1.202 +            res = (Number) x;
   1.203 +        }
   1.204 +        Wrapper xwrap = Wrapper.findWrapperType(x.getClass());
   1.205 +        if (xwrap == null || !cast && !wrap.isConvertibleFrom(xwrap))
   1.206 +            // this will fail with the required ClassCastException:
   1.207 +            return (Number) wrap.wrapperType().cast(x);
   1.208 +        return res;
   1.209 +    }
   1.210 +
   1.211 +    /**
   1.212 +     * The JVM verifier allows boolean, byte, short, or char to widen to int.
   1.213 +     * Support exactly this conversion, from a boxed value type Boolean,
   1.214 +     * Byte, Short, Character, or Integer.
   1.215 +     */
   1.216 +    public static int widenSubword(Object x) {
   1.217 +        if (x instanceof Integer)
   1.218 +            return (int) x;
   1.219 +        else if (x instanceof Boolean)
   1.220 +            return fromBoolean((boolean) x);
   1.221 +        else if (x instanceof Character)
   1.222 +            return (char) x;
   1.223 +        else if (x instanceof Short)
   1.224 +            return (short) x;
   1.225 +        else if (x instanceof Byte)
   1.226 +            return (byte) x;
   1.227 +        else
   1.228 +            // Fail with a ClassCastException.
   1.229 +            return (int) x;
   1.230 +    }
   1.231 +
   1.232 +    /// Converting primitives to references
   1.233 +
   1.234 +    static Integer boxInteger(int x) {
   1.235 +        return x;
   1.236 +    }
   1.237 +
   1.238 +    static Byte boxByte(byte x) {
   1.239 +        return x;
   1.240 +    }
   1.241 +
   1.242 +    static Short boxShort(short x) {
   1.243 +        return x;
   1.244 +    }
   1.245 +
   1.246 +    static Boolean boxBoolean(boolean x) {
   1.247 +        return x;
   1.248 +    }
   1.249 +
   1.250 +    static Character boxCharacter(char x) {
   1.251 +        return x;
   1.252 +    }
   1.253 +
   1.254 +    static Long boxLong(long x) {
   1.255 +        return x;
   1.256 +    }
   1.257 +
   1.258 +    static Float boxFloat(float x) {
   1.259 +        return x;
   1.260 +    }
   1.261 +
   1.262 +    static Double boxDouble(double x) {
   1.263 +        return x;
   1.264 +    }
   1.265 +
   1.266 +    private static MethodType boxType(Wrapper wrap) {
   1.267 +        // be exact, since return casts are hard to compose
   1.268 +        Class<?> boxType = wrap.wrapperType();
   1.269 +        return MethodType.methodType(boxType, wrap.primitiveType());
   1.270 +    }
   1.271 +
   1.272 +    private static final EnumMap<Wrapper, MethodHandle>[]
   1.273 +            BOX_CONVERSIONS = newWrapperCaches(2);
   1.274 +
   1.275 +    private static MethodHandle box(Wrapper wrap, boolean exact) {
   1.276 +        EnumMap<Wrapper, MethodHandle> cache = BOX_CONVERSIONS[(exact?1:0)];
   1.277 +        MethodHandle mh = cache.get(wrap);
   1.278 +        if (mh != null) {
   1.279 +            return mh;
   1.280 +        }
   1.281 +        // slow path
   1.282 +        switch (wrap) {
   1.283 +            case OBJECT:
   1.284 +                mh = IDENTITY; break;
   1.285 +            case VOID:
   1.286 +                mh = ZERO_OBJECT;
   1.287 +                break;
   1.288 +        }
   1.289 +        if (mh != null) {
   1.290 +            cache.put(wrap, mh);
   1.291 +            return mh;
   1.292 +        }
   1.293 +        // look up the method
   1.294 +        String name = "box" + wrap.wrapperSimpleName();
   1.295 +        MethodType type = boxType(wrap);
   1.296 +        if (exact) {
   1.297 +            try {
   1.298 +                mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
   1.299 +            } catch (ReflectiveOperationException ex) {
   1.300 +                mh = null;
   1.301 +            }
   1.302 +        } else {
   1.303 +            mh = box(wrap, !exact).asType(type.erase());
   1.304 +        }
   1.305 +        if (mh != null) {
   1.306 +            cache.put(wrap, mh);
   1.307 +            return mh;
   1.308 +        }
   1.309 +        throw new IllegalArgumentException("cannot find box adapter for "
   1.310 +                + wrap + (exact ? " (exact)" : ""));
   1.311 +    }
   1.312 +
   1.313 +    public static MethodHandle box(Class<?> type) {
   1.314 +        boolean exact = false;
   1.315 +        // e.g., boxShort(short)Short if exact,
   1.316 +        // e.g., boxShort(short)Object if !exact
   1.317 +        return box(Wrapper.forPrimitiveType(type), exact);
   1.318 +    }
   1.319 +
   1.320 +    public static MethodHandle box(Wrapper type) {
   1.321 +        boolean exact = false;
   1.322 +        return box(type, exact);
   1.323 +    }
   1.324 +
   1.325 +    /// Constant functions
   1.326 +
   1.327 +    static void ignore(Object x) {
   1.328 +        // no value to return; this is an unbox of null
   1.329 +    }
   1.330 +
   1.331 +    static void empty() {
   1.332 +    }
   1.333 +
   1.334 +    static Object zeroObject() {
   1.335 +        return null;
   1.336 +    }
   1.337 +
   1.338 +    static int zeroInteger() {
   1.339 +        return 0;
   1.340 +    }
   1.341 +
   1.342 +    static long zeroLong() {
   1.343 +        return 0;
   1.344 +    }
   1.345 +
   1.346 +    static float zeroFloat() {
   1.347 +        return 0;
   1.348 +    }
   1.349 +
   1.350 +    static double zeroDouble() {
   1.351 +        return 0;
   1.352 +    }
   1.353 +
   1.354 +    private static final EnumMap<Wrapper, MethodHandle>[]
   1.355 +            CONSTANT_FUNCTIONS = newWrapperCaches(2);
   1.356 +
   1.357 +    public static MethodHandle zeroConstantFunction(Wrapper wrap) {
   1.358 +        EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[0];
   1.359 +        MethodHandle mh = cache.get(wrap);
   1.360 +        if (mh != null) {
   1.361 +            return mh;
   1.362 +        }
   1.363 +        // slow path
   1.364 +        MethodType type = MethodType.methodType(wrap.primitiveType());
   1.365 +        switch (wrap) {
   1.366 +            case VOID:
   1.367 +                mh = EMPTY;
   1.368 +                break;
   1.369 +            case OBJECT:
   1.370 +            case INT: case LONG: case FLOAT: case DOUBLE:
   1.371 +                try {
   1.372 +                    mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "zero"+wrap.wrapperSimpleName(), type);
   1.373 +                } catch (ReflectiveOperationException ex) {
   1.374 +                    mh = null;
   1.375 +                }
   1.376 +                break;
   1.377 +        }
   1.378 +        if (mh != null) {
   1.379 +            cache.put(wrap, mh);
   1.380 +            return mh;
   1.381 +        }
   1.382 +
   1.383 +        // use zeroInt and cast the result
   1.384 +        if (wrap.isSubwordOrInt() && wrap != Wrapper.INT) {
   1.385 +            mh = MethodHandles.explicitCastArguments(zeroConstantFunction(Wrapper.INT), type);
   1.386 +            cache.put(wrap, mh);
   1.387 +            return mh;
   1.388 +        }
   1.389 +        throw new IllegalArgumentException("cannot find zero constant for " + wrap);
   1.390 +    }
   1.391 +
   1.392 +    /// Converting references to references.
   1.393 +
   1.394 +    /**
   1.395 +     * Identity function.
   1.396 +     * @param x an arbitrary reference value
   1.397 +     * @return the same value x
   1.398 +     */
   1.399 +    static <T> T identity(T x) {
   1.400 +        return x;
   1.401 +    }
   1.402 +
   1.403 +    static <T> T[] identity(T[] x) {
   1.404 +        return x;
   1.405 +    }
   1.406 +
   1.407 +    /**
   1.408 +     * Identity function on ints.
   1.409 +     * @param x an arbitrary int value
   1.410 +     * @return the same value x
   1.411 +     */
   1.412 +    static int identity(int x) {
   1.413 +        return x;
   1.414 +    }
   1.415 +
   1.416 +    static byte identity(byte x) {
   1.417 +        return x;
   1.418 +    }
   1.419 +
   1.420 +    static short identity(short x) {
   1.421 +        return x;
   1.422 +    }
   1.423 +
   1.424 +    static boolean identity(boolean x) {
   1.425 +        return x;
   1.426 +    }
   1.427 +
   1.428 +    static char identity(char x) {
   1.429 +        return x;
   1.430 +    }
   1.431 +
   1.432 +    /**
   1.433 +     * Identity function on longs.
   1.434 +     * @param x an arbitrary long value
   1.435 +     * @return the same value x
   1.436 +     */
   1.437 +    static long identity(long x) {
   1.438 +        return x;
   1.439 +    }
   1.440 +
   1.441 +    static float identity(float x) {
   1.442 +        return x;
   1.443 +    }
   1.444 +
   1.445 +    static double identity(double x) {
   1.446 +        return x;
   1.447 +    }
   1.448 +
   1.449 +    /**
   1.450 +     * Identity function, with reference cast.
   1.451 +     * @param t an arbitrary reference type
   1.452 +     * @param x an arbitrary reference value
   1.453 +     * @return the same value x
   1.454 +     */
   1.455 +    @SuppressWarnings("unchecked")
   1.456 +    static <T,U> T castReference(Class<? extends T> t, U x) {
   1.457 +        // inlined Class.cast because we can't ForceInline it
   1.458 +        if (x != null && !t.isInstance(x))
   1.459 +            throw newClassCastException(t, x);
   1.460 +        return (T) x;
   1.461 +    }
   1.462 +
   1.463 +    private static ClassCastException newClassCastException(Class<?> t, Object obj) {
   1.464 +        return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName());
   1.465 +    }
   1.466 +
   1.467 +    private static final MethodHandle IDENTITY, CAST_REFERENCE, ZERO_OBJECT, IGNORE, EMPTY,
   1.468 +            ARRAY_IDENTITY, FILL_NEW_TYPED_ARRAY, FILL_NEW_ARRAY;
   1.469 +    static {
   1.470 +        try {
   1.471 +            MethodType idType = MethodType.genericMethodType(1);
   1.472 +            MethodType castType = idType.insertParameterTypes(0, Class.class);
   1.473 +            MethodType ignoreType = idType.changeReturnType(void.class);
   1.474 +            MethodType zeroObjectType = MethodType.genericMethodType(0);
   1.475 +            IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", idType);
   1.476 +            //CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
   1.477 +            CAST_REFERENCE = IMPL_LOOKUP.findStatic(THIS_CLASS, "castReference", castType);
   1.478 +            ZERO_OBJECT = IMPL_LOOKUP.findStatic(THIS_CLASS, "zeroObject", zeroObjectType);
   1.479 +            IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType);
   1.480 +            EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1));
   1.481 +            ARRAY_IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", MethodType.methodType(Object[].class, Object[].class));
   1.482 +            FILL_NEW_ARRAY = IMPL_LOOKUP
   1.483 +                    .findStatic(THIS_CLASS, "fillNewArray",
   1.484 +                          MethodType.methodType(Object[].class, Integer.class, Object[].class));
   1.485 +            FILL_NEW_TYPED_ARRAY = IMPL_LOOKUP
   1.486 +                    .findStatic(THIS_CLASS, "fillNewTypedArray",
   1.487 +                          MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
   1.488 +        } catch (NoSuchMethodException | IllegalAccessException ex) {
   1.489 +            throw newInternalError("uncaught exception", ex);
   1.490 +        }
   1.491 +    }
   1.492 +
   1.493 +    // Varargs methods need to be in a separately initialized class, to avoid bootstrapping problems.
   1.494 +    static class LazyStatics {
   1.495 +        private static final MethodHandle COPY_AS_REFERENCE_ARRAY, COPY_AS_PRIMITIVE_ARRAY, MAKE_LIST;
   1.496 +        static {
   1.497 +            try {
   1.498 +                //MAKE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeArray", MethodType.methodType(Object[].class, Object[].class));
   1.499 +                COPY_AS_REFERENCE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsReferenceArray", MethodType.methodType(Object[].class, Class.class, Object[].class));
   1.500 +                COPY_AS_PRIMITIVE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsPrimitiveArray", MethodType.methodType(Object.class, Wrapper.class, Object[].class));
   1.501 +                MAKE_LIST = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeList", MethodType.methodType(List.class, Object[].class));
   1.502 +            } catch (ReflectiveOperationException ex) {
   1.503 +                throw newInternalError("uncaught exception", ex);
   1.504 +            }
   1.505 +        }
   1.506 +    }
   1.507 +
   1.508 +    private static final EnumMap<Wrapper, MethodHandle>[] WRAPPER_CASTS
   1.509 +            = newWrapperCaches(1);
   1.510 +
   1.511 +    /** Return a method that casts its sole argument (an Object) to the given type
   1.512 +     *  and returns it as the given type.
   1.513 +     */
   1.514 +    public static MethodHandle cast(Class<?> type) {
   1.515 +        if (type.isPrimitive())  throw new IllegalArgumentException("cannot cast primitive type "+type);
   1.516 +        MethodHandle mh;
   1.517 +        Wrapper wrap = null;
   1.518 +        EnumMap<Wrapper, MethodHandle> cache = null;
   1.519 +        if (Wrapper.isWrapperType(type)) {
   1.520 +            wrap = Wrapper.forWrapperType(type);
   1.521 +            cache = WRAPPER_CASTS[0];
   1.522 +            mh = cache.get(wrap);
   1.523 +            if (mh != null)  return mh;
   1.524 +        }
   1.525 +        mh = MethodHandles.insertArguments(CAST_REFERENCE, 0, type);
   1.526 +        if (cache != null)
   1.527 +            cache.put(wrap, mh);
   1.528 +        return mh;
   1.529 +    }
   1.530 +
   1.531 +    public static MethodHandle identity() {
   1.532 +        return IDENTITY;
   1.533 +    }
   1.534 +
   1.535 +    public static MethodHandle identity(Class<?> type) {
   1.536 +        if (!type.isPrimitive())
   1.537 +            // Reference identity has been moved into MethodHandles:
   1.538 +            return MethodHandles.identity(type);
   1.539 +        return identity(Wrapper.findPrimitiveType(type));
   1.540 +    }
   1.541 +
   1.542 +    public static MethodHandle identity(Wrapper wrap) {
   1.543 +        EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[1];
   1.544 +        MethodHandle mh = cache.get(wrap);
   1.545 +        if (mh != null) {
   1.546 +            return mh;
   1.547 +        }
   1.548 +        // slow path
   1.549 +        MethodType type = MethodType.methodType(wrap.primitiveType());
   1.550 +        if (wrap != Wrapper.VOID)
   1.551 +            type = type.appendParameterTypes(wrap.primitiveType());
   1.552 +        try {
   1.553 +            mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", type);
   1.554 +        } catch (ReflectiveOperationException ex) {
   1.555 +            mh = null;
   1.556 +        }
   1.557 +        if (mh == null && wrap == Wrapper.VOID) {
   1.558 +            mh = EMPTY;  // #(){} : #()void
   1.559 +        }
   1.560 +        if (mh != null) {
   1.561 +            cache.put(wrap, mh);
   1.562 +            return mh;
   1.563 +        }
   1.564 +
   1.565 +        if (mh != null) {
   1.566 +            cache.put(wrap, mh);
   1.567 +            return mh;
   1.568 +        }
   1.569 +        throw new IllegalArgumentException("cannot find identity for " + wrap);
   1.570 +    }
   1.571 +
   1.572 +    /// Primitive conversions.
   1.573 +    // These are supported directly by the JVM, usually by a single instruction.
   1.574 +    // In the case of narrowing to a subword, there may be a pair of instructions.
   1.575 +    // In the case of booleans, there may be a helper routine to manage a 1-bit value.
   1.576 +    // This is the full 8x8 matrix (minus the diagonal).
   1.577 +
   1.578 +    // narrow double to all other types:
   1.579 +    static float doubleToFloat(double x) {  // bytecode: d2f
   1.580 +        return (float) x;
   1.581 +    }
   1.582 +    static long doubleToLong(double x) {  // bytecode: d2l
   1.583 +        return (long) x;
   1.584 +    }
   1.585 +    static int doubleToInt(double x) {  // bytecode: d2i
   1.586 +        return (int) x;
   1.587 +    }
   1.588 +    static short doubleToShort(double x) {  // bytecodes: d2i, i2s
   1.589 +        return (short) x;
   1.590 +    }
   1.591 +    static char doubleToChar(double x) {  // bytecodes: d2i, i2c
   1.592 +        return (char) x;
   1.593 +    }
   1.594 +    static byte doubleToByte(double x) {  // bytecodes: d2i, i2b
   1.595 +        return (byte) x;
   1.596 +    }
   1.597 +    static boolean doubleToBoolean(double x) {
   1.598 +        return toBoolean((byte) x);
   1.599 +    }
   1.600 +
   1.601 +    // widen float:
   1.602 +    static double floatToDouble(float x) {  // bytecode: f2d
   1.603 +        return x;
   1.604 +    }
   1.605 +    // narrow float:
   1.606 +    static long floatToLong(float x) {  // bytecode: f2l
   1.607 +        return (long) x;
   1.608 +    }
   1.609 +    static int floatToInt(float x) {  // bytecode: f2i
   1.610 +        return (int) x;
   1.611 +    }
   1.612 +    static short floatToShort(float x) {  // bytecodes: f2i, i2s
   1.613 +        return (short) x;
   1.614 +    }
   1.615 +    static char floatToChar(float x) {  // bytecodes: f2i, i2c
   1.616 +        return (char) x;
   1.617 +    }
   1.618 +    static byte floatToByte(float x) {  // bytecodes: f2i, i2b
   1.619 +        return (byte) x;
   1.620 +    }
   1.621 +    static boolean floatToBoolean(float x) {
   1.622 +        return toBoolean((byte) x);
   1.623 +    }
   1.624 +
   1.625 +    // widen long:
   1.626 +    static double longToDouble(long x) {  // bytecode: l2d
   1.627 +        return x;
   1.628 +    }
   1.629 +    static float longToFloat(long x) {  // bytecode: l2f
   1.630 +        return x;
   1.631 +    }
   1.632 +    // narrow long:
   1.633 +    static int longToInt(long x) {  // bytecode: l2i
   1.634 +        return (int) x;
   1.635 +    }
   1.636 +    static short longToShort(long x) {  // bytecodes: f2i, i2s
   1.637 +        return (short) x;
   1.638 +    }
   1.639 +    static char longToChar(long x) {  // bytecodes: f2i, i2c
   1.640 +        return (char) x;
   1.641 +    }
   1.642 +    static byte longToByte(long x) {  // bytecodes: f2i, i2b
   1.643 +        return (byte) x;
   1.644 +    }
   1.645 +    static boolean longToBoolean(long x) {
   1.646 +        return toBoolean((byte) x);
   1.647 +    }
   1.648 +
   1.649 +    // widen int:
   1.650 +    static double intToDouble(int x) {  // bytecode: i2d
   1.651 +        return x;
   1.652 +    }
   1.653 +    static float intToFloat(int x) {  // bytecode: i2f
   1.654 +        return x;
   1.655 +    }
   1.656 +    static long intToLong(int x) {  // bytecode: i2l
   1.657 +        return x;
   1.658 +    }
   1.659 +    // narrow int:
   1.660 +    static short intToShort(int x) {  // bytecode: i2s
   1.661 +        return (short) x;
   1.662 +    }
   1.663 +    static char intToChar(int x) {  // bytecode: i2c
   1.664 +        return (char) x;
   1.665 +    }
   1.666 +    static byte intToByte(int x) {  // bytecode: i2b
   1.667 +        return (byte) x;
   1.668 +    }
   1.669 +    static boolean intToBoolean(int x) {
   1.670 +        return toBoolean((byte) x);
   1.671 +    }
   1.672 +
   1.673 +    // widen short:
   1.674 +    static double shortToDouble(short x) {  // bytecode: i2d (implicit 's2i')
   1.675 +        return x;
   1.676 +    }
   1.677 +    static float shortToFloat(short x) {  // bytecode: i2f (implicit 's2i')
   1.678 +        return x;
   1.679 +    }
   1.680 +    static long shortToLong(short x) {  // bytecode: i2l (implicit 's2i')
   1.681 +        return x;
   1.682 +    }
   1.683 +    static int shortToInt(short x) {  // (implicit 's2i')
   1.684 +        return x;
   1.685 +    }
   1.686 +    // narrow short:
   1.687 +    static char shortToChar(short x) {  // bytecode: i2c (implicit 's2i')
   1.688 +        return (char)x;
   1.689 +    }
   1.690 +    static byte shortToByte(short x) {  // bytecode: i2b (implicit 's2i')
   1.691 +        return (byte)x;
   1.692 +    }
   1.693 +    static boolean shortToBoolean(short x) {
   1.694 +        return toBoolean((byte) x);
   1.695 +    }
   1.696 +
   1.697 +    // widen char:
   1.698 +    static double charToDouble(char x) {  // bytecode: i2d (implicit 'c2i')
   1.699 +        return x;
   1.700 +    }
   1.701 +    static float charToFloat(char x) {  // bytecode: i2f (implicit 'c2i')
   1.702 +        return x;
   1.703 +    }
   1.704 +    static long charToLong(char x) {  // bytecode: i2l (implicit 'c2i')
   1.705 +        return x;
   1.706 +    }
   1.707 +    static int charToInt(char x) {  // (implicit 'c2i')
   1.708 +        return x;
   1.709 +    }
   1.710 +    // narrow char:
   1.711 +    static short charToShort(char x) {  // bytecode: i2s (implicit 'c2i')
   1.712 +        return (short)x;
   1.713 +    }
   1.714 +    static byte charToByte(char x) {  // bytecode: i2b (implicit 'c2i')
   1.715 +        return (byte)x;
   1.716 +    }
   1.717 +    static boolean charToBoolean(char x) {
   1.718 +        return toBoolean((byte) x);
   1.719 +    }
   1.720 +
   1.721 +    // widen byte:
   1.722 +    static double byteToDouble(byte x) {  // bytecode: i2d (implicit 'b2i')
   1.723 +        return x;
   1.724 +    }
   1.725 +    static float byteToFloat(byte x) {  // bytecode: i2f (implicit 'b2i')
   1.726 +        return x;
   1.727 +    }
   1.728 +    static long byteToLong(byte x) {  // bytecode: i2l (implicit 'b2i')
   1.729 +        return x;
   1.730 +    }
   1.731 +    static int byteToInt(byte x) {  // (implicit 'b2i')
   1.732 +        return x;
   1.733 +    }
   1.734 +    static short byteToShort(byte x) {  // bytecode: i2s (implicit 'b2i')
   1.735 +        return (short)x;
   1.736 +    }
   1.737 +    static char byteToChar(byte x) {  // bytecode: i2b (implicit 'b2i')
   1.738 +        return (char)x;
   1.739 +    }
   1.740 +    // narrow byte to boolean:
   1.741 +    static boolean byteToBoolean(byte x) {
   1.742 +        return toBoolean(x);
   1.743 +    }
   1.744 +
   1.745 +    // widen boolean to all types:
   1.746 +    static double booleanToDouble(boolean x) {
   1.747 +        return fromBoolean(x);
   1.748 +    }
   1.749 +    static float booleanToFloat(boolean x) {
   1.750 +        return fromBoolean(x);
   1.751 +    }
   1.752 +    static long booleanToLong(boolean x) {
   1.753 +        return fromBoolean(x);
   1.754 +    }
   1.755 +    static int booleanToInt(boolean x) {
   1.756 +        return fromBoolean(x);
   1.757 +    }
   1.758 +    static short booleanToShort(boolean x) {
   1.759 +        return fromBoolean(x);
   1.760 +    }
   1.761 +    static char booleanToChar(boolean x) {
   1.762 +        return (char)fromBoolean(x);
   1.763 +    }
   1.764 +    static byte booleanToByte(boolean x) {
   1.765 +        return fromBoolean(x);
   1.766 +    }
   1.767 +
   1.768 +    // helpers to force boolean into the conversion scheme:
   1.769 +    static boolean toBoolean(byte x) {
   1.770 +        // see javadoc for MethodHandles.explicitCastArguments
   1.771 +        return ((x & 1) != 0);
   1.772 +    }
   1.773 +    static byte fromBoolean(boolean x) {
   1.774 +        // see javadoc for MethodHandles.explicitCastArguments
   1.775 +        return (x ? (byte)1 : (byte)0);
   1.776 +    }
   1.777 +
   1.778 +    private static final EnumMap<Wrapper, MethodHandle>[]
   1.779 +            CONVERT_PRIMITIVE_FUNCTIONS = newWrapperCaches(Wrapper.values().length);
   1.780 +
   1.781 +    public static MethodHandle convertPrimitive(Wrapper wsrc, Wrapper wdst) {
   1.782 +        EnumMap<Wrapper, MethodHandle> cache = CONVERT_PRIMITIVE_FUNCTIONS[wsrc.ordinal()];
   1.783 +        MethodHandle mh = cache.get(wdst);
   1.784 +        if (mh != null) {
   1.785 +            return mh;
   1.786 +        }
   1.787 +        // slow path
   1.788 +        Class<?> src = wsrc.primitiveType();
   1.789 +        Class<?> dst = wdst.primitiveType();
   1.790 +        MethodType type = src == void.class ? MethodType.methodType(dst) : MethodType.methodType(dst, src);
   1.791 +        if (wsrc == wdst) {
   1.792 +            mh = identity(src);
   1.793 +        } else if (wsrc == Wrapper.VOID) {
   1.794 +            mh = zeroConstantFunction(wdst);
   1.795 +        } else if (wdst == Wrapper.VOID) {
   1.796 +            mh = MethodHandles.dropArguments(EMPTY, 0, src);  // Defer back to MethodHandles.
   1.797 +        } else if (wsrc == Wrapper.OBJECT) {
   1.798 +            mh = unboxCast(dst);
   1.799 +        } else if (wdst == Wrapper.OBJECT) {
   1.800 +            mh = box(src);
   1.801 +        } else {
   1.802 +            assert(src.isPrimitive() && dst.isPrimitive());
   1.803 +            try {
   1.804 +                mh = IMPL_LOOKUP.findStatic(THIS_CLASS, src.getSimpleName()+"To"+capitalize(dst.getSimpleName()), type);
   1.805 +            } catch (ReflectiveOperationException ex) {
   1.806 +                mh = null;
   1.807 +            }
   1.808 +        }
   1.809 +        if (mh != null) {
   1.810 +            assert(mh.type() == type) : mh;
   1.811 +            cache.put(wdst, mh);
   1.812 +            return mh;
   1.813 +        }
   1.814 +
   1.815 +        throw new IllegalArgumentException("cannot find primitive conversion function for " +
   1.816 +                                           src.getSimpleName()+" -> "+dst.getSimpleName());
   1.817 +    }
   1.818 +
   1.819 +    public static MethodHandle convertPrimitive(Class<?> src, Class<?> dst) {
   1.820 +        return convertPrimitive(Wrapper.forPrimitiveType(src), Wrapper.forPrimitiveType(dst));
   1.821 +    }
   1.822 +
   1.823 +    private static String capitalize(String x) {
   1.824 +        return Character.toUpperCase(x.charAt(0))+x.substring(1);
   1.825 +    }
   1.826 +
   1.827 +    /// Collection of multiple arguments.
   1.828 +
   1.829 +    public static Object convertArrayElements(Class<?> arrayType, Object array) {
   1.830 +        Class<?> src = array.getClass().getComponentType();
   1.831 +        Class<?> dst = arrayType.getComponentType();
   1.832 +        if (src == null || dst == null)  throw new IllegalArgumentException("not array type");
   1.833 +        Wrapper sw = (src.isPrimitive() ? Wrapper.forPrimitiveType(src) : null);
   1.834 +        Wrapper dw = (dst.isPrimitive() ? Wrapper.forPrimitiveType(dst) : null);
   1.835 +        int length;
   1.836 +        if (sw == null) {
   1.837 +            Object[] a = (Object[]) array;
   1.838 +            length = a.length;
   1.839 +            if (dw == null)
   1.840 +                return Arrays.copyOf(a, length, arrayType.asSubclass(Object[].class));
   1.841 +            Object res = dw.makeArray(length);
   1.842 +            dw.copyArrayUnboxing(a, 0, res, 0, length);
   1.843 +            return res;
   1.844 +        }
   1.845 +        length = java.lang.reflect.Array.getLength(array);
   1.846 +        Object[] res;
   1.847 +        if (dw == null) {
   1.848 +            res = Arrays.copyOf(NO_ARGS_ARRAY, length, arrayType.asSubclass(Object[].class));
   1.849 +        } else {
   1.850 +            res = new Object[length];
   1.851 +        }
   1.852 +        sw.copyArrayBoxing(array, 0, res, 0, length);
   1.853 +        if (dw == null)  return res;
   1.854 +        Object a = dw.makeArray(length);
   1.855 +        dw.copyArrayUnboxing(res, 0, a, 0, length);
   1.856 +        return a;
   1.857 +    }
   1.858 +
   1.859 +    private static MethodHandle findCollector(String name, int nargs, Class<?> rtype, Class<?>... ptypes) {
   1.860 +        MethodType type = MethodType.genericMethodType(nargs)
   1.861 +                .changeReturnType(rtype)
   1.862 +                .insertParameterTypes(0, ptypes);
   1.863 +        try {
   1.864 +            return IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
   1.865 +        } catch (ReflectiveOperationException ex) {
   1.866 +            return null;
   1.867 +        }
   1.868 +    }
   1.869 +
   1.870 +    private static final Object[] NO_ARGS_ARRAY = {};
   1.871 +    private static Object[] makeArray(Object... args) { return args; }
   1.872 +    private static Object[] array() { return NO_ARGS_ARRAY; }
   1.873 +    private static Object[] array(Object a0)
   1.874 +                { return makeArray(a0); }
   1.875 +    private static Object[] array(Object a0, Object a1)
   1.876 +                { return makeArray(a0, a1); }
   1.877 +    private static Object[] array(Object a0, Object a1, Object a2)
   1.878 +                { return makeArray(a0, a1, a2); }
   1.879 +    private static Object[] array(Object a0, Object a1, Object a2, Object a3)
   1.880 +                { return makeArray(a0, a1, a2, a3); }
   1.881 +    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
   1.882 +                                  Object a4)
   1.883 +                { return makeArray(a0, a1, a2, a3, a4); }
   1.884 +    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
   1.885 +                                  Object a4, Object a5)
   1.886 +                { return makeArray(a0, a1, a2, a3, a4, a5); }
   1.887 +    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
   1.888 +                                  Object a4, Object a5, Object a6)
   1.889 +                { return makeArray(a0, a1, a2, a3, a4, a5, a6); }
   1.890 +    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
   1.891 +                                  Object a4, Object a5, Object a6, Object a7)
   1.892 +                { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); }
   1.893 +    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
   1.894 +                                  Object a4, Object a5, Object a6, Object a7,
   1.895 +                                  Object a8)
   1.896 +                { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
   1.897 +    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
   1.898 +                                  Object a4, Object a5, Object a6, Object a7,
   1.899 +                                  Object a8, Object a9)
   1.900 +                { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
   1.901 +    private static MethodHandle[] makeArrays() {
   1.902 +        ArrayList<MethodHandle> mhs = new ArrayList<>();
   1.903 +        for (;;) {
   1.904 +            MethodHandle mh = findCollector("array", mhs.size(), Object[].class);
   1.905 +            if (mh == null)  break;
   1.906 +            mhs.add(mh);
   1.907 +        }
   1.908 +        assert(mhs.size() == 11);  // current number of methods
   1.909 +        return mhs.toArray(new MethodHandle[MAX_ARITY+1]);
   1.910 +    }
   1.911 +    private static final MethodHandle[] ARRAYS = makeArrays();
   1.912 +
   1.913 +    // filling versions of the above:
   1.914 +    // using Integer len instead of int len and no varargs to avoid bootstrapping problems
   1.915 +    private static Object[] fillNewArray(Integer len, Object[] /*not ...*/ args) {
   1.916 +        Object[] a = new Object[len];
   1.917 +        fillWithArguments(a, 0, args);
   1.918 +        return a;
   1.919 +    }
   1.920 +    private static Object[] fillNewTypedArray(Object[] example, Integer len, Object[] /*not ...*/ args) {
   1.921 +        Object[] a = Arrays.copyOf(example, len);
   1.922 +        fillWithArguments(a, 0, args);
   1.923 +        return a;
   1.924 +    }
   1.925 +    private static void fillWithArguments(Object[] a, int pos, Object... args) {
   1.926 +        System.arraycopy(args, 0, a, pos, args.length);
   1.927 +    }
   1.928 +    // using Integer pos instead of int pos to avoid bootstrapping problems
   1.929 +    private static Object[] fillArray(Integer pos, Object[] a, Object a0)
   1.930 +                { fillWithArguments(a, pos, a0); return a; }
   1.931 +    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1)
   1.932 +                { fillWithArguments(a, pos, a0, a1); return a; }
   1.933 +    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2)
   1.934 +                { fillWithArguments(a, pos, a0, a1, a2); return a; }
   1.935 +    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3)
   1.936 +                { fillWithArguments(a, pos, a0, a1, a2, a3); return a; }
   1.937 +    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
   1.938 +                                  Object a4)
   1.939 +                { fillWithArguments(a, pos, a0, a1, a2, a3, a4); return a; }
   1.940 +    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
   1.941 +                                  Object a4, Object a5)
   1.942 +                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5); return a; }
   1.943 +    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
   1.944 +                                  Object a4, Object a5, Object a6)
   1.945 +                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6); return a; }
   1.946 +    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
   1.947 +                                  Object a4, Object a5, Object a6, Object a7)
   1.948 +                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7); return a; }
   1.949 +    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
   1.950 +                                  Object a4, Object a5, Object a6, Object a7,
   1.951 +                                  Object a8)
   1.952 +                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8); return a; }
   1.953 +    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
   1.954 +                                  Object a4, Object a5, Object a6, Object a7,
   1.955 +                                  Object a8, Object a9)
   1.956 +                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; }
   1.957 +    private static MethodHandle[] makeFillArrays() {
   1.958 +        ArrayList<MethodHandle> mhs = new ArrayList<>();
   1.959 +        mhs.add(null);  // there is no empty fill; at least a0 is required
   1.960 +        for (;;) {
   1.961 +            MethodHandle mh = findCollector("fillArray", mhs.size(), Object[].class, Integer.class, Object[].class);
   1.962 +            if (mh == null)  break;
   1.963 +            mhs.add(mh);
   1.964 +        }
   1.965 +        assert(mhs.size() == 11);  // current number of methods
   1.966 +        return mhs.toArray(new MethodHandle[0]);
   1.967 +    }
   1.968 +    private static final MethodHandle[] FILL_ARRAYS = makeFillArrays();
   1.969 +
   1.970 +    private static Object[] copyAsReferenceArray(Class<? extends Object[]> arrayType, Object... a) {
   1.971 +        return Arrays.copyOf(a, a.length, arrayType);
   1.972 +    }
   1.973 +    private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) {
   1.974 +        Object a = w.makeArray(boxes.length);
   1.975 +        w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length);
   1.976 +        return a;
   1.977 +    }
   1.978 +
   1.979 +    /** Return a method handle that takes the indicated number of Object
   1.980 +     *  arguments and returns an Object array of them, as if for varargs.
   1.981 +     */
   1.982 +    public static MethodHandle varargsArray(int nargs) {
   1.983 +        MethodHandle mh = ARRAYS[nargs];
   1.984 +        if (mh != null)  return mh;
   1.985 +        mh = findCollector("array", nargs, Object[].class);
   1.986 +        if (mh != null)  return ARRAYS[nargs] = mh;
   1.987 +        mh = buildVarargsArray(FILL_NEW_ARRAY, ARRAY_IDENTITY, nargs);
   1.988 +        assert(assertCorrectArity(mh, nargs));
   1.989 +        return ARRAYS[nargs] = mh;
   1.990 +    }
   1.991 +
   1.992 +    private static boolean assertCorrectArity(MethodHandle mh, int arity) {
   1.993 +        assert(mh.type().parameterCount() == arity) : "arity != "+arity+": "+mh;
   1.994 +        return true;
   1.995 +    }
   1.996 +
   1.997 +    private static MethodHandle buildVarargsArray(MethodHandle newArray, MethodHandle finisher, int nargs) {
   1.998 +        // Build up the result mh as a sequence of fills like this:
   1.999 +        //   finisher(fill(fill(newArrayWA(23,x1..x10),10,x11..x20),20,x21..x23))
  1.1000 +        // The various fill(_,10*I,___*[J]) are reusable.
  1.1001 +        int leftLen = Math.min(nargs, LEFT_ARGS);  // absorb some arguments immediately
  1.1002 +        int rightLen = nargs - leftLen;
  1.1003 +        MethodHandle leftCollector = newArray.bindTo(nargs);
  1.1004 +        leftCollector = leftCollector.asCollector(Object[].class, leftLen);
  1.1005 +        MethodHandle mh = finisher;
  1.1006 +        if (rightLen > 0) {
  1.1007 +            MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen);
  1.1008 +            if (mh == ARRAY_IDENTITY)
  1.1009 +                mh = rightFiller;
  1.1010 +            else
  1.1011 +                mh = MethodHandles.collectArguments(mh, 0, rightFiller);
  1.1012 +        }
  1.1013 +        if (mh == ARRAY_IDENTITY)
  1.1014 +            mh = leftCollector;
  1.1015 +        else
  1.1016 +            mh = MethodHandles.collectArguments(mh, 0, leftCollector);
  1.1017 +        return mh;
  1.1018 +    }
  1.1019 +
  1.1020 +    private static final int LEFT_ARGS = (FILL_ARRAYS.length - 1);
  1.1021 +    private static final MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1];
  1.1022 +    /** fill_array_to_right(N).invoke(a, argL..arg[N-1])
  1.1023 +     *  fills a[L]..a[N-1] with corresponding arguments,
  1.1024 +     *  and then returns a.  The value L is a global constant (LEFT_ARGS).
  1.1025 +     */
  1.1026 +    private static MethodHandle fillToRight(int nargs) {
  1.1027 +        MethodHandle filler = FILL_ARRAY_TO_RIGHT[nargs];
  1.1028 +        if (filler != null)  return filler;
  1.1029 +        filler = buildFiller(nargs);
  1.1030 +        assert(assertCorrectArity(filler, nargs - LEFT_ARGS + 1));
  1.1031 +        return FILL_ARRAY_TO_RIGHT[nargs] = filler;
  1.1032 +    }
  1.1033 +    private static MethodHandle buildFiller(int nargs) {
  1.1034 +        if (nargs <= LEFT_ARGS)
  1.1035 +            return ARRAY_IDENTITY;  // no args to fill; return the array unchanged
  1.1036 +        // we need room for both mh and a in mh.invoke(a, arg*[nargs])
  1.1037 +        final int CHUNK = LEFT_ARGS;
  1.1038 +        int rightLen = nargs % CHUNK;
  1.1039 +        int midLen = nargs - rightLen;
  1.1040 +        if (rightLen == 0) {
  1.1041 +            midLen = nargs - (rightLen = CHUNK);
  1.1042 +            if (FILL_ARRAY_TO_RIGHT[midLen] == null) {
  1.1043 +                // build some precursors from left to right
  1.1044 +                for (int j = LEFT_ARGS % CHUNK; j < midLen; j += CHUNK)
  1.1045 +                    if (j > LEFT_ARGS)  fillToRight(j);
  1.1046 +            }
  1.1047 +        }
  1.1048 +        if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS);
  1.1049 +        assert(rightLen > 0);
  1.1050 +        MethodHandle midFill = fillToRight(midLen);  // recursive fill
  1.1051 +        MethodHandle rightFill = FILL_ARRAYS[rightLen].bindTo(midLen);  // [midLen..nargs-1]
  1.1052 +        assert(midFill.type().parameterCount()   == 1 + midLen - LEFT_ARGS);
  1.1053 +        assert(rightFill.type().parameterCount() == 1 + rightLen);
  1.1054 +
  1.1055 +        // Combine the two fills:
  1.1056 +        //   right(mid(a, x10..x19), x20..x23)
  1.1057 +        // The final product will look like this:
  1.1058 +        //   right(mid(newArrayLeft(24, x0..x9), x10..x19), x20..x23)
  1.1059 +        if (midLen == LEFT_ARGS)
  1.1060 +            return rightFill;
  1.1061 +        else
  1.1062 +            return MethodHandles.collectArguments(rightFill, 0, midFill);
  1.1063 +    }
  1.1064 +
  1.1065 +    // Type-polymorphic version of varargs maker.
  1.1066 +    private static final ClassValue<MethodHandle[]> TYPED_COLLECTORS
  1.1067 +        = new ClassValue<MethodHandle[]>() {
  1.1068 +            @Override
  1.1069 +            protected MethodHandle[] computeValue(Class<?> type) {
  1.1070 +                return new MethodHandle[256];
  1.1071 +            }
  1.1072 +    };
  1.1073 +
  1.1074 +    static final int MAX_JVM_ARITY = 255;  // limit imposed by the JVM
  1.1075 +
  1.1076 +    /** Return a method handle that takes the indicated number of
  1.1077 +     *  typed arguments and returns an array of them.
  1.1078 +     *  The type argument is the array type.
  1.1079 +     */
  1.1080 +    public static MethodHandle varargsArray(Class<?> arrayType, int nargs) {
  1.1081 +        Class<?> elemType = arrayType.getComponentType();
  1.1082 +        if (elemType == null)  throw new IllegalArgumentException("not an array: "+arrayType);
  1.1083 +        // FIXME: Need more special casing and caching here.
  1.1084 +        if (nargs >= MAX_JVM_ARITY/2 - 1) {
  1.1085 +            int slots = nargs;
  1.1086 +            final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1;  // 1 for receiver MH
  1.1087 +            if (arrayType == double[].class || arrayType == long[].class)
  1.1088 +                slots *= 2;
  1.1089 +            if (slots > MAX_ARRAY_SLOTS)
  1.1090 +                throw new IllegalArgumentException("too many arguments: "+arrayType.getSimpleName()+", length "+nargs);
  1.1091 +        }
  1.1092 +        if (elemType == Object.class)
  1.1093 +            return varargsArray(nargs);
  1.1094 +        // other cases:  primitive arrays, subtypes of Object[]
  1.1095 +        MethodHandle cache[] = TYPED_COLLECTORS.get(elemType);
  1.1096 +        MethodHandle mh = nargs < cache.length ? cache[nargs] : null;
  1.1097 +        if (mh != null)  return mh;
  1.1098 +        if (elemType.isPrimitive()) {
  1.1099 +            MethodHandle builder = FILL_NEW_ARRAY;
  1.1100 +            MethodHandle producer = buildArrayProducer(arrayType);
  1.1101 +            mh = buildVarargsArray(builder, producer, nargs);
  1.1102 +        } else {
  1.1103 +            @SuppressWarnings("unchecked")
  1.1104 +            Class<? extends Object[]> objArrayType = (Class<? extends Object[]>) arrayType;
  1.1105 +            Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType);
  1.1106 +            MethodHandle builder = FILL_NEW_TYPED_ARRAY.bindTo(example);
  1.1107 +            MethodHandle producer = ARRAY_IDENTITY;
  1.1108 +            mh = buildVarargsArray(builder, producer, nargs);
  1.1109 +        }
  1.1110 +        mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
  1.1111 +        assert(assertCorrectArity(mh, nargs));
  1.1112 +        if (nargs < cache.length)
  1.1113 +            cache[nargs] = mh;
  1.1114 +        return mh;
  1.1115 +    }
  1.1116 +
  1.1117 +    private static MethodHandle buildArrayProducer(Class<?> arrayType) {
  1.1118 +        Class<?> elemType = arrayType.getComponentType();
  1.1119 +        if (elemType.isPrimitive())
  1.1120 +            return LazyStatics.COPY_AS_PRIMITIVE_ARRAY.bindTo(Wrapper.forPrimitiveType(elemType));
  1.1121 +        else
  1.1122 +            return LazyStatics.COPY_AS_REFERENCE_ARRAY.bindTo(arrayType);
  1.1123 +    }
  1.1124 +
  1.1125 +    // List version of varargs maker.
  1.1126 +
  1.1127 +    private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY);
  1.1128 +    private static List<Object> makeList(Object... args) { return Arrays.asList(args); }
  1.1129 +    private static List<Object> list() { return NO_ARGS_LIST; }
  1.1130 +    private static List<Object> list(Object a0)
  1.1131 +                { return makeList(a0); }
  1.1132 +    private static List<Object> list(Object a0, Object a1)
  1.1133 +                { return makeList(a0, a1); }
  1.1134 +    private static List<Object> list(Object a0, Object a1, Object a2)
  1.1135 +                { return makeList(a0, a1, a2); }
  1.1136 +    private static List<Object> list(Object a0, Object a1, Object a2, Object a3)
  1.1137 +                { return makeList(a0, a1, a2, a3); }
  1.1138 +    private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
  1.1139 +                                     Object a4)
  1.1140 +                { return makeList(a0, a1, a2, a3, a4); }
  1.1141 +    private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
  1.1142 +                                     Object a4, Object a5)
  1.1143 +                { return makeList(a0, a1, a2, a3, a4, a5); }
  1.1144 +    private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
  1.1145 +                                     Object a4, Object a5, Object a6)
  1.1146 +                { return makeList(a0, a1, a2, a3, a4, a5, a6); }
  1.1147 +    private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
  1.1148 +                                     Object a4, Object a5, Object a6, Object a7)
  1.1149 +                { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); }
  1.1150 +    private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
  1.1151 +                                     Object a4, Object a5, Object a6, Object a7,
  1.1152 +                                     Object a8)
  1.1153 +                { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
  1.1154 +    private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
  1.1155 +                                     Object a4, Object a5, Object a6, Object a7,
  1.1156 +                                     Object a8, Object a9)
  1.1157 +                { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
  1.1158 +    private static MethodHandle[] makeLists() {
  1.1159 +        ArrayList<MethodHandle> mhs = new ArrayList<>();
  1.1160 +        for (;;) {
  1.1161 +            MethodHandle mh = findCollector("list", mhs.size(), List.class);
  1.1162 +            if (mh == null)  break;
  1.1163 +            mhs.add(mh);
  1.1164 +        }
  1.1165 +        assert(mhs.size() == 11);  // current number of methods
  1.1166 +        return mhs.toArray(new MethodHandle[MAX_ARITY+1]);
  1.1167 +    }
  1.1168 +    private static final MethodHandle[] LISTS = makeLists();
  1.1169 +
  1.1170 +    /** Return a method handle that takes the indicated number of Object
  1.1171 +     *  arguments and returns a List.
  1.1172 +     */
  1.1173 +    public static MethodHandle varargsList(int nargs) {
  1.1174 +        MethodHandle mh = LISTS[nargs];
  1.1175 +        if (mh != null)  return mh;
  1.1176 +        mh = findCollector("list", nargs, List.class);
  1.1177 +        if (mh != null)  return LISTS[nargs] = mh;
  1.1178 +        return LISTS[nargs] = buildVarargsList(nargs);
  1.1179 +    }
  1.1180 +    private static MethodHandle buildVarargsList(int nargs) {
  1.1181 +        return MethodHandles.filterReturnValue(varargsArray(nargs), LazyStatics.MAKE_LIST);
  1.1182 +    }
  1.1183 +
  1.1184 +    // handy shared exception makers (they simplify the common case code)
  1.1185 +    private static InternalError newInternalError(String message, Throwable cause) {
  1.1186 +        return new InternalError(message, cause);
  1.1187 +    }
  1.1188 +    private static InternalError newInternalError(Throwable cause) {
  1.1189 +        return new InternalError(cause);
  1.1190 +    }
  1.1191 +}