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 public enum Wrapper { 29 // wrapperType simple primitiveType simple char emptyArray format 30 BOOLEAN( Boolean.class, "Boolean", boolean.class, "boolean", 'Z', new boolean[0], Format.unsigned( 1)), 31 // These must be in the order defined for widening primitive conversions in JLS 5.1.2 32 // Avoid boxing integral types here to defer initialization of internal caches 33 BYTE ( Byte.class, "Byte", byte.class, "byte", 'B', new byte[0], Format.signed( 8)), 34 SHORT ( Short.class, "Short", short.class, "short", 'S', new short[0], Format.signed( 16)), 35 CHAR (Character.class, "Character", char.class, "char", 'C', new char[0], Format.unsigned(16)), 36 INT ( Integer.class, "Integer", int.class, "int", 'I', new int[0], Format.signed( 32)), 37 LONG ( Long.class, "Long", long.class, "long", 'J', new long[0], Format.signed( 64)), 38 FLOAT ( Float.class, "Float", float.class, "float", 'F', new float[0], Format.floating(32)), 39 DOUBLE ( Double.class, "Double", double.class, "double", 'D', new double[0], Format.floating(64)), 40 OBJECT ( Object.class, "Object", Object.class, "Object", 'L', new Object[0], Format.other( 1)), 41 // VOID must be the last type, since it is "assignable" from any other type: 42 VOID ( Void.class, "Void", void.class, "void", 'V', null, Format.other( 0)), 43 ; 44 45 public static final int COUNT = 10; 46 47 private final Class<?> wrapperType; 48 private final Class<?> primitiveType; 49 private final char basicTypeChar; 50 private final Object emptyArray; 51 private final int format; 52 private final String wrapperSimpleName; 53 private final String primitiveSimpleName; 54 Wrapper(Class<?> wtype, String wtypeName, Class<?> ptype, String ptypeName, char tchar, Object emptyArray, int format)55 private Wrapper(Class<?> wtype, String wtypeName, Class<?> ptype, String ptypeName, char tchar, Object emptyArray, int format) { 56 this.wrapperType = wtype; 57 this.primitiveType = ptype; 58 this.basicTypeChar = tchar; 59 this.emptyArray = emptyArray; 60 this.format = format; 61 this.wrapperSimpleName = wtypeName; 62 this.primitiveSimpleName = ptypeName; 63 } 64 65 /** For debugging, give the details of this wrapper. */ detailString()66 public String detailString() { 67 return wrapperSimpleName+ 68 java.util.Arrays.asList(wrapperType, primitiveType, 69 basicTypeChar, zero(), 70 "0x"+Integer.toHexString(format)); 71 } 72 73 private abstract static class Format { 74 static final int SLOT_SHIFT = 0, SIZE_SHIFT = 2, KIND_SHIFT = 12; 75 static final int 76 SIGNED = (-1) << KIND_SHIFT, 77 UNSIGNED = 0 << KIND_SHIFT, 78 FLOATING = 1 << KIND_SHIFT; 79 static final int 80 SLOT_MASK = ((1<<(SIZE_SHIFT-SLOT_SHIFT))-1), 81 SIZE_MASK = ((1<<(KIND_SHIFT-SIZE_SHIFT))-1); format(int kind, int size, int slots)82 static int format(int kind, int size, int slots) { 83 assert(((kind >> KIND_SHIFT) << KIND_SHIFT) == kind); 84 assert((size & (size-1)) == 0); // power of two 85 assert((kind == SIGNED) ? (size > 0) : 86 (kind == UNSIGNED) ? (size > 0) : 87 (kind == FLOATING) ? (size == 32 || size == 64) : 88 false); 89 assert((slots == 2) ? (size == 64) : 90 (slots == 1) ? (size <= 32) : 91 false); 92 return kind | (size << SIZE_SHIFT) | (slots << SLOT_SHIFT); 93 } 94 static final int 95 INT = SIGNED | (32 << SIZE_SHIFT) | (1 << SLOT_SHIFT), 96 SHORT = SIGNED | (16 << SIZE_SHIFT) | (1 << SLOT_SHIFT), 97 BOOLEAN = UNSIGNED | (1 << SIZE_SHIFT) | (1 << SLOT_SHIFT), 98 CHAR = UNSIGNED | (16 << SIZE_SHIFT) | (1 << SLOT_SHIFT), 99 FLOAT = FLOATING | (32 << SIZE_SHIFT) | (1 << SLOT_SHIFT), 100 VOID = UNSIGNED | (0 << SIZE_SHIFT) | (0 << SLOT_SHIFT), 101 NUM_MASK = (-1) << SIZE_SHIFT; signed(int size)102 static int signed(int size) { return format(SIGNED, size, (size > 32 ? 2 : 1)); } unsigned(int size)103 static int unsigned(int size) { return format(UNSIGNED, size, (size > 32 ? 2 : 1)); } floating(int size)104 static int floating(int size) { return format(FLOATING, size, (size > 32 ? 2 : 1)); } other(int slots)105 static int other(int slots) { return slots << SLOT_SHIFT; } 106 } 107 108 /// format queries: 109 110 /** How many bits are in the wrapped value? Returns 0 for OBJECT or VOID. */ bitWidth()111 public int bitWidth() { return (format >> Format.SIZE_SHIFT) & Format.SIZE_MASK; } 112 /** How many JVM stack slots occupied by the wrapped value? Returns 0 for VOID. */ stackSlots()113 public int stackSlots() { return (format >> Format.SLOT_SHIFT) & Format.SLOT_MASK; } 114 /** Does the wrapped value occupy a single JVM stack slot? */ isSingleWord()115 public boolean isSingleWord() { return (format & (1 << Format.SLOT_SHIFT)) != 0; } 116 /** Does the wrapped value occupy two JVM stack slots? */ isDoubleWord()117 public boolean isDoubleWord() { return (format & (2 << Format.SLOT_SHIFT)) != 0; } 118 /** Is the wrapped type numeric (not void or object)? */ isNumeric()119 public boolean isNumeric() { return (format & Format.NUM_MASK) != 0; } 120 /** Is the wrapped type a primitive other than float, double, or void? */ isIntegral()121 public boolean isIntegral() { return isNumeric() && format < Format.FLOAT; } 122 /** Is the wrapped type one of int, boolean, byte, char, or short? */ isSubwordOrInt()123 public boolean isSubwordOrInt() { return isIntegral() && isSingleWord(); } 124 /* Is the wrapped value a signed integral type (one of byte, short, int, or long)? */ isSigned()125 public boolean isSigned() { return format < Format.VOID; } 126 /* Is the wrapped value an unsigned integral type (one of boolean or char)? */ isUnsigned()127 public boolean isUnsigned() { return format >= Format.BOOLEAN && format < Format.FLOAT; } 128 /** Is the wrapped type either float or double? */ isFloating()129 public boolean isFloating() { return format >= Format.FLOAT; } 130 /** Is the wrapped type either void or a reference? */ isOther()131 public boolean isOther() { return (format & ~Format.SLOT_MASK) == 0; } 132 133 /** Does the JLS 5.1.2 allow a variable of this wrapper's 134 * primitive type to be assigned from a value of the given wrapper's primitive type? 135 * Cases: 136 * <ul> 137 * <li>unboxing followed by widening primitive conversion 138 * <li>any type converted to {@code void} (i.e., dropping a method call's value) 139 * <li>boxing conversion followed by widening reference conversion to {@code Object} 140 * </ul> 141 * These are the cases allowed by MethodHandle.asType. 142 */ isConvertibleFrom(Wrapper source)143 public boolean isConvertibleFrom(Wrapper source) { 144 if (this == source) return true; 145 if (this.compareTo(source) < 0) { 146 // At best, this is a narrowing conversion. 147 return false; 148 } 149 // All conversions are allowed in the enum order between floats and signed ints. 150 // First detect non-signed non-float types (boolean, char, Object, void). 151 boolean floatOrSigned = (((this.format & source.format) & Format.SIGNED) != 0); 152 if (!floatOrSigned) { 153 if (this.isOther()) return true; 154 // can convert char to int or wider, but nothing else 155 if (source.format == Format.CHAR) return true; 156 // no other conversions are classified as widening 157 return false; 158 } 159 // All signed and float conversions in the enum order are widening. 160 assert(this.isFloating() || this.isSigned()); 161 assert(source.isFloating() || source.isSigned()); 162 return true; 163 } 164 165 static { checkConvertibleFrom()166 assert(checkConvertibleFrom()); assert(COUNT == Wrapper.values().length)167 assert(COUNT == Wrapper.values().length); 168 } checkConvertibleFrom()169 private static boolean checkConvertibleFrom() { 170 // Check the matrix for correct classification of widening conversions. 171 for (Wrapper w : values()) { 172 assert(w.isConvertibleFrom(w)); 173 assert(VOID.isConvertibleFrom(w)); 174 if (w != VOID) { 175 assert(OBJECT.isConvertibleFrom(w)); 176 assert(!w.isConvertibleFrom(VOID)); 177 } 178 // check relations with unsigned integral types: 179 if (w != CHAR) { 180 assert(!CHAR.isConvertibleFrom(w)); 181 if (!w.isConvertibleFrom(INT)) 182 assert(!w.isConvertibleFrom(CHAR)); 183 } 184 if (w != BOOLEAN) { 185 assert(!BOOLEAN.isConvertibleFrom(w)); 186 if (w != VOID && w != OBJECT) 187 assert(!w.isConvertibleFrom(BOOLEAN)); 188 } 189 // check relations with signed integral types: 190 if (w.isSigned()) { 191 for (Wrapper x : values()) { 192 if (w == x) continue; 193 if (x.isFloating()) 194 assert(!w.isConvertibleFrom(x)); 195 else if (x.isSigned()) { 196 if (w.compareTo(x) < 0) 197 assert(!w.isConvertibleFrom(x)); 198 else 199 assert(w.isConvertibleFrom(x)); 200 } 201 } 202 } 203 // check relations with floating types: 204 if (w.isFloating()) { 205 for (Wrapper x : values()) { 206 if (w == x) continue; 207 if (x.isSigned()) 208 assert(w.isConvertibleFrom(x)); 209 else if (x.isFloating()) { 210 if (w.compareTo(x) < 0) 211 assert(!w.isConvertibleFrom(x)); 212 else 213 assert(w.isConvertibleFrom(x)); 214 } 215 } 216 } 217 } 218 return true; // i.e., assert(true) 219 } 220 221 /** Produce a zero value for the given wrapper type. 222 * This will be a numeric zero for a number or character, 223 * false for a boolean, and null for a reference or void. 224 * The common thread is that this is what is contained 225 * in a default-initialized variable of the given primitive 226 * type. (For void, it is what a reflective method returns 227 * instead of no value at all.) 228 */ zero()229 public Object zero() { 230 switch (this) { 231 case BOOLEAN: 232 return Boolean.FALSE; 233 case INT: 234 return (Integer)0; 235 case BYTE: 236 return (Byte)(byte)0; 237 case CHAR: 238 return (Character)(char)0; 239 case SHORT: 240 return (Short)(short)0; 241 case LONG: 242 return (Long)(long)0; 243 case FLOAT: 244 return FLOAT_ZERO; 245 case DOUBLE: 246 return DOUBLE_ZERO; 247 case VOID: 248 case OBJECT: 249 default: 250 return null; 251 } 252 } 253 254 private static final Object DOUBLE_ZERO = (Double)(double)0; 255 private static final Object FLOAT_ZERO = (Float)(float)0; 256 257 /** Produce a zero value for the given wrapper type T. 258 * The optional argument must a type compatible with this wrapper. 259 * Equivalent to {@code this.cast(this.zero(), type)}. 260 */ zero(Class<T> type)261 public <T> T zero(Class<T> type) { return convert(zero(), type); } 262 263 /** Return the wrapper that wraps values of the given type. 264 * The type may be {@code Object}, meaning the {@code OBJECT} wrapper. 265 * Otherwise, the type must be a primitive. 266 * @throws IllegalArgumentException for unexpected types 267 */ forPrimitiveType(Class<?> type)268 public static Wrapper forPrimitiveType(Class<?> type) { 269 Wrapper w = findPrimitiveType(type); 270 if (w != null) return w; 271 if (type.isPrimitive()) 272 throw new InternalError(); // redo hash function 273 throw newIllegalArgumentException("not primitive: "+type); 274 } 275 276 /** Return the wrapper that corresponds to the provided basic type char. 277 * The basic type char must be for one of the eight primitive types, or void. 278 * @throws IllegalArgumentException for unexpected types 279 */ forPrimitiveType(char basicTypeChar)280 public static Wrapper forPrimitiveType(char basicTypeChar) { 281 switch (basicTypeChar) { 282 case 'I': return INT; 283 case 'J': return LONG; 284 case 'S': return SHORT; 285 case 'B': return BYTE; 286 case 'C': return CHAR; 287 case 'F': return FLOAT; 288 case 'D': return DOUBLE; 289 case 'Z': return BOOLEAN; 290 case 'V': return VOID; 291 default: throw newIllegalArgumentException("not primitive: " + basicTypeChar); 292 } 293 } 294 findPrimitiveType(Class<?> type)295 static Wrapper findPrimitiveType(Class<?> type) { 296 Wrapper w = FROM_PRIM[hashPrim(type)]; 297 if (w != null && w.primitiveType == type) { 298 return w; 299 } 300 return null; 301 } 302 303 /** Return the wrapper that wraps values into the given wrapper type. 304 * If it is {@code Object}, return {@code OBJECT}. 305 * Otherwise, it must be a wrapper type. 306 * The type must not be a primitive type. 307 * @throws IllegalArgumentException for unexpected types 308 */ forWrapperType(Class<?> type)309 public static Wrapper forWrapperType(Class<?> type) { 310 Wrapper w = findWrapperType(type); 311 if (w != null) return w; 312 for (Wrapper x : values()) 313 if (x.wrapperType == type) 314 throw new InternalError(); // redo hash function 315 throw newIllegalArgumentException("not wrapper: "+type); 316 } 317 findWrapperType(Class<?> type)318 static Wrapper findWrapperType(Class<?> type) { 319 Wrapper w = FROM_WRAP[hashWrap(type)]; 320 if (w != null && w.wrapperType == type) { 321 return w; 322 } 323 return null; 324 } 325 326 /** Return the wrapper that corresponds to the given bytecode 327 * signature character. Return {@code OBJECT} for the character 'L'. 328 * @throws IllegalArgumentException for any non-signature character or {@code '['}. 329 */ forBasicType(char type)330 public static Wrapper forBasicType(char type) { 331 Wrapper w = FROM_CHAR[hashChar(type)]; 332 if (w != null && w.basicTypeChar == type) { 333 return w; 334 } 335 for (Wrapper x : values()) 336 if (w.basicTypeChar == type) 337 throw new InternalError(); // redo hash function 338 throw newIllegalArgumentException("not basic type char: "+type); 339 } 340 341 /** Return the wrapper for the given type, if it is 342 * a primitive type, else return {@code OBJECT}. 343 */ forBasicType(Class<?> type)344 public static Wrapper forBasicType(Class<?> type) { 345 if (type.isPrimitive()) 346 return forPrimitiveType(type); 347 return OBJECT; // any reference, including wrappers or arrays 348 } 349 350 // Note on perfect hashes: 351 // for signature chars c, do (c + (c >> 1)) % 16 352 // for primitive type names n, do (n[0] + n[2]) % 16 353 // The type name hash works for both primitive and wrapper names. 354 // You can add "java/lang/Object" to the primitive names. 355 // But you add the wrapper name Object, use (n[2] + (3*n[1])) % 16. 356 private static final Wrapper[] FROM_PRIM = new Wrapper[16]; 357 private static final Wrapper[] FROM_WRAP = new Wrapper[16]; 358 private static final Wrapper[] FROM_CHAR = new Wrapper[16]; hashPrim(Class<?> x)359 private static int hashPrim(Class<?> x) { 360 String xn = x.getName(); 361 if (xn.length() < 3) return 0; 362 return (xn.charAt(0) + xn.charAt(2)) % 16; 363 } hashWrap(Class<?> x)364 private static int hashWrap(Class<?> x) { 365 String xn = x.getName(); 366 final int offset = 10; assert(offset == "java.lang.".length()); 367 if (xn.length() < offset+3) return 0; 368 return (3*xn.charAt(offset+1) + xn.charAt(offset+2)) % 16; 369 } hashChar(char x)370 private static int hashChar(char x) { 371 return (x + (x >> 1)) % 16; 372 } 373 static { 374 for (Wrapper w : values()) { 375 int pi = hashPrim(w.primitiveType); 376 int wi = hashWrap(w.wrapperType); 377 int ci = hashChar(w.basicTypeChar); assert(FROM_PRIM[pi] == null)378 assert(FROM_PRIM[pi] == null); assert(FROM_WRAP[wi] == null)379 assert(FROM_WRAP[wi] == null); assert(FROM_CHAR[ci] == null)380 assert(FROM_CHAR[ci] == null); 381 FROM_PRIM[pi] = w; 382 FROM_WRAP[wi] = w; 383 FROM_CHAR[ci] = w; 384 } 385 //assert(jdk.sun.invoke.util.WrapperTest.test(false)); 386 } 387 388 /** What is the primitive type wrapped by this wrapper? */ primitiveType()389 public Class<?> primitiveType() { return primitiveType; } 390 391 /** What is the wrapper type for this wrapper? */ wrapperType()392 public Class<?> wrapperType() { return wrapperType; } 393 394 /** What is the wrapper type for this wrapper? 395 * Otherwise, the example type must be the wrapper type, 396 * or the corresponding primitive type. 397 * (For {@code OBJECT}, the example type can be any non-primitive, 398 * and is normalized to {@code Object.class}.) 399 * The resulting class type has the same type parameter. 400 */ wrapperType(Class<T> exampleType)401 public <T> Class<T> wrapperType(Class<T> exampleType) { 402 if (exampleType == wrapperType) { 403 return exampleType; 404 } else if (exampleType == primitiveType || 405 wrapperType == Object.class || 406 exampleType.isInterface()) { 407 return forceType(wrapperType, exampleType); 408 } 409 throw newClassCastException(exampleType, primitiveType); 410 } 411 newClassCastException(Class<?> actual, Class<?> expected)412 private static ClassCastException newClassCastException(Class<?> actual, Class<?> expected) { 413 return new ClassCastException(actual + " is not compatible with " + expected); 414 } 415 416 /** If {@code type} is a primitive type, return the corresponding 417 * wrapper type, else return {@code type} unchanged. 418 */ asWrapperType(Class<T> type)419 public static <T> Class<T> asWrapperType(Class<T> type) { 420 if (type.isPrimitive()) { 421 return forPrimitiveType(type).wrapperType(type); 422 } 423 return type; 424 } 425 426 /** If {@code type} is a wrapper type, return the corresponding 427 * primitive type, else return {@code type} unchanged. 428 */ asPrimitiveType(Class<T> type)429 public static <T> Class<T> asPrimitiveType(Class<T> type) { 430 Wrapper w = findWrapperType(type); 431 if (w != null) { 432 return forceType(w.primitiveType(), type); 433 } 434 return type; 435 } 436 437 /** Query: Is the given type a wrapper, such as {@code Integer} or {@code Void}? */ isWrapperType(Class<?> type)438 public static boolean isWrapperType(Class<?> type) { 439 return findWrapperType(type) != null; 440 } 441 442 /** Query: Is the given type a primitive, such as {@code int} or {@code void}? */ isPrimitiveType(Class<?> type)443 public static boolean isPrimitiveType(Class<?> type) { 444 return type.isPrimitive(); 445 } 446 447 /** What is the bytecode signature character for this type? 448 * All non-primitives, including array types, report as 'L', the signature character for references. 449 */ basicTypeChar(Class<?> type)450 public static char basicTypeChar(Class<?> type) { 451 if (!type.isPrimitive()) 452 return 'L'; 453 else 454 return forPrimitiveType(type).basicTypeChar(); 455 } 456 457 /** What is the bytecode signature character for this wrapper's 458 * primitive type? 459 */ basicTypeChar()460 public char basicTypeChar() { return basicTypeChar; } 461 462 /** What is the simple name of the wrapper type? 463 */ wrapperSimpleName()464 public String wrapperSimpleName() { return wrapperSimpleName; } 465 466 /** What is the simple name of the primitive type? 467 */ primitiveSimpleName()468 public String primitiveSimpleName() { return primitiveSimpleName; } 469 470 // /** Wrap a value in the given type, which may be either a primitive or wrapper type. 471 // * Performs standard primitive conversions, including truncation and float conversions. 472 // */ 473 // public static <T> T wrap(Object x, Class<T> type) { 474 // return Wrapper.valueOf(type).cast(x, type); 475 // } 476 477 /** Cast a wrapped value to the given type, which may be either a primitive or wrapper type. 478 * The given target type must be this wrapper's primitive or wrapper type. 479 * If this wrapper is OBJECT, the target type may also be an interface, perform no runtime check. 480 * Performs standard primitive conversions, including truncation and float conversions. 481 * The given type must be compatible with this wrapper. That is, it must either 482 * be the wrapper type (or a subtype, in the case of {@code OBJECT}) or else 483 * it must be the wrapper's primitive type. 484 * Primitive conversions are only performed if the given type is itself a primitive. 485 * @throws ClassCastException if the given type is not compatible with this wrapper 486 */ cast(Object x, Class<T> type)487 public <T> T cast(Object x, Class<T> type) { 488 return convert(x, type, true); 489 } 490 491 /** Convert a wrapped value to the given type. 492 * The given target type must be this wrapper's primitive or wrapper type. 493 * This is equivalent to {@link #cast}, except that it refuses to perform 494 * narrowing primitive conversions. 495 */ convert(Object x, Class<T> type)496 public <T> T convert(Object x, Class<T> type) { 497 return convert(x, type, false); 498 } 499 convert(Object x, Class<T> type, boolean isCast)500 private <T> T convert(Object x, Class<T> type, boolean isCast) { 501 if (this == OBJECT) { 502 // If the target wrapper is OBJECT, just do a reference cast. 503 // If the target type is an interface, perform no runtime check. 504 // (This loophole is safe, and is allowed by the JVM verifier.) 505 // If the target type is a primitive, change it to a wrapper. 506 assert(!type.isPrimitive()); 507 if (!type.isInterface()) 508 type.cast(x); 509 @SuppressWarnings("unchecked") 510 T result = (T) x; // unchecked warning is expected here 511 return result; 512 } 513 Class<T> wtype = wrapperType(type); 514 if (wtype.isInstance(x)) { 515 return wtype.cast(x); 516 } 517 if (!isCast) { 518 Class<?> sourceType = x.getClass(); // throw NPE if x is null 519 Wrapper source = findWrapperType(sourceType); 520 if (source == null || !this.isConvertibleFrom(source)) { 521 throw newClassCastException(wtype, sourceType); 522 } 523 } else if (x == null) { 524 @SuppressWarnings("unchecked") 525 T z = (T) zero(); 526 return z; 527 } 528 @SuppressWarnings("unchecked") 529 T result = (T) wrap(x); // unchecked warning is expected here 530 assert (result == null ? Void.class : result.getClass()) == wtype; 531 return result; 532 } 533 534 /** Cast a reference type to another reference type. 535 * If the target type is an interface, perform no runtime check. 536 * (This loophole is safe, and is allowed by the JVM verifier.) 537 * If the target type is a primitive, change it to a wrapper. 538 */ forceType(Class<?> type, Class<T> exampleType)539 static <T> Class<T> forceType(Class<?> type, Class<T> exampleType) { 540 assert(type == exampleType || 541 type.isPrimitive() && forPrimitiveType(type) == findWrapperType(exampleType) || 542 exampleType.isPrimitive() && forPrimitiveType(exampleType) == findWrapperType(type) || 543 type == Object.class && !exampleType.isPrimitive()); 544 @SuppressWarnings("unchecked") 545 Class<T> result = (Class<T>) type; // unchecked warning is expected here 546 return result; 547 } 548 549 /** Wrap a value in this wrapper's type. 550 * Performs standard primitive conversions, including truncation and float conversions. 551 * Performs returns the unchanged reference for {@code OBJECT}. 552 * Returns null for {@code VOID}. 553 * Returns a zero value for a null input. 554 * @throws ClassCastException if this wrapper is numeric and the operand 555 * is not a number, character, boolean, or null 556 */ wrap(Object x)557 public Object wrap(Object x) { 558 // do non-numeric wrappers first 559 switch (basicTypeChar) { 560 case 'L': return x; 561 case 'V': return null; 562 } 563 Number xn = numberValue(x); 564 switch (basicTypeChar) { 565 case 'I': return Integer.valueOf(xn.intValue()); 566 case 'J': return Long.valueOf(xn.longValue()); 567 case 'F': return Float.valueOf(xn.floatValue()); 568 case 'D': return Double.valueOf(xn.doubleValue()); 569 case 'S': return Short.valueOf((short) xn.intValue()); 570 case 'B': return Byte.valueOf((byte) xn.intValue()); 571 case 'C': return Character.valueOf((char) xn.intValue()); 572 case 'Z': return Boolean.valueOf(boolValue(xn.byteValue())); 573 } 574 throw new InternalError("bad wrapper"); 575 } 576 577 /** Wrap a value (an int or smaller value) in this wrapper's type. 578 * Performs standard primitive conversions, including truncation and float conversions. 579 * Produces an {@code Integer} for {@code OBJECT}, although the exact type 580 * of the operand is not known. 581 * Returns null for {@code VOID}. 582 */ wrap(int x)583 public Object wrap(int x) { 584 if (basicTypeChar == 'L') return (Integer)x; 585 switch (basicTypeChar) { 586 case 'L': throw newIllegalArgumentException("cannot wrap to object type"); 587 case 'V': return null; 588 case 'I': return Integer.valueOf(x); 589 case 'J': return Long.valueOf(x); 590 case 'F': return Float.valueOf(x); 591 case 'D': return Double.valueOf(x); 592 case 'S': return Short.valueOf((short) x); 593 case 'B': return Byte.valueOf((byte) x); 594 case 'C': return Character.valueOf((char) x); 595 case 'Z': return Boolean.valueOf(boolValue((byte) x)); 596 } 597 throw new InternalError("bad wrapper"); 598 } 599 numberValue(Object x)600 private static Number numberValue(Object x) { 601 if (x instanceof Number) return (Number)x; 602 if (x instanceof Character) return (int)(Character)x; 603 if (x instanceof Boolean) return (Boolean)x ? 1 : 0; 604 // Remaining allowed case of void: Must be a null reference. 605 return (Number)x; 606 } 607 608 // Parameter type of boolValue must be byte, because 609 // MethodHandles.explicitCastArguments defines boolean 610 // conversion as first converting to byte. boolValue(byte bits)611 private static boolean boolValue(byte bits) { 612 bits &= 1; // simple 31-bit zero extension 613 return (bits != 0); 614 } 615 newIllegalArgumentException(String message, Object x)616 private static RuntimeException newIllegalArgumentException(String message, Object x) { 617 return newIllegalArgumentException(message + x); 618 } newIllegalArgumentException(String message)619 private static RuntimeException newIllegalArgumentException(String message) { 620 return new IllegalArgumentException(message); 621 } 622 623 // primitive array support makeArray(int len)624 public Object makeArray(int len) { 625 return java.lang.reflect.Array.newInstance(primitiveType, len); 626 } arrayType()627 public Class<?> arrayType() { 628 return emptyArray.getClass(); 629 } copyArrayUnboxing(Object[] values, int vpos, Object a, int apos, int length)630 public void copyArrayUnboxing(Object[] values, int vpos, Object a, int apos, int length) { 631 if (a.getClass() != arrayType()) 632 arrayType().cast(a); // throw NPE or CCE if bad type 633 for (int i = 0; i < length; i++) { 634 Object value = values[i+vpos]; 635 value = convert(value, primitiveType); 636 java.lang.reflect.Array.set(a, i+apos, value); 637 } 638 } copyArrayBoxing(Object a, int apos, Object[] values, int vpos, int length)639 public void copyArrayBoxing(Object a, int apos, Object[] values, int vpos, int length) { 640 if (a.getClass() != arrayType()) 641 arrayType().cast(a); // throw NPE or CCE if bad type 642 for (int i = 0; i < length; i++) { 643 Object value = java.lang.reflect.Array.get(a, i+apos); 644 //Already done: value = convert(value, primitiveType); 645 assert(value.getClass() == wrapperType); 646 values[i+vpos] = value; 647 } 648 } 649 } 650