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