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:
+51
-50
@@ -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() =
|
||||
|
||||
+33
-31
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user