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