1237 lines · 44.9 KB · Java
RawDownload
/* * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.invoke.util; import java.lang.invoke.MethodHandle;import java.lang.invoke.MethodHandles;import java.lang.invoke.MethodHandles.Lookup;import java.lang.invoke.MethodType;import java.security.AccessController;import java.security.PrivilegedAction;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.EnumMap;import java.util.List; public class ValueConversions {    private static final Class<?> THIS_CLASS = ValueConversions.class;    // Do not adjust this except for special platforms:    private static final int MAX_ARITY;    static {        final Object[] values = { 255 };        AccessController.doPrivileged(new PrivilegedAction<Void>() {                public Void run() {                    values[0] = Integer.getInteger(THIS_CLASS.getName()+".MAX_ARITY", 255);                    return null;                }            });        MAX_ARITY = (Integer) values[0];    }     private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();     private static EnumMap<Wrapper, MethodHandle>[] newWrapperCaches(int n) {        @SuppressWarnings("unchecked")        EnumMap<Wrapper, MethodHandle>[] caches                = (EnumMap<Wrapper, MethodHandle>[]) new EnumMap[n];  // unchecked warning expected here        for (int i = 0; i < n; i++)            caches[i] = new EnumMap<>(Wrapper.class);        return caches;    }     /// Converting references to values.     // There are several levels of this unboxing conversions:    //   no conversions:  exactly Integer.valueOf, etc.    //   implicit conversions sanctioned by JLS 5.1.2, etc.    //   explicit conversions as allowed by explicitCastArguments     static int unboxInteger(Object x, boolean cast) {        if (x instanceof Integer)            return ((Integer) x).intValue();        return primitiveConversion(Wrapper.INT, x, cast).intValue();    }     static byte unboxByte(Object x, boolean cast) {        if (x instanceof Byte)            return ((Byte) x).byteValue();        return primitiveConversion(Wrapper.BYTE, x, cast).byteValue();    }     static short unboxShort(Object x, boolean cast) {        if (x instanceof Short)            return ((Short) x).shortValue();        return primitiveConversion(Wrapper.SHORT, x, cast).shortValue();    }     static boolean unboxBoolean(Object x, boolean cast) {        if (x instanceof Boolean)            return ((Boolean) x).booleanValue();        return (primitiveConversion(Wrapper.BOOLEAN, x, cast).intValue() & 1) != 0;    }     static char unboxCharacter(Object x, boolean cast) {        if (x instanceof Character)            return ((Character) x).charValue();        return (char) primitiveConversion(Wrapper.CHAR, x, cast).intValue();    }     static long unboxLong(Object x, boolean cast) {        if (x instanceof Long)            return ((Long) x).longValue();        return primitiveConversion(Wrapper.LONG, x, cast).longValue();    }     static float unboxFloat(Object x, boolean cast) {        if (x instanceof Float)            return ((Float) x).floatValue();        return primitiveConversion(Wrapper.FLOAT, x, cast).floatValue();    }     static double unboxDouble(Object x, boolean cast) {        if (x instanceof Double)            return ((Double) x).doubleValue();        return primitiveConversion(Wrapper.DOUBLE, x, cast).doubleValue();    }     /// Converting references to "raw" values.    /// A raw primitive value is always an int or long.     static int unboxByteRaw(Object x, boolean cast) {        return unboxByte(x, cast);    }     static int unboxShortRaw(Object x, boolean cast) {        return unboxShort(x, cast);    }     static int unboxBooleanRaw(Object x, boolean cast) {        return unboxBoolean(x, cast) ? 1 : 0;    }     static int unboxCharacterRaw(Object x, boolean cast) {        return unboxCharacter(x, cast);    }     static int unboxFloatRaw(Object x, boolean cast) {        return Float.floatToIntBits(unboxFloat(x, cast));    }     static long unboxDoubleRaw(Object x, boolean cast) {        return Double.doubleToRawLongBits(unboxDouble(x, cast));    }     private static MethodType unboxType(Wrapper wrap, boolean raw) {        return MethodType.methodType(rawWrapper(wrap, raw).primitiveType(), Object.class, boolean.class);    }     private static final EnumMap<Wrapper, MethodHandle>[]            UNBOX_CONVERSIONS = newWrapperCaches(4);     private static MethodHandle unbox(Wrapper wrap, boolean raw, boolean cast) {        EnumMap<Wrapper, MethodHandle> cache = UNBOX_CONVERSIONS[(cast?1:0)+(raw?2:0)];        MethodHandle mh = cache.get(wrap);        if (mh != null) {            return mh;        }        // slow path        switch (wrap) {            case OBJECT:                mh = IDENTITY; break;            case VOID:                mh = raw ? ALWAYS_ZERO : IGNORE; break;            case INT: case LONG:                // these guys don't need separate raw channels                if (raw)  mh = unbox(wrap, false, cast);                break;        }        if (mh != null) {            cache.put(wrap, mh);            return mh;        }        // look up the method        String name = "unbox" + wrap.simpleName() + (raw ? "Raw" : "");        MethodType type = unboxType(wrap, raw);        try {            mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);        } catch (ReflectiveOperationException ex) {            mh = null;        }        if (mh != null) {            mh = MethodHandles.insertArguments(mh, 1, cast);            cache.put(wrap, mh);            return mh;        }        throw new IllegalArgumentException("cannot find unbox adapter for " + wrap                + (cast ? " (cast)" : "") + (raw ? " (raw)" : ""));    }     public static MethodHandle unboxCast(Wrapper type) {        return unbox(type, false, true);    }     public static MethodHandle unboxRaw(Wrapper type) {        return unbox(type, true, false);    }     public static MethodHandle unbox(Class<?> type) {        return unbox(Wrapper.forPrimitiveType(type), false, false);    }     public static MethodHandle unboxCast(Class<?> type) {        return unbox(Wrapper.forPrimitiveType(type), false, true);    }     public static MethodHandle unboxRaw(Class<?> type) {        return unbox(Wrapper.forPrimitiveType(type), true, false);    }     static private final Integer ZERO_INT = 0, ONE_INT = 1;     /// Primitive conversions    public static Number primitiveConversion(Wrapper wrap, Object x, boolean cast) {        // Maybe merge this code with Wrapper.convert/cast.        Number res = null;        if (x == null) {            if (!cast)  return null;            return ZERO_INT;        }        if (x instanceof Number) {            res = (Number) x;        } else if (x instanceof Boolean) {            res = ((boolean)x ? ONE_INT : ZERO_INT);        } else if (x instanceof Character) {            res = (int)(char)x;        } else {            // this will fail with the required ClassCastException:            res = (Number) x;        }        Wrapper xwrap = Wrapper.findWrapperType(x.getClass());        if (xwrap == null || !cast && !wrap.isConvertibleFrom(xwrap))            // this will fail with the required ClassCastException:            return (Number) wrap.wrapperType().cast(x);        return res;    }     /// Converting primitives to references     static Integer boxInteger(int x) {        return x;    }     static Byte boxByte(byte x) {        return x;    }     static Short boxShort(short x) {        return x;    }     static Boolean boxBoolean(boolean x) {        return x;    }     static Character boxCharacter(char x) {        return x;    }     static Long boxLong(long x) {        return x;    }     static Float boxFloat(float x) {        return x;    }     static Double boxDouble(double x) {        return x;    }     /// Converting raw primitives to references     static Byte boxByteRaw(int x) {        return boxByte((byte)x);    }     static Short boxShortRaw(int x) {        return boxShort((short)x);    }     static Boolean boxBooleanRaw(int x) {        return boxBoolean(x != 0);    }     static Character boxCharacterRaw(int x) {        return boxCharacter((char)x);    }     static Float boxFloatRaw(int x) {        return boxFloat(Float.intBitsToFloat(x));    }     static Double boxDoubleRaw(long x) {        return boxDouble(Double.longBitsToDouble(x));    }     // a raw void value is (arbitrarily) a garbage int    static Void boxVoidRaw(int x) {        return null;    }     private static MethodType boxType(Wrapper wrap, boolean raw) {        // be exact, since return casts are hard to compose        Class<?> boxType = wrap.wrapperType();        return MethodType.methodType(boxType, rawWrapper(wrap, raw).primitiveType());    }     private static Wrapper rawWrapper(Wrapper wrap, boolean raw) {        if (raw)  return wrap.isDoubleWord() ? Wrapper.LONG : Wrapper.INT;        return wrap;    }     private static final EnumMap<Wrapper, MethodHandle>[]            BOX_CONVERSIONS = newWrapperCaches(4);     private static MethodHandle box(Wrapper wrap, boolean exact, boolean raw) {        EnumMap<Wrapper, MethodHandle> cache = BOX_CONVERSIONS[(exact?1:0)+(raw?2:0)];        MethodHandle mh = cache.get(wrap);        if (mh != null) {            return mh;        }        // slow path        switch (wrap) {            case OBJECT:                mh = IDENTITY; break;            case VOID:                if (!raw)  mh = ZERO_OBJECT;                break;            case INT: case LONG:                // these guys don't need separate raw channels                if (raw)  mh = box(wrap, exact, false);                break;        }        if (mh != null) {            cache.put(wrap, mh);            return mh;        }        // look up the method        String name = "box" + wrap.simpleName() + (raw ? "Raw" : "");        MethodType type = boxType(wrap, raw);        if (exact) {            try {                mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);            } catch (ReflectiveOperationException ex) {                mh = null;            }        } else {            mh = box(wrap, !exact, raw).asType(type.erase());        }        if (mh != null) {            cache.put(wrap, mh);            return mh;        }        throw new IllegalArgumentException("cannot find box adapter for "                + wrap + (exact ? " (exact)" : "") + (raw ? " (raw)" : ""));    }     public static MethodHandle box(Class<?> type) {        boolean exact = false;        // e.g., boxShort(short)Short if exact,        // e.g., boxShort(short)Object if !exact        return box(Wrapper.forPrimitiveType(type), exact, false);    }     public static MethodHandle boxRaw(Class<?> type) {        boolean exact = false;        // e.g., boxShortRaw(int)Short if exact        // e.g., boxShortRaw(int)Object if !exact        return box(Wrapper.forPrimitiveType(type), exact, true);    }     public static MethodHandle box(Wrapper type) {        boolean exact = false;        return box(type, exact, false);    }     public static MethodHandle boxRaw(Wrapper type) {        boolean exact = false;        return box(type, exact, true);    }     /// Kludges for when raw values get accidentally boxed.     static int unboxRawInteger(Object x) {        if (x instanceof Integer)            return (int) x;        else            return (int) unboxLong(x, false);    }     static Integer reboxRawInteger(Object x) {        if (x instanceof Integer)            return (Integer) x;        else            return (int) unboxLong(x, false);    }     static Byte reboxRawByte(Object x) {        if (x instanceof Byte)  return (Byte) x;        return boxByteRaw(unboxRawInteger(x));    }     static Short reboxRawShort(Object x) {        if (x instanceof Short)  return (Short) x;        return boxShortRaw(unboxRawInteger(x));    }     static Boolean reboxRawBoolean(Object x) {        if (x instanceof Boolean)  return (Boolean) x;        return boxBooleanRaw(unboxRawInteger(x));    }     static Character reboxRawCharacter(Object x) {        if (x instanceof Character)  return (Character) x;        return boxCharacterRaw(unboxRawInteger(x));    }     static Float reboxRawFloat(Object x) {        if (x instanceof Float)  return (Float) x;        return boxFloatRaw(unboxRawInteger(x));    }     static Long reboxRawLong(Object x) {        return (Long) x;  //never a rebox    }     static Double reboxRawDouble(Object x) {        if (x instanceof Double)  return (Double) x;        return boxDoubleRaw(unboxLong(x, true));    }     private static MethodType reboxType(Wrapper wrap) {        Class<?> boxType = wrap.wrapperType();        return MethodType.methodType(boxType, Object.class);    }     private static final EnumMap<Wrapper, MethodHandle>[]            REBOX_CONVERSIONS = newWrapperCaches(1);     /**     * Because we normalize primitive types to reduce the number of signatures,     * primitives are sometimes manipulated under an "erased" type,     * either int (for types other than long/double) or long (for all types).     * When the erased primitive value is then boxed into an Integer or Long,     * the final boxed primitive is sometimes required.  This transformation     * is called a "rebox".  It takes an Integer or Long and produces some     * other boxed value, typed (inexactly) as an Object     */    public static MethodHandle rebox(Wrapper wrap) {        EnumMap<Wrapper, MethodHandle> cache = REBOX_CONVERSIONS[0];        MethodHandle mh = cache.get(wrap);        if (mh != null) {            return mh;        }        // slow path        switch (wrap) {            case OBJECT:                mh = IDENTITY; break;            case VOID:                throw new IllegalArgumentException("cannot rebox a void");        }        if (mh != null) {            cache.put(wrap, mh);            return mh;        }        // look up the method        String name = "reboxRaw" + wrap.simpleName();        MethodType type = reboxType(wrap);        try {            mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);            mh = mh.asType(IDENTITY.type());        } catch (ReflectiveOperationException ex) {            mh = null;        }        if (mh != null) {            cache.put(wrap, mh);            return mh;        }        throw new IllegalArgumentException("cannot find rebox adapter for " + wrap);    }     public static MethodHandle rebox(Class<?> type) {        return rebox(Wrapper.forPrimitiveType(type));    }     /// Width-changing conversions between int and long.     static long widenInt(int x) {        return (long) x;    }     static Long widenBoxedInt(Integer x) {        return (long)(int)x;    }     static int narrowLong(long x) {        return (int) x;

Lines 1–500 of 1237.