diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/BranchedValue.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/BranchedValue.kt index a40ab234b95..7473cebe063 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/BranchedValue.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/BranchedValue.kt @@ -89,6 +89,7 @@ open class BranchedValue(val arg1: StackValue, val arg2: StackValue? = null, val registerOperations(IFGE, IFLT) registerOperations(IFGT, IFLE) registerOperations(IF_ACMPNE, IF_ACMPEQ) + registerOperations(IFNULL, IFNONNULL) } private fun registerOperations(op: Int, negatedOp: Int) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 23622cf4abe..d460d5d9cf0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -98,7 +98,7 @@ import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.Ot import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.TraitImpl; import static org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER; import static org.jetbrains.kotlin.serialization.deserialization.DeserializationPackage.findClassAcrossModuleDependencies; -import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PRIVATE; +import static org.jetbrains.org.objectweb.asm.Opcodes.*; public class ExpressionCodegen extends JetVisitor implements LocalLookup { private static final Set INTEGRAL_RANGES = KotlinBuiltIns.getInstance().getIntegralRanges(); @@ -3063,19 +3063,19 @@ public class ExpressionCodegen extends JetVisitor implem Type rightType = expressionType(right); if (JetPsiUtil.isNullConstant(left)) { - return genCmpWithNull(right, rightType, opToken); + return genCmpWithNull(right, opToken); } if (JetPsiUtil.isNullConstant(right)) { - return genCmpWithNull(left, leftType, opToken); + return genCmpWithNull(left, opToken); } if (isIntZero(left, leftType) && isIntPrimitive(rightType)) { - return genCmpWithZero(right, rightType, opToken); + return genCmpWithZero(right, opToken); } if (isIntZero(right, rightType) && isIntPrimitive(leftType)) { - return genCmpWithZero(left, leftType, opToken); + return genCmpWithZero(left, opToken); } if (isPrimitive(leftType) != isPrimitive(rightType)) { @@ -3100,57 +3100,12 @@ public class ExpressionCodegen extends JetVisitor implem return isIntPrimitive(exprType) && exprValue != null && Integer.valueOf(0).equals(exprValue.getValue()); } - private StackValue genCmpWithZero(final JetExpression exp, final Type expType, final IElementType opToken) { - return StackValue.operation(Type.BOOLEAN_TYPE, new Function1() { - @Override - public Unit invoke(InstructionAdapter v) { - gen(exp, expType); - Label trueLabel = new Label(); - Label afterLabel = new Label(); - if (JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) { - v.ifeq(trueLabel); - } - else { - v.ifne(trueLabel); - } - - v.iconst(0); - v.goTo(afterLabel); - - v.mark(trueLabel); - v.iconst(1); - - v.mark(afterLabel); - return Unit.INSTANCE$; - } - }); + private StackValue genCmpWithZero(JetExpression exp, IElementType opToken) { + return StackValue.compareIntWithZero(gen(exp), (JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) ? IFNE : IFEQ); } - private StackValue genCmpWithNull(final JetExpression exp, final Type expType, final IElementType opToken) { - return StackValue.operation(Type.BOOLEAN_TYPE, new Function1() { - @Override - public Unit invoke(InstructionAdapter v) { - gen(exp, boxType(expType)); - Label trueLabel = new Label(); - Label afterLabel = new Label(); - if (JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) { - v.ifnull(trueLabel); - } - else { - v.ifnonnull(trueLabel); - } - - v.iconst(0); - v.goTo(afterLabel); - - v.mark(trueLabel); - v.iconst(1); - - v.mark(afterLabel); - - return Unit.INSTANCE$; - } - }); + private StackValue genCmpWithNull(JetExpression exp, IElementType opToken) { + return StackValue.compareWithNull(gen(exp), (JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) ? IFNONNULL : IFNULL); } private StackValue generateElvis(@NotNull final JetBinaryExpression expression) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index 2dc6fda9d0d..b148983325e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.psi.JetExpression; import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument; +import org.jetbrains.kotlin.resolve.jvm.AsmTypes; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature; import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; @@ -178,6 +179,14 @@ public abstract class StackValue { return new And(left, right); } + public static StackValue compareIntWithZero(@NotNull StackValue argument, int operation) { + return new BranchedValue(argument, null, Type.INT_TYPE, operation); + } + + public static StackValue compareWithNull(@NotNull StackValue argument, int operation) { + return new BranchedValue(argument, null, AsmTypes.OBJECT_TYPE, operation); + } + @NotNull public static StackValue arrayElement(@NotNull Type type, StackValue array, StackValue index) { return new ArrayElement(type, array, index); diff --git a/compiler/testData/codegen/bytecodeText/boxingOptimization/nullCheck.kt b/compiler/testData/codegen/bytecodeText/boxingOptimization/nullCheck.kt index 7190436651f..4bb1e7004b8 100644 --- a/compiler/testData/codegen/bytecodeText/boxingOptimization/nullCheck.kt +++ b/compiler/testData/codegen/bytecodeText/boxingOptimization/nullCheck.kt @@ -13,5 +13,6 @@ fun bar() { // 0 valueOf // 0 Value\s\(\) -// 1 IFNULL -// 0 IFNONNULL +// 0 IFNULL +// 1 IFNONNULL +// 1 IF diff --git a/compiler/testData/codegen/bytecodeText/conditions/negatedNullCompare.kt b/compiler/testData/codegen/bytecodeText/conditions/negatedNullCompare.kt new file mode 100644 index 00000000000..82770b9acc6 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/conditions/negatedNullCompare.kt @@ -0,0 +1,14 @@ +fun main(p: String?) { + if (!(p == null)) { + "then" + } else { + "else" + } +} + +//0 ICONST_0 +//0 ICONST_1 +//0 ACONST_NULL +//1 IFNULL +//1 IF +//1 GOTO diff --git a/compiler/testData/codegen/bytecodeText/conditions/negatedZeroCompare.kt b/compiler/testData/codegen/bytecodeText/conditions/negatedZeroCompare.kt new file mode 100644 index 00000000000..81afc75facd --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/conditions/negatedZeroCompare.kt @@ -0,0 +1,15 @@ +fun main() { + val a = 1 + if (!(a == 0)) { + "then" + } else { + "else" + } +} + +//0 ICONST_0 +//1 ICONST_1 +//1 IFEQ +//0 IFNE +//1 IF +//1 GOTO \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/conditions/nullCompare.kt b/compiler/testData/codegen/bytecodeText/conditions/nullCompare.kt new file mode 100644 index 00000000000..28110eba44d --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/conditions/nullCompare.kt @@ -0,0 +1,14 @@ +fun main(p: String?) { + if (p == null) { + "then" + } else { + "else" + } +} + +//0 ICONST_0 +//0 ICONST_1 +//0 ACONST_NULL +//1 IFNONNULL +//1 IF +//1 GOTO diff --git a/compiler/testData/codegen/bytecodeText/conditions/zeroCompare.kt b/compiler/testData/codegen/bytecodeText/conditions/zeroCompare.kt new file mode 100644 index 00000000000..ad5c54be239 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/conditions/zeroCompare.kt @@ -0,0 +1,15 @@ +fun main() { + val a = 1 + if (a == 0) { + "then" + } else { + "else" + } +} + +//0 ICONST_0 +//1 ICONST_1 +//0 IFEQ +//1 IFNE +//1 IF +//1 GOTO diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 21c95974ff8..aad4243c84a 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -328,6 +328,30 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/conditions/negatedDisjunction.kt"); doTest(fileName); } + + @TestMetadata("negatedNullCompare.kt") + public void testNegatedNullCompare() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/conditions/negatedNullCompare.kt"); + doTest(fileName); + } + + @TestMetadata("negatedZeroCompare.kt") + public void testNegatedZeroCompare() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/conditions/negatedZeroCompare.kt"); + doTest(fileName); + } + + @TestMetadata("nullCompare.kt") + public void testNullCompare() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/conditions/nullCompare.kt"); + doTest(fileName); + } + + @TestMetadata("zeroCompare.kt") + public void testZeroCompare() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/conditions/zeroCompare.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/codegen/bytecodeText/constants")