From f3c006a5f5a27ffb4dfe77578b6c2f25d4472ebe Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Thu, 21 Apr 2016 16:07:30 +0300 Subject: [PATCH] RedundantCoercionToUnitTransformer: do not create individual objects for each transformation. --- .../RedundantCoercionToUnitTransformer.kt | 72 +++++++++++-------- 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/RedundantCoercionToUnitTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/RedundantCoercionToUnitTransformer.kt index 8d7a9d2cb5e..ffb5bfee958 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/RedundantCoercionToUnitTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/RedundantCoercionToUnitTransformer.kt @@ -27,7 +27,6 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Analyzer import org.jetbrains.org.objectweb.asm.tree.analysis.Frame import org.jetbrains.org.objectweb.asm.tree.analysis.SourceInterpreter import org.jetbrains.org.objectweb.asm.tree.analysis.SourceValue -import org.jetbrains.org.objectweb.asm.util.Printer class RedundantCoercionToUnitTransformer : MethodTransformer() { override fun transform(internalClassName: String, methodNode: MethodNode) { @@ -35,19 +34,38 @@ class RedundantCoercionToUnitTransformer : MethodTransformer() { } 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.replaceNodeGetNext(it, createRemovableNopInsn()) } + private val REPLACE_WITH_POP1 = Transformation { insnList.replaceNodeGetNext(it, InsnNode(Opcodes.POP)) } + private val REPLACE_WITH_POP2 = Transformation { insnList.replaceNodeGetNext(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 dontTouchInsns = hashSetOf() - private val transformations = hashMapOf Unit>() + private val transformations = hashMapOf() private val removableNops = hashSetOf() private val frames: Array?> = analyzeMethodBody() fun transform() { computeTransformations() - transformations.values.forEach { it() } + for ((insn, transformation) in transformations.entries) { + transformation.apply(insn) + } postprocessNops() } @@ -108,7 +126,7 @@ class RedundantCoercionToUnitTransformer : MethodTransformer() { val inputTop = getInputTop(insn) val sources = inputTop.insns if (sources.all { !isDontTouch(it) } && sources.any { isTransformablePopOperand(it) }) { - transformations[insn] = replaceWithNopTransformation(insn) + transformations[insn] = replaceWithNopTransformation() sources.forEach { propagatePopBackwards(it, inputTop.size) } } } @@ -118,25 +136,25 @@ class RedundantCoercionToUnitTransformer : MethodTransformer() { val sources = inputTop.insns val resultType = (insn as TypeInsnNode).desc if (sources.all { !isDontTouch(it) } && sources.any { isTransformableCheckcastOperand(it, resultType) }) { - transformations[insn] = replaceWithNopTransformation(insn) + transformations[insn] = replaceWithNopTransformation() sources.forEach { propagatePopBackwards(it, inputTop.size) } } else { - transformations[insn] = insertPopAfterTransformation(insn, poppedValueSize) + transformations[insn] = insertPopAfterTransformation(poppedValueSize) } } insn.isPrimitiveBoxing() -> { val boxedValueSize = getInputTop(insn).size - transformations[insn] = replaceWithPopTransformation(insn, boxedValueSize) + transformations[insn] = replaceWithPopTransformation(boxedValueSize) } insn.isUnitOrNull() -> { - transformations[insn] = replaceWithNopTransformation(insn) + transformations[insn] = replaceWithNopTransformation() } else -> { - transformations[insn] = insertPopAfterTransformation(insn, poppedValueSize) + transformations[insn] = insertPopAfterTransformation(poppedValueSize) } } } @@ -175,22 +193,23 @@ class RedundantCoercionToUnitTransformer : MethodTransformer() { } } - private fun replaceWithPopTransformation(insn: AbstractInsnNode, size: Int): () -> Unit = - { insnList.replaceNodeGetNext(insn, createPopInsn(size)) } - - private fun insertPopAfterTransformation(insn: AbstractInsnNode, size: Int) = - { insnList.insert(insn, createPopInsn(size)) } - - private fun replaceWithNopTransformation(insn: AbstractInsnNode): () -> Unit = - { insnList.replaceNodeGetNext(insn, createRemovableNopInsn()) } - - private fun createPopInsn(size: Int) = + private fun replaceWithPopTransformation(size: Int): Transformation = when (size) { - 1 -> InsnNode(Opcodes.POP) - 2 -> InsnNode(Opcodes.POP2) - else -> throw AssertionError("Unexpected popped value size: $size") + 1 -> REPLACE_WITH_POP1 + 2 -> REPLACE_WITH_POP2 + else -> throw AssertionError("Unexpected pop value size: $size") } + private fun insertPopAfterTransformation(size: Int): Transformation = + when (size) { + 1 -> INSERT_POP1_AFTER + 2 -> INSERT_POP2_AFTER + 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) } @@ -208,15 +227,6 @@ class RedundantCoercionToUnitTransformer : MethodTransformer() { private fun isDontTouch(insn: AbstractInsnNode) = insn in dontTouchInsns - - private fun throwIllegalStackInsn(i: Int): Nothing = - throw AssertionError("#$i: illegal use of ${Printer.OPCODES[insns[i].opcode]}, input stack: ${formatInputStack(frames[i])}") - - private fun formatInputStack(frame: Frame?): String = - if (frame == null) - "unknown (dead code)" - else - (0..frame.stackSize - 1).map { frame.getStack(it).size }.joinToString(prefix = "[", postfix = "]") } }