/*
* Copyright (c) 2016, Oracle and/or its affiliates.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.oracle.truffle.llvm.runtime.interop;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.interop.ForeignAccess;
import com.oracle.truffle.api.interop.InteropException;
import com.oracle.truffle.api.interop.Message;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.interop.UnsupportedTypeException;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.llvm.runtime.LLVMAddress;
import com.oracle.truffle.llvm.runtime.LLVMBoxedPrimitive;
import com.oracle.truffle.llvm.runtime.LLVMSharedGlobalVariable;
import com.oracle.truffle.llvm.runtime.LLVMTruffleAddress;
import com.oracle.truffle.llvm.runtime.global.LLVMGlobalVariable;
import com.oracle.truffle.llvm.runtime.interop.ToLLVMNodeFactory.ToAnyLLVMValueNodeGen;
import com.oracle.truffle.llvm.runtime.interop.ToLLVMNodeFactory.ToBooleanNodeGen;
import com.oracle.truffle.llvm.runtime.interop.ToLLVMNodeFactory.ToByteNodeGen;
import com.oracle.truffle.llvm.runtime.interop.ToLLVMNodeFactory.ToCharNodeGen;
import com.oracle.truffle.llvm.runtime.interop.ToLLVMNodeFactory.ToDoubleNodeGen;
import com.oracle.truffle.llvm.runtime.interop.ToLLVMNodeFactory.ToFloatNodeGen;
import com.oracle.truffle.llvm.runtime.interop.ToLLVMNodeFactory.ToIntNodeGen;
import com.oracle.truffle.llvm.runtime.interop.ToLLVMNodeFactory.ToLongNodeGen;
import com.oracle.truffle.llvm.runtime.interop.ToLLVMNodeFactory.ToShortNodeGen;
import com.oracle.truffle.llvm.runtime.interop.ToLLVMNodeFactory.ToTruffleObjectNodeGen;
import com.oracle.truffle.llvm.runtime.nodes.api.LLVMExpressionNode;
import com.oracle.truffle.llvm.runtime.types.PointerType;
import com.oracle.truffle.llvm.runtime.types.PrimitiveType;
import com.oracle.truffle.llvm.runtime.types.Type;
import com.oracle.truffle.llvm.runtime.types.VoidType;
public abstract class ToLLVMNode extends Node {
@Child protected Node unbox = Message.UNBOX.createNode();
@Child protected Node isBoxed = Message.IS_BOXED.createNode();
@Child protected Node isPointer = Message.IS_POINTER.createNode();
@Child protected Node asPointer = Message.AS_POINTER.createNode();
public static ToLLVMNode createNode(Class<?> expectedType) {
if (expectedType == TruffleObject.class) {
return ToTruffleObjectNodeGen.create();
} else if (expectedType == int.class) {
return ToIntNodeGen.create();
} else if (expectedType == long.class) {
return ToLongNodeGen.create();
} else if (expectedType == byte.class) {
return ToByteNodeGen.create();
} else if (expectedType == short.class) {
return ToShortNodeGen.create();
} else if (expectedType == char.class) {
return ToCharNodeGen.create();
} else if (expectedType == float.class) {
return ToFloatNodeGen.create();
} else if (expectedType == double.class) {
return ToDoubleNodeGen.create();
} else if (expectedType == boolean.class) {
return ToBooleanNodeGen.create();
} else if (expectedType == null || expectedType == void.class) {
return new SlowConvertNodeObject();
} else if (expectedType == Object.class) {
return ToAnyLLVMValueNodeGen.create();
} else {
throw new IllegalStateException("Unsupported Type");
}
}
public abstract Object executeWithTarget(Object value);
protected static boolean notLLVM(TruffleObject value) {
return LLVMExpressionNode.notLLVM(value);
}
protected static boolean checkIsPointer(Node isPointer, TruffleObject object) {
return ForeignAccess.sendIsPointer(isPointer, object);
}
abstract static class ToIntNode extends ToLLVMNode {
@Child private ToIntNode toInt;
@Specialization
public int fromInt(int value) {
return value;
}
@Specialization
public int fromChar(char value) {
return value;
}
@Specialization
public int fromShort(short value) {
return value;
}
@Specialization
public int fromLong(long value) {
return (int) value;
}
@Specialization
public int fromByte(byte value) {
return value;
}
@Specialization
public int fromFloat(float value) {
return (int) value;
}
@Specialization
public int fromDouble(double value) {
return (int) value;
}
@Specialization
public int fromBoolean(boolean value) {
return value ? 1 : 0;
}
@Specialization
public int fromForeignPrimitive(LLVMBoxedPrimitive boxed) {
if (toInt == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
toInt = ToIntNodeGen.create();
}
return (int) toInt.executeWithTarget(boxed.getValue());
}
@Specialization(guards = "notLLVM(obj)")
public int fromTruffleObject(TruffleObject obj) {
try {
Object unboxed = ForeignAccess.sendUnbox(unbox, obj);
return (int) convertPrimitive(int.class, unboxed);
} catch (UnsupportedMessageException e) {
CompilerDirectives.transferToInterpreter();
throw new IllegalStateException(e);
}
}
}
abstract static class ToLongNode extends ToLLVMNode {
@Child private ToLongNode toLong;
@Specialization
public long fromInt(int value) {
return value;
}
@Specialization
public long fromChar(char value) {
return value;
}
@Specialization
public long fromShort(short value) {
return value;
}
@Specialization
public long fromLong(long value) {
return value;
}
@Specialization
public long fromByte(byte value) {
return value;
}
@Specialization
public long fromFloat(float value) {
return (long) value;
}
@Specialization
public long fromDouble(double value) {
return (long) value;
}
@Specialization
public long fromBoolean(boolean value) {
return value ? 1 : 0;
}
@Specialization
public long fromForeignPrimitive(LLVMBoxedPrimitive boxed) {
if (toLong == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
toLong = ToLongNodeGen.create();
}
return (long) toLong.executeWithTarget(boxed.getValue());
}
@Specialization(guards = "notLLVM(obj)")
public long fromTruffleObject(TruffleObject obj) {
try {
Object unboxed = ForeignAccess.sendUnbox(unbox, obj);
return (long) convertPrimitive(long.class, unboxed);
} catch (UnsupportedMessageException e) {
CompilerDirectives.transferToInterpreter();
throw new IllegalStateException(e);
}
}
}
abstract static class ToShortNode extends ToLLVMNode {
@Child private ToShortNode toShort;
@Specialization
public short fromInt(int value) {
return (short) value;
}
@Specialization
public short fromChar(char value) {
return (short) value;
}
@Specialization
public short fromShort(short value) {
return value;
}
@Specialization
public short fromLong(long value) {
return (short) value;
}
@Specialization
public short fromByte(byte value) {
return value;
}
@Specialization
public short fromFloat(float value) {
return (short) value;
}
@Specialization
public short fromDouble(double value) {
return (short) value;
}
@Specialization
public short fromBoolean(boolean value) {
return (short) (value ? 1 : 0);
}
@Specialization
public short fromForeignPrimitive(LLVMBoxedPrimitive boxed) {
if (toShort == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
toShort = ToShortNodeGen.create();
}
return (short) toShort.executeWithTarget(boxed.getValue());
}
@Specialization(guards = "notLLVM(obj)")
public long fromTruffleObject(TruffleObject obj) {
try {
Object unboxed = ForeignAccess.sendUnbox(unbox, obj);
return (short) convertPrimitive(short.class, unboxed);
} catch (UnsupportedMessageException e) {
CompilerDirectives.transferToInterpreter();
throw new IllegalStateException(e);
}
}
}
abstract static class ToByteNode extends ToLLVMNode {
@Child private ToByteNode toByte;
@Specialization
public byte fromInt(int value) {
return (byte) value;
}
@Specialization
public byte fromChar(char value) {
return (byte) value;
}
@Specialization
public byte fromLong(long value) {
return (byte) value;
}
@Specialization
public byte fromShort(short value) {
return (byte) value;
}
@Specialization
public byte fromByte(byte value) {
return value;
}
@Specialization
public byte fromFloat(float value) {
return (byte) value;
}
@Specialization
public byte fromDouble(double value) {
return (byte) value;
}
@Specialization
public byte fromBoolean(boolean value) {
return (byte) (value ? 1 : 0);
}
@Specialization
public byte fromForeignPrimitive(LLVMBoxedPrimitive boxed) {
if (toByte == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
toByte = ToByteNodeGen.create();
}
return (byte) toByte.executeWithTarget(boxed.getValue());
}
@Specialization(guards = "notLLVM(obj)")
public byte fromTruffleObject(TruffleObject obj) {
try {
Object unboxed = ForeignAccess.sendUnbox(unbox, obj);
return (byte) convertPrimitive(byte.class, unboxed);
} catch (UnsupportedMessageException e) {
CompilerDirectives.transferToInterpreter();
throw new IllegalStateException(e);
}
}
}
abstract static class ToCharNode extends ToLLVMNode {
@Child private ToCharNode toChar;
@Specialization
public char fromInt(int value) {
return (char) value;
}
@Specialization
public char fromLong(long value) {
return (char) value;
}
@Specialization
public char fromChar(char value) {
return value;
}
@Specialization
public char fromShort(short value) {
return (char) value;
}
@Specialization
public char fromByte(byte value) {
return (char) value;
}
@Specialization
public char fromFloat(float value) {
return (char) value;
}
@Specialization
public char fromDouble(double value) {
return (char) value;
}
@Specialization
public char fromBoolean(boolean value) {
return (char) (value ? 1 : 0);
}
@Specialization
public char fromForeignPrimitive(LLVMBoxedPrimitive boxed) {
if (toChar == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
toChar = ToCharNodeGen.create();
}
return (char) toChar.executeWithTarget(boxed.getValue());
}
@Specialization(guards = "notLLVM(obj)")
public char fromTruffleObject(TruffleObject obj) {
try {
Object unboxed = ForeignAccess.sendUnbox(unbox, obj);
return (char) convertPrimitive(char.class, unboxed);
} catch (UnsupportedMessageException e) {
CompilerDirectives.transferToInterpreter();
throw new IllegalStateException(e);
}
}
}
abstract static class ToFloatNode extends ToLLVMNode {
@Child private ToFloatNode toFloat;
@Specialization
public float fromInt(int value) {
return value;
}
@Specialization
public float fromLong(long value) {
return value;
}
@Specialization
public float fromChar(char value) {
return value;
}
@Specialization
public float fromShort(short value) {
return value;
}
@Specialization
public float fromByte(byte value) {
return value;
}
@Specialization
public float fromFloat(float value) {
return value;
}
@Specialization
public float fromDouble(double value) {
return (float) value;
}
@Specialization
public float fromBoolean(boolean value) {
return (value ? 1 : 0);
}
@Specialization
public float fromForeignPrimitive(LLVMBoxedPrimitive boxed) {
if (toFloat == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
toFloat = ToFloatNodeGen.create();
}
return (float) toFloat.executeWithTarget(boxed.getValue());
}
@Specialization(guards = "notLLVM(obj)")
public float fromTruffleObject(TruffleObject obj) {
try {
Object unboxed = ForeignAccess.sendUnbox(unbox, obj);
return (float) convertPrimitive(float.class, unboxed);
} catch (UnsupportedMessageException e) {
CompilerDirectives.transferToInterpreter();
throw new IllegalStateException(e);
}
}
}
abstract static class ToDoubleNode extends ToLLVMNode {
@Child private ToDoubleNode toDouble;
@Specialization
public double fromInt(int value) {
return value;
}
@Specialization
public double fromChar(char value) {
return value;
}
@Specialization
public double fromLong(long value) {
return value;
}
@Specialization
public double fromByte(byte value) {
return value;
}
@Specialization
public double fromShort(short value) {
return value;
}
@Specialization
public double fromFloat(float value) {
return value;
}
@Specialization
public double fromDouble(double value) {
return value;
}
@Specialization
public double fromBoolean(boolean value) {
return (value ? 1 : 0);
}
@Specialization
public double fromForeignPrimitive(LLVMBoxedPrimitive boxed) {
if (toDouble == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
toDouble = ToDoubleNodeGen.create();
}
return (double) toDouble.executeWithTarget(boxed.getValue());
}
@Specialization(guards = "notLLVM(obj)")
public double fromTruffleObject(TruffleObject obj) {
try {
Object unboxed = ForeignAccess.sendUnbox(unbox, obj);
return (double) convertPrimitive(double.class, unboxed);
} catch (UnsupportedMessageException e) {
CompilerDirectives.transferToInterpreter();
throw new IllegalStateException(e);
}
}
}
abstract static class ToBooleanNode extends ToLLVMNode {
@Child private ToBooleanNode toBoolean;
@Specialization
public boolean fromInt(int value) {
return value != 0;
}
@Specialization
public boolean fromChar(char value) {
return value != 0;
}
@Specialization
public boolean fromShort(short value) {
return value != 0;
}
@Specialization
public boolean fromLong(long value) {
return value != 0;
}
@Specialization
public boolean fromByte(byte value) {
return value != 0;
}
@Specialization
public boolean fromFloat(float value) {
return value != 0;
}
@Specialization
public boolean fromDouble(double value) {
return value != 0;
}
@Specialization
public boolean fromBoolean(boolean value) {
return value;
}
@Specialization
public boolean fromForeignPrimitive(LLVMBoxedPrimitive boxed) {
if (toBoolean == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
toBoolean = ToBooleanNodeGen.create();
}
return (boolean) toBoolean.executeWithTarget(boxed.getValue());
}
@Specialization(guards = "notLLVM(obj)")
public boolean fromTruffleObject(TruffleObject obj) {
try {
Object unboxed = ForeignAccess.sendUnbox(unbox, obj);
return (boolean) convertPrimitive(boolean.class, unboxed);
} catch (UnsupportedMessageException e) {
CompilerDirectives.transferToInterpreter();
throw new IllegalStateException(e);
}
}
}
abstract static class ToTruffleObject extends ToLLVMNode {
@Specialization
public Object fromInt(int value) {
return new LLVMBoxedPrimitive(value);
}
@Specialization
public Object fromChar(char value) {
return new LLVMBoxedPrimitive(value);
}
@Specialization
public Object fromLong(long value) {
return new LLVMBoxedPrimitive(value);
}
@Specialization
public Object fromByte(byte value) {
return new LLVMBoxedPrimitive(value);
}
@Specialization
public Object fromShort(short value) {
return new LLVMBoxedPrimitive(value);
}
@Specialization
public Object fromFloat(float value) {
return new LLVMBoxedPrimitive(value);
}
@Specialization
public Object fromDouble(double value) {
return new LLVMBoxedPrimitive(value);
}
@Specialization
public Object fromBoolean(boolean value) {
return new LLVMBoxedPrimitive(value);
}
@Specialization
public String fromString(String obj) {
return obj;
}
@Specialization
public LLVMAddress fromLLVMTruffleAddress(LLVMTruffleAddress obj) {
return obj.getAddress();
}
@Specialization
public LLVMGlobalVariable fromSharedDescriptor(LLVMSharedGlobalVariable shared) {
return shared.getDescriptor();
}
@Specialization(guards = {"checkIsPointer(isPointer, obj)", "notLLVM(obj)"})
public LLVMAddress fromNativePointer(TruffleObject obj) {
try {
long raw = ForeignAccess.sendAsPointer(asPointer, obj);
return LLVMAddress.fromLong(raw);
} catch (UnsupportedMessageException ex) {
CompilerDirectives.transferToInterpreter();
throw new RuntimeException(ex);
}
}
@Specialization(guards = {"!checkIsPointer(isPointer, obj)", "notLLVM(obj)"})
public TruffleObject fromTruffleObject(TruffleObject obj) {
return obj;
}
}
abstract static class ToAnyLLVMValue extends ToLLVMNode {
@Specialization
public int fromInt(int value) {
return value;
}
@Specialization
public char fromChar(char value) {
return value;
}
@Specialization
public long fromLong(long value) {
return value;
}
@Specialization
public byte fromByte(byte value) {
return value;
}
@Specialization
public short fromShort(short value) {
return value;
}
@Specialization
public float fromFloat(float value) {
return value;
}
@Specialization
public double fromDouble(double value) {
return value;
}
@Specialization
public boolean fromBoolean(boolean value) {
return value;
}
@Specialization
public String fromString(String obj) {
return obj;
}
@Specialization
public LLVMAddress fromLLVMTruffleAddress(LLVMTruffleAddress obj) {
return obj.getAddress();
}
@Specialization
public LLVMGlobalVariable fromSharedDescriptor(LLVMSharedGlobalVariable shared) {
return shared.getDescriptor();
}
@Specialization(guards = {"checkIsPointer(isPointer, obj)", "notLLVM(obj)"})
public LLVMAddress fromNativePointer(TruffleObject obj) {
try {
long raw = ForeignAccess.sendAsPointer(asPointer, obj);
return LLVMAddress.fromLong(raw);
} catch (UnsupportedMessageException ex) {
CompilerDirectives.transferToInterpreter();
throw new RuntimeException(ex);
}
}
@Specialization(guards = {"!checkIsPointer(isPointer, obj)", "notLLVM(obj)"})
public TruffleObject fromTruffleObject(TruffleObject obj) {
return obj;
}
}
public static Class<?> convert(Type type) {
Class<?> t;
if (type instanceof PrimitiveType) {
t = getClassForPrimitive(type);
} else if (type instanceof PointerType) {
t = TruffleObject.class;
} else if (type instanceof VoidType) {
t = void.class;
} else {
throw UnsupportedTypeException.raise(new Object[]{type});
}
return t;
}
private static Class<?> getClassForPrimitive(Type type) {
Class<?> t;
switch (((PrimitiveType) type).getPrimitiveKind()) {
case I1:
t = boolean.class;
break;
case I8:
t = byte.class;
break;
case I16:
t = short.class;
break;
case I32:
t = int.class;
break;
case I64:
t = long.class;
break;
case FLOAT:
t = float.class;
break;
case DOUBLE:
t = double.class;
break;
default:
throw UnsupportedTypeException.raise(new Object[]{type});
}
return t;
}
static final class SlowConvertNodeObject extends ToLLVMNode {
@Override
public Object executeWithTarget(Object value) {
return value;
}
}
public Object slowConvert(Object value, Class<?> requestedType) {
if (isPrimitiveType(requestedType)) {
Object attr;
if (value instanceof TruffleObject) {
if (ForeignAccess.sendIsPointer(isPointer, (TruffleObject) value)) {
try {
attr = (long) ForeignAccess.sendAsPointer(asPointer, (TruffleObject) value);
} catch (InteropException e) {
CompilerDirectives.transferToInterpreter();
throw UnsupportedTypeException.raise(new Object[]{value});
}
} else if (ForeignAccess.sendIsBoxed(isBoxed, (TruffleObject) value)) {
try {
attr = ForeignAccess.sendUnbox(unbox, (TruffleObject) value);
} catch (InteropException e) {
CompilerDirectives.transferToInterpreter();
throw UnsupportedTypeException.raise(new Object[]{value});
}
}
return null;
} else {
attr = value;
}
return convertPrimitive(requestedType, attr);
} else if (requestedType == TruffleObject.class) {
if (value instanceof LLVMTruffleAddress) {
return ((LLVMTruffleAddress) value).getAddress();
} else if (isPrimitiveType(value.getClass())) {
return new LLVMBoxedPrimitive(value);
} else if (value instanceof LLVMSharedGlobalVariable) {
return ((LLVMSharedGlobalVariable) value).getDescriptor();
} else if (ForeignAccess.sendIsPointer(isPointer, (TruffleObject) value)) {
try {
return LLVMAddress.fromLong(ForeignAccess.sendAsPointer(asPointer, (TruffleObject) value));
} catch (InteropException e) {
CompilerDirectives.transferToInterpreter();
throw UnsupportedTypeException.raise(new Object[]{value});
}
} else {
return value;
}
} else {
CompilerDirectives.transferToInterpreter();
throw new IllegalStateException("Requested class: " + requestedType + " - but got value: " + value);
}
}
public Object slowConvert(Object value) {
if (isPrimitiveType(value.getClass())) {
return value;
} else if (value instanceof String) {
return value;
} else if (value instanceof LLVMTruffleAddress) {
return ((LLVMTruffleAddress) value).getAddress();
} else if (value instanceof LLVMSharedGlobalVariable) {
return ((LLVMSharedGlobalVariable) value).getDescriptor();
} else if (value instanceof TruffleObject && LLVMExpressionNode.notLLVM((TruffleObject) value)) {
return value;
} else if (value instanceof TruffleObject && LLVMExpressionNode.notLLVM((TruffleObject) value) && ForeignAccess.sendIsPointer(isPointer, (TruffleObject) value)) {
try {
return LLVMAddress.fromLong(ForeignAccess.sendAsPointer(asPointer, (TruffleObject) value));
} catch (InteropException e) {
CompilerDirectives.transferToInterpreter();
throw UnsupportedTypeException.raise(new Object[]{value});
}
} else {
CompilerDirectives.transferToInterpreter();
throw new IllegalStateException();
}
}
@TruffleBoundary
private static boolean isPrimitiveType(Class<?> clazz) {
CompilerAsserts.compilationConstant(clazz);
return clazz == int.class || clazz == Integer.class ||
clazz == boolean.class || clazz == Boolean.class ||
clazz == byte.class || clazz == Byte.class ||
clazz == short.class || clazz == Short.class ||
clazz == long.class || clazz == Long.class ||
clazz == float.class || clazz == Float.class ||
clazz == double.class || clazz == Double.class ||
clazz == char.class || clazz == Character.class ||
CharSequence.class.isAssignableFrom(clazz);
}
@TruffleBoundary
private static Object convertPrimitive(Class<?> requestedType, Object attr) {
if (attr instanceof Number) {
if (requestedType == null) {
return attr;
}
Number n = (Number) attr;
if (requestedType == byte.class || requestedType == Byte.class) {
return n.byteValue();
}
if (requestedType == short.class || requestedType == Short.class) {
return n.shortValue();
}
if (requestedType == int.class || requestedType == Integer.class) {
return n.intValue();
}
if (requestedType == long.class || requestedType == Long.class) {
return n.longValue();
}
if (requestedType == float.class || requestedType == Float.class) {
return n.floatValue();
}
if (requestedType == double.class || requestedType == Double.class) {
return n.doubleValue();
}
if (requestedType == char.class || requestedType == Character.class) {
return (char) n.intValue();
}
return n;
}
if (attr instanceof CharSequence) {
if (requestedType == char.class || requestedType == Character.class) {
if (((String) attr).length() == 1) {
return ((String) attr).charAt(0);
}
}
return String.valueOf(attr);
}
if (attr instanceof Character) {
return attr;
}
if (attr instanceof Boolean) {
return attr;
}
return null;
}
}