Generate unboxing operation on boxed class not Number.class when possible
This commit is contained in:
@@ -302,31 +302,9 @@ public abstract class StackValue {
|
||||
coerce(boxedType, toType, v);
|
||||
}
|
||||
|
||||
private static void unbox(Type type, InstructionAdapter v) {
|
||||
if (type == Type.INT_TYPE) {
|
||||
v.invokevirtual("java/lang/Number", "intValue", "()I", false);
|
||||
}
|
||||
else if (type == Type.BOOLEAN_TYPE) {
|
||||
v.invokevirtual("java/lang/Boolean", "booleanValue", "()Z", false);
|
||||
}
|
||||
else if (type == Type.CHAR_TYPE) {
|
||||
v.invokevirtual("java/lang/Character", "charValue", "()C", false);
|
||||
}
|
||||
else if (type == Type.SHORT_TYPE) {
|
||||
v.invokevirtual("java/lang/Number", "shortValue", "()S", false);
|
||||
}
|
||||
else if (type == Type.LONG_TYPE) {
|
||||
v.invokevirtual("java/lang/Number", "longValue", "()J", false);
|
||||
}
|
||||
else if (type == Type.BYTE_TYPE) {
|
||||
v.invokevirtual("java/lang/Number", "byteValue", "()B", false);
|
||||
}
|
||||
else if (type == Type.FLOAT_TYPE) {
|
||||
v.invokevirtual("java/lang/Number", "floatValue", "()F", false);
|
||||
}
|
||||
else if (type == Type.DOUBLE_TYPE) {
|
||||
v.invokevirtual("java/lang/Number", "doubleValue", "()D", false);
|
||||
}
|
||||
private static void unbox(Type methodOwner, Type type, InstructionAdapter v) {
|
||||
assert isPrimitive(type) : "Unboxing should be performed to primitive type, but " + type.getClassName();
|
||||
v.invokevirtual(methodOwner.getInternalName(), type.getClassName() + "Value", "()" + type.getDescriptor(), false);
|
||||
}
|
||||
|
||||
protected void coerceTo(@NotNull Type toType, @NotNull InstructionAdapter v) {
|
||||
@@ -377,28 +355,29 @@ public abstract class StackValue {
|
||||
}
|
||||
}
|
||||
else if (fromType.getSort() == Type.OBJECT) {
|
||||
//toType is primitive here
|
||||
Type unboxedType = unboxPrimitiveTypeOrNull(fromType);
|
||||
if (unboxedType != null) {
|
||||
unbox(unboxedType, v);
|
||||
unbox(fromType, unboxedType, v);
|
||||
coerce(unboxedType, toType, v);
|
||||
}
|
||||
else if (toType.getSort() == Type.BOOLEAN) {
|
||||
coerce(fromType, boxType(Type.BOOLEAN_TYPE), v);
|
||||
unbox(Type.BOOLEAN_TYPE, v);
|
||||
coerce(fromType, BOOLEAN_WRAPPER_TYPE, v);
|
||||
unbox(BOOLEAN_WRAPPER_TYPE, Type.BOOLEAN_TYPE, v);
|
||||
}
|
||||
else if (toType.getSort() == Type.CHAR) {
|
||||
if (fromType.equals(NUMBER_TYPE)) {
|
||||
unbox(Type.INT_TYPE, v);
|
||||
unbox(NUMBER_TYPE, Type.INT_TYPE, v);
|
||||
v.visitInsn(Opcodes.I2C);
|
||||
}
|
||||
else {
|
||||
coerce(fromType, boxType(Type.CHAR_TYPE), v);
|
||||
unbox(Type.CHAR_TYPE, v);
|
||||
coerce(fromType, CHARACTER_WRAPPER_TYPE, v);
|
||||
unbox(CHARACTER_WRAPPER_TYPE, Type.CHAR_TYPE, v);
|
||||
}
|
||||
}
|
||||
else {
|
||||
coerce(fromType, NUMBER_TYPE, v);
|
||||
unbox(toType, v);
|
||||
unbox(NUMBER_TYPE, toType, v);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -31,6 +31,8 @@ public class AsmTypes {
|
||||
public static final Type JAVA_CLASS_TYPE = getType(Class.class);
|
||||
public static final Type ENUM_TYPE = getType(Enum.class);
|
||||
public static final Type NUMBER_TYPE = getType(Number.class);
|
||||
public static final Type BOOLEAN_WRAPPER_TYPE = getType(Boolean.class);
|
||||
public static final Type CHARACTER_WRAPPER_TYPE = getType(Character.class);
|
||||
|
||||
public static final Type UNIT_TYPE = Type.getObjectType("kotlin/Unit");
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
fun test(p: Int?) {
|
||||
if (p != null) {
|
||||
p.toByte() //intValue & I2B
|
||||
p.toShort() //intValue & I2S
|
||||
p.toInt() //intValue
|
||||
p.toLong() //intValue & I2L
|
||||
p.toFloat() //intValue & I2F
|
||||
p.toDouble() //intValue & I2D
|
||||
}
|
||||
}
|
||||
|
||||
fun test(p: Byte?) {
|
||||
if (p != null) {
|
||||
p.toByte() //byteValue
|
||||
p.toShort() //byteValue & I2S
|
||||
p.toInt() //byteValue
|
||||
p.toLong() //byteValue & I2L
|
||||
p.toFloat() //byteValue & I2F
|
||||
p.toDouble() //byteValue & I2D
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun test(p: Char?) {
|
||||
if (p != null) {
|
||||
p.toByte() //charValue & I2B
|
||||
p.toShort() //charValue & I2S
|
||||
p.toInt() //charValue
|
||||
p.toLong() //charValue & I2L
|
||||
p.toFloat() //charValue & I2F
|
||||
p.toDouble() //charValue & I2D
|
||||
}
|
||||
}
|
||||
|
||||
//6 Integer\.intValue
|
||||
//6 Byte\.byteValue
|
||||
//6 Character\.charValue
|
||||
//2 I2B
|
||||
//3 I2S
|
||||
//3 I2L
|
||||
//3 I2F
|
||||
//3 I2D
|
||||
@@ -84,6 +84,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("boxedNotNumberTypeOnUnboxing.kt")
|
||||
public void testBoxedNotNumberTypeOnUnboxing() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/boxedNotNumberTypeOnUnboxing.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("bridgeForFakeOverride.kt")
|
||||
public void testBridgeForFakeOverride() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/bridgeForFakeOverride.kt");
|
||||
|
||||
Reference in New Issue
Block a user