[JVM] Combine all mergeControlFlowEdge methods
This is just a refactoring commit. All fast analyzers are doing the same thing in `mergeControlFlowEdge`, so we extract it in common `FastAnalyzer`. The only exception is `FastStackAnalyzer`. There was no `isMergeNode` check, but this is an optimization that allows us to reuse a frame and not copy it.
This commit is contained in:
+6
-3
@@ -16,11 +16,14 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.boxing
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.FastMethodAnalyzer
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.FastAnalyzer
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.findPreviousOrNull
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.InsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.LdcInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
|
||||
class StackPeepholeOptimizationsTransformer : MethodTransformer() {
|
||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
@@ -33,7 +36,7 @@ class StackPeepholeOptimizationsTransformer : MethodTransformer() {
|
||||
val instructions = methodNode.instructions
|
||||
var changed = false
|
||||
|
||||
val isMergeNode = FastMethodAnalyzer.findMergeNodes(methodNode)
|
||||
val isMergeNode = FastAnalyzer.findMergeNodes(methodNode)
|
||||
|
||||
fun AbstractInsnNode.previousMeaningful() =
|
||||
findPreviousOrNull {
|
||||
|
||||
+67
-3
@@ -16,9 +16,9 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Value
|
||||
|
||||
abstract class FastAnalyzer<V : Value, I : Interpreter<V>, F : Frame<V>>(
|
||||
protected val owner: String,
|
||||
private val owner: String,
|
||||
protected val method: MethodNode,
|
||||
protected val interpreter: I,
|
||||
private val interpreter: I,
|
||||
private val pruneExceptionEdges: Boolean,
|
||||
) {
|
||||
private val nInsns = method.instructions.size()
|
||||
@@ -26,6 +26,7 @@ abstract class FastAnalyzer<V : Value, I : Interpreter<V>, F : Frame<V>>(
|
||||
|
||||
protected val handlers: Array<MutableList<TryCatchBlockNode>?> = arrayOfNulls(nInsns)
|
||||
protected val isTcbStart = BooleanArray(nInsns)
|
||||
private val isMergeNode = findMergeNodes(method)
|
||||
|
||||
private val queued = BooleanArray(nInsns)
|
||||
private val queue = IntArray(nInsns)
|
||||
@@ -109,7 +110,38 @@ abstract class FastAnalyzer<V : Value, I : Interpreter<V>, F : Frame<V>>(
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun mergeControlFlowEdge(dest: Int, frame: F, canReuse: Boolean = false)
|
||||
protected open fun useFastMergeControlFlowEdge(): Boolean = false
|
||||
|
||||
/**
|
||||
* Updates frame at the index [dest] with its old value if provided and previous control flow node frame [frame].
|
||||
* Reuses old frame when possible and when [canReuse] is true.
|
||||
* If updated, adds the frame to the queue
|
||||
*/
|
||||
private fun mergeControlFlowEdge(dest: Int, frame: F, canReuse: Boolean = false) {
|
||||
val oldFrame = getFrame(dest)
|
||||
val changes = when {
|
||||
canReuse && !isMergeNode[dest] -> {
|
||||
setFrame(dest, frame)
|
||||
true
|
||||
}
|
||||
oldFrame == null -> {
|
||||
setFrame(dest, newFrame(frame.locals, frame.maxStackSize).apply { init(frame) })
|
||||
true
|
||||
}
|
||||
!isMergeNode[dest] -> {
|
||||
oldFrame.init(frame)
|
||||
true
|
||||
}
|
||||
!useFastMergeControlFlowEdge() ->
|
||||
try {
|
||||
oldFrame.merge(frame, interpreter)
|
||||
} catch (e: AnalyzerException) {
|
||||
throw AnalyzerException(null, "${e.message}\nframe: ${frame.dump()}\noldFrame: ${oldFrame.dump()}")
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
updateQueue(changes, dest)
|
||||
}
|
||||
|
||||
private fun analyzeInstruction(
|
||||
insnNode: AbstractInsnNode,
|
||||
@@ -294,4 +326,36 @@ abstract class FastAnalyzer<V : Value, I : Interpreter<V>, F : Frame<V>>(
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-66
@@ -33,8 +33,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.common
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Value
|
||||
@@ -50,8 +49,6 @@ class FastMethodAnalyzer<V : Value>
|
||||
pruneExceptionEdges: Boolean = false,
|
||||
private val createFrame: (Int, Int) -> Frame<V> = { nLocals, nStack -> Frame<V>(nLocals, nStack) }
|
||||
) : FastAnalyzer<V, Interpreter<V>, Frame<V>>(owner, method, interpreter, pruneExceptionEdges) {
|
||||
private val isMergeNode = findMergeNodes(method)
|
||||
|
||||
override fun newFrame(nLocals: Int, nStack: Int): Frame<V> = createFrame(nLocals, nStack)
|
||||
|
||||
override fun beforeAnalyze() {
|
||||
@@ -59,66 +56,4 @@ class FastMethodAnalyzer<V : Value>
|
||||
isTcbStart[tcb.start.indexOf() + 1] = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates frame at the index [dest] with its old value if provided and previous control flow node frame [frame].
|
||||
* Reuses old frame when possible and when [canReuse] is true.
|
||||
* If updated, adds the frame to the queue
|
||||
*/
|
||||
override fun mergeControlFlowEdge(dest: Int, frame: Frame<V>, canReuse: Boolean) {
|
||||
val oldFrame = getFrame(dest)
|
||||
val changes = when {
|
||||
canReuse && !isMergeNode[dest] -> {
|
||||
setFrame(dest, frame)
|
||||
true
|
||||
}
|
||||
oldFrame == null -> {
|
||||
setFrame(dest, newFrame(frame.locals, frame.maxStackSize).apply { init(frame) })
|
||||
true
|
||||
}
|
||||
!isMergeNode[dest] -> {
|
||||
oldFrame.init(frame)
|
||||
true
|
||||
}
|
||||
else ->
|
||||
try {
|
||||
oldFrame.merge(frame, interpreter)
|
||||
} catch (e: AnalyzerException) {
|
||||
throw AnalyzerException(null, "${e.message}\nframe: ${frame.dump()}\noldFrame: ${oldFrame.dump()}")
|
||||
}
|
||||
}
|
||||
updateQueue(changes, dest)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-14
@@ -54,18 +54,5 @@ internal open class FastStackAnalyzer<V : Value, F : Frame<V>>(
|
||||
|
||||
// Don't have to visit the same exception handler multiple times - we care only about stack state at TCB start.
|
||||
override fun useFastComputeExceptionHandlers(): Boolean = true
|
||||
|
||||
override fun mergeControlFlowEdge(dest: Int, frame: F, canReuse: Boolean) {
|
||||
val oldFrame = getFrame(dest)
|
||||
val changes = when {
|
||||
// Don't have to visit the same instruction multiple times - we care only about "initial" stack state.
|
||||
oldFrame == null -> {
|
||||
setFrame(dest, newFrame(frame.locals, frame.maxStackSize).apply { init(frame) })
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
updateQueue(changes, dest)
|
||||
}
|
||||
|
||||
override fun useFastMergeControlFlowEdge(): Boolean = true
|
||||
}
|
||||
|
||||
-20
@@ -34,7 +34,6 @@
|
||||
package org.jetbrains.kotlin.codegen.optimization.temporaryVals
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.FastAnalyzer
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.FastMethodAnalyzer
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.IincInsnNode
|
||||
@@ -68,24 +67,5 @@ class FastStoreLoadAnalyzer<V : Value>(
|
||||
method: MethodNode,
|
||||
interpreter: Interpreter<V>
|
||||
) : FastAnalyzer<V, Interpreter<V>, StoreLoadFrame<V>>(owner, method, interpreter, pruneExceptionEdges = false) {
|
||||
private val isMergeNode = FastMethodAnalyzer.findMergeNodes(method)
|
||||
|
||||
override fun newFrame(nLocals: Int, nStack: Int): StoreLoadFrame<V> = StoreLoadFrame(nLocals)
|
||||
|
||||
override fun mergeControlFlowEdge(dest: Int, frame: StoreLoadFrame<V>, canReuse: Boolean) {
|
||||
val oldFrame = getFrame(dest)
|
||||
val changes = when {
|
||||
oldFrame == null -> {
|
||||
setFrame(dest, newFrame(frame.maxLocals, 0).apply { init(frame) })
|
||||
true
|
||||
}
|
||||
!isMergeNode[dest] -> {
|
||||
oldFrame.init(frame)
|
||||
true
|
||||
}
|
||||
else ->
|
||||
oldFrame.merge(frame, interpreter)
|
||||
}
|
||||
updateQueue(changes, dest)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user