mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
|
@ -0,0 +1,677 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2013, 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 jdk.internal.vm.annotation.Stable;
|
||||
|
||||
public class ValueConversions {
|
||||
private static final Class<?> THIS_CLASS = ValueConversions.class;
|
||||
private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
|
||||
|
||||
/**
|
||||
* Thread-safe canonicalized mapping from Wrapper to MethodHandle
|
||||
* with unsynchronized reads and synchronized writes.
|
||||
* It's safe to publish MethodHandles by data race because they are immutable.
|
||||
*/
|
||||
private static class WrapperCache {
|
||||
@Stable
|
||||
private final MethodHandle[] map = new MethodHandle[Wrapper.COUNT];
|
||||
|
||||
public MethodHandle get(Wrapper w) {
|
||||
return map[w.ordinal()];
|
||||
}
|
||||
public synchronized MethodHandle put(final Wrapper w, final MethodHandle mh) {
|
||||
MethodHandle prev = map[w.ordinal()];
|
||||
if (prev != null) {
|
||||
return prev;
|
||||
} else {
|
||||
map[w.ordinal()] = mh;
|
||||
return mh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static WrapperCache[] newWrapperCaches(int n) {
|
||||
WrapperCache[] caches = new WrapperCache[n];
|
||||
for (int i = 0; i < n; i++)
|
||||
caches[i] = new WrapperCache();
|
||||
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(Integer x) {
|
||||
return x;
|
||||
}
|
||||
static int unboxInteger(Object x, boolean cast) {
|
||||
if (x instanceof Integer)
|
||||
return (Integer) x;
|
||||
return primitiveConversion(Wrapper.INT, x, cast).intValue();
|
||||
}
|
||||
|
||||
static byte unboxByte(Byte x) {
|
||||
return x;
|
||||
}
|
||||
static byte unboxByte(Object x, boolean cast) {
|
||||
if (x instanceof Byte)
|
||||
return (Byte) x;
|
||||
return primitiveConversion(Wrapper.BYTE, x, cast).byteValue();
|
||||
}
|
||||
|
||||
static short unboxShort(Short x) {
|
||||
return x;
|
||||
}
|
||||
static short unboxShort(Object x, boolean cast) {
|
||||
if (x instanceof Short)
|
||||
return (Short) x;
|
||||
return primitiveConversion(Wrapper.SHORT, x, cast).shortValue();
|
||||
}
|
||||
|
||||
static boolean unboxBoolean(Boolean x) {
|
||||
return x;
|
||||
}
|
||||
static boolean unboxBoolean(Object x, boolean cast) {
|
||||
if (x instanceof Boolean)
|
||||
return (Boolean) x;
|
||||
return (primitiveConversion(Wrapper.BOOLEAN, x, cast).intValue() & 1) != 0;
|
||||
}
|
||||
|
||||
static char unboxCharacter(Character x) {
|
||||
return x;
|
||||
}
|
||||
static char unboxCharacter(Object x, boolean cast) {
|
||||
if (x instanceof Character)
|
||||
return (Character) x;
|
||||
return (char) primitiveConversion(Wrapper.CHAR, x, cast).intValue();
|
||||
}
|
||||
|
||||
static long unboxLong(Long x) {
|
||||
return x;
|
||||
}
|
||||
static long unboxLong(Object x, boolean cast) {
|
||||
if (x instanceof Long)
|
||||
return (Long) x;
|
||||
return primitiveConversion(Wrapper.LONG, x, cast).longValue();
|
||||
}
|
||||
|
||||
static float unboxFloat(Float x) {
|
||||
return x;
|
||||
}
|
||||
static float unboxFloat(Object x, boolean cast) {
|
||||
if (x instanceof Float)
|
||||
return (Float) x;
|
||||
return primitiveConversion(Wrapper.FLOAT, x, cast).floatValue();
|
||||
}
|
||||
|
||||
static double unboxDouble(Double x) {
|
||||
return x;
|
||||
}
|
||||
static double unboxDouble(Object x, boolean cast) {
|
||||
if (x instanceof Double)
|
||||
return (Double) x;
|
||||
return primitiveConversion(Wrapper.DOUBLE, x, cast).doubleValue();
|
||||
}
|
||||
|
||||
private static MethodType unboxType(Wrapper wrap, int kind) {
|
||||
if (kind == 0)
|
||||
return MethodType.methodType(wrap.primitiveType(), wrap.wrapperType());
|
||||
return MethodType.methodType(wrap.primitiveType(), Object.class, boolean.class);
|
||||
}
|
||||
|
||||
private static final WrapperCache[] UNBOX_CONVERSIONS = newWrapperCaches(4);
|
||||
|
||||
private static MethodHandle unbox(Wrapper wrap, int kind) {
|
||||
// kind 0 -> strongly typed with NPE
|
||||
// kind 1 -> strongly typed but zero for null,
|
||||
// kind 2 -> asType rules: accept multiple box types but only widening conversions with NPE
|
||||
// kind 3 -> explicitCastArguments rules: allow narrowing conversions, zero for null
|
||||
WrapperCache cache = UNBOX_CONVERSIONS[kind];
|
||||
MethodHandle mh = cache.get(wrap);
|
||||
if (mh != null) {
|
||||
return mh;
|
||||
}
|
||||
// slow path
|
||||
switch (wrap) {
|
||||
case OBJECT:
|
||||
case VOID:
|
||||
throw new IllegalArgumentException("unbox "+wrap);
|
||||
}
|
||||
// look up the method
|
||||
String name = "unbox" + wrap.wrapperSimpleName();
|
||||
MethodType type = unboxType(wrap, kind);
|
||||
try {
|
||||
mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
mh = null;
|
||||
}
|
||||
if (mh != null) {
|
||||
if (kind > 0) {
|
||||
boolean cast = (kind != 2);
|
||||
mh = MethodHandles.insertArguments(mh, 1, cast);
|
||||
}
|
||||
if (kind == 1) { // casting but exact (null -> zero)
|
||||
mh = mh.asType(unboxType(wrap, 0));
|
||||
}
|
||||
return cache.put(wrap, mh);
|
||||
}
|
||||
throw new IllegalArgumentException("cannot find unbox adapter for " + wrap
|
||||
+ (kind <= 1 ? " (exact)" : kind == 3 ? " (cast)" : ""));
|
||||
}
|
||||
|
||||
/** Return an exact unboxer for the given primitive type. */
|
||||
public static MethodHandle unboxExact(Wrapper type) {
|
||||
return unbox(type, 0);
|
||||
}
|
||||
|
||||
/** Return an exact unboxer for the given primitive type, with optional null-to-zero conversion.
|
||||
* The boolean says whether to throw an NPE on a null value (false means unbox a zero).
|
||||
* The type of the unboxer is of a form like (Integer)int.
|
||||
*/
|
||||
public static MethodHandle unboxExact(Wrapper type, boolean throwNPE) {
|
||||
return unbox(type, throwNPE ? 0 : 1);
|
||||
}
|
||||
|
||||
/** Return a widening unboxer for the given primitive type.
|
||||
* Widen narrower primitive boxes to the given type.
|
||||
* Do not narrow any primitive values or convert null to zero.
|
||||
* The type of the unboxer is of a form like (Object)int.
|
||||
*/
|
||||
public static MethodHandle unboxWiden(Wrapper type) {
|
||||
return unbox(type, 2);
|
||||
}
|
||||
|
||||
/** Return a casting unboxer for the given primitive type.
|
||||
* Widen or narrow primitive values to the given type, or convert null to zero, as needed.
|
||||
* The type of the unboxer is of a form like (Object)int.
|
||||
*/
|
||||
public static MethodHandle unboxCast(Wrapper type) {
|
||||
return unbox(type, 3);
|
||||
}
|
||||
|
||||
private static final Integer ZERO_INT = 0, ONE_INT = 1;
|
||||
|
||||
/// Primitive conversions
|
||||
/**
|
||||
* Produce a Number which represents the given value {@code x}
|
||||
* according to the primitive type of the given wrapper {@code wrap}.
|
||||
* Caller must invoke intValue, byteValue, longValue (etc.) on the result
|
||||
* to retrieve the desired primitive value.
|
||||
*/
|
||||
public static Number primitiveConversion(Wrapper wrap, Object x, boolean cast) {
|
||||
// Maybe merge this code with Wrapper.convert/cast.
|
||||
Number res;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* The JVM verifier allows boolean, byte, short, or char to widen to int.
|
||||
* Support exactly this conversion, from a boxed value type Boolean,
|
||||
* Byte, Short, Character, or Integer.
|
||||
*/
|
||||
public static int widenSubword(Object x) {
|
||||
if (x instanceof Integer)
|
||||
return (int) x;
|
||||
else if (x instanceof Boolean)
|
||||
return fromBoolean((boolean) x);
|
||||
else if (x instanceof Character)
|
||||
return (char) x;
|
||||
else if (x instanceof Short)
|
||||
return (short) x;
|
||||
else if (x instanceof Byte)
|
||||
return (byte) x;
|
||||
else
|
||||
// Fail with a ClassCastException.
|
||||
return (int) x;
|
||||
}
|
||||
|
||||
/// 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;
|
||||
}
|
||||
|
||||
private static MethodType boxType(Wrapper wrap) {
|
||||
// be exact, since return casts are hard to compose
|
||||
Class<?> boxType = wrap.wrapperType();
|
||||
return MethodType.methodType(boxType, wrap.primitiveType());
|
||||
}
|
||||
|
||||
private static final WrapperCache[] BOX_CONVERSIONS = newWrapperCaches(1);
|
||||
|
||||
public static MethodHandle boxExact(Wrapper wrap) {
|
||||
WrapperCache cache = BOX_CONVERSIONS[0];
|
||||
MethodHandle mh = cache.get(wrap);
|
||||
if (mh != null) {
|
||||
return mh;
|
||||
}
|
||||
// look up the method
|
||||
String name = "box" + wrap.wrapperSimpleName();
|
||||
MethodType type = boxType(wrap);
|
||||
try {
|
||||
mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
mh = null;
|
||||
}
|
||||
if (mh != null) {
|
||||
return cache.put(wrap, mh);
|
||||
}
|
||||
throw new IllegalArgumentException("cannot find box adapter for " + wrap);
|
||||
}
|
||||
|
||||
/// Constant functions
|
||||
|
||||
static void ignore(Object x) {
|
||||
// no value to return; this is an unbox of null
|
||||
}
|
||||
|
||||
static void empty() {
|
||||
}
|
||||
|
||||
static Object zeroObject() {
|
||||
return null;
|
||||
}
|
||||
|
||||
static int zeroInteger() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long zeroLong() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static float zeroFloat() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static double zeroDouble() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static final WrapperCache[] CONSTANT_FUNCTIONS = newWrapperCaches(2);
|
||||
|
||||
public static MethodHandle zeroConstantFunction(Wrapper wrap) {
|
||||
WrapperCache cache = CONSTANT_FUNCTIONS[0];
|
||||
MethodHandle mh = cache.get(wrap);
|
||||
if (mh != null) {
|
||||
return mh;
|
||||
}
|
||||
// slow path
|
||||
MethodType type = MethodType.methodType(wrap.primitiveType());
|
||||
switch (wrap) {
|
||||
case VOID:
|
||||
mh = EMPTY;
|
||||
break;
|
||||
case OBJECT:
|
||||
case INT: case LONG: case FLOAT: case DOUBLE:
|
||||
try {
|
||||
mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "zero"+wrap.wrapperSimpleName(), type);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
mh = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (mh != null) {
|
||||
return cache.put(wrap, mh);
|
||||
}
|
||||
|
||||
// use zeroInt and cast the result
|
||||
if (wrap.isSubwordOrInt() && wrap != Wrapper.INT) {
|
||||
mh = MethodHandles.explicitCastArguments(zeroConstantFunction(Wrapper.INT), type);
|
||||
return cache.put(wrap, mh);
|
||||
}
|
||||
throw new IllegalArgumentException("cannot find zero constant for " + wrap);
|
||||
}
|
||||
|
||||
private static final MethodHandle CAST_REFERENCE, IGNORE, EMPTY;
|
||||
static {
|
||||
try {
|
||||
MethodType idType = MethodType.genericMethodType(1);
|
||||
MethodType ignoreType = idType.changeReturnType(void.class);
|
||||
CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
|
||||
IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType);
|
||||
EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1));
|
||||
} catch (NoSuchMethodException | IllegalAccessException ex) {
|
||||
throw newInternalError("uncaught exception", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static MethodHandle ignore() {
|
||||
return IGNORE;
|
||||
}
|
||||
|
||||
/** Return a method that casts its second argument (an Object) to the given type (a Class). */
|
||||
public static MethodHandle cast() {
|
||||
return CAST_REFERENCE;
|
||||
}
|
||||
|
||||
/// Primitive conversions.
|
||||
// These are supported directly by the JVM, usually by a single instruction.
|
||||
// In the case of narrowing to a subword, there may be a pair of instructions.
|
||||
// In the case of booleans, there may be a helper routine to manage a 1-bit value.
|
||||
// This is the full 8x8 matrix (minus the diagonal).
|
||||
|
||||
// narrow double to all other types:
|
||||
static float doubleToFloat(double x) { // bytecode: d2f
|
||||
return (float) x;
|
||||
}
|
||||
static long doubleToLong(double x) { // bytecode: d2l
|
||||
return (long) x;
|
||||
}
|
||||
static int doubleToInt(double x) { // bytecode: d2i
|
||||
return (int) x;
|
||||
}
|
||||
static short doubleToShort(double x) { // bytecodes: d2i, i2s
|
||||
return (short) x;
|
||||
}
|
||||
static char doubleToChar(double x) { // bytecodes: d2i, i2c
|
||||
return (char) x;
|
||||
}
|
||||
static byte doubleToByte(double x) { // bytecodes: d2i, i2b
|
||||
return (byte) x;
|
||||
}
|
||||
static boolean doubleToBoolean(double x) {
|
||||
return toBoolean((byte) x);
|
||||
}
|
||||
|
||||
// widen float:
|
||||
static double floatToDouble(float x) { // bytecode: f2d
|
||||
return x;
|
||||
}
|
||||
// narrow float:
|
||||
static long floatToLong(float x) { // bytecode: f2l
|
||||
return (long) x;
|
||||
}
|
||||
static int floatToInt(float x) { // bytecode: f2i
|
||||
return (int) x;
|
||||
}
|
||||
static short floatToShort(float x) { // bytecodes: f2i, i2s
|
||||
return (short) x;
|
||||
}
|
||||
static char floatToChar(float x) { // bytecodes: f2i, i2c
|
||||
return (char) x;
|
||||
}
|
||||
static byte floatToByte(float x) { // bytecodes: f2i, i2b
|
||||
return (byte) x;
|
||||
}
|
||||
static boolean floatToBoolean(float x) {
|
||||
return toBoolean((byte) x);
|
||||
}
|
||||
|
||||
// widen long:
|
||||
static double longToDouble(long x) { // bytecode: l2d
|
||||
return x;
|
||||
}
|
||||
static float longToFloat(long x) { // bytecode: l2f
|
||||
return x;
|
||||
}
|
||||
// narrow long:
|
||||
static int longToInt(long x) { // bytecode: l2i
|
||||
return (int) x;
|
||||
}
|
||||
static short longToShort(long x) { // bytecodes: f2i, i2s
|
||||
return (short) x;
|
||||
}
|
||||
static char longToChar(long x) { // bytecodes: f2i, i2c
|
||||
return (char) x;
|
||||
}
|
||||
static byte longToByte(long x) { // bytecodes: f2i, i2b
|
||||
return (byte) x;
|
||||
}
|
||||
static boolean longToBoolean(long x) {
|
||||
return toBoolean((byte) x);
|
||||
}
|
||||
|
||||
// widen int:
|
||||
static double intToDouble(int x) { // bytecode: i2d
|
||||
return x;
|
||||
}
|
||||
static float intToFloat(int x) { // bytecode: i2f
|
||||
return x;
|
||||
}
|
||||
static long intToLong(int x) { // bytecode: i2l
|
||||
return x;
|
||||
}
|
||||
// narrow int:
|
||||
static short intToShort(int x) { // bytecode: i2s
|
||||
return (short) x;
|
||||
}
|
||||
static char intToChar(int x) { // bytecode: i2c
|
||||
return (char) x;
|
||||
}
|
||||
static byte intToByte(int x) { // bytecode: i2b
|
||||
return (byte) x;
|
||||
}
|
||||
static boolean intToBoolean(int x) {
|
||||
return toBoolean((byte) x);
|
||||
}
|
||||
|
||||
// widen short:
|
||||
static double shortToDouble(short x) { // bytecode: i2d (implicit 's2i')
|
||||
return x;
|
||||
}
|
||||
static float shortToFloat(short x) { // bytecode: i2f (implicit 's2i')
|
||||
return x;
|
||||
}
|
||||
static long shortToLong(short x) { // bytecode: i2l (implicit 's2i')
|
||||
return x;
|
||||
}
|
||||
static int shortToInt(short x) { // (implicit 's2i')
|
||||
return x;
|
||||
}
|
||||
// narrow short:
|
||||
static char shortToChar(short x) { // bytecode: i2c (implicit 's2i')
|
||||
return (char)x;
|
||||
}
|
||||
static byte shortToByte(short x) { // bytecode: i2b (implicit 's2i')
|
||||
return (byte)x;
|
||||
}
|
||||
static boolean shortToBoolean(short x) {
|
||||
return toBoolean((byte) x);
|
||||
}
|
||||
|
||||
// widen char:
|
||||
static double charToDouble(char x) { // bytecode: i2d (implicit 'c2i')
|
||||
return x;
|
||||
}
|
||||
static float charToFloat(char x) { // bytecode: i2f (implicit 'c2i')
|
||||
return x;
|
||||
}
|
||||
static long charToLong(char x) { // bytecode: i2l (implicit 'c2i')
|
||||
return x;
|
||||
}
|
||||
static int charToInt(char x) { // (implicit 'c2i')
|
||||
return x;
|
||||
}
|
||||
// narrow char:
|
||||
static short charToShort(char x) { // bytecode: i2s (implicit 'c2i')
|
||||
return (short)x;
|
||||
}
|
||||
static byte charToByte(char x) { // bytecode: i2b (implicit 'c2i')
|
||||
return (byte)x;
|
||||
}
|
||||
static boolean charToBoolean(char x) {
|
||||
return toBoolean((byte) x);
|
||||
}
|
||||
|
||||
// widen byte:
|
||||
static double byteToDouble(byte x) { // bytecode: i2d (implicit 'b2i')
|
||||
return x;
|
||||
}
|
||||
static float byteToFloat(byte x) { // bytecode: i2f (implicit 'b2i')
|
||||
return x;
|
||||
}
|
||||
static long byteToLong(byte x) { // bytecode: i2l (implicit 'b2i')
|
||||
return x;
|
||||
}
|
||||
static int byteToInt(byte x) { // (implicit 'b2i')
|
||||
return x;
|
||||
}
|
||||
static short byteToShort(byte x) { // bytecode: i2s (implicit 'b2i')
|
||||
return (short)x;
|
||||
}
|
||||
static char byteToChar(byte x) { // bytecode: i2b (implicit 'b2i')
|
||||
return (char)x;
|
||||
}
|
||||
// narrow byte to boolean:
|
||||
static boolean byteToBoolean(byte x) {
|
||||
return toBoolean(x);
|
||||
}
|
||||
|
||||
// widen boolean to all types:
|
||||
static double booleanToDouble(boolean x) {
|
||||
return fromBoolean(x);
|
||||
}
|
||||
static float booleanToFloat(boolean x) {
|
||||
return fromBoolean(x);
|
||||
}
|
||||
static long booleanToLong(boolean x) {
|
||||
return fromBoolean(x);
|
||||
}
|
||||
static int booleanToInt(boolean x) {
|
||||
return fromBoolean(x);
|
||||
}
|
||||
static short booleanToShort(boolean x) {
|
||||
return fromBoolean(x);
|
||||
}
|
||||
static char booleanToChar(boolean x) {
|
||||
return (char)fromBoolean(x);
|
||||
}
|
||||
static byte booleanToByte(boolean x) {
|
||||
return fromBoolean(x);
|
||||
}
|
||||
|
||||
// helpers to force boolean into the conversion scheme:
|
||||
static boolean toBoolean(byte x) {
|
||||
// see javadoc for MethodHandles.explicitCastArguments
|
||||
return ((x & 1) != 0);
|
||||
}
|
||||
static byte fromBoolean(boolean x) {
|
||||
// see javadoc for MethodHandles.explicitCastArguments
|
||||
return (x ? (byte)1 : (byte)0);
|
||||
}
|
||||
|
||||
private static final WrapperCache[] CONVERT_PRIMITIVE_FUNCTIONS = newWrapperCaches(Wrapper.COUNT);
|
||||
|
||||
public static MethodHandle convertPrimitive(Wrapper wsrc, Wrapper wdst) {
|
||||
WrapperCache cache = CONVERT_PRIMITIVE_FUNCTIONS[wsrc.ordinal()];
|
||||
MethodHandle mh = cache.get(wdst);
|
||||
if (mh != null) {
|
||||
return mh;
|
||||
}
|
||||
// slow path
|
||||
Class<?> src = wsrc.primitiveType();
|
||||
Class<?> dst = wdst.primitiveType();
|
||||
MethodType type = MethodType.methodType(dst, src);
|
||||
if (wsrc == wdst) {
|
||||
mh = MethodHandles.identity(src);
|
||||
} else {
|
||||
assert(src.isPrimitive() && dst.isPrimitive());
|
||||
try {
|
||||
mh = IMPL_LOOKUP.findStatic(THIS_CLASS, src.getSimpleName()+"To"+capitalize(dst.getSimpleName()), type);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
mh = null;
|
||||
}
|
||||
}
|
||||
if (mh != null) {
|
||||
assert(mh.type() == type) : mh;
|
||||
return cache.put(wdst, mh);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("cannot find primitive conversion function for " +
|
||||
src.getSimpleName()+" -> "+dst.getSimpleName());
|
||||
}
|
||||
|
||||
public static MethodHandle convertPrimitive(Class<?> src, Class<?> dst) {
|
||||
return convertPrimitive(Wrapper.forPrimitiveType(src), Wrapper.forPrimitiveType(dst));
|
||||
}
|
||||
|
||||
private static String capitalize(String x) {
|
||||
return Character.toUpperCase(x.charAt(0))+x.substring(1);
|
||||
}
|
||||
|
||||
// handy shared exception makers (they simplify the common case code)
|
||||
private static InternalError newInternalError(String message, Throwable cause) {
|
||||
return new InternalError(message, cause);
|
||||
}
|
||||
private static InternalError newInternalError(Throwable cause) {
|
||||
return new InternalError(cause);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue