JVM: ignore non-meaningful instructions during peephole optimization

Also, produce more nops, since they no longer take up memory for frames
and a later pass will remove the unneeded ones anyway.
This commit is contained in:
pyos
2022-04-07 15:23:02 +02:00
committed by max-kammerer
parent c43acba0b9
commit 0ec5975730
2 changed files with 84 additions and 81 deletions
@@ -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() =
@@ -57,7 +57,7 @@ open class FastMethodAnalyzer<V : Value>
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<Frame<V>?> = arrayOfNulls(nInsns)
@@ -74,7 +74,6 @@ open class FastMethodAnalyzer<V : Value>
checkAssertions()
computeExceptionHandlersForEachInsn(method)
initMergeNodes()
val isTcbStart = BooleanArray(nInsns)
for (tcb in method.tryCatchBlocks) {
@@ -179,35 +178,6 @@ open class FastMethodAnalyzer<V : Value>
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<V>? =
frames[insn.indexOf()]
@@ -313,4 +283,36 @@ open class FastMethodAnalyzer<V : Value>
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
}
}
}