Generate unboxing operation on boxed class not Number.class when possible

This commit is contained in:
Mikhael Bogdanov
2017-03-09 13:08:48 +01:00
parent 5e80d80797
commit f2fea9a04a
4 changed files with 61 additions and 32 deletions
@@ -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");