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.
This commit is contained in:
committed by
Dmitry Petrov
parent
32e1ec8e98
commit
4b954c347a
+1
-24
@@ -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
|
||||
}
|
||||
|
||||
@@ -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<T>(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<Int>() as Wrap<Int>).x == null) "OK" else "Fail"
|
||||
|
||||
Reference in New Issue
Block a user