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