RedundantCoercionToUnitTransformer: do not create individual objects for each transformation.
This commit is contained in:
+41
-31
@@ -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 = "]")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user