/* * 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. Load more
/* * 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;