diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/StackPeepholeOptimizationsTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/StackPeepholeOptimizationsTransformer.kt index 68dee7ebafc..931871af16a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/StackPeepholeOptimizationsTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/StackPeepholeOptimizationsTransformer.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.codegen.optimization.boxing +import org.jetbrains.kotlin.codegen.optimization.common.FastMethodAnalyzer import org.jetbrains.kotlin.codegen.optimization.common.findPreviousOrNull import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer import org.jetbrains.org.objectweb.asm.Opcodes @@ -29,83 +30,83 @@ class StackPeepholeOptimizationsTransformer : MethodTransformer() { } private fun transformOnce(methodNode: MethodNode): Boolean { - val actions = ArrayList<(InsnList) -> Unit>() + val instructions = methodNode.instructions + var changed = false - val insns = methodNode.instructions.toArray() + val isMergeNode = FastMethodAnalyzer.findMergeNodes(methodNode) - for (i in 1 until insns.size) { - val insn = insns[i] - val prev = insn.previous - val prevNonNop = insn.findPreviousOrNull { it.opcode != Opcodes.NOP } ?: continue + fun AbstractInsnNode.previousMeaningful() = + findPreviousOrNull { + it.opcode != Opcodes.NOP && it.type != AbstractInsnNode.LINE && + (it.type != AbstractInsnNode.LABEL || isMergeNode[instructions.indexOf(it)]) + } + var insn: AbstractInsnNode? + var next = instructions.first + while (next != null) { + insn = next + next = insn.next + + val prev = insn.previousMeaningful() ?: continue when (insn.opcode) { Opcodes.POP -> { when { - prevNonNop.isEliminatedByPop() -> actions.add { - it.set(insn, InsnNode(Opcodes.NOP)) - it.remove(prevNonNop) + prev.isEliminatedByPop() -> { + instructions.set(insn, InsnNode(Opcodes.NOP)) + instructions.set(prev, InsnNode(Opcodes.NOP)) + changed = true } - prevNonNop.opcode == Opcodes.DUP_X1 -> actions.add { - it.remove(insn) - it.set(prevNonNop, InsnNode(Opcodes.SWAP)) + prev.opcode == Opcodes.DUP_X1 -> { + instructions.set(insn, InsnNode(Opcodes.NOP)) + instructions.set(prev, InsnNode(Opcodes.SWAP)) + changed = true } } } Opcodes.SWAP -> { - val prevNonNop2 = prevNonNop.findPreviousOrNull { it.opcode != Opcodes.NOP } ?: continue - if (prevNonNop.isPurePushOfSize1() && prevNonNop2.isPurePushOfSize1()) { - actions.add { - it.remove(insn) - it.set(prevNonNop, prevNonNop2.clone(emptyMap())) - it.set(prevNonNop2, prevNonNop.clone(emptyMap())) - } + val prev2 = prev.previousMeaningful() ?: continue + if (prev.isPurePushOfSize1() && prev2.isPurePushOfSize1()) { + instructions.set(insn, InsnNode(Opcodes.NOP)) + instructions.set(prev, prev2.clone(emptyMap())) + instructions.set(prev2, prev.clone(emptyMap())) + changed = true } } Opcodes.I2L -> { - when (prevNonNop.opcode) { - Opcodes.ICONST_0 -> actions.add { - it.remove(insn) - it.set(prevNonNop, InsnNode(Opcodes.LCONST_0)) + when (prev.opcode) { + Opcodes.ICONST_0 -> { + instructions.set(insn, InsnNode(Opcodes.NOP)) + instructions.set(prev, InsnNode(Opcodes.LCONST_0)) + changed = true } - Opcodes.ICONST_1 -> actions.add { - it.remove(insn) - it.set(prevNonNop, InsnNode(Opcodes.LCONST_1)) + Opcodes.ICONST_1 -> { + instructions.set(insn, InsnNode(Opcodes.NOP)) + instructions.set(prev, InsnNode(Opcodes.LCONST_1)) + changed = true } } } Opcodes.POP2 -> { - if (prevNonNop.isEliminatedByPop2()) { - actions.add { - it.set(insn, InsnNode(Opcodes.NOP)) - it.remove(prevNonNop) - } - } else if (i > 1) { - val prevNonNop2 = prevNonNop.findPreviousOrNull { it.opcode != Opcodes.NOP } ?: continue - if (prevNonNop.isEliminatedByPop() && prevNonNop2.isEliminatedByPop()) { - actions.add { - it.set(insn, InsnNode(Opcodes.NOP)) - it.remove(prevNonNop) - it.remove(prevNonNop2) - } + if (prev.isEliminatedByPop2()) { + instructions.set(insn, InsnNode(Opcodes.NOP)) + instructions.set(prev, InsnNode(Opcodes.NOP)) + changed = true + } else { + val prev2 = prev.previousMeaningful() ?: continue + if (prev.isEliminatedByPop() && prev2.isEliminatedByPop()) { + instructions.set(insn, InsnNode(Opcodes.NOP)) + instructions.set(prev, InsnNode(Opcodes.NOP)) + instructions.set(prev2, InsnNode(Opcodes.NOP)) + changed = true } } } - - Opcodes.NOP -> - if (prev.opcode == Opcodes.NOP) { - actions.add { - it.remove(prev) - } - } } } - - actions.forEach { it(methodNode.instructions) } - - return actions.isNotEmpty() + return changed } private fun AbstractInsnNode.isEliminatedByPop() = diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FastMethodAnalyzer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FastMethodAnalyzer.kt index 0e8b2228d3e..1c323e8d71d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FastMethodAnalyzer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FastMethodAnalyzer.kt @@ -57,7 +57,7 @@ open class FastMethodAnalyzer private val insnsArray = method.instructions.toArray() private val nInsns = method.instructions.size() - private val isMergeNode = BooleanArray(nInsns) + private val isMergeNode = findMergeNodes(method) private val frames: Array?> = arrayOfNulls(nInsns) @@ -74,7 +74,6 @@ open class FastMethodAnalyzer checkAssertions() computeExceptionHandlersForEachInsn(method) - initMergeNodes() val isTcbStart = BooleanArray(nInsns) for (tcb in method.tryCatchBlocks) { @@ -179,35 +178,6 @@ open class FastMethodAnalyzer private fun AbstractInsnNode.indexOf() = method.instructions.indexOf(this) - private fun initMergeNodes() { - for (insn in insnsArray) { - when (insn.type) { - AbstractInsnNode.JUMP_INSN -> { - val jumpInsn = insn as JumpInsnNode - isMergeNode[jumpInsn.label.indexOf()] = true - } - AbstractInsnNode.LOOKUPSWITCH_INSN -> { - val switchInsn = insn as LookupSwitchInsnNode - isMergeNode[switchInsn.dflt.indexOf()] = true - for (label in switchInsn.labels) { - isMergeNode[label.indexOf()] = true - } - } - AbstractInsnNode.TABLESWITCH_INSN -> { - val switchInsn = insn as TableSwitchInsnNode - isMergeNode[switchInsn.dflt.indexOf()] = true - for (label in switchInsn.labels) { - isMergeNode[label.indexOf()] = true - } - } - } - } - for (tcb in method.tryCatchBlocks) { - isMergeNode[tcb.handler.indexOf()] = true - } - } - - fun getFrame(insn: AbstractInsnNode): Frame? = frames[insn.indexOf()] @@ -313,4 +283,36 @@ open class FastMethodAnalyzer append("}\n") } } + + companion object { + fun findMergeNodes(method: MethodNode): BooleanArray { + val isMergeNode = BooleanArray(method.instructions.size()) + for (insn in method.instructions) { + when (insn.type) { + AbstractInsnNode.JUMP_INSN -> { + val jumpInsn = insn as JumpInsnNode + isMergeNode[method.instructions.indexOf(jumpInsn.label)] = true + } + AbstractInsnNode.LOOKUPSWITCH_INSN -> { + val switchInsn = insn as LookupSwitchInsnNode + isMergeNode[method.instructions.indexOf(switchInsn.dflt)] = true + for (label in switchInsn.labels) { + isMergeNode[method.instructions.indexOf(label)] = true + } + } + AbstractInsnNode.TABLESWITCH_INSN -> { + val switchInsn = insn as TableSwitchInsnNode + isMergeNode[method.instructions.indexOf(switchInsn.dflt)] = true + for (label in switchInsn.labels) { + isMergeNode[method.instructions.indexOf(label)] = true + } + } + } + } + for (tcb in method.tryCatchBlocks) { + isMergeNode[method.instructions.indexOf(tcb.handler)] = true + } + return isMergeNode + } + } }