1 /*
2  * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.invoke.util;
27 
28 import java.lang.invoke.MethodHandle;
29 import java.lang.invoke.MethodHandles;
30 import java.lang.invoke.MethodHandles.Lookup;
31 import java.lang.invoke.MethodType;
32 import jdk.internal.vm.annotation.Stable;
33 
34 public class ValueConversions {
35     private static final Class<?> THIS_CLASS = ValueConversions.class;
36     private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
37 
38     /**
39      * Thread-safe canonicalized mapping from Wrapper to MethodHandle
40      * with unsynchronized reads and synchronized writes.
41      * It's safe to publish MethodHandles by data race because they are immutable.
42      */
43     private static class WrapperCache {
44         @Stable
45         private final MethodHandle[] map = new MethodHandle[Wrapper.COUNT];
46 
get(Wrapper w)47         public MethodHandle get(Wrapper w) {
48             return map[w.ordinal()];
49         }
put(final Wrapper w, final MethodHandle mh)50         public synchronized MethodHandle put(final Wrapper w, final MethodHandle mh) {
51             MethodHandle prev = map[w.ordinal()];
52             if (prev != null) {
53                 return prev;
54             } else {
55                 map[w.ordinal()] = mh;
56                 return mh;
57             }
58         }
59     }
60 
newWrapperCaches(int n)61     private static WrapperCache[] newWrapperCaches(int n) {
62         WrapperCache[] caches = new WrapperCache[n];
63         for (int i = 0; i < n; i++)
64             caches[i] = new WrapperCache();
65         return caches;
66     }
67 
68     /// Converting references to values.
69 
70     // There are several levels of this unboxing conversions:
71     //   no conversions:  exactly Integer.valueOf, etc.
72     //   implicit conversions sanctioned by JLS 5.1.2, etc.
73     //   explicit conversions as allowed by explicitCastArguments
74 
unboxInteger(Integer x)75     static int unboxInteger(Integer x) {
76         return x;
77     }
unboxInteger(Object x, boolean cast)78     static int unboxInteger(Object x, boolean cast) {
79         if (x instanceof Integer)
80             return (Integer) x;
81         return primitiveConversion(Wrapper.INT, x, cast).intValue();
82     }
83 
unboxByte(Byte x)84     static byte unboxByte(Byte x) {
85         return x;
86     }
unboxByte(Object x, boolean cast)87     static byte unboxByte(Object x, boolean cast) {
88         if (x instanceof Byte)
89             return (Byte) x;
90         return primitiveConversion(Wrapper.BYTE, x, cast).byteValue();
91     }
92 
unboxShort(Short x)93     static short unboxShort(Short x) {
94         return x;
95     }
unboxShort(Object x, boolean cast)96     static short unboxShort(Object x, boolean cast) {
97         if (x instanceof Short)
98             return (Short) x;
99         return primitiveConversion(Wrapper.SHORT, x, cast).shortValue();
100     }
101 
unboxBoolean(Boolean x)102     static boolean unboxBoolean(Boolean x) {
103         return x;
104     }
unboxBoolean(Object x, boolean cast)105     static boolean unboxBoolean(Object x, boolean cast) {
106         if (x instanceof Boolean)
107             return (Boolean) x;
108         return (primitiveConversion(Wrapper.BOOLEAN, x, cast).intValue() & 1) != 0;
109     }
110 
unboxCharacter(Character x)111     static char unboxCharacter(Character x) {
112         return x;
113     }
unboxCharacter(Object x, boolean cast)114     static char unboxCharacter(Object x, boolean cast) {
115         if (x instanceof Character)
116             return (Character) x;
117         return (char) primitiveConversion(Wrapper.CHAR, x, cast).intValue();
118     }
119 
unboxLong(Long x)120     static long unboxLong(Long x) {
121         return x;
122     }
unboxLong(Object x, boolean cast)123     static long unboxLong(Object x, boolean cast) {
124         if (x instanceof Long)
125             return (Long) x;
126         return primitiveConversion(Wrapper.LONG, x, cast).longValue();
127     }
128 
unboxFloat(Float x)129     static float unboxFloat(Float x) {
130         return x;
131     }
unboxFloat(Object x, boolean cast)132     static float unboxFloat(Object x, boolean cast) {
133         if (x instanceof Float)
134             return (Float) x;
135         return primitiveConversion(Wrapper.FLOAT, x, cast).floatValue();
136     }
137 
unboxDouble(Double x)138     static double unboxDouble(Double x) {
139         return x;
140     }
unboxDouble(Object x, boolean cast)141     static double unboxDouble(Object x, boolean cast) {
142         if (x instanceof Double)
143             return (Double) x;
144         return primitiveConversion(Wrapper.DOUBLE, x, cast).doubleValue();
145     }
146 
unboxType(Wrapper wrap, int kind)147     private static MethodType unboxType(Wrapper wrap, int kind) {
148         if (kind == 0)
149             return MethodType.methodType(wrap.primitiveType(), wrap.wrapperType());
150         return MethodType.methodType(wrap.primitiveType(), Object.class, boolean.class);
151     }
152 
153     private static final WrapperCache[] UNBOX_CONVERSIONS = newWrapperCaches(4);
154 
unbox(Wrapper wrap, int kind)155     private static MethodHandle unbox(Wrapper wrap, int kind) {
156         // kind 0 -> strongly typed with NPE
157         // kind 1 -> strongly typed but zero for null,
158         // kind 2 -> asType rules: accept multiple box types but only widening conversions with NPE
159         // kind 3 -> explicitCastArguments rules: allow narrowing conversions, zero for null
160         WrapperCache cache = UNBOX_CONVERSIONS[kind];
161         MethodHandle mh = cache.get(wrap);
162         if (mh != null) {
163             return mh;
164         }
165         // slow path
166         switch (wrap) {
167             case OBJECT:
168             case VOID:
169                 throw new IllegalArgumentException("unbox "+wrap);
170         }
171         // look up the method
172         String name = "unbox" + wrap.wrapperSimpleName();
173         MethodType type = unboxType(wrap, kind);
174         try {
175             mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
176         } catch (ReflectiveOperationException ex) {
177             mh = null;
178         }
179         if (mh != null) {
180             if (kind > 0) {
181                 boolean cast = (kind != 2);
182                 mh = MethodHandles.insertArguments(mh, 1, cast);
183             }
184             if (kind == 1) {  // casting but exact (null -> zero)
185                 mh = mh.asType(unboxType(wrap, 0));
186             }
187             return cache.put(wrap, mh);
188         }
189         throw new IllegalArgumentException("cannot find unbox adapter for " + wrap
190                 + (kind <= 1 ? " (exact)" : kind == 3 ? " (cast)" : ""));
191     }
192 
193     /** Return an exact unboxer for the given primitive type. */
unboxExact(Wrapper type)194     public static MethodHandle unboxExact(Wrapper type) {
195         return unbox(type, 0);
196     }
197 
198     /** Return an exact unboxer for the given primitive type, with optional null-to-zero conversion.
199      *  The boolean says whether to throw an NPE on a null value (false means unbox a zero).
200      *  The type of the unboxer is of a form like (Integer)int.
201      */
unboxExact(Wrapper type, boolean throwNPE)202     public static MethodHandle unboxExact(Wrapper type, boolean throwNPE) {
203         return unbox(type, throwNPE ? 0 : 1);
204     }
205 
206     /** Return a widening unboxer for the given primitive type.
207      *  Widen narrower primitive boxes to the given type.
208      *  Do not narrow any primitive values or convert null to zero.
209      *  The type of the unboxer is of a form like (Object)int.
210      */
unboxWiden(Wrapper type)211     public static MethodHandle unboxWiden(Wrapper type) {
212         return unbox(type, 2);
213     }
214 
215     /** Return a casting unboxer for the given primitive type.
216      *  Widen or narrow primitive values to the given type, or convert null to zero, as needed.
217      *  The type of the unboxer is of a form like (Object)int.
218      */
unboxCast(Wrapper type)219     public static MethodHandle unboxCast(Wrapper type) {
220         return unbox(type, 3);
221     }
222 
223     private static final Integer ZERO_INT = 0, ONE_INT = 1;
224 
225     /// Primitive conversions
226     /**
227      * Produce a Number which represents the given value {@code x}
228      * according to the primitive type of the given wrapper {@code wrap}.
229      * Caller must invoke intValue, byteValue, longValue (etc.) on the result
230      * to retrieve the desired primitive value.
231      */
primitiveConversion(Wrapper wrap, Object x, boolean cast)232     public static Number primitiveConversion(Wrapper wrap, Object x, boolean cast) {
233         // Maybe merge this code with Wrapper.convert/cast.
234         Number res;
235         if (x == null) {
236             if (!cast)  return null;
237             return ZERO_INT;
238         }
239         if (x instanceof Number) {
240             res = (Number) x;
241         } else if (x instanceof Boolean) {
242             res = ((boolean)x ? ONE_INT : ZERO_INT);
243         } else if (x instanceof Character) {
244             res = (int)(char)x;
245         } else {
246             // this will fail with the required ClassCastException:
247             res = (Number) x;
248         }
249         Wrapper xwrap = Wrapper.findWrapperType(x.getClass());
250         if (xwrap == null || !cast && !wrap.isConvertibleFrom(xwrap))
251             // this will fail with the required ClassCastException:
252             return (Number) wrap.wrapperType().cast(x);
253         return res;
254     }
255 
256     /**
257      * The JVM verifier allows boolean, byte, short, or char to widen to int.
258      * Support exactly this conversion, from a boxed value type Boolean,
259      * Byte, Short, Character, or Integer.
260      */
widenSubword(Object x)261     public static int widenSubword(Object x) {
262         if (x instanceof Integer)
263             return (int) x;
264         else if (x instanceof Boolean)
265             return fromBoolean((boolean) x);
266         else if (x instanceof Character)
267             return (char) x;
268         else if (x instanceof Short)
269             return (short) x;
270         else if (x instanceof Byte)
271             return (byte) x;
272         else
273             // Fail with a ClassCastException.
274             return (int) x;
275     }
276 
277     /// Converting primitives to references
278 
boxInteger(int x)279     static Integer boxInteger(int x) {
280         return x;
281     }
282 
boxByte(byte x)283     static Byte boxByte(byte x) {
284         return x;
285     }
286 
boxShort(short x)287     static Short boxShort(short x) {
288         return x;
289     }
290 
boxBoolean(boolean x)291     static Boolean boxBoolean(boolean x) {
292         return x;
293     }
294 
boxCharacter(char x)295     static Character boxCharacter(char x) {
296         return x;
297     }
298 
boxLong(long x)299     static Long boxLong(long x) {
300         return x;
301     }
302 
boxFloat(float x)303     static Float boxFloat(float x) {
304         return x;
305     }
306 
boxDouble(double x)307     static Double boxDouble(double x) {
308         return x;
309     }
310 
boxType(Wrapper wrap)311     private static MethodType boxType(Wrapper wrap) {
312         // be exact, since return casts are hard to compose
313         Class<?> boxType = wrap.wrapperType();
314         return MethodType.methodType(boxType, wrap.primitiveType());
315     }
316 
317     private static final WrapperCache[] BOX_CONVERSIONS = newWrapperCaches(1);
318 
boxExact(Wrapper wrap)319     public static MethodHandle boxExact(Wrapper wrap) {
320         WrapperCache cache = BOX_CONVERSIONS[0];
321         MethodHandle mh = cache.get(wrap);
322         if (mh != null) {
323             return mh;
324         }
325         // look up the method
326         String name = "box" + wrap.wrapperSimpleName();
327         MethodType type = boxType(wrap);
328         try {
329             mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
330         } catch (ReflectiveOperationException ex) {
331             mh = null;
332         }
333         if (mh != null) {
334             return cache.put(wrap, mh);
335         }
336         throw new IllegalArgumentException("cannot find box adapter for " + wrap);
337     }
338 
339     /// Constant functions
340 
ignore(Object x)341     static void ignore(Object x) {
342         // no value to return; this is an unbox of null
343     }
344 
empty()345     static void empty() {
346     }
347 
zeroObject()348     static Object zeroObject() {
349         return null;
350     }
351 
zeroInteger()352     static int zeroInteger() {
353         return 0;
354     }
355 
zeroLong()356     static long zeroLong() {
357         return 0;
358     }
359 
zeroFloat()360     static float zeroFloat() {
361         return 0;
362     }
363 
zeroDouble()364     static double zeroDouble() {
365         return 0;
366     }
367 
368     private static final WrapperCache[] CONSTANT_FUNCTIONS = newWrapperCaches(2);
369 
zeroConstantFunction(Wrapper wrap)370     public static MethodHandle zeroConstantFunction(Wrapper wrap) {
371         WrapperCache cache = CONSTANT_FUNCTIONS[0];
372         MethodHandle mh = cache.get(wrap);
373         if (mh != null) {
374             return mh;
375         }
376         // slow path
377         MethodType type = MethodType.methodType(wrap.primitiveType());
378         switch (wrap) {
379             case VOID:
380                 mh = Handles.EMPTY;
381                 break;
382             case OBJECT:
383             case INT: case LONG: case FLOAT: case DOUBLE:
384                 try {
385                     mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "zero"+wrap.wrapperSimpleName(), type);
386                 } catch (ReflectiveOperationException ex) {
387                     mh = null;
388                 }
389                 break;
390         }
391         if (mh != null) {
392             return cache.put(wrap, mh);
393         }
394 
395         // use zeroInt and cast the result
396         if (wrap.isSubwordOrInt() && wrap != Wrapper.INT) {
397             mh = MethodHandles.explicitCastArguments(zeroConstantFunction(Wrapper.INT), type);
398             return cache.put(wrap, mh);
399         }
400         throw new IllegalArgumentException("cannot find zero constant for " + wrap);
401     }
402 
403     private static class Handles {
404         static final MethodHandle CAST_REFERENCE, IGNORE, EMPTY;
405         static {
406             try {
407                 MethodType idType = MethodType.genericMethodType(1);
408                 MethodType ignoreType = idType.changeReturnType(void.class);
409                 CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
410                 IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType);
411                 EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1));
412             } catch (NoSuchMethodException | IllegalAccessException ex) {
413                 throw newInternalError("uncaught exception", ex);
414             }
415         }
416     }
417 
ignore()418     public static MethodHandle ignore() {
419         return Handles.IGNORE;
420     }
421 
422     /** Return a method that casts its second argument (an Object) to the given type (a Class). */
cast()423     public static MethodHandle cast() {
424         return Handles.CAST_REFERENCE;
425     }
426 
427     /// Primitive conversions.
428     // These are supported directly by the JVM, usually by a single instruction.
429     // In the case of narrowing to a subword, there may be a pair of instructions.
430     // In the case of booleans, there may be a helper routine to manage a 1-bit value.
431     // This is the full 8x8 matrix (minus the diagonal).
432 
433     // narrow double to all other types:
doubleToFloat(double x)434     static float doubleToFloat(double x) {  // bytecode: d2f
435         return (float) x;
436     }
doubleToLong(double x)437     static long doubleToLong(double x) {  // bytecode: d2l
438         return (long) x;
439     }
doubleToInt(double x)440     static int doubleToInt(double x) {  // bytecode: d2i
441         return (int) x;
442     }
doubleToShort(double x)443     static short doubleToShort(double x) {  // bytecodes: d2i, i2s
444         return (short) x;
445     }
doubleToChar(double x)446     static char doubleToChar(double x) {  // bytecodes: d2i, i2c
447         return (char) x;
448     }
doubleToByte(double x)449     static byte doubleToByte(double x) {  // bytecodes: d2i, i2b
450         return (byte) x;
451     }
doubleToBoolean(double x)452     static boolean doubleToBoolean(double x) {
453         return toBoolean((byte) x);
454     }
455 
456     // widen float:
floatToDouble(float x)457     static double floatToDouble(float x) {  // bytecode: f2d
458         return x;
459     }
460     // narrow float:
floatToLong(float x)461     static long floatToLong(float x) {  // bytecode: f2l
462         return (long) x;
463     }
floatToInt(float x)464     static int floatToInt(float x) {  // bytecode: f2i
465         return (int) x;
466     }
floatToShort(float x)467     static short floatToShort(float x) {  // bytecodes: f2i, i2s
468         return (short) x;
469     }
floatToChar(float x)470     static char floatToChar(float x) {  // bytecodes: f2i, i2c
471         return (char) x;
472     }
floatToByte(float x)473     static byte floatToByte(float x) {  // bytecodes: f2i, i2b
474         return (byte) x;
475     }
floatToBoolean(float x)476     static boolean floatToBoolean(float x) {
477         return toBoolean((byte) x);
478     }
479 
480     // widen long:
longToDouble(long x)481     static double longToDouble(long x) {  // bytecode: l2d
482         return x;
483     }
longToFloat(long x)484     static float longToFloat(long x) {  // bytecode: l2f
485         return x;
486     }
487     // narrow long:
longToInt(long x)488     static int longToInt(long x) {  // bytecode: l2i
489         return (int) x;
490     }
longToShort(long x)491     static short longToShort(long x) {  // bytecodes: f2i, i2s
492         return (short) x;
493     }
longToChar(long x)494     static char longToChar(long x) {  // bytecodes: f2i, i2c
495         return (char) x;
496     }
longToByte(long x)497     static byte longToByte(long x) {  // bytecodes: f2i, i2b
498         return (byte) x;
499     }
longToBoolean(long x)500     static boolean longToBoolean(long x) {
501         return toBoolean((byte) x);
502     }
503 
504     // widen int:
intToDouble(int x)505     static double intToDouble(int x) {  // bytecode: i2d
506         return x;
507     }
intToFloat(int x)508     static float intToFloat(int x) {  // bytecode: i2f
509         return x;
510     }
intToLong(int x)511     static long intToLong(int x) {  // bytecode: i2l
512         return x;
513     }
514     // narrow int:
intToShort(int x)515     static short intToShort(int x) {  // bytecode: i2s
516         return (short) x;
517     }
intToChar(int x)518     static char intToChar(int x) {  // bytecode: i2c
519         return (char) x;
520     }
intToByte(int x)521     static byte intToByte(int x) {  // bytecode: i2b
522         return (byte) x;
523     }
intToBoolean(int x)524     static boolean intToBoolean(int x) {
525         return toBoolean((byte) x);
526     }
527 
528     // widen short:
shortToDouble(short x)529     static double shortToDouble(short x) {  // bytecode: i2d (implicit 's2i')
530         return x;
531     }
shortToFloat(short x)532     static float shortToFloat(short x) {  // bytecode: i2f (implicit 's2i')
533         return x;
534     }
shortToLong(short x)535     static long shortToLong(short x) {  // bytecode: i2l (implicit 's2i')
536         return x;
537     }
shortToInt(short x)538     static int shortToInt(short x) {  // (implicit 's2i')
539         return x;
540     }
541     // narrow short:
shortToChar(short x)542     static char shortToChar(short x) {  // bytecode: i2c (implicit 's2i')
543         return (char)x;
544     }
shortToByte(short x)545     static byte shortToByte(short x) {  // bytecode: i2b (implicit 's2i')
546         return (byte)x;
547     }
shortToBoolean(short x)548     static boolean shortToBoolean(short x) {
549         return toBoolean((byte) x);
550     }
551 
552     // widen char:
charToDouble(char x)553     static double charToDouble(char x) {  // bytecode: i2d (implicit 'c2i')
554         return x;
555     }
charToFloat(char x)556     static float charToFloat(char x) {  // bytecode: i2f (implicit 'c2i')
557         return x;
558     }
charToLong(char x)559     static long charToLong(char x) {  // bytecode: i2l (implicit 'c2i')
560         return x;
561     }
charToInt(char x)562     static int charToInt(char x) {  // (implicit 'c2i')
563         return x;
564     }
565     // narrow char:
charToShort(char x)566     static short charToShort(char x) {  // bytecode: i2s (implicit 'c2i')
567         return (short)x;
568     }
charToByte(char x)569     static byte charToByte(char x) {  // bytecode: i2b (implicit 'c2i')
570         return (byte)x;
571     }
charToBoolean(char x)572     static boolean charToBoolean(char x) {
573         return toBoolean((byte) x);
574     }
575 
576     // widen byte:
byteToDouble(byte x)577     static double byteToDouble(byte x) {  // bytecode: i2d (implicit 'b2i')
578         return x;
579     }
byteToFloat(byte x)580     static float byteToFloat(byte x) {  // bytecode: i2f (implicit 'b2i')
581         return x;
582     }
byteToLong(byte x)583     static long byteToLong(byte x) {  // bytecode: i2l (implicit 'b2i')
584         return x;
585     }
byteToInt(byte x)586     static int byteToInt(byte x) {  // (implicit 'b2i')
587         return x;
588     }
byteToShort(byte x)589     static short byteToShort(byte x) {  // bytecode: i2s (implicit 'b2i')
590         return (short)x;
591     }
byteToChar(byte x)592     static char byteToChar(byte x) {  // bytecode: i2b (implicit 'b2i')
593         return (char)x;
594     }
595     // narrow byte to boolean:
byteToBoolean(byte x)596     static boolean byteToBoolean(byte x) {
597         return toBoolean(x);
598     }
599 
600     // widen boolean to all types:
booleanToDouble(boolean x)601     static double booleanToDouble(boolean x) {
602         return fromBoolean(x);
603     }
booleanToFloat(boolean x)604     static float booleanToFloat(boolean x) {
605         return fromBoolean(x);
606     }
booleanToLong(boolean x)607     static long booleanToLong(boolean x) {
608         return fromBoolean(x);
609     }
booleanToInt(boolean x)610     static int booleanToInt(boolean x) {
611         return fromBoolean(x);
612     }
booleanToShort(boolean x)613     static short booleanToShort(boolean x) {
614         return fromBoolean(x);
615     }
booleanToChar(boolean x)616     static char booleanToChar(boolean x) {
617         return (char)fromBoolean(x);
618     }
booleanToByte(boolean x)619     static byte booleanToByte(boolean x) {
620         return fromBoolean(x);
621     }
622 
623     // helpers to force boolean into the conversion scheme:
toBoolean(byte x)624     static boolean toBoolean(byte x) {
625         // see javadoc for MethodHandles.explicitCastArguments
626         return ((x & 1) != 0);
627     }
fromBoolean(boolean x)628     static byte fromBoolean(boolean x) {
629         // see javadoc for MethodHandles.explicitCastArguments
630         return (x ? (byte)1 : (byte)0);
631     }
632 
633     private static final WrapperCache[] CONVERT_PRIMITIVE_FUNCTIONS = newWrapperCaches(Wrapper.COUNT);
634 
convertPrimitive(Wrapper wsrc, Wrapper wdst)635     public static MethodHandle convertPrimitive(Wrapper wsrc, Wrapper wdst) {
636         WrapperCache cache = CONVERT_PRIMITIVE_FUNCTIONS[wsrc.ordinal()];
637         MethodHandle mh = cache.get(wdst);
638         if (mh != null) {
639             return mh;
640         }
641         // slow path
642         Class<?> src = wsrc.primitiveType();
643         Class<?> dst = wdst.primitiveType();
644         MethodType type = MethodType.methodType(dst, src);
645         if (wsrc == wdst) {
646             mh = MethodHandles.identity(src);
647         } else {
648             assert(src.isPrimitive() && dst.isPrimitive());
649             try {
650                 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, src.getSimpleName()+"To"+capitalize(dst.getSimpleName()), type);
651             } catch (ReflectiveOperationException ex) {
652                 mh = null;
653             }
654         }
655         if (mh != null) {
656             assert(mh.type() == type) : mh;
657             return cache.put(wdst, mh);
658         }
659 
660         throw new IllegalArgumentException("cannot find primitive conversion function for " +
661                                            src.getSimpleName()+" -> "+dst.getSimpleName());
662     }
663 
convertPrimitive(Class<?> src, Class<?> dst)664     public static MethodHandle convertPrimitive(Class<?> src, Class<?> dst) {
665         return convertPrimitive(Wrapper.forPrimitiveType(src), Wrapper.forPrimitiveType(dst));
666     }
667 
capitalize(String x)668     private static String capitalize(String x) {
669         return Character.toUpperCase(x.charAt(0))+x.substring(1);
670     }
671 
672     // handy shared exception makers (they simplify the common case code)
newInternalError(String message, Throwable cause)673     private static InternalError newInternalError(String message, Throwable cause) {
674         return new InternalError(message, cause);
675     }
newInternalError(Throwable cause)676     private static InternalError newInternalError(Throwable cause) {
677         return new InternalError(cause);
678     }
679 }
680