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