Recalculate max stack on method emitting: optimizations could change it

This commit is contained in:
Mikhael Bogdanov
2017-09-04 12:00:36 +02:00
parent 638cf346aa
commit 81a1bf3319
4 changed files with 30 additions and 15 deletions
@@ -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() {
@@ -46,14 +46,13 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
private var changes = false
fun run(): Boolean {
val stackOnThrowExceptions = hashMapOf<AbstractInsnNode, Int>()
val checkedReferenceTypes = analyzeTypesAndRemoveDeadCode(stackOnThrowExceptions)
eliminateRedundantChecks(checkedReferenceTypes, stackOnThrowExceptions)
val checkedReferenceTypes = analyzeTypesAndRemoveDeadCode()
eliminateRedundantChecks(checkedReferenceTypes)
return changes
}
private fun analyzeTypesAndRemoveDeadCode(stackOnThrowExceptionsHolder: MutableMap<AbstractInsnNode, Int>): Map<AbstractInsnNode, Type> {
private fun analyzeTypesAndRemoveDeadCode(): Map<AbstractInsnNode, Type> {
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<AbstractInsnNode, Type>,
stackOnThrowExceptions: MutableMap<AbstractInsnNode, Int>
checkedReferenceTypes: Map<AbstractInsnNode, Type>
) {
val nullabilityAssumptions = injectNullabilityAssumptions(checkedReferenceTypes, stackOnThrowExceptions)
val nullabilityAssumptions = injectNullabilityAssumptions(checkedReferenceTypes)
val nullabilityMap = analyzeNullabilities()
@@ -100,9 +96,8 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
}
private fun injectNullabilityAssumptions(
checkedReferenceTypes: Map<AbstractInsnNode, Type>,
stackOnThrowExceptions: MutableMap<AbstractInsnNode, Int>
) = NullabilityAssumptionsBuilder(checkedReferenceTypes, stackOnThrowExceptions).injectNullabilityAssumptions()
checkedReferenceTypes: Map<AbstractInsnNode, Type>
) = NullabilityAssumptionsBuilder(checkedReferenceTypes).injectNullabilityAssumptions()
private fun analyzeNullabilities(): Map<AbstractInsnNode, StrictBasicValue> {
val frames = analyze(internalClassName, methodNode, NullabilityInterpreter())
@@ -186,8 +181,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() {
}
private inner class NullabilityAssumptionsBuilder(
val relatedReferenceTypes: Map<AbstractInsnNode, Type>,
val stackOnThrowExceptions: MutableMap<AbstractInsnNode, Int>
val relatedReferenceTypes: Map<AbstractInsnNode, Type>
) {
private val checksDependingOnVariable = HashMap<Int, MutableList<AbstractInsnNode>>()
@@ -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) {
@@ -0,0 +1,5 @@
fun test() {
1
}
// 1 MAXSTACK = 0
@@ -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");