jdk/src/share/classes/sun/invoke/util/ValueConversions.java
changeset 8822 8145ab9f5f86
parent 8821 2836ee97ee27
child 9646 5ebbe5ab084f
equal deleted inserted replaced
8821:2836ee97ee27 8822:8145ab9f5f86
       
     1 /*
       
     2  * Copyright (c) 2008, 2011, 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.util.ArrayList;
       
    33 import java.util.Arrays;
       
    34 import java.util.EnumMap;
       
    35 import java.util.List;
       
    36 
       
    37 public class ValueConversions {
       
    38     private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
       
    39 
       
    40     private static EnumMap<Wrapper, MethodHandle>[] newWrapperCaches(int n) {
       
    41         @SuppressWarnings("unchecked")
       
    42         EnumMap<Wrapper, MethodHandle>[] caches
       
    43                 = (EnumMap<Wrapper, MethodHandle>[]) new EnumMap[n];  // unchecked warning expected here
       
    44         for (int i = 0; i < n; i++)
       
    45             caches[i] = new EnumMap<Wrapper, MethodHandle>(Wrapper.class);
       
    46         return caches;
       
    47     }
       
    48 
       
    49     /// Converting references to values.
       
    50 
       
    51     static int unboxInteger(Object x) {
       
    52         if (x == null)  return 0;  // never NPE
       
    53         return ((Integer) x).intValue();
       
    54     }
       
    55 
       
    56     static byte unboxByte(Object x) {
       
    57         if (x == null)  return 0;  // never NPE
       
    58         return ((Byte) x).byteValue();
       
    59     }
       
    60 
       
    61     static short unboxShort(Object x) {
       
    62         if (x == null)  return 0;  // never NPE
       
    63         return ((Short) x).shortValue();
       
    64     }
       
    65 
       
    66     static boolean unboxBoolean(Object x) {
       
    67         if (x == null)  return false;  // never NPE
       
    68         return ((Boolean) x).booleanValue();
       
    69     }
       
    70 
       
    71     static char unboxCharacter(Object x) {
       
    72         if (x == null)  return 0;  // never NPE
       
    73         return ((Character) x).charValue();
       
    74     }
       
    75 
       
    76     static long unboxLong(Object x) {
       
    77         if (x == null)  return 0;  // never NPE
       
    78         return ((Long) x).longValue();
       
    79     }
       
    80 
       
    81     static float unboxFloat(Object x) {
       
    82         if (x == null)  return 0;  // never NPE
       
    83         return ((Float) x).floatValue();
       
    84     }
       
    85 
       
    86     static double unboxDouble(Object x) {
       
    87         if (x == null)  return 0;  // never NPE
       
    88         return ((Double) x).doubleValue();
       
    89     }
       
    90 
       
    91     /// Converting references to "raw" values.
       
    92     /// A raw primitive value is always an int or long.
       
    93 
       
    94     static int unboxByteRaw(Object x) {
       
    95         return unboxByte(x);
       
    96     }
       
    97 
       
    98     static int unboxShortRaw(Object x) {
       
    99         return unboxShort(x);
       
   100     }
       
   101 
       
   102     static int unboxBooleanRaw(Object x) {
       
   103         return unboxBoolean(x) ? 1 : 0;
       
   104     }
       
   105 
       
   106     static int unboxCharacterRaw(Object x) {
       
   107         return unboxCharacter(x);
       
   108     }
       
   109 
       
   110     static int unboxFloatRaw(Object x) {
       
   111         return Float.floatToIntBits(unboxFloat(x));
       
   112     }
       
   113 
       
   114     static long unboxDoubleRaw(Object x) {
       
   115         return Double.doubleToRawLongBits(unboxDouble(x));
       
   116     }
       
   117 
       
   118     private static MethodType unboxType(Wrapper wrap, boolean raw) {
       
   119         return MethodType.methodType(rawWrapper(wrap, raw).primitiveType(), wrap.wrapperType());
       
   120     }
       
   121 
       
   122     private static final EnumMap<Wrapper, MethodHandle>[]
       
   123             UNBOX_CONVERSIONS = newWrapperCaches(4);
       
   124 
       
   125     private static MethodHandle unbox(Wrapper wrap, boolean exact, boolean raw) {
       
   126         EnumMap<Wrapper, MethodHandle> cache = UNBOX_CONVERSIONS[(exact?1:0)+(raw?2:0)];
       
   127         MethodHandle mh = cache.get(wrap);
       
   128         if (mh != null) {
       
   129             return mh;
       
   130         }
       
   131         // slow path
       
   132         switch (wrap) {
       
   133             case OBJECT:
       
   134                 mh = IDENTITY; break;
       
   135             case VOID:
       
   136                 mh = raw ? ALWAYS_ZERO : IGNORE; break;
       
   137             case INT: case LONG:
       
   138                 // these guys don't need separate raw channels
       
   139                 if (raw)  mh = unbox(wrap, exact, false);
       
   140                 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.simpleName() + (raw ? "Raw" : "");
       
   148         MethodType type = unboxType(wrap, raw);
       
   149         if (!exact) {
       
   150             try {
       
   151                 // actually, type is wrong; the Java method takes Object
       
   152                 mh = IMPL_LOOKUP.findStatic(ValueConversions.class, name, type.erase());
       
   153             } catch (ReflectiveOperationException ex) {
       
   154                 mh = null;
       
   155             }
       
   156         } else {
       
   157             mh = unbox(wrap, !exact, raw).asType(type);
       
   158         }
       
   159         if (mh != null) {
       
   160             cache.put(wrap, mh);
       
   161             return mh;
       
   162         }
       
   163         throw new IllegalArgumentException("cannot find unbox adapter for " + wrap + (raw ? " (raw)" : ""));
       
   164     }
       
   165 
       
   166     public static MethodHandle unbox(Wrapper type, boolean exact) {
       
   167         return unbox(type, exact, false);
       
   168     }
       
   169 
       
   170     public static MethodHandle unboxRaw(Wrapper type, boolean exact) {
       
   171         return unbox(type, exact, true);
       
   172     }
       
   173 
       
   174     public static MethodHandle unbox(Class<?> type, boolean exact) {
       
   175         return unbox(Wrapper.forPrimitiveType(type), exact, false);
       
   176     }
       
   177 
       
   178     public static MethodHandle unboxRaw(Class<?> type, boolean exact) {
       
   179         return unbox(Wrapper.forPrimitiveType(type), exact, true);
       
   180     }
       
   181 
       
   182     /// Converting primitives to references
       
   183 
       
   184     static Integer boxInteger(int x) {
       
   185         return x;
       
   186     }
       
   187 
       
   188     static Byte boxByte(byte x) {
       
   189         return x;
       
   190     }
       
   191 
       
   192     static Short boxShort(short x) {
       
   193         return x;
       
   194     }
       
   195 
       
   196     static Boolean boxBoolean(boolean x) {
       
   197         return x;
       
   198     }
       
   199 
       
   200     static Character boxCharacter(char x) {
       
   201         return x;
       
   202     }
       
   203 
       
   204     static Long boxLong(long x) {
       
   205         return x;
       
   206     }
       
   207 
       
   208     static Float boxFloat(float x) {
       
   209         return x;
       
   210     }
       
   211 
       
   212     static Double boxDouble(double x) {
       
   213         return x;
       
   214     }
       
   215 
       
   216     /// Converting raw primitives to references
       
   217 
       
   218     static Byte boxByteRaw(int x) {
       
   219         return boxByte((byte)x);
       
   220     }
       
   221 
       
   222     static Short boxShortRaw(int x) {
       
   223         return boxShort((short)x);
       
   224     }
       
   225 
       
   226     static Boolean boxBooleanRaw(int x) {
       
   227         return boxBoolean(x != 0);
       
   228     }
       
   229 
       
   230     static Character boxCharacterRaw(int x) {
       
   231         return boxCharacter((char)x);
       
   232     }
       
   233 
       
   234     static Float boxFloatRaw(int x) {
       
   235         return boxFloat(Float.intBitsToFloat(x));
       
   236     }
       
   237 
       
   238     static Double boxDoubleRaw(long x) {
       
   239         return boxDouble(Double.longBitsToDouble(x));
       
   240     }
       
   241 
       
   242     // a raw void value is (arbitrarily) a garbage int
       
   243     static Void boxVoidRaw(int x) {
       
   244         return null;
       
   245     }
       
   246 
       
   247     private static MethodType boxType(Wrapper wrap, boolean raw) {
       
   248         // be exact, since return casts are hard to compose
       
   249         Class<?> boxType = wrap.wrapperType();
       
   250         return MethodType.methodType(boxType, rawWrapper(wrap, raw).primitiveType());
       
   251     }
       
   252 
       
   253     private static Wrapper rawWrapper(Wrapper wrap, boolean raw) {
       
   254         if (raw)  return wrap.isDoubleWord() ? Wrapper.LONG : Wrapper.INT;
       
   255         return wrap;
       
   256     }
       
   257 
       
   258     private static final EnumMap<Wrapper, MethodHandle>[]
       
   259             BOX_CONVERSIONS = newWrapperCaches(4);
       
   260 
       
   261     private static MethodHandle box(Wrapper wrap, boolean exact, boolean raw) {
       
   262         EnumMap<Wrapper, MethodHandle> cache = BOX_CONVERSIONS[(exact?1:0)+(raw?2:0)];
       
   263         MethodHandle mh = cache.get(wrap);
       
   264         if (mh != null) {
       
   265             return mh;
       
   266         }
       
   267         // slow path
       
   268         switch (wrap) {
       
   269             case OBJECT:
       
   270                 mh = IDENTITY; break;
       
   271             case VOID:
       
   272                 if (!raw)  mh = ZERO_OBJECT;
       
   273                 break;
       
   274             case INT: case LONG:
       
   275                 // these guys don't need separate raw channels
       
   276                 if (raw)  mh = box(wrap, exact, false);
       
   277                 break;
       
   278         }
       
   279         if (mh != null) {
       
   280             cache.put(wrap, mh);
       
   281             return mh;
       
   282         }
       
   283         // look up the method
       
   284         String name = "box" + wrap.simpleName() + (raw ? "Raw" : "");
       
   285         MethodType type = boxType(wrap, raw);
       
   286         if (exact) {
       
   287             try {
       
   288                 mh = IMPL_LOOKUP.findStatic(ValueConversions.class, name, type);
       
   289             } catch (ReflectiveOperationException ex) {
       
   290                 mh = null;
       
   291             }
       
   292         } else {
       
   293             mh = box(wrap, !exact, raw).asType(type.erase());
       
   294         }
       
   295         if (mh != null) {
       
   296             cache.put(wrap, mh);
       
   297             return mh;
       
   298         }
       
   299         throw new IllegalArgumentException("cannot find box adapter for " + wrap + (raw ? " (raw)" : ""));
       
   300     }
       
   301 
       
   302     public static MethodHandle box(Class<?> type, boolean exact) {
       
   303         return box(Wrapper.forPrimitiveType(type), exact, false);
       
   304     }
       
   305 
       
   306     public static MethodHandle boxRaw(Class<?> type, boolean exact) {
       
   307         return box(Wrapper.forPrimitiveType(type), exact, true);
       
   308     }
       
   309 
       
   310     public static MethodHandle box(Wrapper type, boolean exact) {
       
   311         return box(type, exact, false);
       
   312     }
       
   313 
       
   314     public static MethodHandle boxRaw(Wrapper type, boolean exact) {
       
   315         return box(type, exact, true);
       
   316     }
       
   317 
       
   318     /// Kludges for when raw values get accidentally boxed.
       
   319 
       
   320     static int unboxRawInteger(Object x) {
       
   321         if (x instanceof Integer)
       
   322             return unboxInteger(x);
       
   323         else
       
   324             return (int) unboxLong(x);
       
   325     }
       
   326 
       
   327     static Integer reboxRawInteger(Object x) {
       
   328         if (x instanceof Integer)
       
   329             return (Integer) x;
       
   330         else
       
   331             return (int) unboxLong(x);
       
   332     }
       
   333 
       
   334     static Byte reboxRawByte(Object x) {
       
   335         if (x instanceof Byte)  return (Byte) x;
       
   336         return boxByteRaw(unboxRawInteger(x));
       
   337     }
       
   338 
       
   339     static Short reboxRawShort(Object x) {
       
   340         if (x instanceof Short)  return (Short) x;
       
   341         return boxShortRaw(unboxRawInteger(x));
       
   342     }
       
   343 
       
   344     static Boolean reboxRawBoolean(Object x) {
       
   345         if (x instanceof Boolean)  return (Boolean) x;
       
   346         return boxBooleanRaw(unboxRawInteger(x));
       
   347     }
       
   348 
       
   349     static Character reboxRawCharacter(Object x) {
       
   350         if (x instanceof Character)  return (Character) x;
       
   351         return boxCharacterRaw(unboxRawInteger(x));
       
   352     }
       
   353 
       
   354     static Float reboxRawFloat(Object x) {
       
   355         if (x instanceof Float)  return (Float) x;
       
   356         return boxFloatRaw(unboxRawInteger(x));
       
   357     }
       
   358 
       
   359     static Long reboxRawLong(Object x) {
       
   360         return (Long) x;  //never a rebox
       
   361     }
       
   362 
       
   363     static Double reboxRawDouble(Object x) {
       
   364         if (x instanceof Double)  return (Double) x;
       
   365         return boxDoubleRaw(unboxLong(x));
       
   366     }
       
   367 
       
   368     private static MethodType reboxType(Wrapper wrap) {
       
   369         Class<?> boxType = wrap.wrapperType();
       
   370         return MethodType.methodType(boxType, Object.class);
       
   371     }
       
   372 
       
   373     private static final EnumMap<Wrapper, MethodHandle>[]
       
   374             REBOX_CONVERSIONS = newWrapperCaches(2);
       
   375 
       
   376     /**
       
   377      * Because we normalize primitive types to reduce the number of signatures,
       
   378      * primitives are sometimes manipulated under an "erased" type,
       
   379      * either int (for types other than long/double) or long (for all types).
       
   380      * When the erased primitive value is then boxed into an Integer or Long,
       
   381      * the final boxed primitive is sometimes required.  This transformation
       
   382      * is called a "rebox".  It takes an Integer or Long and produces some
       
   383      * other boxed value.
       
   384      */
       
   385     public static MethodHandle rebox(Wrapper wrap, boolean exact) {
       
   386         EnumMap<Wrapper, MethodHandle> cache = REBOX_CONVERSIONS[exact?1:0];
       
   387         MethodHandle mh = cache.get(wrap);
       
   388         if (mh != null) {
       
   389             return mh;
       
   390         }
       
   391         // slow path
       
   392         switch (wrap) {
       
   393             case OBJECT:
       
   394                 mh = IDENTITY; break;
       
   395             case VOID:
       
   396                 throw new IllegalArgumentException("cannot rebox a void");
       
   397         }
       
   398         if (mh != null) {
       
   399             cache.put(wrap, mh);
       
   400             return mh;
       
   401         }
       
   402         // look up the method
       
   403         String name = "reboxRaw" + wrap.simpleName();
       
   404         MethodType type = reboxType(wrap);
       
   405         if (exact) {
       
   406             try {
       
   407                 mh = IMPL_LOOKUP.findStatic(ValueConversions.class, name, type);
       
   408             } catch (ReflectiveOperationException ex) {
       
   409                 mh = null;
       
   410             }
       
   411         } else {
       
   412             mh = rebox(wrap, !exact).asType(IDENTITY.type());
       
   413         }
       
   414         if (mh != null) {
       
   415             cache.put(wrap, mh);
       
   416             return mh;
       
   417         }
       
   418         throw new IllegalArgumentException("cannot find rebox adapter for " + wrap);
       
   419     }
       
   420 
       
   421     public static MethodHandle rebox(Class<?> type, boolean exact) {
       
   422         return rebox(Wrapper.forPrimitiveType(type), exact);
       
   423     }
       
   424 
       
   425     /// Width-changing conversions between int and long.
       
   426 
       
   427     static long widenInt(int x) {
       
   428         return (long) x;
       
   429     }
       
   430 
       
   431     static Long widenBoxedInt(Integer x) {
       
   432         return (long)(int)x;
       
   433     }
       
   434 
       
   435     static int narrowLong(long x) {
       
   436         return (int) x;
       
   437     }
       
   438 
       
   439     static Integer narrowBoxedLong(Long x) {
       
   440         return (int)(long) x;
       
   441     }
       
   442 
       
   443     /// Constant functions
       
   444 
       
   445     static void ignore(Object x) {
       
   446         // no value to return; this is an unbox of null
       
   447         return;
       
   448     }
       
   449 
       
   450     static void empty() {
       
   451         return;
       
   452     }
       
   453 
       
   454     static Object zeroObject() {
       
   455         return null;
       
   456     }
       
   457 
       
   458     static int zeroInteger() {
       
   459         return 0;
       
   460     }
       
   461 
       
   462     static long zeroLong() {
       
   463         return 0;
       
   464     }
       
   465 
       
   466     static float zeroFloat() {
       
   467         return 0;
       
   468     }
       
   469 
       
   470     static double zeroDouble() {
       
   471         return 0;
       
   472     }
       
   473 
       
   474     private static final EnumMap<Wrapper, MethodHandle>[]
       
   475             CONSTANT_FUNCTIONS = newWrapperCaches(2);
       
   476 
       
   477     public static MethodHandle zeroConstantFunction(Wrapper wrap) {
       
   478         EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[0];
       
   479         MethodHandle mh = cache.get(wrap);
       
   480         if (mh != null) {
       
   481             return mh;
       
   482         }
       
   483         // slow path
       
   484         MethodType type = MethodType.methodType(wrap.primitiveType());
       
   485         switch (wrap) {
       
   486             case VOID:
       
   487                 mh = EMPTY;
       
   488                 break;
       
   489             case INT: case LONG: case FLOAT: case DOUBLE:
       
   490                 try {
       
   491                     mh = IMPL_LOOKUP.findStatic(ValueConversions.class, "zero"+wrap.simpleName(), type);
       
   492                 } catch (ReflectiveOperationException ex) {
       
   493                     mh = null;
       
   494                 }
       
   495                 break;
       
   496         }
       
   497         if (mh != null) {
       
   498             cache.put(wrap, mh);
       
   499             return mh;
       
   500         }
       
   501 
       
   502         // use the raw method
       
   503         Wrapper rawWrap = wrap.rawPrimitive();
       
   504         if (mh == null && rawWrap != wrap) {
       
   505             mh = MethodHandles.explicitCastArguments(zeroConstantFunction(rawWrap), type);
       
   506         }
       
   507         if (mh != null) {
       
   508             cache.put(wrap, mh);
       
   509             return mh;
       
   510         }
       
   511         throw new IllegalArgumentException("cannot find zero constant for " + wrap);
       
   512     }
       
   513 
       
   514     /// Converting references to references.
       
   515 
       
   516     /**
       
   517      * Value-killing function.
       
   518      * @param x an arbitrary reference value
       
   519      * @return a null
       
   520      */
       
   521     static Object alwaysNull(Object x) {
       
   522         return null;
       
   523     }
       
   524 
       
   525     /**
       
   526      * Value-killing function.
       
   527      * @param x an arbitrary reference value
       
   528      * @return a zero
       
   529      */
       
   530     static int alwaysZero(Object x) {
       
   531         return 0;
       
   532     }
       
   533 
       
   534     /**
       
   535      * Identity function.
       
   536      * @param x an arbitrary reference value
       
   537      * @return the same value x
       
   538      */
       
   539     static <T> T identity(T x) {
       
   540         return x;
       
   541     }
       
   542 
       
   543     /**
       
   544      * Identity function on ints.
       
   545      * @param x an arbitrary int value
       
   546      * @return the same value x
       
   547      */
       
   548     static int identity(int x) {
       
   549         return x;
       
   550     }
       
   551 
       
   552     static byte identity(byte x) {
       
   553         return x;
       
   554     }
       
   555 
       
   556     static short identity(short x) {
       
   557         return x;
       
   558     }
       
   559 
       
   560     static boolean identity(boolean x) {
       
   561         return x;
       
   562     }
       
   563 
       
   564     static char identity(char x) {
       
   565         return x;
       
   566     }
       
   567 
       
   568     /**
       
   569      * Identity function on longs.
       
   570      * @param x an arbitrary long value
       
   571      * @return the same value x
       
   572      */
       
   573     static long identity(long x) {
       
   574         return x;
       
   575     }
       
   576 
       
   577     static float identity(float x) {
       
   578         return x;
       
   579     }
       
   580 
       
   581     static double identity(double x) {
       
   582         return x;
       
   583     }
       
   584 
       
   585     /**
       
   586      * Identity function, with reference cast.
       
   587      * @param t an arbitrary reference type
       
   588      * @param x an arbitrary reference value
       
   589      * @return the same value x
       
   590      */
       
   591     static <T,U> T castReference(Class<? extends T> t, U x) {
       
   592         return t.cast(x);
       
   593     }
       
   594 
       
   595     private static final MethodHandle IDENTITY, IDENTITY_I, IDENTITY_J, CAST_REFERENCE, ALWAYS_NULL, ALWAYS_ZERO, ZERO_OBJECT, IGNORE, EMPTY;
       
   596     static {
       
   597         try {
       
   598             MethodType idType = MethodType.genericMethodType(1);
       
   599             MethodType castType = idType.insertParameterTypes(0, Class.class);
       
   600             MethodType alwaysZeroType = idType.changeReturnType(int.class);
       
   601             MethodType ignoreType = idType.changeReturnType(void.class);
       
   602             MethodType zeroObjectType = MethodType.genericMethodType(0);
       
   603             IDENTITY = IMPL_LOOKUP.findStatic(ValueConversions.class, "identity", idType);
       
   604             IDENTITY_I = IMPL_LOOKUP.findStatic(ValueConversions.class, "identity", MethodType.methodType(int.class, int.class));
       
   605             IDENTITY_J = IMPL_LOOKUP.findStatic(ValueConversions.class, "identity", MethodType.methodType(long.class, long.class));
       
   606             //CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
       
   607             CAST_REFERENCE = IMPL_LOOKUP.findStatic(ValueConversions.class, "castReference", castType);
       
   608             ALWAYS_NULL = IMPL_LOOKUP.findStatic(ValueConversions.class, "alwaysNull", idType);
       
   609             ALWAYS_ZERO = IMPL_LOOKUP.findStatic(ValueConversions.class, "alwaysZero", alwaysZeroType);
       
   610             ZERO_OBJECT = IMPL_LOOKUP.findStatic(ValueConversions.class, "zeroObject", zeroObjectType);
       
   611             IGNORE = IMPL_LOOKUP.findStatic(ValueConversions.class, "ignore", ignoreType);
       
   612             EMPTY = IMPL_LOOKUP.findStatic(ValueConversions.class, "empty", ignoreType.dropParameterTypes(0, 1));
       
   613         } catch (Exception ex) {
       
   614             Error err = new InternalError("uncaught exception");
       
   615             err.initCause(ex);
       
   616             throw err;
       
   617         }
       
   618     }
       
   619 
       
   620     private static final EnumMap<Wrapper, MethodHandle> WRAPPER_CASTS
       
   621             = new EnumMap<Wrapper, MethodHandle>(Wrapper.class);
       
   622 
       
   623     private static final EnumMap<Wrapper, MethodHandle> EXACT_WRAPPER_CASTS
       
   624             = new EnumMap<Wrapper, MethodHandle>(Wrapper.class);
       
   625 
       
   626     /** Return a method that casts its sole argument (an Object) to the given type
       
   627      *  and returns it as the given type (if exact is true), or as plain Object (if erase is true).
       
   628      */
       
   629     public static MethodHandle cast(Class<?> type, boolean exact) {
       
   630         if (type.isPrimitive())  throw new IllegalArgumentException("cannot cast primitive type "+type);
       
   631         MethodHandle mh = null;
       
   632         Wrapper wrap = null;
       
   633         EnumMap<Wrapper, MethodHandle> cache = null;
       
   634         if (Wrapper.isWrapperType(type)) {
       
   635             wrap = Wrapper.forWrapperType(type);
       
   636             cache = (exact ? EXACT_WRAPPER_CASTS : WRAPPER_CASTS);
       
   637             mh = cache.get(wrap);
       
   638             if (mh != null)  return mh;
       
   639         }
       
   640         if (VerifyType.isNullReferenceConversion(Object.class, type))
       
   641             mh = IDENTITY;
       
   642         else if (VerifyType.isNullType(type))
       
   643             mh = ALWAYS_NULL;
       
   644         else
       
   645             mh = MethodHandles.insertArguments(CAST_REFERENCE, 0, type);
       
   646         if (exact) {
       
   647             MethodType xmt = MethodType.methodType(type, Object.class);
       
   648             mh = MethodHandles.explicitCastArguments(mh, xmt);
       
   649             //mh = AdapterMethodHandle.makeRetypeRaw(IMPL_TOKEN, xmt, mh);
       
   650         }
       
   651         if (cache != null)
       
   652             cache.put(wrap, mh);
       
   653         return mh;
       
   654     }
       
   655 
       
   656     public static MethodHandle identity() {
       
   657         return IDENTITY;
       
   658     }
       
   659 
       
   660     public static MethodHandle identity(Class<?> type) {
       
   661         // This stuff has been moved into MethodHandles:
       
   662         return MethodHandles.identity(type);
       
   663     }
       
   664 
       
   665     public static MethodHandle identity(Wrapper wrap) {
       
   666         EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[1];
       
   667         MethodHandle mh = cache.get(wrap);
       
   668         if (mh != null) {
       
   669             return mh;
       
   670         }
       
   671         // slow path
       
   672         MethodType type = MethodType.methodType(wrap.primitiveType());
       
   673         if (wrap != Wrapper.VOID)
       
   674             type = type.appendParameterTypes(wrap.primitiveType());
       
   675         try {
       
   676             mh = IMPL_LOOKUP.findStatic(ValueConversions.class, "identity", type);
       
   677         } catch (ReflectiveOperationException ex) {
       
   678             mh = null;
       
   679         }
       
   680         if (mh == null && wrap == Wrapper.VOID) {
       
   681             mh = EMPTY;  // #(){} : #()void
       
   682         }
       
   683         if (mh != null) {
       
   684             cache.put(wrap, mh);
       
   685             return mh;
       
   686         }
       
   687 
       
   688         if (mh != null) {
       
   689             cache.put(wrap, mh);
       
   690             return mh;
       
   691         }
       
   692         throw new IllegalArgumentException("cannot find identity for " + wrap);
       
   693     }
       
   694 
       
   695     private static final Object[] NO_ARGS_ARRAY = {};
       
   696     private static Object[] makeArray(Object... args) { return args; }
       
   697     private static Object[] array() { return NO_ARGS_ARRAY; }
       
   698     private static Object[] array(Object a0)
       
   699                 { return makeArray(a0); }
       
   700     private static Object[] array(Object a0, Object a1)
       
   701                 { return makeArray(a0, a1); }
       
   702     private static Object[] array(Object a0, Object a1, Object a2)
       
   703                 { return makeArray(a0, a1, a2); }
       
   704     private static Object[] array(Object a0, Object a1, Object a2, Object a3)
       
   705                 { return makeArray(a0, a1, a2, a3); }
       
   706     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
       
   707                                   Object a4)
       
   708                 { return makeArray(a0, a1, a2, a3, a4); }
       
   709     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
       
   710                                   Object a4, Object a5)
       
   711                 { return makeArray(a0, a1, a2, a3, a4, a5); }
       
   712     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
       
   713                                   Object a4, Object a5, Object a6)
       
   714                 { return makeArray(a0, a1, a2, a3, a4, a5, a6); }
       
   715     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
       
   716                                   Object a4, Object a5, Object a6, Object a7)
       
   717                 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); }
       
   718     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
       
   719                                   Object a4, Object a5, Object a6, Object a7,
       
   720                                   Object a8)
       
   721                 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
       
   722     private static Object[] array(Object a0, Object a1, Object a2, Object a3,
       
   723                                   Object a4, Object a5, Object a6, Object a7,
       
   724                                   Object a8, Object a9)
       
   725                 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
       
   726     static MethodHandle[] makeArrays() {
       
   727         ArrayList<MethodHandle> arrays = new ArrayList<MethodHandle>();
       
   728         MethodHandles.Lookup lookup = IMPL_LOOKUP;
       
   729         for (;;) {
       
   730             int nargs = arrays.size();
       
   731             MethodType type = MethodType.genericMethodType(nargs).changeReturnType(Object[].class);
       
   732             String name = "array";
       
   733             MethodHandle array = null;
       
   734             try {
       
   735                 array = lookup.findStatic(ValueConversions.class, name, type);
       
   736             } catch (ReflectiveOperationException ex) {
       
   737             }
       
   738             if (array == null)  break;
       
   739             arrays.add(array);
       
   740         }
       
   741         assert(arrays.size() == 11);  // current number of methods
       
   742         return arrays.toArray(new MethodHandle[0]);
       
   743     }
       
   744     static final MethodHandle[] ARRAYS = makeArrays();
       
   745 
       
   746     /** Return a method handle that takes the indicated number of Object
       
   747      *  arguments and returns an Object array of them, as if for varargs.
       
   748      */
       
   749     public static MethodHandle varargsArray(int nargs) {
       
   750         if (nargs < ARRAYS.length)
       
   751             return ARRAYS[nargs];
       
   752         // else need to spin bytecode or do something else fancy
       
   753         throw new UnsupportedOperationException("NYI: cannot form a varargs array of length "+nargs);
       
   754     }
       
   755 
       
   756     private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY);
       
   757     private static List<Object> makeList(Object... args) { return Arrays.asList(args); }
       
   758     private static List<Object> list() { return NO_ARGS_LIST; }
       
   759     private static List<Object> list(Object a0)
       
   760                 { return makeList(a0); }
       
   761     private static List<Object> list(Object a0, Object a1)
       
   762                 { return makeList(a0, a1); }
       
   763     private static List<Object> list(Object a0, Object a1, Object a2)
       
   764                 { return makeList(a0, a1, a2); }
       
   765     private static List<Object> list(Object a0, Object a1, Object a2, Object a3)
       
   766                 { return makeList(a0, a1, a2, a3); }
       
   767     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
       
   768                                      Object a4)
       
   769                 { return makeList(a0, a1, a2, a3, a4); }
       
   770     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
       
   771                                      Object a4, Object a5)
       
   772                 { return makeList(a0, a1, a2, a3, a4, a5); }
       
   773     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
       
   774                                      Object a4, Object a5, Object a6)
       
   775                 { return makeList(a0, a1, a2, a3, a4, a5, a6); }
       
   776     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
       
   777                                      Object a4, Object a5, Object a6, Object a7)
       
   778                 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); }
       
   779     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
       
   780                                      Object a4, Object a5, Object a6, Object a7,
       
   781                                      Object a8)
       
   782                 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
       
   783     private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
       
   784                                      Object a4, Object a5, Object a6, Object a7,
       
   785                                      Object a8, Object a9)
       
   786                 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
       
   787     static MethodHandle[] makeLists() {
       
   788         ArrayList<MethodHandle> arrays = new ArrayList<MethodHandle>();
       
   789         MethodHandles.Lookup lookup = IMPL_LOOKUP;
       
   790         for (;;) {
       
   791             int nargs = arrays.size();
       
   792             MethodType type = MethodType.genericMethodType(nargs).changeReturnType(List.class);
       
   793             String name = "list";
       
   794             MethodHandle array = null;
       
   795             try {
       
   796                 array = lookup.findStatic(ValueConversions.class, name, type);
       
   797             } catch (ReflectiveOperationException ex) {
       
   798             }
       
   799             if (array == null)  break;
       
   800             arrays.add(array);
       
   801         }
       
   802         assert(arrays.size() == 11);  // current number of methods
       
   803         return arrays.toArray(new MethodHandle[0]);
       
   804     }
       
   805     static final MethodHandle[] LISTS = makeLists();
       
   806 
       
   807     /** Return a method handle that takes the indicated number of Object
       
   808      *  arguments and returns List.
       
   809      */
       
   810     public static MethodHandle varargsList(int nargs) {
       
   811         if (nargs < LISTS.length)
       
   812             return LISTS[nargs];
       
   813         // else need to spin bytecode or do something else fancy
       
   814         throw new UnsupportedOperationException("NYI");
       
   815     }
       
   816 }
       
   817