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 java.util.EnumMap; 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 /** Thread-safe canonicalized mapping from Wrapper to MethodHandle 39 * with unsynchronized reads and synchronized writes. 40 * It's safe to publish MethodHandles by data race because they are immutable. */ 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]; 58 for (int i = 0; i < n; i++) 59 caches[i] = new WrapperCache(); 60 return caches; 61 } 62 63 /// Converting references to values. 64 65 // There are several levels of this unboxing conversions: 66 // no conversions: exactly Integer.valueOf, etc. 67 // implicit conversions sanctioned by JLS 5.1.2, etc. 68 // explicit conversions as allowed by explicitCastArguments 69 70 static int unboxInteger(Integer x) { 71 return x; 72 } 73 static int unboxInteger(Object x, boolean cast) { 74 if (x instanceof Integer) 75 return (Integer) x; 76 return primitiveConversion(Wrapper.INT, x, cast).intValue(); 77 } 78 79 static byte unboxByte(Byte x) { 80 return x; 81 } 82 static byte unboxByte(Object x, boolean cast) { 83 if (x instanceof Byte) 84 return (Byte) x; 85 return primitiveConversion(Wrapper.BYTE, x, cast).byteValue(); 86 } 87 88 static short unboxShort(Short x) { 89 return x; 90 } 91 static short unboxShort(Object x, boolean cast) { 92 if (x instanceof Short) 93 return (Short) x; 94 return primitiveConversion(Wrapper.SHORT, x, cast).shortValue(); 95 } 96 97 static boolean unboxBoolean(Boolean x) { 98 return x; 99 } 100 static boolean unboxBoolean(Object x, boolean cast) { 101 if (x instanceof Boolean) 102 return (Boolean) x; 103 return (primitiveConversion(Wrapper.BOOLEAN, x, cast).intValue() & 1) != 0; 104 } 105 106 static char unboxCharacter(Character x) { 107 return x; 108 } 109 static char unboxCharacter(Object x, boolean cast) { 110 if (x instanceof Character) 111 return (Character) x; 112 return (char) primitiveConversion(Wrapper.CHAR, x, cast).intValue(); 113 } 114 115 static long unboxLong(Long x) { 116 return x; 117 } 118 static long unboxLong(Object x, boolean cast) { 119 if (x instanceof Long) 120 return (Long) x; 121 return primitiveConversion(Wrapper.LONG, x, cast).longValue(); 122 } 123 124 static float unboxFloat(Float x) { 125 return x; 126 } 127 static float unboxFloat(Object x, boolean cast) { 128 if (x instanceof Float) 129 return (Float) x; 130 return primitiveConversion(Wrapper.FLOAT, x, cast).floatValue(); 131 } 132 133 static double unboxDouble(Double x) { 134 return x; 135 } 136 static double unboxDouble(Object x, boolean cast) { 137 if (x instanceof Double) 138 return (Double) x; 139 return primitiveConversion(Wrapper.DOUBLE, x, cast).doubleValue(); 140 } 141 142 private static MethodType unboxType(Wrapper wrap, int kind) { 143 if (kind == 0) 144 return MethodType.methodType(wrap.primitiveType(), wrap.wrapperType()); 145 return MethodType.methodType(wrap.primitiveType(), Object.class, boolean.class); 146 } 147 148 private static final WrapperCache[] UNBOX_CONVERSIONS = newWrapperCaches(4); 149 150 private static MethodHandle unbox(Wrapper wrap, int kind) { 151 // kind 0 -> strongly typed with NPE 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]; 156 MethodHandle mh = cache.get(wrap); 157 if (mh != null) { 158 return mh; 159 } 160 // slow path 161 switch (wrap) { 162 case OBJECT: 163 case VOID: 164 throw new IllegalArgumentException("unbox "+wrap); 165 } 166 // look up the method 167 String name = "unbox" + wrap.wrapperSimpleName(); 168 MethodType type = unboxType(wrap, kind); 169 try { 170 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type); 171 } catch (ReflectiveOperationException ex) { 172 mh = null; 173 } 174 if (mh != null) { 175 if (kind > 0) { 176 boolean cast = (kind != 2); 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); 183 } 184 throw new IllegalArgumentException("cannot find unbox adapter for " + wrap 185 + (kind <= 1 ? " (exact)" : kind == 3 ? " (cast)" : "")); 186 } 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 */ 214 public static MethodHandle unboxCast(Wrapper type) { 215 return unbox(type, 3); 216 } 217 218 static private final Integer ZERO_INT = 0, ONE_INT = 1; 219 220 /// Primitive conversions 221 /** 222 * Produce a Number which represents the given value {@code x} 223 * according to the primitive type of the given wrapper {@code wrap}. 224 * Caller must invoke intValue, byteValue, longValue (etc.) on the result 225 * to retrieve the desired primitive value. 226 */ 227 public static Number primitiveConversion(Wrapper wrap, Object x, boolean cast) { 228 // Maybe merge this code with Wrapper.convert/cast. 229 Number res; 230 if (x == null) { 231 if (!cast) return null; 232 return ZERO_INT; 233 } 234 if (x instanceof Number) { 235 res = (Number) x; 236 } else if (x instanceof Boolean) { 237 res = ((boolean)x ? ONE_INT : ZERO_INT); 238 } else if (x instanceof Character) { 239 res = (int)(char)x; 240 } else { 241 // this will fail with the required ClassCastException: 242 res = (Number) x; 243 } 244 Wrapper xwrap = Wrapper.findWrapperType(x.getClass()); 245 if (xwrap == null || !cast && !wrap.isConvertibleFrom(xwrap)) 246 // this will fail with the required ClassCastException: 247 return (Number) wrap.wrapperType().cast(x); 248 return res; 249 } 250 251 /** 252 * The JVM verifier allows boolean, byte, short, or char to widen to int. 253 * Support exactly this conversion, from a boxed value type Boolean, 254 * Byte, Short, Character, or Integer. 255 */ 256 public static int widenSubword(Object x) { 257 if (x instanceof Integer) 258 return (int) x; 259 else if (x instanceof Boolean) 260 return fromBoolean((boolean) x); 261 else if (x instanceof Character) 262 return (char) x; 263 else if (x instanceof Short) 264 return (short) x; 265 else if (x instanceof Byte) 266 return (byte) x; 267 else 268 // Fail with a ClassCastException. 269 return (int) x; 270 } 271 272 /// Converting primitives to references 273 274 static Integer boxInteger(int x) { 275 return x; 276 } 277 278 static Byte boxByte(byte x) { 279 return x; 280 } 281 282 static Short boxShort(short x) { 283 return x; 284 } 285 286 static Boolean boxBoolean(boolean x) { 287 return x; 288 } 289 290 static Character boxCharacter(char x) { 291 return x; 292 } 293 294 static Long boxLong(long x) { 295 return x; 296 } 297 298 static Float boxFloat(float x) { 299 return x; 300 } 301 302 static Double boxDouble(double x) { 303 return x; 304 } 305 306 private static MethodType boxType(Wrapper wrap) { 307 // be exact, since return casts are hard to compose 308 Class<?> boxType = wrap.wrapperType(); 309 return MethodType.methodType(boxType, wrap.primitiveType()); 310 } 311 312 private static final WrapperCache[] BOX_CONVERSIONS = newWrapperCaches(1); 313 314 public static MethodHandle boxExact(Wrapper wrap) { 315 WrapperCache cache = BOX_CONVERSIONS[0]; 316 MethodHandle mh = cache.get(wrap); 317 if (mh != null) { 318 return mh; 319 } 320 // look up the method 321 String name = "box" + wrap.wrapperSimpleName(); 322 MethodType type = boxType(wrap); 323 try { 324 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type); 325 } catch (ReflectiveOperationException ex) { 326 mh = null; 327 } 328 if (mh != null) { 329 return cache.put(wrap, mh); 330 } 331 throw new IllegalArgumentException("cannot find box adapter for " + wrap); 332 } 333 334 /// Constant functions 335 336 static void ignore(Object x) { 337 // no value to return; this is an unbox of null 338 } 339 340 static void empty() { 341 } 342 343 static Object zeroObject() { 344 return null; 345 } 346 347 static int zeroInteger() { 348 return 0; 349 } 350 351 static long zeroLong() { 352 return 0; 353 } 354 355 static float zeroFloat() { 356 return 0; 357 } 358 359 static double zeroDouble() { 360 return 0; 361 } 362 363 private static final WrapperCache[] CONSTANT_FUNCTIONS = newWrapperCaches(2); 364 365 public static MethodHandle zeroConstantFunction(Wrapper wrap) { 366 WrapperCache cache = CONSTANT_FUNCTIONS[0]; 367 MethodHandle mh = cache.get(wrap); 368 if (mh != null) { 369 return mh; 370 } 371 // slow path 372 MethodType type = MethodType.methodType(wrap.primitiveType()); 373 switch (wrap) { 374 case VOID: 375 mh = EMPTY; 376 break; 377 case OBJECT: 378 case INT: case LONG: case FLOAT: case DOUBLE: 379 try { 380 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "zero"+wrap.wrapperSimpleName(), type); 381 } catch (ReflectiveOperationException ex) { 382 mh = null; 383 } 384 break; 385 } 386 if (mh != null) { 387 return cache.put(wrap, mh); 388 } 389 390 // use zeroInt and cast the result 391 if (wrap.isSubwordOrInt() && wrap != Wrapper.INT) { 392 mh = MethodHandles.explicitCastArguments(zeroConstantFunction(Wrapper.INT), type); 393 return cache.put(wrap, mh); 394 } 395 throw new IllegalArgumentException("cannot find zero constant for " + wrap); 396 } 397 398 /// Converting references to references. 399 400 /** 401 * Identity function. 402 * @param x an arbitrary reference value 403 * @return the same value x 404 */ 405 static <T> T identity(T x) { 406 return x; 407 } 408 409 static <T> T[] identity(T[] x) { 410 return x; 411 } 412 413 /** 414 * Identity function on ints. 415 * @param x an arbitrary int value 416 * @return the same value x 417 */ 418 static int identity(int x) { 419 return x; 420 } 421 422 static byte identity(byte x) { 423 return x; 424 } 425 426 static short identity(short x) { 427 return x; 428 } 429 430 static boolean identity(boolean x) { 431 return x; 432 } 433 434 static char identity(char x) { 435 return x; 436 } 437 438 /** 439 * Identity function on longs. 440 * @param x an arbitrary long value 441 * @return the same value x 442 */ 443 static long identity(long x) { 444 return x; 445 } 446 447 static float identity(float x) { 448 return x; 449 } 450 451 static double identity(double x) { 452 return x; 453 } 454 455 private static final MethodHandle IDENTITY, CAST_REFERENCE, IGNORE, EMPTY; 456 static { 457 try { 458 MethodType idType = MethodType.genericMethodType(1); 459 MethodType ignoreType = idType.changeReturnType(void.class); 460 IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", idType); 461 CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType); 462 IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType); 463 EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1)); 464 } catch (NoSuchMethodException | IllegalAccessException ex) { 465 throw newInternalError("uncaught exception", ex); 466 } 467 } 468 469 public static MethodHandle ignore() { 470 return IGNORE; 471 } 472 473 public static MethodHandle identity() { 474 return IDENTITY; 475 } 476 477 public static MethodHandle identity(Class<?> type) { 478 if (!type.isPrimitive()) 479 // Reference identity has been moved into MethodHandles: 480 return MethodHandles.identity(type); 481 return identity(Wrapper.findPrimitiveType(type)); 482 } 483 484 public static MethodHandle identity(Wrapper wrap) { 485 WrapperCache cache = CONSTANT_FUNCTIONS[1]; 486 MethodHandle mh = cache.get(wrap); 487 if (mh != null) { 488 return mh; 489 } 490 // slow path 491 MethodType type = MethodType.methodType(wrap.primitiveType()); 492 if (wrap != Wrapper.VOID) 493 type = type.appendParameterTypes(wrap.primitiveType()); 494 try { 495 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", type); 496 } catch (ReflectiveOperationException ex) { 497 mh = null; 498 } 499 if (mh == null && wrap == Wrapper.VOID) { 500 mh = EMPTY; // #(){} : #()void 501 } 502 if (mh != null) { 503 return cache.put(wrap, mh); 504 } 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; 511 } 512 513 /// Primitive conversions. 514 // These are supported directly by the JVM, usually by a single instruction. 515 // In the case of narrowing to a subword, there may be a pair of instructions. 516 // In the case of booleans, there may be a helper routine to manage a 1-bit value. 517 // This is the full 8x8 matrix (minus the diagonal). 518 519 // narrow double to all other types: 520 static float doubleToFloat(double x) { // bytecode: d2f 521 return (float) x; 522 } 523 static long doubleToLong(double x) { // bytecode: d2l 524 return (long) x; 525 } 526 static int doubleToInt(double x) { // bytecode: d2i 527 return (int) x; 528 } 529 static short doubleToShort(double x) { // bytecodes: d2i, i2s 530 return (short) x; 531 } 532 static char doubleToChar(double x) { // bytecodes: d2i, i2c 533 return (char) x; 534 } 535 static byte doubleToByte(double x) { // bytecodes: d2i, i2b 536 return (byte) x; 537 } 538 static boolean doubleToBoolean(double x) { 539 return toBoolean((byte) x); 540 } 541 542 // widen float: 543 static double floatToDouble(float x) { // bytecode: f2d 544 return x; 545 } 546 // narrow float: 547 static long floatToLong(float x) { // bytecode: f2l 548 return (long) x; 549 } 550 static int floatToInt(float x) { // bytecode: f2i 551 return (int) x; 552 } 553 static short floatToShort(float x) { // bytecodes: f2i, i2s 554 return (short) x; 555 } 556 static char floatToChar(float x) { // bytecodes: f2i, i2c 557 return (char) x; 558 } 559 static byte floatToByte(float x) { // bytecodes: f2i, i2b 560 return (byte) x; 561 } 562 static boolean floatToBoolean(float x) { 563 return toBoolean((byte) x); 564 } 565 566 // widen long: 567 static double longToDouble(long x) { // bytecode: l2d 568 return x; 569 } 570 static float longToFloat(long x) { // bytecode: l2f 571 return x; 572 } 573 // narrow long: 574 static int longToInt(long x) { // bytecode: l2i 575 return (int) x; 576 } 577 static short longToShort(long x) { // bytecodes: f2i, i2s 578 return (short) x; 579 } 580 static char longToChar(long x) { // bytecodes: f2i, i2c 581 return (char) x; 582 } 583 static byte longToByte(long x) { // bytecodes: f2i, i2b 584 return (byte) x; 585 } 586 static boolean longToBoolean(long x) { 587 return toBoolean((byte) x); 588 } 589 590 // widen int: 591 static double intToDouble(int x) { // bytecode: i2d 592 return x; 593 } 594 static float intToFloat(int x) { // bytecode: i2f 595 return x; 596 } 597 static long intToLong(int x) { // bytecode: i2l 598 return x; 599 } 600 // narrow int: 601 static short intToShort(int x) { // bytecode: i2s 602 return (short) x; 603 } 604 static char intToChar(int x) { // bytecode: i2c 605 return (char) x; 606 } 607 static byte intToByte(int x) { // bytecode: i2b 608 return (byte) x; 609 } 610 static boolean intToBoolean(int x) { 611 return toBoolean((byte) x); 612 } 613 614 // widen short: 615 static double shortToDouble(short x) { // bytecode: i2d (implicit 's2i') 616 return x; 617 } 618 static float shortToFloat(short x) { // bytecode: i2f (implicit 's2i') 619 return x; 620 } 621 static long shortToLong(short x) { // bytecode: i2l (implicit 's2i') 622 return x; 623 } 624 static int shortToInt(short x) { // (implicit 's2i') 625 return x; 626 } 627 // narrow short: 628 static char shortToChar(short x) { // bytecode: i2c (implicit 's2i') 629 return (char)x; 630 } 631 static byte shortToByte(short x) { // bytecode: i2b (implicit 's2i') 632 return (byte)x; 633 } 634 static boolean shortToBoolean(short x) { 635 return toBoolean((byte) x); 636 } 637 638 // widen char: 639 static double charToDouble(char x) { // bytecode: i2d (implicit 'c2i') 640 return x; 641 } 642 static float charToFloat(char x) { // bytecode: i2f (implicit 'c2i') 643 return x; 644 } 645 static long charToLong(char x) { // bytecode: i2l (implicit 'c2i') 646 return x; 647 } 648 static int charToInt(char x) { // (implicit 'c2i') 649 return x; 650 } 651 // narrow char: 652 static short charToShort(char x) { // bytecode: i2s (implicit 'c2i') 653 return (short)x; 654 } 655 static byte charToByte(char x) { // bytecode: i2b (implicit 'c2i') 656 return (byte)x; 657 } 658 static boolean charToBoolean(char x) { 659 return toBoolean((byte) x); 660 } 661 662 // widen byte: 663 static double byteToDouble(byte x) { // bytecode: i2d (implicit 'b2i') 664 return x; 665 } 666 static float byteToFloat(byte x) { // bytecode: i2f (implicit 'b2i') 667 return x; 668 } 669 static long byteToLong(byte x) { // bytecode: i2l (implicit 'b2i') 670 return x; 671 } 672 static int byteToInt(byte x) { // (implicit 'b2i') 673 return x; 674 } 675 static short byteToShort(byte x) { // bytecode: i2s (implicit 'b2i') 676 return (short)x; 677 } 678 static char byteToChar(byte x) { // bytecode: i2b (implicit 'b2i') 679 return (char)x; 680 } 681 // narrow byte to boolean: 682 static boolean byteToBoolean(byte x) { 683 return toBoolean(x); 684 } 685 686 // widen boolean to all types: 687 static double booleanToDouble(boolean x) { 688 return fromBoolean(x); 689 } 690 static float booleanToFloat(boolean x) { 691 return fromBoolean(x); 692 } 693 static long booleanToLong(boolean x) { 694 return fromBoolean(x); 695 } 696 static int booleanToInt(boolean x) { 697 return fromBoolean(x); 698 } 699 static short booleanToShort(boolean x) { 700 return fromBoolean(x); 701 } 702 static char booleanToChar(boolean x) { 703 return (char)fromBoolean(x); 704 } 705 static byte booleanToByte(boolean x) { 706 return fromBoolean(x); 707 } 708 709 // helpers to force boolean into the conversion scheme: 710 static boolean toBoolean(byte x) { 711 // see javadoc for MethodHandles.explicitCastArguments 712 return ((x & 1) != 0); 713 } 714 static byte fromBoolean(boolean x) { 715 // see javadoc for MethodHandles.explicitCastArguments 716 return (x ? (byte)1 : (byte)0); 717 } 718 719 private static final WrapperCache[] CONVERT_PRIMITIVE_FUNCTIONS = newWrapperCaches(Wrapper.values().length); 720 721 public static MethodHandle convertPrimitive(Wrapper wsrc, Wrapper wdst) { 722 WrapperCache cache = CONVERT_PRIMITIVE_FUNCTIONS[wsrc.ordinal()]; 723 MethodHandle mh = cache.get(wdst); 724 if (mh != null) { 725 return mh; 726 } 727 // slow path 728 Class<?> src = wsrc.primitiveType(); 729 Class<?> dst = wdst.primitiveType(); 730 MethodType type = MethodType.methodType(dst, src); 731 if (wsrc == wdst) { 732 mh = MethodHandles.identity(src); 733 } else { 734 assert(src.isPrimitive() && dst.isPrimitive()); 735 try { 736 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, src.getSimpleName()+"To"+capitalize(dst.getSimpleName()), type); 737 } catch (ReflectiveOperationException ex) { 738 mh = null; 739 } 740 } 741 if (mh != null) { 742 assert(mh.type() == type) : mh; 743 return cache.put(wdst, mh); 744 } 745 746 throw new IllegalArgumentException("cannot find primitive conversion function for " + 747 src.getSimpleName()+" -> "+dst.getSimpleName()); 748 } 749 750 public static MethodHandle convertPrimitive(Class<?> src, Class<?> dst) { 751 return convertPrimitive(Wrapper.forPrimitiveType(src), Wrapper.forPrimitiveType(dst)); 752 } 753 754 private static String capitalize(String x) { 755 return Character.toUpperCase(x.charAt(0))+x.substring(1); 756 } 757 758 // handy shared exception makers (they simplify the common case code) 759 private static InternalError newInternalError(String message, Throwable cause) { 760 return new InternalError(message, cause); 761 } 762 private static InternalError newInternalError(Throwable cause) { 763 return new InternalError(cause); 764 } 765 }