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