diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index 67cd365f407..1c00e4114ee 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -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 { diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java index db7bb2a7d45..add99a73509 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java @@ -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"); diff --git a/compiler/testData/codegen/bytecodeText/boxedNotNumberTypeOnUnboxing.kt b/compiler/testData/codegen/bytecodeText/boxedNotNumberTypeOnUnboxing.kt new file mode 100644 index 00000000000..93dacfb6f3c --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/boxedNotNumberTypeOnUnboxing.kt @@ -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 \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 20e50dd07c5..0ada6388345 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -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");