diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index 2a94abd0be9..77654d0060f 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -718,7 +718,7 @@ class ExpressionCodegen( is Float -> mv.fconst(value) is Double -> mv.dconst(value) is Number -> mv.iconst(value.toInt()) - else -> mv.aconst(value) + else -> if (expression.kind == IrConstKind.Null) return nullConstant else mv.aconst(value) } return expression.onStack } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/PromisedValue.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/PromisedValue.kt index 43d5980b842..3b86a8e1354 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/PromisedValue.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/PromisedValue.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.parentAsClass +import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Type @@ -162,3 +163,12 @@ val IrType.unboxed: IrType // A Non-materialized value of Unit type that is only materialized through coercion. val ExpressionCodegen.unitValue: PromisedValue get() = MaterialValue(this, Type.VOID_TYPE, context.irBuiltIns.unitType) + +val ExpressionCodegen.nullConstant: PromisedValue + get() = object : PromisedValue(this, AsmTypes.OBJECT_TYPE, context.irBuiltIns.nothingNType) { + override fun materializeAt(target: Type, irTarget: IrType) { + mv.aconst(null) + } + + override fun discard() {} + } diff --git a/compiler/testData/codegen/box/classes/kt1018.kt b/compiler/testData/codegen/box/classes/kt1018.kt index 6e192f5e0be..74cc65d8331 100644 --- a/compiler/testData/codegen/box/classes/kt1018.kt +++ b/compiler/testData/codegen/box/classes/kt1018.kt @@ -1,3 +1,6 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// The IR prduced by FIR implicitly casts `null` of type `Nothing?` to type `Int` instead of `Int?` in `getColumnCount`. + public class StockMarketTableModel() { public fun getColumnCount() : Int { diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline_ir.txt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline_ir.txt index 1aa86e4304a..cb1ed2c1537 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline_ir.txt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline_ir.txt @@ -2,7 +2,6 @@ @kotlin.coroutines.jvm.internal.DebugMetadata public final class CrossinlineKt$box$1$invokeSuspend$$inlined$filter$1$1 { field L$0: java.lang.Object - field L$1: java.lang.Object field label: int synthetic field result: java.lang.Object synthetic final field this$0: CrossinlineKt$box$1$invokeSuspend$$inlined$filter$1 @@ -98,7 +97,6 @@ public final class CrossinlineKt$consumeEach$2 { @kotlin.coroutines.jvm.internal.DebugMetadata public final class CrossinlineKt$filter$$inlined$source$1$1 { field L$0: java.lang.Object - field L$1: java.lang.Object field label: int synthetic field result: java.lang.Object synthetic final field this$0: CrossinlineKt$filter$$inlined$source$1 @@ -190,7 +188,6 @@ public final class CrossinlineKt$range$$inlined$source$1$1 { field I$1: int field L$0: java.lang.Object field L$1: java.lang.Object - field L$2: java.lang.Object field label: int synthetic field result: java.lang.Object synthetic final field this$0: CrossinlineKt$range$$inlined$source$1 @@ -216,7 +213,6 @@ public final class CrossinlineKt$range$$inlined$source$1 { public final class CrossinlineKt$source$1$consume$1 { // source: 'crossinline.kt' field L$0: java.lang.Object - field L$1: java.lang.Object field label: int synthetic field result: java.lang.Object synthetic final field this$0: CrossinlineKt$source$1 diff --git a/compiler/testData/codegen/bytecodeText/checkcast/kt15411.kt b/compiler/testData/codegen/bytecodeText/checkcast/kt15411.kt index 8b947fcf2eb..89b22367a87 100644 --- a/compiler/testData/codegen/bytecodeText/checkcast/kt15411.kt +++ b/compiler/testData/codegen/bytecodeText/checkcast/kt15411.kt @@ -1,7 +1,3 @@ -// IGNORE_BACKEND: JVM_IR -// TODO KT-36650 Don't generate CHECKCAST on null values in JVM_IR -// KT-15411 Unnecessary CHECKCAST bytecode when dealing with null - fun test1(): String? { return null } diff --git a/compiler/testData/codegen/bytecodeText/coercionToUnitOptimization/safeLet.kt b/compiler/testData/codegen/bytecodeText/coercionToUnitOptimization/safeLet.kt index d9e127454b4..51825c13f29 100644 --- a/compiler/testData/codegen/bytecodeText/coercionToUnitOptimization/safeLet.kt +++ b/compiler/testData/codegen/bytecodeText/coercionToUnitOptimization/safeLet.kt @@ -16,14 +16,12 @@ fun test(ss: List) { } } -// JVM_TEMPLATES -// 2 POP // 0 INVOKESTATIC java/lang/Boolean\.valueOf // 0 CHECKCAST java/lang/Boolean // 0 ACONST_NULL -// JVM_IR_TEMPLATES +// JVM_TEMPLATES // 2 POP -// 0 INVOKESTATIC java/lang/Boolean\.valueOf -// 1 CHECKCAST java/lang/Boolean -// 1 ACONST_NULL + +// JVM_IR_TEMPLATES +// 1 POP diff --git a/compiler/testData/codegen/bytecodeText/coroutines/cleanup/nullCleanup.kt b/compiler/testData/codegen/bytecodeText/coroutines/cleanup/nullCleanup.kt index 33090f7aed9..45604c69da6 100644 --- a/compiler/testData/codegen/bytecodeText/coroutines/cleanup/nullCleanup.kt +++ b/compiler/testData/codegen/bytecodeText/coroutines/cleanup/nullCleanup.kt @@ -12,6 +12,12 @@ suspend fun test() { blackhole(a) } -// jsut before suspension point +// 2 PUTFIELD .*L\$0 : Ljava/lang/Object; + +// JVM_TEMPLATES: +// just before suspension point // 1 ACONST_NULL -// 2 PUTFIELD .*L\$0 : Ljava/lang/Object; \ No newline at end of file + +// JVM_IR_TEMPLATES: +// two stores to initialize the `a` variable and one null constant to store in the spill slot. +// 3 ACONST_NULL