JVM_IR: Optimize null checks.

Introduce lowering to remove null checks for primitive type
expressions and replace them with true/false. Side-effects
are preserved.

Generate ifnull/ifnonnull instructions for null checks instead
of materializing a null literal for an equality check.
This commit is contained in:
Mads Ager
2019-01-11 13:56:11 +01:00
committed by Mikhael Bogdanov
parent f5312f42c5
commit 690b8e0ac9
35 changed files with 240 additions and 106 deletions
@@ -217,10 +217,10 @@ private val ToArrayPhase = makeJvmPhase(
description = "Handle toArray functions"
)
private val NegatedExpressionLowering = makeJvmPhase(
{ context, file -> NegatedExpressionLowering(context).lower(file) },
name = "NegatedExpression",
description = "Handle negated expressions"
private val JvmBuiltinOptimizationLowering = makeJvmPhase(
{ context, file -> JvmBuiltinOptimizationLowering(context).lower(file) },
name = "JvmBuiltinOptimizationLowering",
description = "Optimize builtin calls for JVM code generation"
)
object IrFileEndPhase : CompilerPhase<BackendContext, IrFile> {
@@ -273,7 +273,7 @@ val jvmPhases = listOf(
TailrecPhase,
ToArrayPhase,
NegatedExpressionLowering,
JvmBuiltinOptimizationLowering,
makePatchParentsPhase(3),
@@ -9,8 +9,8 @@ import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicFunction
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
import org.jetbrains.kotlin.backend.jvm.lower.CrIrType
import org.jetbrains.kotlin.backend.jvm.lower.NegatedExpressionLowering.Companion.isNegation
import org.jetbrains.kotlin.backend.jvm.lower.NegatedExpressionLowering.Companion.negationArgument
import org.jetbrains.kotlin.backend.jvm.lower.JvmBuiltinOptimizationLowering.Companion.isNegation
import org.jetbrains.kotlin.backend.jvm.lower.JvmBuiltinOptimizationLowering.Companion.negationArgument
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.AsmUtil.*
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.isNullConst
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -631,30 +632,18 @@ class ExpressionCodegen(
return expression.onStack
}
override fun visitWhen(expression: IrWhen, data: BlockInfo): StackValue {
expression.markLineNumber(startOffset = true)
return genIfWithBranches(expression.branches[0], data, expression.type.toKotlinType(), expression.branches.drop(1))
}
private fun genIfWithBranches(branch: IrBranch, data: BlockInfo, type: KotlinType, otherBranches: List<IrBranch>): StackValue {
val elseLabel = Label()
var condition = branch.condition
val thenBranch = branch.result
//TODO don't generate condition for else branch - java verifier fails with empty stack
val elseBranch = branch is IrElseBranch
if (!elseBranch) {
var jumpIfFalse = true
if (isNegation(condition, classCodegen.context)) {
// Instead of materializing a negated value when used for control flow, flip the branch
// targets instead. This significantly cuts down the amount of branches and loads of
// const_0 and const_1 in the generated java bytecode.
condition = negationArgument(condition as IrCall)
jumpIfFalse = false
}
gen(condition, data).put(condition.asmType, mv)
BranchedValue.condJump(StackValue.onStack(condition.asmType), elseLabel, jumpIfFalse, mv)
genConditionWithOptimizationsIfPossible(branch, data, elseLabel)
}
val end = Label()
@@ -676,6 +665,40 @@ class ExpressionCodegen(
return result
}
private fun genConditionWithOptimizationsIfPossible(branch: IrBranch, data: BlockInfo, elseLabel: Label) {
var condition = branch.condition
var jumpIfFalse = true
if (isNegation(condition, classCodegen.context)) {
// Instead of materializing a negated value when used for control flow, flip the branch
// targets instead. This significantly cuts down the amount of branches and loads of
// const_0 and const_1 in the generated java bytecode.
condition = negationArgument(condition as IrCall)
jumpIfFalse = false
}
if (isNullCheck(condition)) {
// Do not materialize null constants to check for null. Instead use the JVM bytecode
// ifnull and ifnonnull instructions.
val call = condition as IrCall
val left = call.getValueArgument(0)!!
val right = call.getValueArgument(1)!!
val other = if (left.isNullConst()) right else left
gen(other, data).put(other.asmType, mv)
if (jumpIfFalse) {
mv.ifnonnull(elseLabel)
} else {
mv.ifnull(elseLabel)
}
} else {
gen(condition, data).put(condition.asmType, mv)
BranchedValue.condJump(onStack(condition.asmType), elseLabel, jumpIfFalse, mv)
}
}
private fun isNullCheck(expression: IrExpression): Boolean {
return expression is IrCall
&& expression.symbol == classCodegen.context.irBuiltIns.eqeqSymbol
&& (expression.getValueArgument(0)!!.isNullConst() || expression.getValueArgument(1)!!.isNullConst())
}
override fun visitTypeOperator(expression: IrTypeOperatorCall, data: BlockInfo): StackValue {
val asmType = expression.typeOperand.toKotlinType().asmType
@@ -0,0 +1,98 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.codegen.intrinsics.Not
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.types.isPrimitiveType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.coerceToUnitIfNeeded
import org.jetbrains.kotlin.ir.util.isNullConst
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
class JvmBuiltinOptimizationLowering(val context: JvmBackendContext) : FileLoweringPass {
companion object {
fun isNegation(expression: IrExpression, context: JvmBackendContext): Boolean {
// TODO: there should be only one representation of the 'not' operator.
return expression is IrCall &&
(expression.symbol == context.irBuiltIns.booleanNotSymbol ||
context.state.intrinsics.getIntrinsic(expression.symbol.descriptor) is Not)
}
fun negationArgument(call: IrCall): IrExpression {
// TODO: there should be only one representation of the 'not' operator.
// Once there is only the IR definition the negation argument will
// always be a value argument and this method can be removed.
return call.dispatchReceiver ?: call.getValueArgument(0)!!
}
}
private fun hasNoSideEffectsForNullCompare(expression: IrExpression): Boolean {
return expression.type.isPrimitiveType() && (expression is IrConst<*> || expression is IrGetValue)
}
private fun isNullCheckOfPrimitiveTypeValue(call: IrCall, context: JvmBackendContext): Boolean {
if (call.symbol == context.irBuiltIns.eqeqSymbol) {
val left = call.getValueArgument(0)!!
val right = call.getValueArgument(1)!!
// When used for null checks, it is safe to eliminate constants and local variable loads.
// Even if a local variable of simple type is updated via the debugger it still cannot
// be null.
return (right.isNullConst() && left.type.isPrimitiveType())
|| (left.isNullConst() && right.type.isPrimitiveType())
}
return false
}
private fun isNullCheckOfNullConstant(call: IrCall, context: JvmBackendContext): Boolean {
if (call.symbol == context.irBuiltIns.eqeqSymbol) {
val left = call.getValueArgument(0)!!
val right = call.getValueArgument(1)!!
return right.isNullConst() && left.isNullConst()
}
return false
}
override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this)
return if (isNegation(expression, context) && isNegation(negationArgument(expression), context)) {
// TODO: This lowering is currently JvmBackend specific because there are multiple
// definitions of the boolean 'not' operator. Once there is only the irBuiltins
// definition this lowering could be shared with other backends.
negationArgument(negationArgument(expression) as IrCall)
} else if (isNullCheckOfPrimitiveTypeValue(expression, context)) {
val left = expression.getValueArgument(0)!!
val nonNullArgument = if (left.isNullConst()) expression.getValueArgument(1)!! else left
val constFalse = IrConstImpl.constFalse(expression.startOffset, expression.endOffset, context.irBuiltIns.booleanType)
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)
}
}
} else if (isNullCheckOfNullConstant(expression, context)) {
IrConstImpl.constTrue(expression.startOffset, expression.endOffset, context.irBuiltIns.booleanType)
} else {
expression
}
}
})
}
}
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.TypeTranslator
import org.jetbrains.kotlin.ir.util.coerceToUnitIfNeeded
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.psi2ir.transformations.InsertImplicitCasts
@@ -30,7 +31,7 @@ class JvmCoercionToUnitPatcher(val context: JvmBackendContext) :
override fun IrExpression.coerceToUnit(): IrExpression {
if (type.isSubtypeOf(context.irBuiltIns.unitType) && this is IrCall) {
return coerceToUnitIfNeeded(symbol.owner.returnType.toKotlinType())
return coerceToUnitIfNeeded(symbol.owner.returnType.toKotlinType(), context.irBuiltIns)
}
return this
@@ -1,50 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.codegen.intrinsics.Not
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
// TODO: This lowering is currently JvmBackend specific because there are multiple
// definitions of the boolean 'not' operator. Once there is only the irBuiltins
// definition this lowering could be shared with other backends.
class NegatedExpressionLowering(val context: JvmBackendContext) : FileLoweringPass {
companion object {
fun isNegation(expression: IrExpression, context: JvmBackendContext) : Boolean {
// TODO: there should be only one representation of the 'not' operator.
return expression is IrCall &&
(expression.symbol == context.irBuiltIns.booleanNotSymbol ||
context.state.intrinsics.getIntrinsic(expression.symbol.descriptor) is Not)
}
fun negationArgument(call: IrCall) : IrExpression {
// TODO: there should be only one representation of the 'not' operator.
// Once there is only the IR definition the negation argument will
// always be a value argument and this method can be removed.
return call.dispatchReceiver ?: call.getValueArgument(0)!!
}
}
override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this)
return if (isNegation(expression, context) && isNegation(negationArgument(expression), context))
negationArgument(negationArgument(expression) as IrCall)
else
expression
}
})
}
}
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
import org.jetbrains.kotlin.ir.util.TypeTranslator
import org.jetbrains.kotlin.ir.util.coerceToUnitIfNeeded
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
@@ -259,28 +260,12 @@ open class InsertImplicitCasts(
protected open fun IrExpression.coerceToUnit(): IrExpression {
val valueType = getKotlinType(this)
return coerceToUnitIfNeeded(valueType)
return coerceToUnitIfNeeded(valueType, irBuiltIns)
}
protected fun getKotlinType(irExpression: IrExpression) =
irExpression.type.originalKotlinType!!
protected fun IrExpression.coerceToUnitIfNeeded(valueType: KotlinType): IrExpression {
return if (isUnitSubtype(valueType))
this
else
IrTypeOperatorCallImpl(
startOffset, endOffset,
irBuiltIns.unitType,
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT,
irBuiltIns.unitType, irBuiltIns.unitType.classifierOrFail,
this
)
}
protected fun isUnitSubtype(valueType: KotlinType) =
KotlinTypeChecker.DEFAULT.isSubtypeOf(valueType, builtIns.unitType)
private fun KotlinType.isBuiltInIntegerType(): Boolean =
KotlinBuiltIns.isByte(this) ||
KotlinBuiltIns.isShort(this) ||
@@ -14,8 +14,10 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.name.FqName
@@ -24,6 +26,8 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
/**
* Binds the arguments explicitly represented in the IR to the parameters of the accessed function.
@@ -140,6 +144,20 @@ fun IrMemberAccessExpression.addArguments(args: List<Pair<ParameterDescriptor, I
fun IrExpression.isNullConst() = this is IrConst<*> && this.kind == IrConstKind.Null
fun IrExpression.coerceToUnitIfNeeded(valueType: KotlinType, irBuiltIns: IrBuiltIns): IrExpression {
return if (KotlinTypeChecker.DEFAULT.isSubtypeOf(valueType, irBuiltIns.unitType.toKotlinType()))
this
else
IrTypeOperatorCallImpl(
startOffset, endOffset,
irBuiltIns.unitType,
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT,
irBuiltIns.unitType, irBuiltIns.unitType.classifierOrFail,
this
)
}
fun IrMemberAccessExpression.usesDefaultArguments(): Boolean =
this.descriptor.valueParameters.any { this.getValueArgument(it) == null }
@@ -0,0 +1,23 @@
var result = "fail 1"
fun withSideEffect() : Int {
result = "OK"
return 42
}
fun box(): String {
if (withSideEffect() == null) {
return "fail 2"
}
if (result != "OK") {
return "fail 3"
}
result = "fail 4"
if (withSideEffect() != null) {
return result
}
return result
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
fun box(): String {
230?.hashCode()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
fun box(): String {
var result = 0
if (1 == 1) {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
fun returningBoxed() : Int? = 1
fun acceptingBoxed(x : Int?) : Int ? = x
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
fun main(p: String?) {
if (!(p == null)) {
"then"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
fun main(p: String?) {
if (p == null) {
"then"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
class A
fun foo(x: Any?) {}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
fun box() {
val x: Any? = "abc"
val y: Any? = if (1 == 1) x else "cde"
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
class A
fun box() {
val x: A? = A()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
class A
fun box() {
val x: A? = A()
@@ -1,5 +1,4 @@
// !LANGUAGE: +ProperIeee754Comparisons
// IGNORE_BACKEND: JVM_IR
fun equals5(a: Any?, b: Any?) = if (a is Double && b is Double?) a == b else null!!
fun equals6(a: Any?, b: Any?) = if (a is Double? && b is Double) a == b else null!!
@@ -1,5 +1,4 @@
// !LANGUAGE: +ProperIeee754Comparisons
// IGNORE_BACKEND: JVM_IR
fun equals5(a: Any?, b: Any?) = if (a is Float && b is Float?) a == b else null!!
fun equals6(a: Any?, b: Any?) = if (a is Float? && b is Float) a == b else null!!
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
val a : Int? = 10
fun foo() = a!!.toString()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
fun test(x: String?) {
if (x == null) return
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
fun test1() {
val a = null
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
fun test1() {
val a = Unit
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
fun test() {
val value = System.getProperty("key")
if (value != null) {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
fun almostAlwaysTrue() = true
fun runNoInline(f: () -> Unit) = f()
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_IR
fun test() {
lateinit var z: String
run {
@@ -0,0 +1,18 @@
fun f() : Int {
return 42
}
fun box(): String {
if (f() == null) {
return "fail 1"
}
if (f() != null) {
return "OK"
}
return "fail 2"
}
// 0 IF
// 0 ACONST_NULL
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
fun findUserId(username: String): Long? = null
fun main(args: Array<String>) {
@@ -15977,6 +15977,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/nullCheckOptimization/kt7774.kt");
}
@TestMetadata("primitiveCheckWithSideEffect.kt")
public void testPrimitiveCheckWithSideEffect() throws Exception {
runTest("compiler/testData/codegen/box/nullCheckOptimization/primitiveCheckWithSideEffect.kt");
}
@TestMetadata("trivialInstanceOf.kt")
public void testTrivialInstanceOf() throws Exception {
runTest("compiler/testData/codegen/box/nullCheckOptimization/trivialInstanceOf.kt");
@@ -2798,6 +2798,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/notNullAsNotNullable.kt");
}
@TestMetadata("primitiveCheck.kt")
public void testPrimitiveCheck() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/primitiveCheck.kt");
}
@TestMetadata("redundantSafeCall.kt")
public void testRedundantSafeCall() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/redundantSafeCall.kt");
@@ -2798,6 +2798,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/notNullAsNotNullable.kt");
}
@TestMetadata("primitiveCheck.kt")
public void testPrimitiveCheck() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/primitiveCheck.kt");
}
@TestMetadata("redundantSafeCall.kt")
public void testRedundantSafeCall() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/redundantSafeCall.kt");
@@ -15977,6 +15977,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/nullCheckOptimization/kt7774.kt");
}
@TestMetadata("primitiveCheckWithSideEffect.kt")
public void testPrimitiveCheckWithSideEffect() throws Exception {
runTest("compiler/testData/codegen/box/nullCheckOptimization/primitiveCheckWithSideEffect.kt");
}
@TestMetadata("trivialInstanceOf.kt")
public void testTrivialInstanceOf() throws Exception {
runTest("compiler/testData/codegen/box/nullCheckOptimization/trivialInstanceOf.kt");
@@ -15982,6 +15982,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/nullCheckOptimization/kt7774.kt");
}
@TestMetadata("primitiveCheckWithSideEffect.kt")
public void testPrimitiveCheckWithSideEffect() throws Exception {
runTest("compiler/testData/codegen/box/nullCheckOptimization/primitiveCheckWithSideEffect.kt");
}
@TestMetadata("trivialInstanceOf.kt")
public void testTrivialInstanceOf() throws Exception {
runTest("compiler/testData/codegen/box/nullCheckOptimization/trivialInstanceOf.kt");
@@ -12372,6 +12372,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/nullCheckOptimization/kt7774.kt");
}
@TestMetadata("primitiveCheckWithSideEffect.kt")
public void testPrimitiveCheckWithSideEffect() throws Exception {
runTest("compiler/testData/codegen/box/nullCheckOptimization/primitiveCheckWithSideEffect.kt");
}
@TestMetadata("trivialInstanceOf.kt")
public void testTrivialInstanceOf() throws Exception {
runTest("compiler/testData/codegen/box/nullCheckOptimization/trivialInstanceOf.kt");
@@ -13427,6 +13427,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/nullCheckOptimization/kt7774.kt");
}
@TestMetadata("primitiveCheckWithSideEffect.kt")
public void testPrimitiveCheckWithSideEffect() throws Exception {
runTest("compiler/testData/codegen/box/nullCheckOptimization/primitiveCheckWithSideEffect.kt");
}
@TestMetadata("trivialInstanceOf.kt")
public void testTrivialInstanceOf() throws Exception {
runTest("compiler/testData/codegen/box/nullCheckOptimization/trivialInstanceOf.kt");