RedundantCoercionToUnitTransformer: do not create individual objects for each transformation.

This commit is contained in:
Dmitry Petrov
2016-04-21 16:07:30 +03:00
parent 6980d28eb0
commit f3c006a5f5
@@ -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.Frame
import org.jetbrains.org.objectweb.asm.tree.analysis.SourceInterpreter import org.jetbrains.org.objectweb.asm.tree.analysis.SourceInterpreter
import org.jetbrains.org.objectweb.asm.tree.analysis.SourceValue import org.jetbrains.org.objectweb.asm.tree.analysis.SourceValue
import org.jetbrains.org.objectweb.asm.util.Printer
class RedundantCoercionToUnitTransformer : MethodTransformer() { class RedundantCoercionToUnitTransformer : MethodTransformer() {
override fun transform(internalClassName: String, methodNode: MethodNode) { override fun transform(internalClassName: String, methodNode: MethodNode) {
@@ -35,19 +34,38 @@ class RedundantCoercionToUnitTransformer : MethodTransformer() {
} }
private class Transformer(val methodNode: MethodNode) { 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 insnList = methodNode.instructions
private val insns = insnList.toArray() private val insns = insnList.toArray()
private val dontTouchInsns = hashSetOf<AbstractInsnNode>() private val dontTouchInsns = hashSetOf<AbstractInsnNode>()
private val transformations = hashMapOf<AbstractInsnNode, () -> Unit>() private val transformations = hashMapOf<AbstractInsnNode, Transformation>()
private val removableNops = hashSetOf<InsnNode>() private val removableNops = hashSetOf<InsnNode>()
private val frames: Array<out Frame<SourceValue>?> = analyzeMethodBody() private val frames: Array<out Frame<SourceValue>?> = analyzeMethodBody()
fun transform() { fun transform() {
computeTransformations() computeTransformations()
transformations.values.forEach { it() } for ((insn, transformation) in transformations.entries) {
transformation.apply(insn)
}
postprocessNops() postprocessNops()
} }
@@ -108,7 +126,7 @@ class RedundantCoercionToUnitTransformer : MethodTransformer() {
val inputTop = getInputTop(insn) val inputTop = getInputTop(insn)
val sources = inputTop.insns val sources = inputTop.insns
if (sources.all { !isDontTouch(it) } && sources.any { isTransformablePopOperand(it) }) { if (sources.all { !isDontTouch(it) } && sources.any { isTransformablePopOperand(it) }) {
transformations[insn] = replaceWithNopTransformation(insn) transformations[insn] = replaceWithNopTransformation()
sources.forEach { propagatePopBackwards(it, inputTop.size) } sources.forEach { propagatePopBackwards(it, inputTop.size) }
} }
} }
@@ -118,25 +136,25 @@ class RedundantCoercionToUnitTransformer : MethodTransformer() {
val sources = inputTop.insns val sources = inputTop.insns
val resultType = (insn as TypeInsnNode).desc val resultType = (insn as TypeInsnNode).desc
if (sources.all { !isDontTouch(it) } && sources.any { isTransformableCheckcastOperand(it, resultType) }) { if (sources.all { !isDontTouch(it) } && sources.any { isTransformableCheckcastOperand(it, resultType) }) {
transformations[insn] = replaceWithNopTransformation(insn) transformations[insn] = replaceWithNopTransformation()
sources.forEach { propagatePopBackwards(it, inputTop.size) } sources.forEach { propagatePopBackwards(it, inputTop.size) }
} }
else { else {
transformations[insn] = insertPopAfterTransformation(insn, poppedValueSize) transformations[insn] = insertPopAfterTransformation(poppedValueSize)
} }
} }
insn.isPrimitiveBoxing() -> { insn.isPrimitiveBoxing() -> {
val boxedValueSize = getInputTop(insn).size val boxedValueSize = getInputTop(insn).size
transformations[insn] = replaceWithPopTransformation(insn, boxedValueSize) transformations[insn] = replaceWithPopTransformation(boxedValueSize)
} }
insn.isUnitOrNull() -> { insn.isUnitOrNull() -> {
transformations[insn] = replaceWithNopTransformation(insn) transformations[insn] = replaceWithNopTransformation()
} }
else -> { 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 = private fun replaceWithPopTransformation(size: Int): Transformation =
{ 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) =
when (size) { when (size) {
1 -> InsnNode(Opcodes.POP) 1 -> REPLACE_WITH_POP1
2 -> InsnNode(Opcodes.POP2) 2 -> REPLACE_WITH_POP2
else -> throw AssertionError("Unexpected popped value size: $size") 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() = private fun createRemovableNopInsn() =
InsnNode(Opcodes.NOP).apply { removableNops.add(this) } InsnNode(Opcodes.NOP).apply { removableNops.add(this) }
@@ -208,15 +227,6 @@ class RedundantCoercionToUnitTransformer : MethodTransformer() {
private fun isDontTouch(insn: AbstractInsnNode) = private fun isDontTouch(insn: AbstractInsnNode) =
insn in dontTouchInsns 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<SourceValue>?): String =
if (frame == null)
"unknown (dead code)"
else
(0..frame.stackSize - 1).map { frame.getStack(it).size }.joinToString(prefix = "[", postfix = "]")
} }
} }