diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/temporaryVals/TemporaryVariablesEliminationTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/temporaryVals/TemporaryVariablesEliminationTransformer.kt index b842a1e754f..402f639f11b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/temporaryVals/TemporaryVariablesEliminationTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/temporaryVals/TemporaryVariablesEliminationTransformer.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.codegen.optimization.temporaryVals import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful import org.jetbrains.kotlin.codegen.optimization.common.removeUnusedLocalVariables +import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckExpressionValueIsNotNull import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.utils.SmartList @@ -206,6 +207,8 @@ class TemporaryVariablesEliminationTransformer(private val state: GenerationStat private fun optimizeTemporaryVals(cfg: ControlFlowGraph, temporaryVals: List) { val insnList = cfg.methodNode.instructions + var maxStackIncrement = 0 + for (tmp in temporaryVals) { if (tmp.loadInsns.isEmpty()) { // Drop unused temporary store @@ -270,8 +273,42 @@ class TemporaryVariablesEliminationTransformer(private val state: GenerationStat continue } } + } else if (tmp.loadInsns.size == 2) { + val storeInsn = tmp.storeInsn + + if (storeInsn.matchOpcodes(Opcodes.ASTORE, Opcodes.ALOAD, Opcodes.LDC, Opcodes.INVOKESTATIC, Opcodes.ALOAD)) { + val aLoad1Insn = storeInsn.next + val ldcInsn = aLoad1Insn.next + val invokeStaticInsn = ldcInsn.next + val aLoad2Insn = invokeStaticInsn.next + + if ((aLoad1Insn as VarInsnNode).`var` == tmp.index && + (ldcInsn as LdcInsnNode).cst is String && + invokeStaticInsn.isCheckExpressionValueIsNotNull() && + (aLoad2Insn as VarInsnNode).`var` == tmp.index + ) { + // Replace instruction sequence: + // ASTORE tmp + // ALOAD tmp + // LDC "expression" + // INVOKESTATIC (Ljava/lang/Object;Ljava/lang/String;)V + // ALOAD tmp + // with + // DUP + // LDC "expression + // INVOKESTATIC (Ljava/lang/Object;Ljava/lang/String;)V + insnList.remove(storeInsn) + insnList.remove(aLoad1Insn) + insnList.insertBefore(ldcInsn, InsnNode(Opcodes.DUP)) + insnList.remove(aLoad2Insn) + maxStackIncrement = max(maxStackIncrement, 1) + continue + } + } } } + + cfg.methodNode.maxStack += maxStackIncrement } @Suppress("DuplicatedCode") diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java index a618a0e228b..2a46166d11e 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java @@ -4663,6 +4663,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest { public void testNoAssertionsForKotlin() throws Exception { runTest("compiler/testData/codegen/bytecodeText/notNullAssertions/noAssertionsForKotlin.kt"); } + + @Test + @TestMetadata("noTemporaryVariableInNullCheckOnExpression.kt") + public void testNoTemporaryVariableInNullCheckOnExpression() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/notNullAssertions/noTemporaryVariableInNullCheckOnExpression.kt"); + } } @Nested diff --git a/compiler/testData/codegen/bytecodeText/notNullAssertions/noTemporaryVariableInNullCheckOnExpression.kt b/compiler/testData/codegen/bytecodeText/notNullAssertions/noTemporaryVariableInNullCheckOnExpression.kt new file mode 100644 index 00000000000..a422c5104b6 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/notNullAssertions/noTemporaryVariableInNullCheckOnExpression.kt @@ -0,0 +1,10 @@ +// FULL_JDK + +fun use(a: Any) {} + +fun test() { + use(System.getProperty("abc")) +} + +// 1 ALOAD +// 0 ASTORE diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java index 561f7bfbf64..9bd5cd70886 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java @@ -4519,6 +4519,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { public void testNoAssertionsForKotlin() throws Exception { runTest("compiler/testData/codegen/bytecodeText/notNullAssertions/noAssertionsForKotlin.kt"); } + + @Test + @TestMetadata("noTemporaryVariableInNullCheckOnExpression.kt") + public void testNoTemporaryVariableInNullCheckOnExpression() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/notNullAssertions/noTemporaryVariableInNullCheckOnExpression.kt"); + } } @Nested diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java index 2d2ce479015..09b7df8c13d 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java @@ -4663,6 +4663,12 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { public void testNoAssertionsForKotlin() throws Exception { runTest("compiler/testData/codegen/bytecodeText/notNullAssertions/noAssertionsForKotlin.kt"); } + + @Test + @TestMetadata("noTemporaryVariableInNullCheckOnExpression.kt") + public void testNoTemporaryVariableInNullCheckOnExpression() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/notNullAssertions/noTemporaryVariableInNullCheckOnExpression.kt"); + } } @Nested