[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
|
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.common.findPreviousOrNull
|
||||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
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() {
|
class StackPeepholeOptimizationsTransformer : MethodTransformer() {
|
||||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||||
@@ -33,7 +36,7 @@ class StackPeepholeOptimizationsTransformer : MethodTransformer() {
|
|||||||
val instructions = methodNode.instructions
|
val instructions = methodNode.instructions
|
||||||
var changed = false
|
var changed = false
|
||||||
|
|
||||||
val isMergeNode = FastMethodAnalyzer.findMergeNodes(methodNode)
|
val isMergeNode = FastAnalyzer.findMergeNodes(methodNode)
|
||||||
|
|
||||||
fun AbstractInsnNode.previousMeaningful() =
|
fun AbstractInsnNode.previousMeaningful() =
|
||||||
findPreviousOrNull {
|
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
|
import org.jetbrains.org.objectweb.asm.tree.analysis.Value
|
||||||
|
|
||||||
abstract class FastAnalyzer<V : Value, I : Interpreter<V>, F : Frame<V>>(
|
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 method: MethodNode,
|
||||||
protected val interpreter: I,
|
private val interpreter: I,
|
||||||
private val pruneExceptionEdges: Boolean,
|
private val pruneExceptionEdges: Boolean,
|
||||||
) {
|
) {
|
||||||
private val nInsns = method.instructions.size()
|
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 handlers: Array<MutableList<TryCatchBlockNode>?> = arrayOfNulls(nInsns)
|
||||||
protected val isTcbStart = BooleanArray(nInsns)
|
protected val isTcbStart = BooleanArray(nInsns)
|
||||||
|
private val isMergeNode = findMergeNodes(method)
|
||||||
|
|
||||||
private val queued = BooleanArray(nInsns)
|
private val queued = BooleanArray(nInsns)
|
||||||
private val queue = IntArray(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(
|
private fun analyzeInstruction(
|
||||||
insnNode: AbstractInsnNode,
|
insnNode: AbstractInsnNode,
|
||||||
@@ -294,4 +326,36 @@ abstract class FastAnalyzer<V : Value, I : Interpreter<V>, F : Frame<V>>(
|
|||||||
append("}\n")
|
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
|
package org.jetbrains.kotlin.codegen.optimization.common
|
||||||
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.*
|
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||||
import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException
|
|
||||||
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.Interpreter
|
import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
|
||||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Value
|
import org.jetbrains.org.objectweb.asm.tree.analysis.Value
|
||||||
@@ -50,8 +49,6 @@ class FastMethodAnalyzer<V : Value>
|
|||||||
pruneExceptionEdges: Boolean = false,
|
pruneExceptionEdges: Boolean = false,
|
||||||
private val createFrame: (Int, Int) -> Frame<V> = { nLocals, nStack -> Frame<V>(nLocals, nStack) }
|
private val createFrame: (Int, Int) -> Frame<V> = { nLocals, nStack -> Frame<V>(nLocals, nStack) }
|
||||||
) : FastAnalyzer<V, Interpreter<V>, Frame<V>>(owner, method, interpreter, pruneExceptionEdges) {
|
) : 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 newFrame(nLocals: Int, nStack: Int): Frame<V> = createFrame(nLocals, nStack)
|
||||||
|
|
||||||
override fun beforeAnalyze() {
|
override fun beforeAnalyze() {
|
||||||
@@ -59,66 +56,4 @@ class FastMethodAnalyzer<V : Value>
|
|||||||
isTcbStart[tcb.start.indexOf() + 1] = true
|
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.
|
// 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 useFastComputeExceptionHandlers(): Boolean = true
|
||||||
|
override fun useFastMergeControlFlowEdge(): 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
-20
@@ -34,7 +34,6 @@
|
|||||||
package org.jetbrains.kotlin.codegen.optimization.temporaryVals
|
package org.jetbrains.kotlin.codegen.optimization.temporaryVals
|
||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.FastAnalyzer
|
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.Opcodes
|
||||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||||
import org.jetbrains.org.objectweb.asm.tree.IincInsnNode
|
import org.jetbrains.org.objectweb.asm.tree.IincInsnNode
|
||||||
@@ -68,24 +67,5 @@ class FastStoreLoadAnalyzer<V : Value>(
|
|||||||
method: MethodNode,
|
method: MethodNode,
|
||||||
interpreter: Interpreter<V>
|
interpreter: Interpreter<V>
|
||||||
) : FastAnalyzer<V, Interpreter<V>, StoreLoadFrame<V>>(owner, method, interpreter, pruneExceptionEdges = false) {
|
) : 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 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