1 /* 2 * Copyright (c) 2008, 2012, 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.security.AccessController; 33 import java.security.PrivilegedAction; 34 import java.util.ArrayList; 35 import java.util.Arrays; 36 import java.util.Collections; 37 import java.util.EnumMap; 38 import java.util.List; 39 40 public class ValueConversions { 41 private static final Class<?> THIS_CLASS = ValueConversions.class; 42 // Do not adjust this except for special platforms: 43 private static final int MAX_ARITY; 44 static { 45 final Object[] values = { 255 }; 46 AccessController.doPrivileged(new PrivilegedAction<Void>() { 47 @Override 48 public Void run() { 49 values[0] = Integer.getInteger(THIS_CLASS.getName()+".MAX_ARITY", 255); 50 return null; 51 } 52 }); 53 MAX_ARITY = (Integer) values[0]; 54 } 55 56 private static final Lookup IMPL_LOOKUP = MethodHandles.lookup(); 57 58 private static EnumMap<Wrapper, MethodHandle>[] newWrapperCaches(int n) { 59 @SuppressWarnings("unchecked") // generic array creation 60 EnumMap<Wrapper, MethodHandle>[] caches 61 = (EnumMap<Wrapper, MethodHandle>[]) new EnumMap<?,?>[n]; 62 for (int i = 0; i < n; i++) 63 caches[i] = new EnumMap<>(Wrapper.class); 64 return caches; 65 } 66 67 /// Converting references to values. 68 69 // There are several levels of this unboxing conversions: 70 // no conversions: exactly Integer.valueOf, etc. 71 // implicit conversions sanctioned by JLS 5.1.2, etc. 72 // explicit conversions as allowed by explicitCastArguments 73 74 static int unboxInteger(Object x, boolean cast) { 75 if (x instanceof Integer) 76 return ((Integer) x).intValue(); 77 return primitiveConversion(Wrapper.INT, x, cast).intValue(); 78 } 79 80 static byte unboxByte(Object x, boolean cast) { 81 if (x instanceof Byte) 82 return ((Byte) x).byteValue(); 83 return primitiveConversion(Wrapper.BYTE, x, cast).byteValue(); 84 } 85 86 static short unboxShort(Object x, boolean cast) { 87 if (x instanceof Short) 88 return ((Short) x).shortValue(); 89 return primitiveConversion(Wrapper.SHORT, x, cast).shortValue(); 90 } 91 92 static boolean unboxBoolean(Object x, boolean cast) { 93 if (x instanceof Boolean) 94 return ((Boolean) x).booleanValue(); 95 return (primitiveConversion(Wrapper.BOOLEAN, x, cast).intValue() & 1) != 0; 96 } 97 98 static char unboxCharacter(Object x, boolean cast) { 99 if (x instanceof Character) 100 return ((Character) x).charValue(); 101 return (char) primitiveConversion(Wrapper.CHAR, x, cast).intValue(); 102 } 103 104 static long unboxLong(Object x, boolean cast) { 105 if (x instanceof Long) 106 return ((Long) x).longValue(); 107 return primitiveConversion(Wrapper.LONG, x, cast).longValue(); 108 } 109 110 static float unboxFloat(Object x, boolean cast) { 111 if (x instanceof Float) 112 return ((Float) x).floatValue(); 113 return primitiveConversion(Wrapper.FLOAT, x, cast).floatValue(); 114 } 115 116 static double unboxDouble(Object x, boolean cast) { 117 if (x instanceof Double) 118 return ((Double) x).doubleValue(); 119 return primitiveConversion(Wrapper.DOUBLE, x, cast).doubleValue(); 120 } 121 122 private static MethodType unboxType(Wrapper wrap) { 123 return MethodType.methodType(wrap.primitiveType(), Object.class, boolean.class); 124 } 125 126 private static final EnumMap<Wrapper, MethodHandle>[] 127 UNBOX_CONVERSIONS = newWrapperCaches(2); 128 129 private static MethodHandle unbox(Wrapper wrap, boolean cast) { 130 EnumMap<Wrapper, MethodHandle> cache = UNBOX_CONVERSIONS[(cast?1:0)]; 131 MethodHandle mh = cache.get(wrap); 132 if (mh != null) { 133 return mh; 134 } 135 // slow path 136 switch (wrap) { 137 case OBJECT: 138 mh = IDENTITY; break; 139 case VOID: 140 mh = IGNORE; break; 141 } 142 if (mh != null) { 143 cache.put(wrap, mh); 144 return mh; 145 } 146 // look up the method 147 String name = "unbox" + wrap.wrapperSimpleName(); 148 MethodType type = unboxType(wrap); 149 try { 150 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type); 151 } catch (ReflectiveOperationException ex) { 152 mh = null; 153 } 154 if (mh != null) { 155 mh = MethodHandles.insertArguments(mh, 1, cast); 156 cache.put(wrap, mh); 157 return mh; 158 } 159 throw new IllegalArgumentException("cannot find unbox adapter for " + wrap 160 + (cast ? " (cast)" : "")); 161 } 162 163 public static MethodHandle unboxCast(Wrapper type) { 164 return unbox(type, true); 165 } 166 167 public static MethodHandle unbox(Class<?> type) { 168 return unbox(Wrapper.forPrimitiveType(type), false); 169 } 170 171 public static MethodHandle unboxCast(Class<?> type) { 172 return unbox(Wrapper.forPrimitiveType(type), true); 173 } 174 175 static private final Integer ZERO_INT = 0, ONE_INT = 1; 176 177 /// Primitive conversions 178 /** 179 * Produce a Number which represents the given value {@code x} 180 * according to the primitive type of the given wrapper {@code wrap}. 181 * Caller must invoke intValue, byteValue, longValue (etc.) on the result 182 * to retrieve the desired primitive value. 183 */ 184 public static Number primitiveConversion(Wrapper wrap, Object x, boolean cast) { 185 // Maybe merge this code with Wrapper.convert/cast. 186 Number res; 187 if (x == null) { 188 if (!cast) return null; 189 return ZERO_INT; 190 } 191 if (x instanceof Number) { 192 res = (Number) x; 193 } else if (x instanceof Boolean) { 194 res = ((boolean)x ? ONE_INT : ZERO_INT); 195 } else if (x instanceof Character) { 196 res = (int)(char)x; 197 } else { 198 // this will fail with the required ClassCastException: 199 res = (Number) x; 200 } 201 Wrapper xwrap = Wrapper.findWrapperType(x.getClass()); 202 if (xwrap == null || !cast && !wrap.isConvertibleFrom(xwrap)) 203 // this will fail with the required ClassCastException: 204 return (Number) wrap.wrapperType().cast(x); 205 return res; 206 } 207 208 /** 209 * The JVM verifier allows boolean, byte, short, or char to widen to int. 210 * Support exactly this conversion, from a boxed value type Boolean, 211 * Byte, Short, Character, or Integer. 212 */ 213 public static int widenSubword(Object x) { 214 if (x instanceof Integer) 215 return (int) x; 216 else if (x instanceof Boolean) 217 return fromBoolean((boolean) x); 218 else if (x instanceof Character) 219 return (char) x; 220 else if (x instanceof Short) 221 return (short) x; 222 else if (x instanceof Byte) 223 return (byte) x; 224 else 225 // Fail with a ClassCastException. 226 return (int) x; 227 } 228 229 /// Converting primitives to references 230 231 static Integer boxInteger(int x) { 232 return x; 233 } 234 235 static Byte boxByte(byte x) { 236 return x; 237 } 238 239 static Short boxShort(short x) { 240 return x; 241 } 242 243 static Boolean boxBoolean(boolean x) { 244 return x; 245 } 246 247 static Character boxCharacter(char x) { 248 return x; 249 } 250 251 static Long boxLong(long x) { 252 return x; 253 } 254 255 static Float boxFloat(float x) { 256 return x; 257 } 258 259 static Double boxDouble(double x) { 260 return x; 261 } 262 263 private static MethodType boxType(Wrapper wrap) { 264 // be exact, since return casts are hard to compose 265 Class<?> boxType = wrap.wrapperType(); 266 return MethodType.methodType(boxType, wrap.primitiveType()); 267 } 268 269 private static final EnumMap<Wrapper, MethodHandle>[] 270 BOX_CONVERSIONS = newWrapperCaches(2); 271 272 private static MethodHandle box(Wrapper wrap, boolean exact) { 273 EnumMap<Wrapper, MethodHandle> cache = BOX_CONVERSIONS[(exact?1:0)]; 274 MethodHandle mh = cache.get(wrap); 275 if (mh != null) { 276 return mh; 277 } 278 // slow path 279 switch (wrap) { 280 case OBJECT: 281 mh = IDENTITY; break; 282 case VOID: 283 mh = ZERO_OBJECT; 284 break; 285 } 286 if (mh != null) { 287 cache.put(wrap, mh); 288 return mh; 289 } 290 // look up the method 291 String name = "box" + wrap.wrapperSimpleName(); 292 MethodType type = boxType(wrap); 293 if (exact) { 294 try { 295 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type); 296 } catch (ReflectiveOperationException ex) { 297 mh = null; 298 } 299 } else { 300 mh = box(wrap, !exact).asType(type.erase()); 301 } 302 if (mh != null) { 303 cache.put(wrap, mh); 304 return mh; 305 } 306 throw new IllegalArgumentException("cannot find box adapter for " 307 + wrap + (exact ? " (exact)" : "")); 308 } 309 310 public static MethodHandle box(Class<?> type) { 311 boolean exact = false; 312 // e.g., boxShort(short)Short if exact, 313 // e.g., boxShort(short)Object if !exact 314 return box(Wrapper.forPrimitiveType(type), exact); 315 } 316 317 public static MethodHandle box(Wrapper type) { 318 boolean exact = false; 319 return box(type, exact); 320 } 321 322 /// Constant functions 323 324 static void ignore(Object x) { 325 // no value to return; this is an unbox of null 326 } 327 328 static void empty() { 329 } 330 331 static Object zeroObject() { 332 return null; 333 } 334 335 static int zeroInteger() { 336 return 0; 337 } 338 339 static long zeroLong() { 340 return 0; 341 } 342 343 static float zeroFloat() { 344 return 0; 345 } 346 347 static double zeroDouble() { 348 return 0; 349 } 350 351 private static final EnumMap<Wrapper, MethodHandle>[] 352 CONSTANT_FUNCTIONS = newWrapperCaches(2); 353 354 public static MethodHandle zeroConstantFunction(Wrapper wrap) { 355 EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[0]; 356 MethodHandle mh = cache.get(wrap); 357 if (mh != null) { 358 return mh; 359 } 360 // slow path 361 MethodType type = MethodType.methodType(wrap.primitiveType()); 362 switch (wrap) { 363 case VOID: 364 mh = EMPTY; 365 break; 366 case OBJECT: 367 case INT: case LONG: case FLOAT: case DOUBLE: 368 try { 369 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "zero"+wrap.wrapperSimpleName(), type); 370 } catch (ReflectiveOperationException ex) { 371 mh = null; 372 } 373 break; 374 } 375 if (mh != null) { 376 cache.put(wrap, mh); 377 return mh; 378 } 379 380 // use zeroInt and cast the result 381 if (wrap.isSubwordOrInt() && wrap != Wrapper.INT) { 382 mh = MethodHandles.explicitCastArguments(zeroConstantFunction(Wrapper.INT), type); 383 cache.put(wrap, mh); 384 return mh; 385 } 386 throw new IllegalArgumentException("cannot find zero constant for " + wrap); 387 } 388 389 /// Converting references to references. 390 391 /** 392 * Identity function. 393 * @param x an arbitrary reference value 394 * @return the same value x 395 */ 396 static <T> T identity(T x) { 397 return x; 398 } 399 400 static <T> T[] identity(T[] x) { 401 return x; 402 } 403 404 /** 405 * Identity function on ints. 406 * @param x an arbitrary int value 407 * @return the same value x 408 */ 409 static int identity(int x) { 410 return x; 411 } 412 413 static byte identity(byte x) { 414 return x; 415 } 416 417 static short identity(short x) { 418 return x; 419 } 420 421 static boolean identity(boolean x) { 422 return x; 423 } 424 425 static char identity(char x) { 426 return x; 427 } 428 429 /** 430 * Identity function on longs. 431 * @param x an arbitrary long value 432 * @return the same value x 433 */ 434 static long identity(long x) { 435 return x; 436 } 437 438 static float identity(float x) { 439 return x; 440 } 441 442 static double identity(double x) { 443 return x; 444 } 445 446 /** 447 * Identity function, with reference cast. 448 * @param t an arbitrary reference type 449 * @param x an arbitrary reference value 450 * @return the same value x 451 */ 452 @SuppressWarnings("unchecked") 453 static <T,U> T castReference(Class<? extends T> t, U x) { 454 // inlined Class.cast because we can't ForceInline it 455 if (x != null && !t.isInstance(x)) 456 throw newClassCastException(t, x); 457 return (T) x; 458 } 459 460 private static ClassCastException newClassCastException(Class<?> t, Object obj) { 461 return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName()); 462 } 463 464 private static final MethodHandle IDENTITY, CAST_REFERENCE, ZERO_OBJECT, IGNORE, EMPTY, 465 ARRAY_IDENTITY, FILL_NEW_TYPED_ARRAY, FILL_NEW_ARRAY; 466 static { 467 try { 468 MethodType idType = MethodType.genericMethodType(1); 469 MethodType castType = idType.insertParameterTypes(0, Class.class); 470 MethodType ignoreType = idType.changeReturnType(void.class); 471 MethodType zeroObjectType = MethodType.genericMethodType(0); 472 IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", idType); 473 //CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType); 474 CAST_REFERENCE = IMPL_LOOKUP.findStatic(THIS_CLASS, "castReference", castType); 475 ZERO_OBJECT = IMPL_LOOKUP.findStatic(THIS_CLASS, "zeroObject", zeroObjectType); 476 IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType); 477 EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1)); 478 ARRAY_IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", MethodType.methodType(Object[].class, Object[].class)); 479 FILL_NEW_ARRAY = IMPL_LOOKUP 480 .findStatic(THIS_CLASS, "fillNewArray", 481 MethodType.methodType(Object[].class, Integer.class, Object[].class)); 482 FILL_NEW_TYPED_ARRAY = IMPL_LOOKUP 483 .findStatic(THIS_CLASS, "fillNewTypedArray", 484 MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class)); 485 } catch (NoSuchMethodException | IllegalAccessException ex) { 486 throw newInternalError("uncaught exception", ex); 487 } 488 } 489 490 // Varargs methods need to be in a separately initialized class, to avoid bootstrapping problems. 491 static class LazyStatics { 492 private static final MethodHandle COPY_AS_REFERENCE_ARRAY, COPY_AS_PRIMITIVE_ARRAY, MAKE_LIST; 493 static { 494 try { 495 //MAKE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeArray", MethodType.methodType(Object[].class, Object[].class)); 496 COPY_AS_REFERENCE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsReferenceArray", MethodType.methodType(Object[].class, Class.class, Object[].class)); 497 COPY_AS_PRIMITIVE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsPrimitiveArray", MethodType.methodType(Object.class, Wrapper.class, Object[].class)); 498 MAKE_LIST = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeList", MethodType.methodType(List.class, Object[].class)); 499 } catch (ReflectiveOperationException ex) { 500 throw newInternalError("uncaught exception", ex); 501 } 502 } 503 } 504 505 private static final EnumMap<Wrapper, MethodHandle>[] WRAPPER_CASTS 506 = newWrapperCaches(1); 507 508 /** Return a method that casts its sole argument (an Object) to the given type 509 * and returns it as the given type. 510 */ 511 public static MethodHandle cast(Class<?> type) { 512 if (type.isPrimitive()) throw new IllegalArgumentException("cannot cast primitive type "+type); 513 MethodHandle mh; 514 Wrapper wrap = null; 515 EnumMap<Wrapper, MethodHandle> cache = null; 516 if (Wrapper.isWrapperType(type)) { 517 wrap = Wrapper.forWrapperType(type); 518 cache = WRAPPER_CASTS[0]; 519 mh = cache.get(wrap); 520 if (mh != null) return mh; 521 } 522 mh = MethodHandles.insertArguments(CAST_REFERENCE, 0, type); 523 if (cache != null) 524 cache.put(wrap, mh); 525 return mh; 526 } 527 528 public static MethodHandle identity() { 529 return IDENTITY; 530 } 531 532 public static MethodHandle identity(Class<?> type) { 533 if (!type.isPrimitive()) 534 // Reference identity has been moved into MethodHandles: 535 return MethodHandles.identity(type); 536 return identity(Wrapper.findPrimitiveType(type)); 537 } 538 539 public static MethodHandle identity(Wrapper wrap) { 540 EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[1]; 541 MethodHandle mh = cache.get(wrap); 542 if (mh != null) { 543 return mh; 544 } 545 // slow path 546 MethodType type = MethodType.methodType(wrap.primitiveType()); 547 if (wrap != Wrapper.VOID) 548 type = type.appendParameterTypes(wrap.primitiveType()); 549 try { 550 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", type); 551 } catch (ReflectiveOperationException ex) { 552 mh = null; 553 } 554 if (mh == null && wrap == Wrapper.VOID) { 555 mh = EMPTY; // #(){} : #()void 556 } 557 if (mh != null) { 558 cache.put(wrap, mh); 559 return mh; 560 } 561 562 if (mh != null) { 563 cache.put(wrap, mh); 564 return mh; 565 } 566 throw new IllegalArgumentException("cannot find identity for " + wrap); 567 } 568 569 /// Primitive conversions. 570 // These are supported directly by the JVM, usually by a single instruction. 571 // In the case of narrowing to a subword, there may be a pair of instructions. 572 // In the case of booleans, there may be a helper routine to manage a 1-bit value. 573 // This is the full 8x8 matrix (minus the diagonal). 574 575 // narrow double to all other types: 576 static float doubleToFloat(double x) { // bytecode: d2f 577 return (float) x; 578 } 579 static long doubleToLong(double x) { // bytecode: d2l 580 return (long) x; 581 } 582 static int doubleToInt(double x) { // bytecode: d2i 583 return (int) x; 584 } 585 static short doubleToShort(double x) { // bytecodes: d2i, i2s 586 return (short) x; 587 } 588 static char doubleToChar(double x) { // bytecodes: d2i, i2c 589 return (char) x; 590 } 591 static byte doubleToByte(double x) { // bytecodes: d2i, i2b 592 return (byte) x; 593 } 594 static boolean doubleToBoolean(double x) { 595 return toBoolean((byte) x); 596 } 597 598 // widen float: 599 static double floatToDouble(float x) { // bytecode: f2d 600 return x; 601 } 602 // narrow float: 603 static long floatToLong(float x) { // bytecode: f2l 604 return (long) x; 605 } 606 static int floatToInt(float x) { // bytecode: f2i 607 return (int) x; 608 } 609 static short floatToShort(float x) { // bytecodes: f2i, i2s 610 return (short) x; 611 } 612 static char floatToChar(float x) { // bytecodes: f2i, i2c 613 return (char) x; 614 } 615 static byte floatToByte(float x) { // bytecodes: f2i, i2b 616 return (byte) x; 617 } 618 static boolean floatToBoolean(float x) { 619 return toBoolean((byte) x); 620 } 621 622 // widen long: 623 static double longToDouble(long x) { // bytecode: l2d 624 return x; 625 } 626 static float longToFloat(long x) { // bytecode: l2f 627 return x; 628 } 629 // narrow long: 630 static int longToInt(long x) { // bytecode: l2i 631 return (int) x; 632 } 633 static short longToShort(long x) { // bytecodes: f2i, i2s 634 return (short) x; 635 } 636 static char longToChar(long x) { // bytecodes: f2i, i2c 637 return (char) x; 638 } 639 static byte longToByte(long x) { // bytecodes: f2i, i2b 640 return (byte) x; 641 } 642 static boolean longToBoolean(long x) { 643 return toBoolean((byte) x); 644 } 645 646 // widen int: 647 static double intToDouble(int x) { // bytecode: i2d 648 return x; 649 } 650 static float intToFloat(int x) { // bytecode: i2f 651 return x; 652 } 653 static long intToLong(int x) { // bytecode: i2l 654 return x; 655 } 656 // narrow int: 657 static short intToShort(int x) { // bytecode: i2s 658 return (short) x; 659 } 660 static char intToChar(int x) { // bytecode: i2c 661 return (char) x; 662 } 663 static byte intToByte(int x) { // bytecode: i2b 664 return (byte) x; 665 } 666 static boolean intToBoolean(int x) { 667 return toBoolean((byte) x); 668 } 669 670 // widen short: 671 static double shortToDouble(short x) { // bytecode: i2d (implicit 's2i') 672 return x; 673 } 674 static float shortToFloat(short x) { // bytecode: i2f (implicit 's2i') 675 return x; 676 } 677 static long shortToLong(short x) { // bytecode: i2l (implicit 's2i') 678 return x; 679 } 680 static int shortToInt(short x) { // (implicit 's2i') 681 return x; 682 } 683 // narrow short: 684 static char shortToChar(short x) { // bytecode: i2c (implicit 's2i') 685 return (char)x; 686 } 687 static byte shortToByte(short x) { // bytecode: i2b (implicit 's2i') 688 return (byte)x; 689 } 690 static boolean shortToBoolean(short x) { 691 return toBoolean((byte) x); 692 } 693 694 // widen char: 695 static double charToDouble(char x) { // bytecode: i2d (implicit 'c2i') 696 return x; 697 } 698 static float charToFloat(char x) { // bytecode: i2f (implicit 'c2i') 699 return x; 700 } 701 static long charToLong(char x) { // bytecode: i2l (implicit 'c2i') 702 return x; 703 } 704 static int charToInt(char x) { // (implicit 'c2i') 705 return x; 706 } 707 // narrow char: 708 static short charToShort(char x) { // bytecode: i2s (implicit 'c2i') 709 return (short)x; 710 } 711 static byte charToByte(char x) { // bytecode: i2b (implicit 'c2i') 712 return (byte)x; 713 } 714 static boolean charToBoolean(char x) { 715 return toBoolean((byte) x); 716 } 717 718 // widen byte: 719 static double byteToDouble(byte x) { // bytecode: i2d (implicit 'b2i') 720 return x; 721 } 722 static float byteToFloat(byte x) { // bytecode: i2f (implicit 'b2i') 723 return x; 724 } 725 static long byteToLong(byte x) { // bytecode: i2l (implicit 'b2i') 726 return x; 727 } 728 static int byteToInt(byte x) { // (implicit 'b2i') 729 return x; 730 } 731 static short byteToShort(byte x) { // bytecode: i2s (implicit 'b2i') 732 return (short)x; 733 } 734 static char byteToChar(byte x) { // bytecode: i2b (implicit 'b2i') 735 return (char)x; 736 } 737 // narrow byte to boolean: 738 static boolean byteToBoolean(byte x) { 739 return toBoolean(x); 740 } 741 742 // widen boolean to all types: 743 static double booleanToDouble(boolean x) { 744 return fromBoolean(x); 745 } 746 static float booleanToFloat(boolean x) { 747 return fromBoolean(x); 748 } 749 static long booleanToLong(boolean x) { 750 return fromBoolean(x); 751 } 752 static int booleanToInt(boolean x) { 753 return fromBoolean(x); 754 } 755 static short booleanToShort(boolean x) { 756 return fromBoolean(x); 757 } 758 static char booleanToChar(boolean x) { 759 return (char)fromBoolean(x); 760 } 761 static byte booleanToByte(boolean x) { 762 return fromBoolean(x); 763 } 764 765 // helpers to force boolean into the conversion scheme: 766 static boolean toBoolean(byte x) { 767 // see javadoc for MethodHandles.explicitCastArguments 768 return ((x & 1) != 0); 769 } 770 static byte fromBoolean(boolean x) { 771 // see javadoc for MethodHandles.explicitCastArguments 772 return (x ? (byte)1 : (byte)0); 773 } 774 775 private static final EnumMap<Wrapper, MethodHandle>[] 776 CONVERT_PRIMITIVE_FUNCTIONS = newWrapperCaches(Wrapper.values().length); 777 778 public static MethodHandle convertPrimitive(Wrapper wsrc, Wrapper wdst) { 779 EnumMap<Wrapper, MethodHandle> cache = CONVERT_PRIMITIVE_FUNCTIONS[wsrc.ordinal()]; 780 MethodHandle mh = cache.get(wdst); 781 if (mh != null) { 782 return mh; 783 } 784 // slow path 785 Class<?> src = wsrc.primitiveType(); 786 Class<?> dst = wdst.primitiveType(); 787 MethodType type = src == void.class ? MethodType.methodType(dst) : MethodType.methodType(dst, src); 788 if (wsrc == wdst) { 789 mh = identity(src); 790 } else if (wsrc == Wrapper.VOID) { 791 mh = zeroConstantFunction(wdst); 792 } else if (wdst == Wrapper.VOID) { 793 mh = MethodHandles.dropArguments(EMPTY, 0, src); // Defer back to MethodHandles. 794 } else if (wsrc == Wrapper.OBJECT) { 795 mh = unboxCast(dst); 796 } else if (wdst == Wrapper.OBJECT) { 797 mh = box(src); 798 } else { 799 assert(src.isPrimitive() && dst.isPrimitive()); 800 try { 801 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, src.getSimpleName()+"To"+capitalize(dst.getSimpleName()), type); 802 } catch (ReflectiveOperationException ex) { 803 mh = null; 804 } 805 } 806 if (mh != null) { 807 assert(mh.type() == type) : mh; 808 cache.put(wdst, mh); 809 return mh; 810 } 811 812 throw new IllegalArgumentException("cannot find primitive conversion function for " + 813 src.getSimpleName()+" -> "+dst.getSimpleName()); 814 } 815 816 public static MethodHandle convertPrimitive(Class<?> src, Class<?> dst) { 817 return convertPrimitive(Wrapper.forPrimitiveType(src), Wrapper.forPrimitiveType(dst)); 818 } 819 820 private static String capitalize(String x) { 821 return Character.toUpperCase(x.charAt(0))+x.substring(1); 822 } 823 824 /// Collection of multiple arguments. 825 826 public static Object convertArrayElements(Class<?> arrayType, Object array) { 827 Class<?> src = array.getClass().getComponentType(); 828 Class<?> dst = arrayType.getComponentType(); 829 if (src == null || dst == null) throw new IllegalArgumentException("not array type"); 830 Wrapper sw = (src.isPrimitive() ? Wrapper.forPrimitiveType(src) : null); 831 Wrapper dw = (dst.isPrimitive() ? Wrapper.forPrimitiveType(dst) : null); 832 int length; 833 if (sw == null) { 834 Object[] a = (Object[]) array; 835 length = a.length; 836 if (dw == null) 837 return Arrays.copyOf(a, length, arrayType.asSubclass(Object[].class)); 838 Object res = dw.makeArray(length); 839 dw.copyArrayUnboxing(a, 0, res, 0, length); 840 return res; 841 } 842 length = java.lang.reflect.Array.getLength(array); 843 Object[] res; 844 if (dw == null) { 845 res = Arrays.copyOf(NO_ARGS_ARRAY, length, arrayType.asSubclass(Object[].class)); 846 } else { 847 res = new Object[length]; 848 } 849 sw.copyArrayBoxing(array, 0, res, 0, length); 850 if (dw == null) return res; 851 Object a = dw.makeArray(length); 852 dw.copyArrayUnboxing(res, 0, a, 0, length); 853 return a; 854 } 855 856 private static MethodHandle findCollector(String name, int nargs, Class<?> rtype, Class<?>... ptypes) { 857 MethodType type = MethodType.genericMethodType(nargs) 858 .changeReturnType(rtype) 859 .insertParameterTypes(0, ptypes); 860 try { 861 return IMPL_LOOKUP.findStatic(THIS_CLASS, name, type); 862 } catch (ReflectiveOperationException ex) { 863 return null; 864 } 865 } 866 867 private static final Object[] NO_ARGS_ARRAY = {}; 868 private static Object[] makeArray(Object... args) { return args; } 869 private static Object[] array() { return NO_ARGS_ARRAY; } 870 private static Object[] array(Object a0) 871 { return makeArray(a0); } 872 private static Object[] array(Object a0, Object a1) 873 { return makeArray(a0, a1); } 874 private static Object[] array(Object a0, Object a1, Object a2) 875 { return makeArray(a0, a1, a2); } 876 private static Object[] array(Object a0, Object a1, Object a2, Object a3) 877 { return makeArray(a0, a1, a2, a3); } 878 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 879 Object a4) 880 { return makeArray(a0, a1, a2, a3, a4); } 881 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 882 Object a4, Object a5) 883 { return makeArray(a0, a1, a2, a3, a4, a5); } 884 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 885 Object a4, Object a5, Object a6) 886 { return makeArray(a0, a1, a2, a3, a4, a5, a6); } 887 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 888 Object a4, Object a5, Object a6, Object a7) 889 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); } 890 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 891 Object a4, Object a5, Object a6, Object a7, 892 Object a8) 893 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); } 894 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 895 Object a4, Object a5, Object a6, Object a7, 896 Object a8, Object a9) 897 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } 898 private static MethodHandle[] makeArrays() { 899 ArrayList<MethodHandle> mhs = new ArrayList<>(); 900 for (;;) { 901 MethodHandle mh = findCollector("array", mhs.size(), Object[].class); 902 if (mh == null) break; 903 mhs.add(mh); 904 } 905 assert(mhs.size() == 11); // current number of methods 906 return mhs.toArray(new MethodHandle[MAX_ARITY+1]); 907 } 908 private static final MethodHandle[] ARRAYS = makeArrays(); 909 910 // filling versions of the above: 911 // using Integer len instead of int len and no varargs to avoid bootstrapping problems 912 private static Object[] fillNewArray(Integer len, Object[] /*not ...*/ args) { 913 Object[] a = new Object[len]; 914 fillWithArguments(a, 0, args); 915 return a; 916 } 917 private static Object[] fillNewTypedArray(Object[] example, Integer len, Object[] /*not ...*/ args) { 918 Object[] a = Arrays.copyOf(example, len); 919 fillWithArguments(a, 0, args); 920 return a; 921 } 922 private static void fillWithArguments(Object[] a, int pos, Object... args) { 923 System.arraycopy(args, 0, a, pos, args.length); 924 } 925 // using Integer pos instead of int pos to avoid bootstrapping problems 926 private static Object[] fillArray(Integer pos, Object[] a, Object a0) 927 { fillWithArguments(a, pos, a0); return a; } 928 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1) 929 { fillWithArguments(a, pos, a0, a1); return a; } 930 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2) 931 { fillWithArguments(a, pos, a0, a1, a2); return a; } 932 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3) 933 { fillWithArguments(a, pos, a0, a1, a2, a3); return a; } 934 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, 935 Object a4) 936 { fillWithArguments(a, pos, a0, a1, a2, a3, a4); return a; } 937 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, 938 Object a4, Object a5) 939 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5); return a; } 940 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, 941 Object a4, Object a5, Object a6) 942 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6); return a; } 943 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, 944 Object a4, Object a5, Object a6, Object a7) 945 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7); return a; } 946 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, 947 Object a4, Object a5, Object a6, Object a7, 948 Object a8) 949 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8); return a; } 950 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, 951 Object a4, Object a5, Object a6, Object a7, 952 Object a8, Object a9) 953 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; } 954 private static MethodHandle[] makeFillArrays() { 955 ArrayList<MethodHandle> mhs = new ArrayList<>(); 956 mhs.add(null); // there is no empty fill; at least a0 is required 957 for (;;) { 958 MethodHandle mh = findCollector("fillArray", mhs.size(), Object[].class, Integer.class, Object[].class); 959 if (mh == null) break; 960 mhs.add(mh); 961 } 962 assert(mhs.size() == 11); // current number of methods 963 return mhs.toArray(new MethodHandle[0]); 964 } 965 private static final MethodHandle[] FILL_ARRAYS = makeFillArrays(); 966 967 private static Object[] copyAsReferenceArray(Class<? extends Object[]> arrayType, Object... a) { 968 return Arrays.copyOf(a, a.length, arrayType); 969 } 970 private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) { 971 Object a = w.makeArray(boxes.length); 972 w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length); 973 return a; 974 } 975 976 /** Return a method handle that takes the indicated number of Object 977 * arguments and returns an Object array of them, as if for varargs. 978 */ 979 public static MethodHandle varargsArray(int nargs) { 980 MethodHandle mh = ARRAYS[nargs]; 981 if (mh != null) return mh; 982 mh = findCollector("array", nargs, Object[].class); 983 if (mh != null) return ARRAYS[nargs] = mh; 984 mh = buildVarargsArray(FILL_NEW_ARRAY, ARRAY_IDENTITY, nargs); 985 assert(assertCorrectArity(mh, nargs)); 986 return ARRAYS[nargs] = mh; 987 } 988 989 private static boolean assertCorrectArity(MethodHandle mh, int arity) { 990 assert(mh.type().parameterCount() == arity) : "arity != "+arity+": "+mh; 991 return true; 992 } 993 994 private static MethodHandle buildVarargsArray(MethodHandle newArray, MethodHandle finisher, int nargs) { 995 // Build up the result mh as a sequence of fills like this: 996 // finisher(fill(fill(newArrayWA(23,x1..x10),10,x11..x20),20,x21..x23)) 997 // The various fill(_,10*I,___*[J]) are reusable. 998 int leftLen = Math.min(nargs, LEFT_ARGS); // absorb some arguments immediately 999 int rightLen = nargs - leftLen; 1000 MethodHandle leftCollector = newArray.bindTo(nargs); 1001 leftCollector = leftCollector.asCollector(Object[].class, leftLen); 1002 MethodHandle mh = finisher; 1003 if (rightLen > 0) { 1004 MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen); 1005 if (mh == ARRAY_IDENTITY) 1006 mh = rightFiller; 1007 else 1008 mh = MethodHandles.collectArguments(mh, 0, rightFiller); 1009 } 1010 if (mh == ARRAY_IDENTITY) 1011 mh = leftCollector; 1012 else 1013 mh = MethodHandles.collectArguments(mh, 0, leftCollector); 1014 return mh; 1015 } 1016 1017 private static final int LEFT_ARGS = (FILL_ARRAYS.length - 1); 1018 private static final MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1]; 1019 /** fill_array_to_right(N).invoke(a, argL..arg[N-1]) 1020 * fills a[L]..a[N-1] with corresponding arguments, 1021 * and then returns a. The value L is a global constant (LEFT_ARGS). 1022 */ 1023 private static MethodHandle fillToRight(int nargs) { 1024 MethodHandle filler = FILL_ARRAY_TO_RIGHT[nargs]; 1025 if (filler != null) return filler; 1026 filler = buildFiller(nargs); 1027 assert(assertCorrectArity(filler, nargs - LEFT_ARGS + 1)); 1028 return FILL_ARRAY_TO_RIGHT[nargs] = filler; 1029 } 1030 private static MethodHandle buildFiller(int nargs) { 1031 if (nargs <= LEFT_ARGS) 1032 return ARRAY_IDENTITY; // no args to fill; return the array unchanged 1033 // we need room for both mh and a in mh.invoke(a, arg*[nargs]) 1034 final int CHUNK = LEFT_ARGS; 1035 int rightLen = nargs % CHUNK; 1036 int midLen = nargs - rightLen; 1037 if (rightLen == 0) { 1038 midLen = nargs - (rightLen = CHUNK); 1039 if (FILL_ARRAY_TO_RIGHT[midLen] == null) { 1040 // build some precursors from left to right 1041 for (int j = LEFT_ARGS % CHUNK; j < midLen; j += CHUNK) 1042 if (j > LEFT_ARGS) fillToRight(j); 1043 } 1044 } 1045 if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS); 1046 assert(rightLen > 0); 1047 MethodHandle midFill = fillToRight(midLen); // recursive fill 1048 MethodHandle rightFill = FILL_ARRAYS[rightLen].bindTo(midLen); // [midLen..nargs-1] 1049 assert(midFill.type().parameterCount() == 1 + midLen - LEFT_ARGS); 1050 assert(rightFill.type().parameterCount() == 1 + rightLen); 1051 1052 // Combine the two fills: 1053 // right(mid(a, x10..x19), x20..x23) 1054 // The final product will look like this: 1055 // right(mid(newArrayLeft(24, x0..x9), x10..x19), x20..x23) 1056 if (midLen == LEFT_ARGS) 1057 return rightFill; 1058 else 1059 return MethodHandles.collectArguments(rightFill, 0, midFill); 1060 } 1061 1062 // Type-polymorphic version of varargs maker. 1063 private static final ClassValue<MethodHandle[]> TYPED_COLLECTORS 1064 = new ClassValue<MethodHandle[]>() { 1065 @Override 1066 protected MethodHandle[] computeValue(Class<?> type) { 1067 return new MethodHandle[256]; 1068 } 1069 }; 1070 1071 static final int MAX_JVM_ARITY = 255; // limit imposed by the JVM 1072 1073 /** Return a method handle that takes the indicated number of 1074 * typed arguments and returns an array of them. 1075 * The type argument is the array type. 1076 */ 1077 public static MethodHandle varargsArray(Class<?> arrayType, int nargs) { 1078 Class<?> elemType = arrayType.getComponentType(); 1079 if (elemType == null) throw new IllegalArgumentException("not an array: "+arrayType); 1080 // FIXME: Need more special casing and caching here. 1081 if (nargs >= MAX_JVM_ARITY/2 - 1) { 1082 int slots = nargs; 1083 final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1; // 1 for receiver MH 1084 if (arrayType == double[].class || arrayType == long[].class) 1085 slots *= 2; 1086 if (slots > MAX_ARRAY_SLOTS) 1087 throw new IllegalArgumentException("too many arguments: "+arrayType.getSimpleName()+", length "+nargs); 1088 } 1089 if (elemType == Object.class) 1090 return varargsArray(nargs); 1091 // other cases: primitive arrays, subtypes of Object[] 1092 MethodHandle cache[] = TYPED_COLLECTORS.get(elemType); 1093 MethodHandle mh = nargs < cache.length ? cache[nargs] : null; 1094 if (mh != null) return mh; 1095 if (elemType.isPrimitive()) { 1096 MethodHandle builder = FILL_NEW_ARRAY; 1097 MethodHandle producer = buildArrayProducer(arrayType); 1098 mh = buildVarargsArray(builder, producer, nargs); 1099 } else { 1100 @SuppressWarnings("unchecked") 1101 Class<? extends Object[]> objArrayType = (Class<? extends Object[]>) arrayType; 1102 Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType); 1103 MethodHandle builder = FILL_NEW_TYPED_ARRAY.bindTo(example); 1104 MethodHandle producer = ARRAY_IDENTITY; 1105 mh = buildVarargsArray(builder, producer, nargs); 1106 } 1107 mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType))); 1108 assert(assertCorrectArity(mh, nargs)); 1109 if (nargs < cache.length) 1110 cache[nargs] = mh; 1111 return mh; 1112 } 1113 1114 private static MethodHandle buildArrayProducer(Class<?> arrayType) { 1115 Class<?> elemType = arrayType.getComponentType(); 1116 if (elemType.isPrimitive()) 1117 return LazyStatics.COPY_AS_PRIMITIVE_ARRAY.bindTo(Wrapper.forPrimitiveType(elemType)); 1118 else 1119 return LazyStatics.COPY_AS_REFERENCE_ARRAY.bindTo(arrayType); 1120 } 1121 1122 // List version of varargs maker. 1123 1124 private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY); 1125 private static List<Object> makeList(Object... args) { return Arrays.asList(args); } 1126 private static List<Object> list() { return NO_ARGS_LIST; } 1127 private static List<Object> list(Object a0) 1128 { return makeList(a0); } 1129 private static List<Object> list(Object a0, Object a1) 1130 { return makeList(a0, a1); } 1131 private static List<Object> list(Object a0, Object a1, Object a2) 1132 { return makeList(a0, a1, a2); } 1133 private static List<Object> list(Object a0, Object a1, Object a2, Object a3) 1134 { return makeList(a0, a1, a2, a3); } 1135 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 1136 Object a4) 1137 { return makeList(a0, a1, a2, a3, a4); } 1138 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 1139 Object a4, Object a5) 1140 { return makeList(a0, a1, a2, a3, a4, a5); } 1141 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 1142 Object a4, Object a5, Object a6) 1143 { return makeList(a0, a1, a2, a3, a4, a5, a6); } 1144 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 1145 Object a4, Object a5, Object a6, Object a7) 1146 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); } 1147 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 1148 Object a4, Object a5, Object a6, Object a7, 1149 Object a8) 1150 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); } 1151 private static List<Object> list(Object a0, Object a1, Object a2, Object a3, 1152 Object a4, Object a5, Object a6, Object a7, 1153 Object a8, Object a9) 1154 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } 1155 private static MethodHandle[] makeLists() { 1156 ArrayList<MethodHandle> mhs = new ArrayList<>(); 1157 for (;;) { 1158 MethodHandle mh = findCollector("list", mhs.size(), List.class); 1159 if (mh == null) break; 1160 mhs.add(mh); 1161 } 1162 assert(mhs.size() == 11); // current number of methods 1163 return mhs.toArray(new MethodHandle[MAX_ARITY+1]); 1164 } 1165 private static final MethodHandle[] LISTS = makeLists(); 1166 1167 /** Return a method handle that takes the indicated number of Object 1168 * arguments and returns a List. 1169 */ 1170 public static MethodHandle varargsList(int nargs) { 1171 MethodHandle mh = LISTS[nargs]; 1172 if (mh != null) return mh; 1173 mh = findCollector("list", nargs, List.class); 1174 if (mh != null) return LISTS[nargs] = mh; 1175 return LISTS[nargs] = buildVarargsList(nargs); 1176 } 1177 private static MethodHandle buildVarargsList(int nargs) { 1178 return MethodHandles.filterReturnValue(varargsArray(nargs), LazyStatics.MAKE_LIST); 1179 } 1180 1181 // handy shared exception makers (they simplify the common case code) 1182 private static InternalError newInternalError(String message, Throwable cause) { 1183 return new InternalError(message, cause); 1184 } 1185 private static InternalError newInternalError(Throwable cause) { 1186 return new InternalError(cause); 1187 } 1188 }