From 4b954c347a189dd61eb5ddb98f502f525c749a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steven=20Sch=C3=A4fer?= Date: Thu, 13 Feb 2020 14:45:49 +0100 Subject: [PATCH] JVM IR: Avoid optimizing comparisons between boxed primitives and null A comparison of the form `x == null` where `x` is of type `Int` might not be vacuous if `x` is a boxed value coming from Java code. --- .../jvm/lower/JvmOptimizationLowering.kt | 25 +------------------ .../unsafeNullCheckWithPrimitive.kt | 3 --- 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmOptimizationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmOptimizationLowering.kt index f8d7f4aa9ed..6419a705e56 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmOptimizationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmOptimizationLowering.kt @@ -10,7 +10,6 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.irBlock import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.jvm.JvmBackendContext -import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass import org.jetbrains.kotlin.codegen.intrinsics.Not import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.IrStatement @@ -24,7 +23,6 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.types.isBoolean import org.jetbrains.kotlin.ir.types.isNullableAny import org.jetbrains.kotlin.ir.types.isPrimitiveType -import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformer @@ -110,33 +108,12 @@ class JvmOptimizationLowering(val context: JvmBackendContext) : FileLoweringPass } getOperandsIfCallToEqeqOrEquals(expression)?.let { (left, right) -> - val constFalse = - IrConstImpl.constFalse(expression.startOffset, expression.endOffset, context.irBuiltIns.booleanType) - return when { left.isNullConst() && right.isNullConst() -> IrConstImpl.constTrue(expression.startOffset, expression.endOffset, context.irBuiltIns.booleanType) left.isNullConst() && right is IrConst<*> || right.isNullConst() && left is IrConst<*> -> - constFalse - - right.isNullConst() && left.type.unboxInlineClass().isPrimitiveType() || - left.isNullConst() && right.type.unboxInlineClass().isPrimitiveType() -> { - val nonNullArgument = if (left.isNullConst()) right else left - if (hasNoSideEffectsForNullCompare(nonNullArgument)) { - constFalse - } else { - IrBlockImpl(expression.startOffset, expression.endOffset, expression.type, expression.origin).apply { - statements.add( - nonNullArgument.coerceToUnitIfNeeded( - nonNullArgument.type.toKotlinType(), - context.irBuiltIns - ) - ) - statements.add(constFalse) - } - } - } + IrConstImpl.constFalse(expression.startOffset, expression.endOffset, context.irBuiltIns.booleanType) else -> expression } diff --git a/compiler/testData/codegen/box/platformTypes/unsafeNullCheckWithPrimitive.kt b/compiler/testData/codegen/box/platformTypes/unsafeNullCheckWithPrimitive.kt index 5ae07aadc28..1da594894f9 100644 --- a/compiler/testData/codegen/box/platformTypes/unsafeNullCheckWithPrimitive.kt +++ b/compiler/testData/codegen/box/platformTypes/unsafeNullCheckWithPrimitive.kt @@ -1,6 +1,5 @@ // IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM -// IGNORE_BACKEND: JVM_IR // FILE: Unsound.java import test.Wrap; @@ -17,6 +16,4 @@ package test class Wrap(val x: T) -// JVM IR generates bytecode that fails with NPE because it unwraps the value with `Number.intValue()`, -// whereas JVM generates a simple null check without unwrapping the box. fun box(): String = if ((Unsound.get() as Wrap).x == null) "OK" else "Fail"