1 /* |
|
2 * Copyright (c) 2008, 2010, 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 } |
|