rt/emul/compact/src/main/java/sun/invoke/util/ValueConversions.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 09 Aug 2014 11:11:13 +0200
branchjdk8-b132
changeset 1646 c880a8a8803b
permissions -rw-r--r--
Batch of classes necessary to implement invoke dynamic interfaces. Taken from JDK8 build 132
     1 /*
     2  * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    25 
    26 package sun.invoke.util;
    27 
    28 import java.lang.invoke.MethodHandle;
    29 import java.lang.invoke.MethodHandles;
    30 import java.lang.invoke.MethodHandles.Lookup;
    31 import java.lang.invoke.MethodType;
    32 import java.security.AccessController;
    33 import java.security.PrivilegedAction;
    34 import java.util.ArrayList;
    35 import java.util.Arrays;
    36 import java.util.Collections;
    37 import java.util.EnumMap;
    38 import java.util.List;
    39 
    40 public class ValueConversions {
    41     private static final Class<?> THIS_CLASS = ValueConversions.class;
    42     // Do not adjust this except for special platforms:
    43     private static final int MAX_ARITY;
    44     static {
    45         final Object[] values = { 255 };
    46         AccessController.doPrivileged(new PrivilegedAction<Void>() {
    47                 @Override
    48                 public Void run() {
    49                     values[0] = Integer.getInteger(THIS_CLASS.getName()+".MAX_ARITY", 255);
    50                     return null;
    51                 }
    52             });
    53         MAX_ARITY = (Integer) values[0];
    54     }
    55 
    56     private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
    57 
    58     private static EnumMap<Wrapper, MethodHandle>[] newWrapperCaches(int n) {
    59         @SuppressWarnings("unchecked")  // generic array creation
    60         EnumMap<Wrapper, MethodHandle>[] caches
    61                 = (EnumMap<Wrapper, MethodHandle>[]) new EnumMap<?,?>[n];
    62         for (int i = 0; i < n; i++)
    63             caches[i] = new EnumMap<>(Wrapper.class);
    64         return caches;
    65     }
    66 
    67     /// Converting references to values.
    68 
    69     // There are several levels of this unboxing conversions:
    70     //   no conversions:  exactly Integer.valueOf, etc.
    71     //   implicit conversions sanctioned by JLS 5.1.2, etc.
    72     //   explicit conversions as allowed by explicitCastArguments
    73 
    74     static int unboxInteger(Object x, boolean cast) {
    75         if (x instanceof Integer)
    76             return ((Integer) x).intValue();
    77         return primitiveConversion(Wrapper.INT, x, cast).intValue();
    78     }
    79 
    80     static byte unboxByte(Object x, boolean cast) {
    81         if (x instanceof Byte)
    82             return ((Byte) x).byteValue();
    83         return primitiveConversion(Wrapper.BYTE, x, cast).byteValue();
    84     }
    85 
    86     static short unboxShort(Object x, boolean cast) {
    87         if (x instanceof Short)
    88             return ((Short) x).shortValue();
    89         return primitiveConversion(Wrapper.SHORT, x, cast).shortValue();
    90     }
    91 
    92     static boolean unboxBoolean(Object x, boolean cast) {
    93         if (x instanceof Boolean)
    94             return ((Boolean) x).booleanValue();
    95         return (primitiveConversion(Wrapper.BOOLEAN, x, cast).intValue() & 1) != 0;
    96     }
    97 
    98     static char unboxCharacter(Object x, boolean cast) {
    99         if (x instanceof Character)
   100             return ((Character) x).charValue();
   101         return (char) primitiveConversion(Wrapper.CHAR, x, cast).intValue();
   102     }
   103 
   104     static long unboxLong(Object x, boolean cast) {
   105         if (x instanceof Long)
   106             return ((Long) x).longValue();
   107         return primitiveConversion(Wrapper.LONG, x, cast).longValue();
   108     }
   109 
   110     static float unboxFloat(Object x, boolean cast) {
   111         if (x instanceof Float)
   112             return ((Float) x).floatValue();
   113         return primitiveConversion(Wrapper.FLOAT, x, cast).floatValue();
   114     }
   115 
   116     static double unboxDouble(Object x, boolean cast) {
   117         if (x instanceof Double)
   118             return ((Double) x).doubleValue();
   119         return primitiveConversion(Wrapper.DOUBLE, x, cast).doubleValue();
   120     }
   121 
   122     private static MethodType unboxType(Wrapper wrap) {
   123         return MethodType.methodType(wrap.primitiveType(), Object.class, boolean.class);
   124     }
   125 
   126     private static final EnumMap<Wrapper, MethodHandle>[]
   127             UNBOX_CONVERSIONS = newWrapperCaches(2);
   128 
   129     private static MethodHandle unbox(Wrapper wrap, boolean cast) {
   130         EnumMap<Wrapper, MethodHandle> cache = UNBOX_CONVERSIONS[(cast?1:0)];
   131         MethodHandle mh = cache.get(wrap);
   132         if (mh != null) {
   133             return mh;
   134         }
   135         // slow path
   136         switch (wrap) {
   137             case OBJECT:
   138                 mh = IDENTITY; break;
   139             case VOID:
   140                 mh = IGNORE; break;
   141         }
   142         if (mh != null) {
   143             cache.put(wrap, mh);
   144             return mh;
   145         }
   146         // look up the method
   147         String name = "unbox" + wrap.wrapperSimpleName();
   148         MethodType type = unboxType(wrap);
   149         try {
   150             mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
   151         } catch (ReflectiveOperationException ex) {
   152             mh = null;
   153         }
   154         if (mh != null) {
   155             mh = MethodHandles.insertArguments(mh, 1, cast);
   156             cache.put(wrap, mh);
   157             return mh;
   158         }
   159         throw new IllegalArgumentException("cannot find unbox adapter for " + wrap
   160                 + (cast ? " (cast)" : ""));
   161     }
   162 
   163     public static MethodHandle unboxCast(Wrapper type) {
   164         return unbox(type, true);
   165     }
   166 
   167     public static MethodHandle unbox(Class<?> type) {
   168         return unbox(Wrapper.forPrimitiveType(type), false);
   169     }
   170 
   171     public static MethodHandle unboxCast(Class<?> type) {
   172         return unbox(Wrapper.forPrimitiveType(type), true);
   173     }
   174 
   175     static private final Integer ZERO_INT = 0, ONE_INT = 1;
   176 
   177     /// Primitive conversions
   178     /**
   179      * Produce a Number which represents the given value {@code x}
   180      * according to the primitive type of the given wrapper {@code wrap}.
   181      * Caller must invoke intValue, byteValue, longValue (etc.) on the result
   182      * to retrieve the desired primitive value.
   183      */
   184     public static Number primitiveConversion(Wrapper wrap, Object x, boolean cast) {
   185         // Maybe merge this code with Wrapper.convert/cast.
   186         Number res;
   187         if (x == null) {
   188             if (!cast)  return null;
   189             return ZERO_INT;
   190         }
   191         if (x instanceof Number) {
   192             res = (Number) x;
   193         } else if (x instanceof Boolean) {
   194             res = ((boolean)x ? ONE_INT : ZERO_INT);
   195         } else if (x instanceof Character) {
   196             res = (int)(char)x;
   197         } else {
   198             // this will fail with the required ClassCastException:
   199             res = (Number) x;
   200         }
   201         Wrapper xwrap = Wrapper.findWrapperType(x.getClass());
   202         if (xwrap == null || !cast && !wrap.isConvertibleFrom(xwrap))
   203             // this will fail with the required ClassCastException:
   204             return (Number) wrap.wrapperType().cast(x);
   205         return res;
   206     }
   207 
   208     /**
   209      * The JVM verifier allows boolean, byte, short, or char to widen to int.
   210      * Support exactly this conversion, from a boxed value type Boolean,
   211      * Byte, Short, Character, or Integer.
   212      */
   213     public static int widenSubword(Object x) {
   214         if (x instanceof Integer)
   215             return (int) x;
   216         else if (x instanceof Boolean)
   217             return fromBoolean((boolean) x);
   218         else if (x instanceof Character)
   219             return (char) x;
   220         else if (x instanceof Short)
   221             return (short) x;
   222         else if (x instanceof Byte)
   223             return (byte) x;
   224         else
   225             // Fail with a ClassCastException.
   226             return (int) x;
   227     }
   228 
   229     /// Converting primitives to references
   230 
   231     static Integer boxInteger(int x) {
   232         return x;
   233     }
   234 
   235     static Byte boxByte(byte x) {
   236         return x;
   237     }
   238 
   239     static Short boxShort(short x) {
   240         return x;
   241     }
   242 
   243     static Boolean boxBoolean(boolean x) {
   244         return x;
   245     }
   246 
   247     static Character boxCharacter(char x) {
   248         return x;
   249     }
   250 
   251     static Long boxLong(long x) {
   252         return x;
   253     }
   254 
   255     static Float boxFloat(float x) {
   256         return x;
   257     }
   258 
   259     static Double boxDouble(double x) {
   260         return x;
   261     }
   262 
   263     private static MethodType boxType(Wrapper wrap) {
   264         // be exact, since return casts are hard to compose
   265         Class<?> boxType = wrap.wrapperType();
   266         return MethodType.methodType(boxType, wrap.primitiveType());
   267     }
   268 
   269     private static final EnumMap<Wrapper, MethodHandle>[]
   270             BOX_CONVERSIONS = newWrapperCaches(2);
   271 
   272     private static MethodHandle box(Wrapper wrap, boolean exact) {
   273         EnumMap<Wrapper, MethodHandle> cache = BOX_CONVERSIONS[(exact?1:0)];
   274         MethodHandle mh = cache.get(wrap);
   275         if (mh != null) {
   276             return mh;
   277         }
   278         // slow path
   279         switch (wrap) {
   280             case OBJECT:
   281                 mh = IDENTITY; break;
   282             case VOID:
   283                 mh = ZERO_OBJECT;
   284                 break;
   285         }
   286         if (mh != null) {
   287             cache.put(wrap, mh);
   288             return mh;
   289         }
   290         // look up the method
   291         String name = "box" + wrap.wrapperSimpleName();
   292         MethodType type = boxType(wrap);
   293         if (exact) {
   294             try {
   295                 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
   296             } catch (ReflectiveOperationException ex) {
   297                 mh = null;
   298             }
   299         } else {
   300             mh = box(wrap, !exact).asType(type.erase());
   301         }
   302         if (mh != null) {
   303             cache.put(wrap, mh);
   304             return mh;
   305         }
   306         throw new IllegalArgumentException("cannot find box adapter for "
   307                 + wrap + (exact ? " (exact)" : ""));
   308     }
   309 
   310     public static MethodHandle box(Class<?> type) {
   311         boolean exact = false;
   312         // e.g., boxShort(short)Short if exact,
   313         // e.g., boxShort(short)Object if !exact
   314         return box(Wrapper.forPrimitiveType(type), exact);
   315     }
   316 
   317     public static MethodHandle box(Wrapper type) {
   318         boolean exact = false;
   319         return box(type, exact);
   320     }
   321 
   322     /// Constant functions
   323 
   324     static void ignore(Object x) {
   325         // no value to return; this is an unbox of null
   326     }
   327 
   328     static void empty() {
   329     }
   330 
   331     static Object zeroObject() {
   332         return null;
   333     }
   334 
   335     static int zeroInteger() {
   336         return 0;
   337     }
   338 
   339     static long zeroLong() {
   340         return 0;
   341     }
   342 
   343     static float zeroFloat() {
   344         return 0;
   345     }
   346 
   347     static double zeroDouble() {
   348         return 0;
   349     }
   350 
   351     private static final EnumMap<Wrapper, MethodHandle>[]
   352             CONSTANT_FUNCTIONS = newWrapperCaches(2);
   353 
   354     public static MethodHandle zeroConstantFunction(Wrapper wrap) {
   355         EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[0];
   356         MethodHandle mh = cache.get(wrap);
   357         if (mh != null) {
   358             return mh;
   359         }
   360         // slow path
   361         MethodType type = MethodType.methodType(wrap.primitiveType());
   362         switch (wrap) {
   363             case VOID:
   364                 mh = EMPTY;
   365                 break;
   366             case OBJECT:
   367             case INT: case LONG: case FLOAT: case DOUBLE:
   368                 try {
   369                     mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "zero"+wrap.wrapperSimpleName(), type);
   370                 } catch (ReflectiveOperationException ex) {
   371                     mh = null;
   372                 }
   373                 break;
   374         }
   375         if (mh != null) {
   376             cache.put(wrap, mh);
   377             return mh;
   378         }
   379 
   380         // use zeroInt and cast the result
   381         if (wrap.isSubwordOrInt() && wrap != Wrapper.INT) {
   382             mh = MethodHandles.explicitCastArguments(zeroConstantFunction(Wrapper.INT), type);
   383             cache.put(wrap, mh);
   384             return mh;
   385         }
   386         throw new IllegalArgumentException("cannot find zero constant for " + wrap);
   387     }
   388 
   389     /// Converting references to references.
   390 
   391     /**
   392      * Identity function.
   393      * @param x an arbitrary reference value
   394      * @return the same value x
   395      */
   396     static <T> T identity(T x) {
   397         return x;
   398     }
   399 
   400     static <T> T[] identity(T[] x) {
   401         return x;
   402     }
   403 
   404     /**
   405      * Identity function on ints.
   406      * @param x an arbitrary int value
   407      * @return the same value x
   408      */
   409     static int identity(int x) {
   410         return x;
   411     }
   412 
   413     static byte identity(byte x) {
   414         return x;
   415     }
   416 
   417     static short identity(short x) {
   418         return x;
   419     }
   420 
   421     static boolean identity(boolean x) {
   422         return x;
   423     }
   424 
   425     static char identity(char x) {
   426         return x;
   427     }
   428 
   429     /**
   430      * Identity function on longs.
   431      * @param x an arbitrary long value
   432      * @return the same value x
   433      */
   434     static long identity(long x) {
   435         return x;
   436     }
   437 
   438     static float identity(float x) {
   439         return x;
   440     }
   441 
   442     static double identity(double x) {
   443         return x;
   444     }
   445 
   446     /**
   447      * Identity function, with reference cast.
   448      * @param t an arbitrary reference type
   449      * @param x an arbitrary reference value
   450      * @return the same value x
   451      */
   452     @SuppressWarnings("unchecked")
   453     static <T,U> T castReference(Class<? extends T> t, U x) {
   454         // inlined Class.cast because we can't ForceInline it
   455         if (x != null && !t.isInstance(x))
   456             throw newClassCastException(t, x);
   457         return (T) x;
   458     }
   459 
   460     private static ClassCastException newClassCastException(Class<?> t, Object obj) {
   461         return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName());
   462     }
   463 
   464     private static final MethodHandle IDENTITY, CAST_REFERENCE, ZERO_OBJECT, IGNORE, EMPTY,
   465             ARRAY_IDENTITY, FILL_NEW_TYPED_ARRAY, FILL_NEW_ARRAY;
   466     static {
   467         try {
   468             MethodType idType = MethodType.genericMethodType(1);
   469             MethodType castType = idType.insertParameterTypes(0, Class.class);
   470             MethodType ignoreType = idType.changeReturnType(void.class);
   471             MethodType zeroObjectType = MethodType.genericMethodType(0);
   472             IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", idType);
   473             //CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
   474             CAST_REFERENCE = IMPL_LOOKUP.findStatic(THIS_CLASS, "castReference", castType);
   475             ZERO_OBJECT = IMPL_LOOKUP.findStatic(THIS_CLASS, "zeroObject", zeroObjectType);
   476             IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType);
   477             EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1));
   478             ARRAY_IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", MethodType.methodType(Object[].class, Object[].class));
   479             FILL_NEW_ARRAY = IMPL_LOOKUP
   480                     .findStatic(THIS_CLASS, "fillNewArray",
   481                           MethodType.methodType(Object[].class, Integer.class, Object[].class));
   482             FILL_NEW_TYPED_ARRAY = IMPL_LOOKUP
   483                     .findStatic(THIS_CLASS, "fillNewTypedArray",
   484                           MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
   485         } catch (NoSuchMethodException | IllegalAccessException ex) {
   486             throw newInternalError("uncaught exception", ex);
   487         }
   488     }
   489 
   490     // Varargs methods need to be in a separately initialized class, to avoid bootstrapping problems.
   491     static class LazyStatics {
   492         private static final MethodHandle COPY_AS_REFERENCE_ARRAY, COPY_AS_PRIMITIVE_ARRAY, MAKE_LIST;
   493         static {
   494             try {
   495                 //MAKE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeArray", MethodType.methodType(Object[].class, Object[].class));
   496                 COPY_AS_REFERENCE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsReferenceArray", MethodType.methodType(Object[].class, Class.class, Object[].class));
   497                 COPY_AS_PRIMITIVE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsPrimitiveArray", MethodType.methodType(Object.class, Wrapper.class, Object[].class));
   498                 MAKE_LIST = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeList", MethodType.methodType(List.class, Object[].class));
   499             } catch (ReflectiveOperationException ex) {
   500                 throw newInternalError("uncaught exception", ex);
   501             }
   502         }
   503     }
   504 
   505     private static final EnumMap<Wrapper, MethodHandle>[] WRAPPER_CASTS
   506             = newWrapperCaches(1);
   507 
   508     /** Return a method that casts its sole argument (an Object) to the given type
   509      *  and returns it as the given type.
   510      */
   511     public static MethodHandle cast(Class<?> type) {
   512         if (type.isPrimitive())  throw new IllegalArgumentException("cannot cast primitive type "+type);
   513         MethodHandle mh;
   514         Wrapper wrap = null;
   515         EnumMap<Wrapper, MethodHandle> cache = null;
   516         if (Wrapper.isWrapperType(type)) {
   517             wrap = Wrapper.forWrapperType(type);
   518             cache = WRAPPER_CASTS[0];
   519             mh = cache.get(wrap);
   520             if (mh != null)  return mh;
   521         }
   522         mh = MethodHandles.insertArguments(CAST_REFERENCE, 0, type);
   523         if (cache != null)
   524             cache.put(wrap, mh);
   525         return mh;
   526     }
   527 
   528     public static MethodHandle identity() {
   529         return IDENTITY;
   530     }
   531 
   532     public static MethodHandle identity(Class<?> type) {
   533         if (!type.isPrimitive())
   534             // Reference identity has been moved into MethodHandles:
   535             return MethodHandles.identity(type);
   536         return identity(Wrapper.findPrimitiveType(type));
   537     }
   538 
   539     public static MethodHandle identity(Wrapper wrap) {
   540         EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[1];
   541         MethodHandle mh = cache.get(wrap);
   542         if (mh != null) {
   543             return mh;
   544         }
   545         // slow path
   546         MethodType type = MethodType.methodType(wrap.primitiveType());
   547         if (wrap != Wrapper.VOID)
   548             type = type.appendParameterTypes(wrap.primitiveType());
   549         try {
   550             mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", type);
   551         } catch (ReflectiveOperationException ex) {
   552             mh = null;
   553         }
   554         if (mh == null && wrap == Wrapper.VOID) {
   555             mh = EMPTY;  // #(){} : #()void
   556         }
   557         if (mh != null) {
   558             cache.put(wrap, mh);
   559             return mh;
   560         }
   561 
   562         if (mh != null) {
   563             cache.put(wrap, mh);
   564             return mh;
   565         }
   566         throw new IllegalArgumentException("cannot find identity for " + wrap);
   567     }
   568 
   569     /// Primitive conversions.
   570     // These are supported directly by the JVM, usually by a single instruction.
   571     // In the case of narrowing to a subword, there may be a pair of instructions.
   572     // In the case of booleans, there may be a helper routine to manage a 1-bit value.
   573     // This is the full 8x8 matrix (minus the diagonal).
   574 
   575     // narrow double to all other types:
   576     static float doubleToFloat(double x) {  // bytecode: d2f
   577         return (float) x;
   578     }
   579     static long doubleToLong(double x) {  // bytecode: d2l
   580         return (long) x;
   581     }
   582     static int doubleToInt(double x) {  // bytecode: d2i
   583         return (int) x;
   584     }
   585     static short doubleToShort(double x) {  // bytecodes: d2i, i2s
   586         return (short) x;
   587     }
   588     static char doubleToChar(double x) {  // bytecodes: d2i, i2c
   589         return (char) x;
   590     }
   591     static byte doubleToByte(double x) {  // bytecodes: d2i, i2b
   592         return (byte) x;
   593     }
   594     static boolean doubleToBoolean(double x) {
   595         return toBoolean((byte) x);
   596     }
   597 
   598     // widen float:
   599     static double floatToDouble(float x) {  // bytecode: f2d
   600         return x;
   601     }
   602     // narrow float:
   603     static long floatToLong(float x) {  // bytecode: f2l
   604         return (long) x;
   605     }
   606     static int floatToInt(float x) {  // bytecode: f2i
   607         return (int) x;
   608     }
   609     static short floatToShort(float x) {  // bytecodes: f2i, i2s
   610         return (short) x;
   611     }
   612     static char floatToChar(float x) {  // bytecodes: f2i, i2c
   613         return (char) x;
   614     }
   615     static byte floatToByte(float x) {  // bytecodes: f2i, i2b
   616         return (byte) x;
   617     }
   618     static boolean floatToBoolean(float x) {
   619         return toBoolean((byte) x);
   620     }
   621 
   622     // widen long:
   623     static double longToDouble(long x) {  // bytecode: l2d
   624         return x;
   625     }
   626     static float longToFloat(long x) {  // bytecode: l2f
   627         return x;
   628     }
   629     // narrow long:
   630     static int longToInt(long x) {  // bytecode: l2i
   631         return (int) x;
   632     }
   633     static short longToShort(long x) {  // bytecodes: f2i, i2s
   634         return (short) x;
   635     }
   636     static char longToChar(long x) {  // bytecodes: f2i, i2c
   637         return (char) x;
   638     }
   639     static byte longToByte(long x) {  // bytecodes: f2i, i2b
   640         return (byte) x;
   641     }
   642     static boolean longToBoolean(long x) {
   643         return toBoolean((byte) x);
   644     }
   645 
   646     // widen int:
   647     static double intToDouble(int x) {  // bytecode: i2d
   648         return x;
   649     }
   650     static float intToFloat(int x) {  // bytecode: i2f
   651         return x;
   652     }
   653     static long intToLong(int x) {  // bytecode: i2l
   654         return x;
   655     }
   656     // narrow int:
   657     static short intToShort(int x) {  // bytecode: i2s
   658         return (short) x;
   659     }
   660     static char intToChar(int x) {  // bytecode: i2c
   661         return (char) x;
   662     }
   663     static byte intToByte(int x) {  // bytecode: i2b
   664         return (byte) x;
   665     }
   666     static boolean intToBoolean(int x) {
   667         return toBoolean((byte) x);
   668     }
   669 
   670     // widen short:
   671     static double shortToDouble(short x) {  // bytecode: i2d (implicit 's2i')
   672         return x;
   673     }
   674     static float shortToFloat(short x) {  // bytecode: i2f (implicit 's2i')
   675         return x;
   676     }
   677     static long shortToLong(short x) {  // bytecode: i2l (implicit 's2i')
   678         return x;
   679     }
   680     static int shortToInt(short x) {  // (implicit 's2i')
   681         return x;
   682     }
   683     // narrow short:
   684     static char shortToChar(short x) {  // bytecode: i2c (implicit 's2i')
   685         return (char)x;
   686     }
   687     static byte shortToByte(short x) {  // bytecode: i2b (implicit 's2i')
   688         return (byte)x;
   689     }
   690     static boolean shortToBoolean(short x) {
   691         return toBoolean((byte) x);
   692     }
   693 
   694     // widen char:
   695     static double charToDouble(char x) {  // bytecode: i2d (implicit 'c2i')
   696         return x;
   697     }
   698     static float charToFloat(char x) {  // bytecode: i2f (implicit 'c2i')
   699         return x;
   700     }
   701     static long charToLong(char x) {  // bytecode: i2l (implicit 'c2i')
   702         return x;
   703     }
   704     static int charToInt(char x) {  // (implicit 'c2i')
   705         return x;
   706     }
   707     // narrow char:
   708     static short charToShort(char x) {  // bytecode: i2s (implicit 'c2i')
   709         return (short)x;
   710     }
   711     static byte charToByte(char x) {  // bytecode: i2b (implicit 'c2i')
   712         return (byte)x;
   713     }
   714     static boolean charToBoolean(char x) {
   715         return toBoolean((byte) x);
   716     }
   717 
   718     // widen byte:
   719     static double byteToDouble(byte x) {  // bytecode: i2d (implicit 'b2i')
   720         return x;
   721     }
   722     static float byteToFloat(byte x) {  // bytecode: i2f (implicit 'b2i')
   723         return x;
   724     }
   725     static long byteToLong(byte x) {  // bytecode: i2l (implicit 'b2i')
   726         return x;
   727     }
   728     static int byteToInt(byte x) {  // (implicit 'b2i')
   729         return x;
   730     }
   731     static short byteToShort(byte x) {  // bytecode: i2s (implicit 'b2i')
   732         return (short)x;
   733     }
   734     static char byteToChar(byte x) {  // bytecode: i2b (implicit 'b2i')
   735         return (char)x;
   736     }
   737     // narrow byte to boolean:
   738     static boolean byteToBoolean(byte x) {
   739         return toBoolean(x);
   740     }
   741 
   742     // widen boolean to all types:
   743     static double booleanToDouble(boolean x) {
   744         return fromBoolean(x);
   745     }
   746     static float booleanToFloat(boolean x) {
   747         return fromBoolean(x);
   748     }
   749     static long booleanToLong(boolean x) {
   750         return fromBoolean(x);
   751     }
   752     static int booleanToInt(boolean x) {
   753         return fromBoolean(x);
   754     }
   755     static short booleanToShort(boolean x) {
   756         return fromBoolean(x);
   757     }
   758     static char booleanToChar(boolean x) {
   759         return (char)fromBoolean(x);
   760     }
   761     static byte booleanToByte(boolean x) {
   762         return fromBoolean(x);
   763     }
   764 
   765     // helpers to force boolean into the conversion scheme:
   766     static boolean toBoolean(byte x) {
   767         // see javadoc for MethodHandles.explicitCastArguments
   768         return ((x & 1) != 0);
   769     }
   770     static byte fromBoolean(boolean x) {
   771         // see javadoc for MethodHandles.explicitCastArguments
   772         return (x ? (byte)1 : (byte)0);
   773     }
   774 
   775     private static final EnumMap<Wrapper, MethodHandle>[]
   776             CONVERT_PRIMITIVE_FUNCTIONS = newWrapperCaches(Wrapper.values().length);
   777 
   778     public static MethodHandle convertPrimitive(Wrapper wsrc, Wrapper wdst) {
   779         EnumMap<Wrapper, MethodHandle> cache = CONVERT_PRIMITIVE_FUNCTIONS[wsrc.ordinal()];
   780         MethodHandle mh = cache.get(wdst);
   781         if (mh != null) {
   782             return mh;
   783         }
   784         // slow path
   785         Class<?> src = wsrc.primitiveType();
   786         Class<?> dst = wdst.primitiveType();
   787         MethodType type = src == void.class ? MethodType.methodType(dst) : MethodType.methodType(dst, src);
   788         if (wsrc == wdst) {
   789             mh = identity(src);
   790         } else if (wsrc == Wrapper.VOID) {
   791             mh = zeroConstantFunction(wdst);
   792         } else if (wdst == Wrapper.VOID) {
   793             mh = MethodHandles.dropArguments(EMPTY, 0, src);  // Defer back to MethodHandles.
   794         } else if (wsrc == Wrapper.OBJECT) {
   795             mh = unboxCast(dst);
   796         } else if (wdst == Wrapper.OBJECT) {
   797             mh = box(src);
   798         } else {
   799             assert(src.isPrimitive() && dst.isPrimitive());
   800             try {
   801                 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, src.getSimpleName()+"To"+capitalize(dst.getSimpleName()), type);
   802             } catch (ReflectiveOperationException ex) {
   803                 mh = null;
   804             }
   805         }
   806         if (mh != null) {
   807             assert(mh.type() == type) : mh;
   808             cache.put(wdst, mh);
   809             return mh;
   810         }
   811 
   812         throw new IllegalArgumentException("cannot find primitive conversion function for " +
   813                                            src.getSimpleName()+" -> "+dst.getSimpleName());
   814     }
   815 
   816     public static MethodHandle convertPrimitive(Class<?> src, Class<?> dst) {
   817         return convertPrimitive(Wrapper.forPrimitiveType(src), Wrapper.forPrimitiveType(dst));
   818     }
   819 
   820     private static String capitalize(String x) {
   821         return Character.toUpperCase(x.charAt(0))+x.substring(1);
   822     }
   823 
   824     /// Collection of multiple arguments.
   825 
   826     public static Object convertArrayElements(Class<?> arrayType, Object array) {
   827         Class<?> src = array.getClass().getComponentType();
   828         Class<?> dst = arrayType.getComponentType();
   829         if (src == null || dst == null)  throw new IllegalArgumentException("not array type");
   830         Wrapper sw = (src.isPrimitive() ? Wrapper.forPrimitiveType(src) : null);
   831         Wrapper dw = (dst.isPrimitive() ? Wrapper.forPrimitiveType(dst) : null);
   832         int length;
   833         if (sw == null) {
   834             Object[] a = (Object[]) array;
   835             length = a.length;
   836             if (dw == null)
   837                 return Arrays.copyOf(a, length, arrayType.asSubclass(Object[].class));
   838             Object res = dw.makeArray(length);
   839             dw.copyArrayUnboxing(a, 0, res, 0, length);
   840             return res;
   841         }
   842         length = java.lang.reflect.Array.getLength(array);
   843         Object[] res;
   844         if (dw == null) {
   845             res = Arrays.copyOf(NO_ARGS_ARRAY, length, arrayType.asSubclass(Object[].class));
   846         } else {
   847             res = new Object[length];
   848         }
   849         sw.copyArrayBoxing(array, 0, res, 0, length);
   850         if (dw == null)  return res;
   851         Object a = dw.makeArray(length);
   852         dw.copyArrayUnboxing(res, 0, a, 0, length);
   853         return a;
   854     }
   855 
   856     private static MethodHandle findCollector(String name, int nargs, Class<?> rtype, Class<?>... ptypes) {
   857         MethodType type = MethodType.genericMethodType(nargs)
   858                 .changeReturnType(rtype)
   859                 .insertParameterTypes(0, ptypes);
   860         try {
   861             return IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
   862         } catch (ReflectiveOperationException ex) {
   863             return null;
   864         }
   865     }
   866 
   867     private static final Object[] NO_ARGS_ARRAY = {};
   868     private static Object[] makeArray(Object... args) { return args; }
   869     private static Object[] array() { return NO_ARGS_ARRAY; }
   870     private static Object[] array(Object a0)
   871                 { return makeArray(a0); }
   872     private static Object[] array(Object a0, Object a1)
   873                 { return makeArray(a0, a1); }
   874     private static Object[] array(Object a0, Object a1, Object a2)
   875                 { return makeArray(a0, a1, a2); }
   876     private static Object[] array(Object a0, Object a1, Object a2, Object a3)
   877                 { return makeArray(a0, a1, a2, a3); }
   878     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
   879                                   Object a4)
   880                 { return makeArray(a0, a1, a2, a3, a4); }
   881     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
   882                                   Object a4, Object a5)
   883                 { return makeArray(a0, a1, a2, a3, a4, a5); }
   884     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
   885                                   Object a4, Object a5, Object a6)
   886                 { return makeArray(a0, a1, a2, a3, a4, a5, a6); }
   887     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
   888                                   Object a4, Object a5, Object a6, Object a7)
   889                 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); }
   890     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
   891                                   Object a4, Object a5, Object a6, Object a7,
   892                                   Object a8)
   893                 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
   894     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
   895                                   Object a4, Object a5, Object a6, Object a7,
   896                                   Object a8, Object a9)
   897                 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
   898     private static MethodHandle[] makeArrays() {
   899         ArrayList<MethodHandle> mhs = new ArrayList<>();
   900         for (;;) {
   901             MethodHandle mh = findCollector("array", mhs.size(), Object[].class);
   902             if (mh == null)  break;
   903             mhs.add(mh);
   904         }
   905         assert(mhs.size() == 11);  // current number of methods
   906         return mhs.toArray(new MethodHandle[MAX_ARITY+1]);
   907     }
   908     private static final MethodHandle[] ARRAYS = makeArrays();
   909 
   910     // filling versions of the above:
   911     // using Integer len instead of int len and no varargs to avoid bootstrapping problems
   912     private static Object[] fillNewArray(Integer len, Object[] /*not ...*/ args) {
   913         Object[] a = new Object[len];
   914         fillWithArguments(a, 0, args);
   915         return a;
   916     }
   917     private static Object[] fillNewTypedArray(Object[] example, Integer len, Object[] /*not ...*/ args) {
   918         Object[] a = Arrays.copyOf(example, len);
   919         fillWithArguments(a, 0, args);
   920         return a;
   921     }
   922     private static void fillWithArguments(Object[] a, int pos, Object... args) {
   923         System.arraycopy(args, 0, a, pos, args.length);
   924     }
   925     // using Integer pos instead of int pos to avoid bootstrapping problems
   926     private static Object[] fillArray(Integer pos, Object[] a, Object a0)
   927                 { fillWithArguments(a, pos, a0); return a; }
   928     private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1)
   929                 { fillWithArguments(a, pos, a0, a1); return a; }
   930     private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2)
   931                 { fillWithArguments(a, pos, a0, a1, a2); return a; }
   932     private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3)
   933                 { fillWithArguments(a, pos, a0, a1, a2, a3); return a; }
   934     private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
   935                                   Object a4)
   936                 { fillWithArguments(a, pos, a0, a1, a2, a3, a4); return a; }
   937     private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
   938                                   Object a4, Object a5)
   939                 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5); return a; }
   940     private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
   941                                   Object a4, Object a5, Object a6)
   942                 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6); return a; }
   943     private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
   944                                   Object a4, Object a5, Object a6, Object a7)
   945                 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7); return a; }
   946     private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
   947                                   Object a4, Object a5, Object a6, Object a7,
   948                                   Object a8)
   949                 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8); return a; }
   950     private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
   951                                   Object a4, Object a5, Object a6, Object a7,
   952                                   Object a8, Object a9)
   953                 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; }
   954     private static MethodHandle[] makeFillArrays() {
   955         ArrayList<MethodHandle> mhs = new ArrayList<>();
   956         mhs.add(null);  // there is no empty fill; at least a0 is required
   957         for (;;) {
   958             MethodHandle mh = findCollector("fillArray", mhs.size(), Object[].class, Integer.class, Object[].class);
   959             if (mh == null)  break;
   960             mhs.add(mh);
   961         }
   962         assert(mhs.size() == 11);  // current number of methods
   963         return mhs.toArray(new MethodHandle[0]);
   964     }
   965     private static final MethodHandle[] FILL_ARRAYS = makeFillArrays();
   966 
   967     private static Object[] copyAsReferenceArray(Class<? extends Object[]> arrayType, Object... a) {
   968         return Arrays.copyOf(a, a.length, arrayType);
   969     }
   970     private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) {
   971         Object a = w.makeArray(boxes.length);
   972         w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length);
   973         return a;
   974     }
   975 
   976     /** Return a method handle that takes the indicated number of Object
   977      *  arguments and returns an Object array of them, as if for varargs.
   978      */
   979     public static MethodHandle varargsArray(int nargs) {
   980         MethodHandle mh = ARRAYS[nargs];
   981         if (mh != null)  return mh;
   982         mh = findCollector("array", nargs, Object[].class);
   983         if (mh != null)  return ARRAYS[nargs] = mh;
   984         mh = buildVarargsArray(FILL_NEW_ARRAY, ARRAY_IDENTITY, nargs);
   985         assert(assertCorrectArity(mh, nargs));
   986         return ARRAYS[nargs] = mh;
   987     }
   988 
   989     private static boolean assertCorrectArity(MethodHandle mh, int arity) {
   990         assert(mh.type().parameterCount() == arity) : "arity != "+arity+": "+mh;
   991         return true;
   992     }
   993 
   994     private static MethodHandle buildVarargsArray(MethodHandle newArray, MethodHandle finisher, int nargs) {
   995         // Build up the result mh as a sequence of fills like this:
   996         //   finisher(fill(fill(newArrayWA(23,x1..x10),10,x11..x20),20,x21..x23))
   997         // The various fill(_,10*I,___*[J]) are reusable.
   998         int leftLen = Math.min(nargs, LEFT_ARGS);  // absorb some arguments immediately
   999         int rightLen = nargs - leftLen;
  1000         MethodHandle leftCollector = newArray.bindTo(nargs);
  1001         leftCollector = leftCollector.asCollector(Object[].class, leftLen);
  1002         MethodHandle mh = finisher;
  1003         if (rightLen > 0) {
  1004             MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen);
  1005             if (mh == ARRAY_IDENTITY)
  1006                 mh = rightFiller;
  1007             else
  1008                 mh = MethodHandles.collectArguments(mh, 0, rightFiller);
  1009         }
  1010         if (mh == ARRAY_IDENTITY)
  1011             mh = leftCollector;
  1012         else
  1013             mh = MethodHandles.collectArguments(mh, 0, leftCollector);
  1014         return mh;
  1015     }
  1016 
  1017     private static final int LEFT_ARGS = (FILL_ARRAYS.length - 1);
  1018     private static final MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1];
  1019     /** fill_array_to_right(N).invoke(a, argL..arg[N-1])
  1020      *  fills a[L]..a[N-1] with corresponding arguments,
  1021      *  and then returns a.  The value L is a global constant (LEFT_ARGS).
  1022      */
  1023     private static MethodHandle fillToRight(int nargs) {
  1024         MethodHandle filler = FILL_ARRAY_TO_RIGHT[nargs];
  1025         if (filler != null)  return filler;
  1026         filler = buildFiller(nargs);
  1027         assert(assertCorrectArity(filler, nargs - LEFT_ARGS + 1));
  1028         return FILL_ARRAY_TO_RIGHT[nargs] = filler;
  1029     }
  1030     private static MethodHandle buildFiller(int nargs) {
  1031         if (nargs <= LEFT_ARGS)
  1032             return ARRAY_IDENTITY;  // no args to fill; return the array unchanged
  1033         // we need room for both mh and a in mh.invoke(a, arg*[nargs])
  1034         final int CHUNK = LEFT_ARGS;
  1035         int rightLen = nargs % CHUNK;
  1036         int midLen = nargs - rightLen;
  1037         if (rightLen == 0) {
  1038             midLen = nargs - (rightLen = CHUNK);
  1039             if (FILL_ARRAY_TO_RIGHT[midLen] == null) {
  1040                 // build some precursors from left to right
  1041                 for (int j = LEFT_ARGS % CHUNK; j < midLen; j += CHUNK)
  1042                     if (j > LEFT_ARGS)  fillToRight(j);
  1043             }
  1044         }
  1045         if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS);
  1046         assert(rightLen > 0);
  1047         MethodHandle midFill = fillToRight(midLen);  // recursive fill
  1048         MethodHandle rightFill = FILL_ARRAYS[rightLen].bindTo(midLen);  // [midLen..nargs-1]
  1049         assert(midFill.type().parameterCount()   == 1 + midLen - LEFT_ARGS);
  1050         assert(rightFill.type().parameterCount() == 1 + rightLen);
  1051 
  1052         // Combine the two fills:
  1053         //   right(mid(a, x10..x19), x20..x23)
  1054         // The final product will look like this:
  1055         //   right(mid(newArrayLeft(24, x0..x9), x10..x19), x20..x23)
  1056         if (midLen == LEFT_ARGS)
  1057             return rightFill;
  1058         else
  1059             return MethodHandles.collectArguments(rightFill, 0, midFill);
  1060     }
  1061 
  1062     // Type-polymorphic version of varargs maker.
  1063     private static final ClassValue<MethodHandle[]> TYPED_COLLECTORS
  1064         = new ClassValue<MethodHandle[]>() {
  1065             @Override
  1066             protected MethodHandle[] computeValue(Class<?> type) {
  1067                 return new MethodHandle[256];
  1068             }
  1069     };
  1070 
  1071     static final int MAX_JVM_ARITY = 255;  // limit imposed by the JVM
  1072 
  1073     /** Return a method handle that takes the indicated number of
  1074      *  typed arguments and returns an array of them.
  1075      *  The type argument is the array type.
  1076      */
  1077     public static MethodHandle varargsArray(Class<?> arrayType, int nargs) {
  1078         Class<?> elemType = arrayType.getComponentType();
  1079         if (elemType == null)  throw new IllegalArgumentException("not an array: "+arrayType);
  1080         // FIXME: Need more special casing and caching here.
  1081         if (nargs >= MAX_JVM_ARITY/2 - 1) {
  1082             int slots = nargs;
  1083             final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1;  // 1 for receiver MH
  1084             if (arrayType == double[].class || arrayType == long[].class)
  1085                 slots *= 2;
  1086             if (slots > MAX_ARRAY_SLOTS)
  1087                 throw new IllegalArgumentException("too many arguments: "+arrayType.getSimpleName()+", length "+nargs);
  1088         }
  1089         if (elemType == Object.class)
  1090             return varargsArray(nargs);
  1091         // other cases:  primitive arrays, subtypes of Object[]
  1092         MethodHandle cache[] = TYPED_COLLECTORS.get(elemType);
  1093         MethodHandle mh = nargs < cache.length ? cache[nargs] : null;
  1094         if (mh != null)  return mh;
  1095         if (elemType.isPrimitive()) {
  1096             MethodHandle builder = FILL_NEW_ARRAY;
  1097             MethodHandle producer = buildArrayProducer(arrayType);
  1098             mh = buildVarargsArray(builder, producer, nargs);
  1099         } else {
  1100             @SuppressWarnings("unchecked")
  1101             Class<? extends Object[]> objArrayType = (Class<? extends Object[]>) arrayType;
  1102             Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType);
  1103             MethodHandle builder = FILL_NEW_TYPED_ARRAY.bindTo(example);
  1104             MethodHandle producer = ARRAY_IDENTITY;
  1105             mh = buildVarargsArray(builder, producer, nargs);
  1106         }
  1107         mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
  1108         assert(assertCorrectArity(mh, nargs));
  1109         if (nargs < cache.length)
  1110             cache[nargs] = mh;
  1111         return mh;
  1112     }
  1113 
  1114     private static MethodHandle buildArrayProducer(Class<?> arrayType) {
  1115         Class<?> elemType = arrayType.getComponentType();
  1116         if (elemType.isPrimitive())
  1117             return LazyStatics.COPY_AS_PRIMITIVE_ARRAY.bindTo(Wrapper.forPrimitiveType(elemType));
  1118         else
  1119             return LazyStatics.COPY_AS_REFERENCE_ARRAY.bindTo(arrayType);
  1120     }
  1121 
  1122     // List version of varargs maker.
  1123 
  1124     private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY);
  1125     private static List<Object> makeList(Object... args) { return Arrays.asList(args); }
  1126     private static List<Object> list() { return NO_ARGS_LIST; }
  1127     private static List<Object> list(Object a0)
  1128                 { return makeList(a0); }
  1129     private static List<Object> list(Object a0, Object a1)
  1130                 { return makeList(a0, a1); }
  1131     private static List<Object> list(Object a0, Object a1, Object a2)
  1132                 { return makeList(a0, a1, a2); }
  1133     private static List<Object> list(Object a0, Object a1, Object a2, Object a3)
  1134                 { return makeList(a0, a1, a2, a3); }
  1135     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
  1136                                      Object a4)
  1137                 { return makeList(a0, a1, a2, a3, a4); }
  1138     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
  1139                                      Object a4, Object a5)
  1140                 { return makeList(a0, a1, a2, a3, a4, a5); }
  1141     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
  1142                                      Object a4, Object a5, Object a6)
  1143                 { return makeList(a0, a1, a2, a3, a4, a5, a6); }
  1144     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
  1145                                      Object a4, Object a5, Object a6, Object a7)
  1146                 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); }
  1147     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
  1148                                      Object a4, Object a5, Object a6, Object a7,
  1149                                      Object a8)
  1150                 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
  1151     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
  1152                                      Object a4, Object a5, Object a6, Object a7,
  1153                                      Object a8, Object a9)
  1154                 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
  1155     private static MethodHandle[] makeLists() {
  1156         ArrayList<MethodHandle> mhs = new ArrayList<>();
  1157         for (;;) {
  1158             MethodHandle mh = findCollector("list", mhs.size(), List.class);
  1159             if (mh == null)  break;
  1160             mhs.add(mh);
  1161         }
  1162         assert(mhs.size() == 11);  // current number of methods
  1163         return mhs.toArray(new MethodHandle[MAX_ARITY+1]);
  1164     }
  1165     private static final MethodHandle[] LISTS = makeLists();
  1166 
  1167     /** Return a method handle that takes the indicated number of Object
  1168      *  arguments and returns a List.
  1169      */
  1170     public static MethodHandle varargsList(int nargs) {
  1171         MethodHandle mh = LISTS[nargs];
  1172         if (mh != null)  return mh;
  1173         mh = findCollector("list", nargs, List.class);
  1174         if (mh != null)  return LISTS[nargs] = mh;
  1175         return LISTS[nargs] = buildVarargsList(nargs);
  1176     }
  1177     private static MethodHandle buildVarargsList(int nargs) {
  1178         return MethodHandles.filterReturnValue(varargsArray(nargs), LazyStatics.MAKE_LIST);
  1179     }
  1180 
  1181     // handy shared exception makers (they simplify the common case code)
  1182     private static InternalError newInternalError(String message, Throwable cause) {
  1183         return new InternalError(message, cause);
  1184     }
  1185     private static InternalError newInternalError(Throwable cause) {
  1186         return new InternalError(cause);
  1187     }
  1188 }