diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/Util.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/Util.kt index 58b2bcf2a48..77fb229f4d8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/Util.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/Util.kt @@ -16,10 +16,12 @@ package org.jetbrains.kotlin.codegen.optimization.common +import org.jetbrains.kotlin.codegen.inline.MaxStackFrameSizeAndLocalsCalculator import org.jetbrains.kotlin.codegen.inline.insnText import org.jetbrains.kotlin.codegen.optimization.removeNodeGetNext import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn import org.jetbrains.kotlin.utils.addToStdlib.safeAs +import org.jetbrains.org.objectweb.asm.MethodVisitor import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes.* import org.jetbrains.org.objectweb.asm.Type @@ -71,6 +73,14 @@ fun MethodNode.prepareForEmitting() { current = prev } + maxStack = -1 + accept(MaxStackFrameSizeAndLocalsCalculator( + Opcodes.ASM5, access, desc, + object : MethodVisitor(Opcodes.ASM5) { + override fun visitMaxs(maxStack: Int, maxLocals: Int) { + this@prepareForEmitting.maxStack = maxStack + } + })) } fun MethodNode.stripOptimizationMarkers() { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/RedundantNullCheckMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/RedundantNullCheckMethodTransformer.kt index db939c342c3..50852bb8e56 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/RedundantNullCheckMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/RedundantNullCheckMethodTransformer.kt @@ -46,14 +46,13 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() { private var changes = false fun run(): Boolean { - val stackOnThrowExceptions = hashMapOf() - val checkedReferenceTypes = analyzeTypesAndRemoveDeadCode(stackOnThrowExceptions) - eliminateRedundantChecks(checkedReferenceTypes, stackOnThrowExceptions) + val checkedReferenceTypes = analyzeTypesAndRemoveDeadCode() + eliminateRedundantChecks(checkedReferenceTypes) return changes } - private fun analyzeTypesAndRemoveDeadCode(stackOnThrowExceptionsHolder: MutableMap): Map { + private fun analyzeTypesAndRemoveDeadCode(): Map { val insns = methodNode.instructions.toArray() val frames = analyze(internalClassName, methodNode, OptimizationBasicInterpreter()) @@ -67,8 +66,6 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() { insn.isCheckParameterIsNotNull() || insn.isCheckExpressionValueIsNotNull() -> relevantReferenceTypes[insn] = frame.peek(1)?.type ?: continue@insnLoop - insn.isThrowIntrinsicWithoutArguments() -> - stackOnThrowExceptionsHolder[insn] = frame.maxStackSize insn.isPseudo(PseudoInsn.STORE_NOT_NULL) -> { val previous = insn.previous ?: continue@insnLoop if (previous.opcode != Opcodes.ASTORE) continue@insnLoop @@ -87,10 +84,9 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() { } private fun eliminateRedundantChecks( - checkedReferenceTypes: Map, - stackOnThrowExceptions: MutableMap + checkedReferenceTypes: Map ) { - val nullabilityAssumptions = injectNullabilityAssumptions(checkedReferenceTypes, stackOnThrowExceptions) + val nullabilityAssumptions = injectNullabilityAssumptions(checkedReferenceTypes) val nullabilityMap = analyzeNullabilities() @@ -100,9 +96,8 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() { } private fun injectNullabilityAssumptions( - checkedReferenceTypes: Map, - stackOnThrowExceptions: MutableMap - ) = NullabilityAssumptionsBuilder(checkedReferenceTypes, stackOnThrowExceptions).injectNullabilityAssumptions() + checkedReferenceTypes: Map + ) = NullabilityAssumptionsBuilder(checkedReferenceTypes).injectNullabilityAssumptions() private fun analyzeNullabilities(): Map { val frames = analyze(internalClassName, methodNode, NullabilityInterpreter()) @@ -186,8 +181,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() { } private inner class NullabilityAssumptionsBuilder( - val relatedReferenceTypes: Map, - val stackOnThrowExceptions: MutableMap + val relatedReferenceTypes: Map ) { private val checksDependingOnVariable = HashMap>() @@ -387,7 +381,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() { }) } - methodNode.maxStack = Math.max(methodNode.maxStack, (stackOnThrowExceptions[insn] ?: -1) + 1) + methodNode.maxStack = methodNode.maxStack + 1 //will be recalculated in prepareForEmitting } private fun NullabilityAssumptions.injectCodeForStoreNotNull(insn: AbstractInsnNode, varType: Type) { diff --git a/compiler/testData/codegen/bytecodeText/maxStackAfterOptimizations.kt b/compiler/testData/codegen/bytecodeText/maxStackAfterOptimizations.kt new file mode 100644 index 00000000000..766c543731a --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/maxStackAfterOptimizations.kt @@ -0,0 +1,5 @@ +fun test() { + 1 +} + +// 1 MAXSTACK = 0 \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index f11f1dbc6a9..73879200d6f 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -300,6 +300,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { doTest(fileName); } + @TestMetadata("maxStackAfterOptimizations.kt") + public void testMaxStackAfterOptimizations() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/maxStackAfterOptimizations.kt"); + doTest(fileName); + } + @TestMetadata("noFlagAnnotations.kt") public void testNoFlagAnnotations() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/noFlagAnnotations.kt");