jdk/src/java.base/share/classes/sun/invoke/util/ValueConversions.java
changeset 26474 655d08549e43
parent 26466 3bbb6a284bd4
child 26475 acf0c98309d3
equal deleted inserted replaced
26473:0abc9399a1a6 26474:655d08549e43
    33 
    33 
    34 public class ValueConversions {
    34 public class ValueConversions {
    35     private static final Class<?> THIS_CLASS = ValueConversions.class;
    35     private static final Class<?> THIS_CLASS = ValueConversions.class;
    36     private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
    36     private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
    37 
    37 
    38     private static EnumMap<Wrapper, MethodHandle>[] newWrapperCaches(int n) {
    38     /** Thread-safe canonicalized mapping from Wrapper to MethodHandle
    39         @SuppressWarnings("unchecked")  // generic array creation
    39      * with unsynchronized reads and synchronized writes.
    40         EnumMap<Wrapper, MethodHandle>[] caches
    40      * It's safe to publish MethodHandles by data race because they are immutable. */
    41                 = (EnumMap<Wrapper, MethodHandle>[]) new EnumMap<?,?>[n];
    41     private static class WrapperCache {
       
    42         /** EnumMap uses preconstructed array internally, which is constant during it's lifetime. */
       
    43         private final EnumMap<Wrapper, MethodHandle> map = new EnumMap<>(Wrapper.class);
       
    44 
       
    45         public MethodHandle get(Wrapper w) {
       
    46             return map.get(w);
       
    47         }
       
    48         public synchronized MethodHandle put(final Wrapper w, final MethodHandle mh) {
       
    49             // Simulate CAS to avoid racy duplication
       
    50             MethodHandle prev = map.putIfAbsent(w, mh);
       
    51             if (prev != null)  return prev;
       
    52             return mh;
       
    53         }
       
    54     }
       
    55 
       
    56     private static WrapperCache[] newWrapperCaches(int n) {
       
    57         WrapperCache[] caches = new WrapperCache[n];
    42         for (int i = 0; i < n; i++)
    58         for (int i = 0; i < n; i++)
    43             caches[i] = new EnumMap<>(Wrapper.class);
    59             caches[i] = new WrapperCache();
    44         return caches;
    60         return caches;
    45     }
    61     }
    46 
    62 
    47     /// Converting references to values.
    63     /// Converting references to values.
    48 
    64 
    49     // There are several levels of this unboxing conversions:
    65     // There are several levels of this unboxing conversions:
    50     //   no conversions:  exactly Integer.valueOf, etc.
    66     //   no conversions:  exactly Integer.valueOf, etc.
    51     //   implicit conversions sanctioned by JLS 5.1.2, etc.
    67     //   implicit conversions sanctioned by JLS 5.1.2, etc.
    52     //   explicit conversions as allowed by explicitCastArguments
    68     //   explicit conversions as allowed by explicitCastArguments
    53 
    69 
       
    70     static int unboxInteger(Integer x) {
       
    71         return x;
       
    72     }
    54     static int unboxInteger(Object x, boolean cast) {
    73     static int unboxInteger(Object x, boolean cast) {
    55         if (x instanceof Integer)
    74         if (x instanceof Integer)
    56             return ((Integer) x).intValue();
    75             return (Integer) x;
    57         return primitiveConversion(Wrapper.INT, x, cast).intValue();
    76         return primitiveConversion(Wrapper.INT, x, cast).intValue();
    58     }
    77     }
    59 
    78 
       
    79     static byte unboxByte(Byte x) {
       
    80         return x;
       
    81     }
    60     static byte unboxByte(Object x, boolean cast) {
    82     static byte unboxByte(Object x, boolean cast) {
    61         if (x instanceof Byte)
    83         if (x instanceof Byte)
    62             return ((Byte) x).byteValue();
    84             return (Byte) x;
    63         return primitiveConversion(Wrapper.BYTE, x, cast).byteValue();
    85         return primitiveConversion(Wrapper.BYTE, x, cast).byteValue();
    64     }
    86     }
    65 
    87 
       
    88     static short unboxShort(Short x) {
       
    89         return x;
       
    90     }
    66     static short unboxShort(Object x, boolean cast) {
    91     static short unboxShort(Object x, boolean cast) {
    67         if (x instanceof Short)
    92         if (x instanceof Short)
    68             return ((Short) x).shortValue();
    93             return (Short) x;
    69         return primitiveConversion(Wrapper.SHORT, x, cast).shortValue();
    94         return primitiveConversion(Wrapper.SHORT, x, cast).shortValue();
    70     }
    95     }
    71 
    96 
       
    97     static boolean unboxBoolean(Boolean x) {
       
    98         return x;
       
    99     }
    72     static boolean unboxBoolean(Object x, boolean cast) {
   100     static boolean unboxBoolean(Object x, boolean cast) {
    73         if (x instanceof Boolean)
   101         if (x instanceof Boolean)
    74             return ((Boolean) x).booleanValue();
   102             return (Boolean) x;
    75         return (primitiveConversion(Wrapper.BOOLEAN, x, cast).intValue() & 1) != 0;
   103         return (primitiveConversion(Wrapper.BOOLEAN, x, cast).intValue() & 1) != 0;
    76     }
   104     }
    77 
   105 
       
   106     static char unboxCharacter(Character x) {
       
   107         return x;
       
   108     }
    78     static char unboxCharacter(Object x, boolean cast) {
   109     static char unboxCharacter(Object x, boolean cast) {
    79         if (x instanceof Character)
   110         if (x instanceof Character)
    80             return ((Character) x).charValue();
   111             return (Character) x;
    81         return (char) primitiveConversion(Wrapper.CHAR, x, cast).intValue();
   112         return (char) primitiveConversion(Wrapper.CHAR, x, cast).intValue();
    82     }
   113     }
    83 
   114 
       
   115     static long unboxLong(Long x) {
       
   116         return x;
       
   117     }
    84     static long unboxLong(Object x, boolean cast) {
   118     static long unboxLong(Object x, boolean cast) {
    85         if (x instanceof Long)
   119         if (x instanceof Long)
    86             return ((Long) x).longValue();
   120             return (Long) x;
    87         return primitiveConversion(Wrapper.LONG, x, cast).longValue();
   121         return primitiveConversion(Wrapper.LONG, x, cast).longValue();
    88     }
   122     }
    89 
   123 
       
   124     static float unboxFloat(Float x) {
       
   125         return x;
       
   126     }
    90     static float unboxFloat(Object x, boolean cast) {
   127     static float unboxFloat(Object x, boolean cast) {
    91         if (x instanceof Float)
   128         if (x instanceof Float)
    92             return ((Float) x).floatValue();
   129             return (Float) x;
    93         return primitiveConversion(Wrapper.FLOAT, x, cast).floatValue();
   130         return primitiveConversion(Wrapper.FLOAT, x, cast).floatValue();
    94     }
   131     }
    95 
   132 
       
   133     static double unboxDouble(Double x) {
       
   134         return x;
       
   135     }
    96     static double unboxDouble(Object x, boolean cast) {
   136     static double unboxDouble(Object x, boolean cast) {
    97         if (x instanceof Double)
   137         if (x instanceof Double)
    98             return ((Double) x).doubleValue();
   138             return (Double) x;
    99         return primitiveConversion(Wrapper.DOUBLE, x, cast).doubleValue();
   139         return primitiveConversion(Wrapper.DOUBLE, x, cast).doubleValue();
   100     }
   140     }
   101 
   141 
   102     private static MethodType unboxType(Wrapper wrap) {
   142     private static MethodType unboxType(Wrapper wrap, int kind) {
       
   143         if (kind == 0)
       
   144             return MethodType.methodType(wrap.primitiveType(), wrap.wrapperType());
   103         return MethodType.methodType(wrap.primitiveType(), Object.class, boolean.class);
   145         return MethodType.methodType(wrap.primitiveType(), Object.class, boolean.class);
   104     }
   146     }
   105 
   147 
   106     private static final EnumMap<Wrapper, MethodHandle>[]
   148     private static final WrapperCache[] UNBOX_CONVERSIONS = newWrapperCaches(4);
   107             UNBOX_CONVERSIONS = newWrapperCaches(2);
   149 
   108 
   150     private static MethodHandle unbox(Wrapper wrap, int kind) {
   109     private static MethodHandle unbox(Wrapper wrap, boolean cast) {
   151         // kind 0 -> strongly typed with NPE
   110         EnumMap<Wrapper, MethodHandle> cache = UNBOX_CONVERSIONS[(cast?1:0)];
   152         // kind 1 -> strongly typed but zero for null,
       
   153         // kind 2 -> asType rules: accept multiple box types but only widening conversions with NPE
       
   154         // kind 3 -> explicitCastArguments rules: allow narrowing conversions, zero for null
       
   155         WrapperCache cache = UNBOX_CONVERSIONS[kind];
   111         MethodHandle mh = cache.get(wrap);
   156         MethodHandle mh = cache.get(wrap);
   112         if (mh != null) {
   157         if (mh != null) {
   113             return mh;
   158             return mh;
   114         }
   159         }
   115         // slow path
   160         // slow path
   116         switch (wrap) {
   161         switch (wrap) {
   117             case OBJECT:
   162             case OBJECT:
   118                 mh = IDENTITY; break;
       
   119             case VOID:
   163             case VOID:
   120                 mh = IGNORE; break;
   164                 throw new IllegalArgumentException("unbox "+wrap);
   121         }
       
   122         if (mh != null) {
       
   123             cache.put(wrap, mh);
       
   124             return mh;
       
   125         }
   165         }
   126         // look up the method
   166         // look up the method
   127         String name = "unbox" + wrap.wrapperSimpleName();
   167         String name = "unbox" + wrap.wrapperSimpleName();
   128         MethodType type = unboxType(wrap);
   168         MethodType type = unboxType(wrap, kind);
   129         try {
   169         try {
   130             mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
   170             mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
   131         } catch (ReflectiveOperationException ex) {
   171         } catch (ReflectiveOperationException ex) {
   132             mh = null;
   172             mh = null;
   133         }
   173         }
   134         if (mh != null) {
   174         if (mh != null) {
   135             mh = MethodHandles.insertArguments(mh, 1, cast);
   175             if (kind > 0) {
   136             cache.put(wrap, mh);
   176                 boolean cast = (kind != 2);
   137             return mh;
   177                 mh = MethodHandles.insertArguments(mh, 1, cast);
       
   178             }
       
   179             if (kind == 1) {  // casting but exact (null -> zero)
       
   180                 mh = mh.asType(unboxType(wrap, 0));
       
   181             }
       
   182             return cache.put(wrap, mh);
   138         }
   183         }
   139         throw new IllegalArgumentException("cannot find unbox adapter for " + wrap
   184         throw new IllegalArgumentException("cannot find unbox adapter for " + wrap
   140                 + (cast ? " (cast)" : ""));
   185                 + (kind <= 1 ? " (exact)" : kind == 3 ? " (cast)" : ""));
   141     }
   186     }
   142 
   187 
       
   188     /** Return an exact unboxer for the given primitive type. */
       
   189     public static MethodHandle unboxExact(Wrapper type) {
       
   190         return unbox(type, 0);
       
   191     }
       
   192 
       
   193     /** Return an exact unboxer for the given primitive type, with optional null-to-zero conversion.
       
   194      *  The boolean says whether to throw an NPE on a null value (false means unbox a zero).
       
   195      *  The type of the unboxer is of a form like (Integer)int.
       
   196      */
       
   197     public static MethodHandle unboxExact(Wrapper type, boolean throwNPE) {
       
   198         return unbox(type, throwNPE ? 0 : 1);
       
   199     }
       
   200 
       
   201     /** Return a widening unboxer for the given primitive type.
       
   202      *  Widen narrower primitive boxes to the given type.
       
   203      *  Do not narrow any primitive values or convert null to zero.
       
   204      *  The type of the unboxer is of a form like (Object)int.
       
   205      */
       
   206     public static MethodHandle unboxWiden(Wrapper type) {
       
   207         return unbox(type, 2);
       
   208     }
       
   209 
       
   210     /** Return a casting unboxer for the given primitive type.
       
   211      *  Widen or narrow primitive values to the given type, or convert null to zero, as needed.
       
   212      *  The type of the unboxer is of a form like (Object)int.
       
   213      */
   143     public static MethodHandle unboxCast(Wrapper type) {
   214     public static MethodHandle unboxCast(Wrapper type) {
   144         return unbox(type, true);
   215         return unbox(type, 3);
   145     }
       
   146 
       
   147     public static MethodHandle unbox(Class<?> type) {
       
   148         return unbox(Wrapper.forPrimitiveType(type), false);
       
   149     }
       
   150 
       
   151     public static MethodHandle unboxCast(Class<?> type) {
       
   152         return unbox(Wrapper.forPrimitiveType(type), true);
       
   153     }
   216     }
   154 
   217 
   155     static private final Integer ZERO_INT = 0, ONE_INT = 1;
   218     static private final Integer ZERO_INT = 0, ONE_INT = 1;
   156 
   219 
   157     /// Primitive conversions
   220     /// Primitive conversions
   244         // be exact, since return casts are hard to compose
   307         // be exact, since return casts are hard to compose
   245         Class<?> boxType = wrap.wrapperType();
   308         Class<?> boxType = wrap.wrapperType();
   246         return MethodType.methodType(boxType, wrap.primitiveType());
   309         return MethodType.methodType(boxType, wrap.primitiveType());
   247     }
   310     }
   248 
   311 
   249     private static final EnumMap<Wrapper, MethodHandle>[]
   312     private static final WrapperCache[] BOX_CONVERSIONS = newWrapperCaches(1);
   250             BOX_CONVERSIONS = newWrapperCaches(2);
   313 
   251 
   314     public static MethodHandle boxExact(Wrapper wrap) {
   252     private static MethodHandle box(Wrapper wrap, boolean exact) {
   315         WrapperCache cache = BOX_CONVERSIONS[0];
   253         EnumMap<Wrapper, MethodHandle> cache = BOX_CONVERSIONS[(exact?1:0)];
       
   254         MethodHandle mh = cache.get(wrap);
   316         MethodHandle mh = cache.get(wrap);
   255         if (mh != null) {
   317         if (mh != null) {
   256             return mh;
       
   257         }
       
   258         // slow path
       
   259         switch (wrap) {
       
   260             case OBJECT:
       
   261                 mh = IDENTITY; break;
       
   262             case VOID:
       
   263                 mh = ZERO_OBJECT;
       
   264                 break;
       
   265         }
       
   266         if (mh != null) {
       
   267             cache.put(wrap, mh);
       
   268             return mh;
   318             return mh;
   269         }
   319         }
   270         // look up the method
   320         // look up the method
   271         String name = "box" + wrap.wrapperSimpleName();
   321         String name = "box" + wrap.wrapperSimpleName();
   272         MethodType type = boxType(wrap);
   322         MethodType type = boxType(wrap);
   273         if (exact) {
   323         try {
   274             try {
   324             mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
   275                 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
   325         } catch (ReflectiveOperationException ex) {
   276             } catch (ReflectiveOperationException ex) {
   326             mh = null;
   277                 mh = null;
   327         }
   278             }
   328         if (mh != null) {
   279         } else {
   329             return cache.put(wrap, mh);
   280             mh = box(wrap, !exact).asType(type.erase());
   330         }
   281         }
   331         throw new IllegalArgumentException("cannot find box adapter for " + wrap);
   282         if (mh != null) {
       
   283             cache.put(wrap, mh);
       
   284             return mh;
       
   285         }
       
   286         throw new IllegalArgumentException("cannot find box adapter for "
       
   287                 + wrap + (exact ? " (exact)" : ""));
       
   288     }
       
   289 
       
   290     public static MethodHandle box(Class<?> type) {
       
   291         boolean exact = false;
       
   292         // e.g., boxShort(short)Short if exact,
       
   293         // e.g., boxShort(short)Object if !exact
       
   294         return box(Wrapper.forPrimitiveType(type), exact);
       
   295     }
       
   296 
       
   297     public static MethodHandle box(Wrapper type) {
       
   298         boolean exact = false;
       
   299         return box(type, exact);
       
   300     }
   332     }
   301 
   333 
   302     /// Constant functions
   334     /// Constant functions
   303 
   335 
   304     static void ignore(Object x) {
   336     static void ignore(Object x) {
   326 
   358 
   327     static double zeroDouble() {
   359     static double zeroDouble() {
   328         return 0;
   360         return 0;
   329     }
   361     }
   330 
   362 
   331     private static final EnumMap<Wrapper, MethodHandle>[]
   363     private static final WrapperCache[] CONSTANT_FUNCTIONS = newWrapperCaches(2);
   332             CONSTANT_FUNCTIONS = newWrapperCaches(2);
       
   333 
   364 
   334     public static MethodHandle zeroConstantFunction(Wrapper wrap) {
   365     public static MethodHandle zeroConstantFunction(Wrapper wrap) {
   335         EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[0];
   366         WrapperCache cache = CONSTANT_FUNCTIONS[0];
   336         MethodHandle mh = cache.get(wrap);
   367         MethodHandle mh = cache.get(wrap);
   337         if (mh != null) {
   368         if (mh != null) {
   338             return mh;
   369             return mh;
   339         }
   370         }
   340         // slow path
   371         // slow path
   351                     mh = null;
   382                     mh = null;
   352                 }
   383                 }
   353                 break;
   384                 break;
   354         }
   385         }
   355         if (mh != null) {
   386         if (mh != null) {
   356             cache.put(wrap, mh);
   387             return cache.put(wrap, mh);
   357             return mh;
       
   358         }
   388         }
   359 
   389 
   360         // use zeroInt and cast the result
   390         // use zeroInt and cast the result
   361         if (wrap.isSubwordOrInt() && wrap != Wrapper.INT) {
   391         if (wrap.isSubwordOrInt() && wrap != Wrapper.INT) {
   362             mh = MethodHandles.explicitCastArguments(zeroConstantFunction(Wrapper.INT), type);
   392             mh = MethodHandles.explicitCastArguments(zeroConstantFunction(Wrapper.INT), type);
   363             cache.put(wrap, mh);
   393             return cache.put(wrap, mh);
   364             return mh;
       
   365         }
   394         }
   366         throw new IllegalArgumentException("cannot find zero constant for " + wrap);
   395         throw new IllegalArgumentException("cannot find zero constant for " + wrap);
   367     }
   396     }
   368 
   397 
   369     /// Converting references to references.
   398     /// Converting references to references.
   421 
   450 
   422     static double identity(double x) {
   451     static double identity(double x) {
   423         return x;
   452         return x;
   424     }
   453     }
   425 
   454 
   426     private static final MethodHandle IDENTITY, CAST_REFERENCE, ZERO_OBJECT, IGNORE, EMPTY;
   455     private static final MethodHandle IDENTITY, CAST_REFERENCE, IGNORE, EMPTY;
   427     static {
   456     static {
   428         try {
   457         try {
   429             MethodType idType = MethodType.genericMethodType(1);
   458             MethodType idType = MethodType.genericMethodType(1);
   430             MethodType ignoreType = idType.changeReturnType(void.class);
   459             MethodType ignoreType = idType.changeReturnType(void.class);
   431             MethodType zeroObjectType = MethodType.genericMethodType(0);
       
   432             IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", idType);
   460             IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", idType);
   433             CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
   461             CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
   434             ZERO_OBJECT = IMPL_LOOKUP.findStatic(THIS_CLASS, "zeroObject", zeroObjectType);
       
   435             IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType);
   462             IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType);
   436             EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1));
   463             EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1));
   437         } catch (NoSuchMethodException | IllegalAccessException ex) {
   464         } catch (NoSuchMethodException | IllegalAccessException ex) {
   438             throw newInternalError("uncaught exception", ex);
   465             throw newInternalError("uncaught exception", ex);
   439         }
   466         }
   440     }
   467     }
   441 
   468 
   442     private static final EnumMap<Wrapper, MethodHandle>[] WRAPPER_CASTS
   469     public static MethodHandle ignore() {
   443             = newWrapperCaches(1);
   470         return IGNORE;
   444 
       
   445     /** Return a method that casts its sole argument (an Object) to the given type
       
   446      *  and returns it as the given type.
       
   447      */
       
   448     public static MethodHandle cast(Class<?> type) {
       
   449         return cast(type, CAST_REFERENCE);
       
   450     }
       
   451     public static MethodHandle cast(Class<?> type, MethodHandle castReference) {
       
   452         if (type.isPrimitive())  throw new IllegalArgumentException("cannot cast primitive type "+type);
       
   453         MethodHandle mh;
       
   454         Wrapper wrap = null;
       
   455         EnumMap<Wrapper, MethodHandle> cache = null;
       
   456         if (Wrapper.isWrapperType(type)) {
       
   457             wrap = Wrapper.forWrapperType(type);
       
   458             cache = WRAPPER_CASTS[0];
       
   459             mh = cache.get(wrap);
       
   460             if (mh != null)  return mh;
       
   461         }
       
   462         mh = MethodHandles.insertArguments(castReference, 0, type);
       
   463         if (cache != null)
       
   464             cache.put(wrap, mh);
       
   465         return mh;
       
   466     }
   471     }
   467 
   472 
   468     public static MethodHandle identity() {
   473     public static MethodHandle identity() {
   469         return IDENTITY;
   474         return IDENTITY;
   470     }
   475     }
   475             return MethodHandles.identity(type);
   480             return MethodHandles.identity(type);
   476         return identity(Wrapper.findPrimitiveType(type));
   481         return identity(Wrapper.findPrimitiveType(type));
   477     }
   482     }
   478 
   483 
   479     public static MethodHandle identity(Wrapper wrap) {
   484     public static MethodHandle identity(Wrapper wrap) {
   480         EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[1];
   485         WrapperCache cache = CONSTANT_FUNCTIONS[1];
   481         MethodHandle mh = cache.get(wrap);
   486         MethodHandle mh = cache.get(wrap);
   482         if (mh != null) {
   487         if (mh != null) {
   483             return mh;
   488             return mh;
   484         }
   489         }
   485         // slow path
   490         // slow path
   493         }
   498         }
   494         if (mh == null && wrap == Wrapper.VOID) {
   499         if (mh == null && wrap == Wrapper.VOID) {
   495             mh = EMPTY;  // #(){} : #()void
   500             mh = EMPTY;  // #(){} : #()void
   496         }
   501         }
   497         if (mh != null) {
   502         if (mh != null) {
   498             cache.put(wrap, mh);
   503             return cache.put(wrap, mh);
   499             return mh;
       
   500         }
       
   501 
       
   502         if (mh != null) {
       
   503             cache.put(wrap, mh);
       
   504             return mh;
       
   505         }
   504         }
   506         throw new IllegalArgumentException("cannot find identity for " + wrap);
   505         throw new IllegalArgumentException("cannot find identity for " + wrap);
       
   506     }
       
   507 
       
   508     /** Return a method that casts its second argument (an Object) to the given type (a Class). */
       
   509     public static MethodHandle cast() {
       
   510         return CAST_REFERENCE;
   507     }
   511     }
   508 
   512 
   509     /// Primitive conversions.
   513     /// Primitive conversions.
   510     // These are supported directly by the JVM, usually by a single instruction.
   514     // These are supported directly by the JVM, usually by a single instruction.
   511     // In the case of narrowing to a subword, there may be a pair of instructions.
   515     // In the case of narrowing to a subword, there may be a pair of instructions.
   710     static byte fromBoolean(boolean x) {
   714     static byte fromBoolean(boolean x) {
   711         // see javadoc for MethodHandles.explicitCastArguments
   715         // see javadoc for MethodHandles.explicitCastArguments
   712         return (x ? (byte)1 : (byte)0);
   716         return (x ? (byte)1 : (byte)0);
   713     }
   717     }
   714 
   718 
   715     private static final EnumMap<Wrapper, MethodHandle>[]
   719     private static final WrapperCache[] CONVERT_PRIMITIVE_FUNCTIONS = newWrapperCaches(Wrapper.values().length);
   716             CONVERT_PRIMITIVE_FUNCTIONS = newWrapperCaches(Wrapper.values().length);
       
   717 
   720 
   718     public static MethodHandle convertPrimitive(Wrapper wsrc, Wrapper wdst) {
   721     public static MethodHandle convertPrimitive(Wrapper wsrc, Wrapper wdst) {
   719         EnumMap<Wrapper, MethodHandle> cache = CONVERT_PRIMITIVE_FUNCTIONS[wsrc.ordinal()];
   722         WrapperCache cache = CONVERT_PRIMITIVE_FUNCTIONS[wsrc.ordinal()];
   720         MethodHandle mh = cache.get(wdst);
   723         MethodHandle mh = cache.get(wdst);
   721         if (mh != null) {
   724         if (mh != null) {
   722             return mh;
   725             return mh;
   723         }
   726         }
   724         // slow path
   727         // slow path
   725         Class<?> src = wsrc.primitiveType();
   728         Class<?> src = wsrc.primitiveType();
   726         Class<?> dst = wdst.primitiveType();
   729         Class<?> dst = wdst.primitiveType();
   727         MethodType type = src == void.class ? MethodType.methodType(dst) : MethodType.methodType(dst, src);
   730         MethodType type = MethodType.methodType(dst, src);
   728         if (wsrc == wdst) {
   731         if (wsrc == wdst) {
   729             mh = identity(src);
   732             mh = MethodHandles.identity(src);
   730         } else if (wsrc == Wrapper.VOID) {
       
   731             mh = zeroConstantFunction(wdst);
       
   732         } else if (wdst == Wrapper.VOID) {
       
   733             mh = MethodHandles.dropArguments(EMPTY, 0, src);  // Defer back to MethodHandles.
       
   734         } else if (wsrc == Wrapper.OBJECT) {
       
   735             mh = unboxCast(dst);
       
   736         } else if (wdst == Wrapper.OBJECT) {
       
   737             mh = box(src);
       
   738         } else {
   733         } else {
   739             assert(src.isPrimitive() && dst.isPrimitive());
   734             assert(src.isPrimitive() && dst.isPrimitive());
   740             try {
   735             try {
   741                 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, src.getSimpleName()+"To"+capitalize(dst.getSimpleName()), type);
   736                 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, src.getSimpleName()+"To"+capitalize(dst.getSimpleName()), type);
   742             } catch (ReflectiveOperationException ex) {
   737             } catch (ReflectiveOperationException ex) {
   743                 mh = null;
   738                 mh = null;
   744             }
   739             }
   745         }
   740         }
   746         if (mh != null) {
   741         if (mh != null) {
   747             assert(mh.type() == type) : mh;
   742             assert(mh.type() == type) : mh;
   748             cache.put(wdst, mh);
   743             return cache.put(wdst, mh);
   749             return mh;
       
   750         }
   744         }
   751 
   745 
   752         throw new IllegalArgumentException("cannot find primitive conversion function for " +
   746         throw new IllegalArgumentException("cannot find primitive conversion function for " +
   753                                            src.getSimpleName()+" -> "+dst.getSimpleName());
   747                                            src.getSimpleName()+" -> "+dst.getSimpleName());
   754     }
   748     }