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