diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/PopBackwardPropagationTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/PopBackwardPropagationTransformer.kt index 9ccd437aae2..0c0489d42d7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/PopBackwardPropagationTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/PopBackwardPropagationTransformer.kt @@ -19,10 +19,8 @@ package org.jetbrains.kotlin.codegen.optimization.boxing import org.jetbrains.kotlin.codegen.optimization.OptimizationMethodVisitor import org.jetbrains.kotlin.codegen.optimization.common.debugText import org.jetbrains.kotlin.codegen.optimization.common.isLoadOperation -import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful import org.jetbrains.kotlin.codegen.optimization.fixStack.peekWords import org.jetbrains.kotlin.codegen.optimization.fixStack.top -import org.jetbrains.kotlin.codegen.optimization.removeNodeGetNext import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.tree.* @@ -32,59 +30,49 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.SourceInterpreter import org.jetbrains.org.objectweb.asm.tree.analysis.SourceValue import java.util.* +private typealias Transformation = (AbstractInsnNode) -> Unit + class PopBackwardPropagationTransformer : MethodTransformer() { override fun transform(internalClassName: String, methodNode: MethodNode) { if (!OptimizationMethodVisitor.canBeOptimizedUsingSourceInterpreter(methodNode)) return - Transformer(methodNode).transform() + if (methodNode.instructions.any { it.isPop() || it.isPurePush() }) { + Transformer(methodNode).transform() + } } private class Transformer(val methodNode: MethodNode) { - private interface Transformation { - fun apply(insn: AbstractInsnNode) - } - - private inline fun Transformation(crossinline body: (AbstractInsnNode) -> Unit): Transformation = - object : Transformation { - override fun apply(insn: AbstractInsnNode) { - body(insn) - } - } - - private val REPLACE_WITH_NOP = Transformation { insnList.set(it, createRemovableNopInsn()) } - private val REPLACE_WITH_POP1 = Transformation { insnList.set(it, InsnNode(Opcodes.POP)) } - private val REPLACE_WITH_POP2 = Transformation { insnList.set(it, InsnNode(Opcodes.POP2)) } - private val INSERT_POP1_AFTER = Transformation { insnList.insert(it, InsnNode(Opcodes.POP)) } - private val INSERT_POP2_AFTER = Transformation { insnList.insert(it, InsnNode(Opcodes.POP2)) } + private val REPLACE_WITH_NOP: Transformation = { insnList.set(it, InsnNode(Opcodes.NOP)) } + private val REPLACE_WITH_POP1: Transformation = { insnList.set(it, InsnNode(Opcodes.POP)) } + private val REPLACE_WITH_POP2: Transformation = { insnList.set(it, InsnNode(Opcodes.POP2)) } + private val INSERT_POP1_AFTER: Transformation = { insnList.insert(it, InsnNode(Opcodes.POP)) } + private val INSERT_POP2_AFTER: Transformation = { insnList.insert(it, InsnNode(Opcodes.POP2)) } private val insnList = methodNode.instructions - private val insns = insnList.toArray() private val dontTouchInsnIndices = BitSet(insns.size) - private val transformations = hashMapOf() - private val removableNops = hashSetOf() - private val frames by lazy { analyzeMethodBody() } + private val transformations = hashMapOf() + private val frames = analyzeMethodBody() fun transform() { - if (insns.none { it.isPop() || it.isPurePush() }) return - - computeTransformations() - for ((insn, transformation) in transformations.entries) { - transformation.apply(insn) + for ((i, insn) in insns.withIndex()) { + if (insn.opcode == Opcodes.POP && frames[i] != null) { + val inputTop = getInputTop(insn) + val sources = inputTop.insns + if (sources.all { !isDontTouch(it) } && sources.any { isTransformablePopOperand(it) }) { + transformations[insn] = REPLACE_WITH_NOP + sources.forEach { propagatePopBackwards(it, inputTop.size) } + } + } + } + for ((insn, transformation) in transformations.entries) { + transformation(insn) } - postprocessNops() } private fun analyzeMethodBody(): Array?> { - val frames = Analyzer(HazardsTrackingInterpreter()).analyze("fake", methodNode) - - postprocessStackHazards(frames) - - return frames - } - - private fun postprocessStackHazards(frames: Array?>) { + val frames = Analyzer(HazardsTrackingInterpreter()).analyze("fake", methodNode) val insns = methodNode.instructions.toArray() for (i in frames.indices) { val frame = frames[i] ?: continue @@ -113,6 +101,7 @@ class PopBackwardPropagationTransformer : MethodTransformer() { } } } + return frames } private fun throwIncorrectBytecode(insn: AbstractInsnNode?, frame: Frame): Nothing { @@ -164,39 +153,16 @@ class PopBackwardPropagationTransformer : MethodTransformer() { } } - - private fun computeTransformations() { - transformations.clear() - - for (i in insns.indices) { - if (frames[i] == null) continue - val insn = insns[i] - - if (insn.opcode == Opcodes.POP) { - propagatePopBackwards(insn, 0) - } - } - } - private fun propagatePopBackwards(insn: AbstractInsnNode, poppedValueSize: Int) { if (transformations.containsKey(insn)) return when { - insn.opcode == Opcodes.POP -> { - val inputTop = getInputTop(insn) - val sources = inputTop.insns - if (sources.all { !isDontTouch(it) } && sources.any { isTransformablePopOperand(it) }) { - transformations[insn] = replaceWithNopTransformation() - sources.forEach { propagatePopBackwards(it, inputTop.size) } - } - } - insn.opcode == Opcodes.CHECKCAST -> { val inputTop = getInputTop(insn) val sources = inputTop.insns val resultType = (insn as TypeInsnNode).desc if (sources.all { !isDontTouch(it) } && sources.any { isTransformableCheckcastOperand(it, resultType) }) { - transformations[insn] = replaceWithNopTransformation() + transformations[insn] = REPLACE_WITH_NOP sources.forEach { propagatePopBackwards(it, inputTop.size) } } else { transformations[insn] = insertPopAfterTransformation(poppedValueSize) @@ -204,22 +170,21 @@ class PopBackwardPropagationTransformer : MethodTransformer() { } insn.isPrimitiveBoxing() -> { - val boxedValueSize = getInputTop(insn).size - transformations[insn] = replaceWithPopTransformation(boxedValueSize) + transformations[insn] = replaceWithPopTransformation(getInputTop(insn).size) } insn.isPurePush() -> { - transformations[insn] = replaceWithNopTransformation() + transformations[insn] = REPLACE_WITH_NOP } insn.isPrimitiveTypeConversion() -> { val inputTop = getInputTop(insn) val sources = inputTop.insns if (sources.all { !isDontTouch(it) }) { - transformations[insn] = replaceWithNopTransformation() + transformations[insn] = REPLACE_WITH_NOP sources.forEach { propagatePopBackwards(it, inputTop.size) } } else { - transformations[insn] = replaceWithPopTransformation(poppedValueSize) + transformations[insn] = replaceWithPopTransformation(inputTop.size) } } @@ -229,39 +194,6 @@ class PopBackwardPropagationTransformer : MethodTransformer() { } } - private fun postprocessNops() { - var node: AbstractInsnNode? = insnList.first - var hasRemovableNops = false - while (node != null) { - node = node.next - val begin = node ?: break - while (node != null && node !is LabelNode) { - if (node in removableNops) { - hasRemovableNops = true - } - node = node.next - } - val end = node - if (hasRemovableNops) { - removeUnneededNopsInRange(begin, end) - } - hasRemovableNops = false - } - } - - private fun removeUnneededNopsInRange(begin: AbstractInsnNode, end: AbstractInsnNode?) { - var node: AbstractInsnNode? = begin - var keepNop = true - while (node != null && node != end) { - if (node in removableNops && !keepNop) { - node = insnList.removeNodeGetNext(node) - } else { - if (node.isMeaningful) keepNop = false - node = node.next - } - } - } - private fun replaceWithPopTransformation(size: Int): Transformation = when (size) { 1 -> REPLACE_WITH_POP1 @@ -276,12 +208,6 @@ class PopBackwardPropagationTransformer : MethodTransformer() { else -> throw AssertionError("Unexpected pop value size: $size") } - private fun replaceWithNopTransformation(): Transformation = - REPLACE_WITH_NOP - - private fun createRemovableNopInsn() = - InsnNode(Opcodes.NOP).apply { removableNops.add(this) } - private fun getInputTop(insn: AbstractInsnNode): SourceValue { val i = insnList.indexOf(insn) val frame = frames[i] ?: throw AssertionError("Unexpected dead instruction #$i") @@ -301,16 +227,13 @@ class PopBackwardPropagationTransformer : MethodTransformer() { } fun AbstractInsnNode.isPurePush() = - isLoadOperation() || - opcode in Opcodes.ACONST_NULL..Opcodes.LDC + 2 || - isUnitInstance() + isLoadOperation() || opcode in Opcodes.ACONST_NULL..Opcodes.LDC + 2 || isUnitInstance() fun AbstractInsnNode.isPop() = opcode == Opcodes.POP || opcode == Opcodes.POP2 fun AbstractInsnNode.isUnitInstance() = - opcode == Opcodes.GETSTATIC && - this is FieldInsnNode && owner == "kotlin/Unit" && name == "INSTANCE" + opcode == Opcodes.GETSTATIC && this is FieldInsnNode && owner == "kotlin/Unit" && name == "INSTANCE" fun AbstractInsnNode.isPrimitiveTypeConversion() = opcode in Opcodes.I2L..Opcodes.I2S