diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FastAnalyzer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FastAnalyzer.kt index bce205d5eed..c261e86e53c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FastAnalyzer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FastAnalyzer.kt @@ -29,6 +29,8 @@ abstract class FastAnalyzer, F : Frame>( private val queue = IntArray(nInsns) private var top = 0 + protected open fun visitControlFlowEdge(insnNode: AbstractInsnNode, successor: Int): Boolean = true + fun analyze(): Array?> { if (nInsns == 0) return frames @@ -101,6 +103,12 @@ abstract class FastAnalyzer, F : Frame>( } } + protected fun processControlFlowEdge(current: F, insnNode: AbstractInsnNode, jump: Int) { + if (visitControlFlowEdge(insnNode, jump)) { + mergeControlFlowEdge(jump, current) + } + } + protected abstract fun mergeControlFlowEdge(dest: Int, frame: F, canReuse: Boolean = false) protected abstract fun analyzeInstruction( @@ -140,10 +148,35 @@ abstract class FastAnalyzer, F : Frame>( } } - protected abstract fun visitJumpInsnNode(insnNode: JumpInsnNode, current: F, insn: Int, insnOpcode: Int) - protected abstract fun visitLookupSwitchInsnNode(insnNode: LookupSwitchInsnNode, current: F) - protected abstract fun visitTableSwitchInsnNode(insnNode: TableSwitchInsnNode, current: F) - protected abstract fun visitOpInsn(insnNode: AbstractInsnNode, current: F, insn: Int) + private fun visitOpInsn(insnNode: AbstractInsnNode, current: F, insn: Int) { + processControlFlowEdge(current, insnNode, insn + 1) + } + + private fun visitTableSwitchInsnNode(insnNode: TableSwitchInsnNode, current: F) { + processControlFlowEdge(current, insnNode, insnNode.dflt.indexOf()) + // In most cases order of visiting switch labels should not matter + // The only one is a tableswitch being added in the beginning of coroutine method, these switch' labels may lead + // in the middle of try/catch block, and FastAnalyzer is not ready for this (trying to restore stack before it was saved) + // So we just fix the order of labels being traversed: the first one should be one at the method beginning + // Using 'asReversed' is because nodes are processed in LIFO order + for (label in insnNode.labels.asReversed()) { + processControlFlowEdge(current, insnNode, label.indexOf()) + } + } + + private fun visitLookupSwitchInsnNode(insnNode: LookupSwitchInsnNode, current: F) { + processControlFlowEdge(current, insnNode, insnNode.dflt.indexOf()) + for (label in insnNode.labels) { + processControlFlowEdge(current, insnNode, label.indexOf()) + } + } + + private fun visitJumpInsnNode(insnNode: JumpInsnNode, current: F, insn: Int, insnOpcode: Int) { + if (insnOpcode != Opcodes.GOTO) { + processControlFlowEdge(current, insnNode, insn + 1) + } + processControlFlowEdge(current, insnNode, insnNode.label.indexOf()) + } private fun checkAssertions() { if (method.instructions.any { it.opcode == Opcodes.JSR || it.opcode == Opcodes.RET }) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FastMethodAnalyzer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FastMethodAnalyzer.kt index 433d23e9baf..1a4e2b97640 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FastMethodAnalyzer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FastMethodAnalyzer.kt @@ -104,36 +104,6 @@ class FastMethodAnalyzer } } - override fun visitOpInsn(insnNode: AbstractInsnNode, current: Frame, insn: Int) { - mergeControlFlowEdge(insn + 1, current) - } - - override fun visitTableSwitchInsnNode(insnNode: TableSwitchInsnNode, current: Frame) { - mergeControlFlowEdge(insnNode.dflt.indexOf(), current) - // In most cases order of visiting switch labels should not matter - // The only one is a tableswitch being added in the beginning of coroutine method, these switch' labels may lead - // in the middle of try/catch block, and FixStackAnalyzer is not ready for this (trying to restore stack before it was saved) - // So we just fix the order of labels being traversed: the first one should be one at the method beginning - // Using 'reversed' is because nodes are processed in LIFO order - for (label in insnNode.labels.asReversed()) { - mergeControlFlowEdge(label.indexOf(), current) - } - } - - override fun visitLookupSwitchInsnNode(insnNode: LookupSwitchInsnNode, current: Frame) { - mergeControlFlowEdge(insnNode.dflt.indexOf(), current) - for (label in insnNode.labels) { - mergeControlFlowEdge(label.indexOf(), current) - } - } - - override fun visitJumpInsnNode(insnNode: JumpInsnNode, current: Frame, insn: Int, insnOpcode: Int) { - mergeControlFlowEdge(insnNode.label.indexOf(), current) - if (insnOpcode != Opcodes.GOTO) { - mergeControlFlowEdge(insn + 1, current) - } - } - /** * 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. diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FastStackAnalyzer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FastStackAnalyzer.kt index be0ab9a7d4b..680c90b5dd0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FastStackAnalyzer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FastStackAnalyzer.kt @@ -54,8 +54,6 @@ internal open class FastStackAnalyzer>( @Suppress("UNCHECKED_CAST") override fun newFrame(nLocals: Int, nStack: Int): F = Frame(nLocals, nStack) as F - protected open fun visitControlFlowEdge(insnNode: AbstractInsnNode, successor: Int): Boolean = true - // 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 @@ -90,51 +88,10 @@ internal open class FastStackAnalyzer>( } } - override fun visitOpInsn(insnNode: AbstractInsnNode, current: F, insn: Int) { - processControlFlowEdge(current, insnNode, insn + 1) - } - private fun visitNopInsn(insnNode: AbstractInsnNode, f: F, insn: Int) { processControlFlowEdge(f, insnNode, insn + 1) } - override fun visitTableSwitchInsnNode(insnNode: TableSwitchInsnNode, current: F) { - var jump = insnNode.dflt.indexOf() - processControlFlowEdge(current, insnNode, jump) - // In most cases order of visiting switch labels should not matter - // The only one is a tableswitch being added in the beginning of coroutine method, these switch' labels may lead - // in the middle of try/catch block, and FixStackAnalyzer is not ready for this (trying to restore stack before it was saved) - // So we just fix the order of labels being traversed: the first one should be one at the method beginning - // Using 'reversed' is because nodes are processed in LIFO order - for (label in insnNode.labels.reversed()) { - jump = label.indexOf() - processControlFlowEdge(current, insnNode, jump) - } - } - - override fun visitLookupSwitchInsnNode(insnNode: LookupSwitchInsnNode, current: F) { - var jump = insnNode.dflt.indexOf() - processControlFlowEdge(current, insnNode, jump) - for (label in insnNode.labels) { - jump = label.indexOf() - processControlFlowEdge(current, insnNode, jump) - } - } - - override fun visitJumpInsnNode(insnNode: JumpInsnNode, current: F, insn: Int, insnOpcode: Int) { - if (insnOpcode != Opcodes.GOTO) { - processControlFlowEdge(current, insnNode, insn + 1) - } - val jump = insnNode.label.indexOf() - processControlFlowEdge(current, insnNode, jump) - } - - private fun processControlFlowEdge(current: F, insnNode: AbstractInsnNode, jump: Int) { - if (visitControlFlowEdge(insnNode, jump)) { - mergeControlFlowEdge(jump, current) - } - } - override fun mergeControlFlowEdge(dest: Int, frame: F, canReuse: Boolean) { val oldFrame = getFrame(dest) val changes = when { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/temporaryVals/FastStoreLoadAnalyzer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/temporaryVals/FastStoreLoadAnalyzer.kt index b81f3ca449b..7c7954495e3 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/temporaryVals/FastStoreLoadAnalyzer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/temporaryVals/FastStoreLoadAnalyzer.kt @@ -36,8 +36,10 @@ 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.Opcodes.API_VERSION -import org.jetbrains.org.objectweb.asm.tree.* +import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode +import org.jetbrains.org.objectweb.asm.tree.IincInsnNode +import org.jetbrains.org.objectweb.asm.tree.MethodNode +import org.jetbrains.org.objectweb.asm.tree.VarInsnNode 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 @@ -91,32 +93,7 @@ class FastStoreLoadAnalyzer( } } - override fun newFrame(nLocals: Int, nStack: Int): StoreLoadFrame = StoreLoadFrame(nLocals) - - override fun visitOpInsn(insnNode: AbstractInsnNode, current: StoreLoadFrame, insn: Int) { - mergeControlFlowEdge(insn + 1, current) - } - - override fun visitTableSwitchInsnNode(insnNode: TableSwitchInsnNode, current: StoreLoadFrame) { - mergeControlFlowEdge(insnNode.dflt.indexOf(), current) - for (label in insnNode.labels) { - mergeControlFlowEdge(label.indexOf(), current) - } - } - - override fun visitLookupSwitchInsnNode(insnNode: LookupSwitchInsnNode, current: StoreLoadFrame) { - mergeControlFlowEdge(insnNode.dflt.indexOf(), current) - for (label in insnNode.labels) { - mergeControlFlowEdge(label.indexOf(), current) - } - } - - override fun visitJumpInsnNode(insnNode: JumpInsnNode, current: StoreLoadFrame, insn: Int, insnOpcode: Int) { - if (insnOpcode != Opcodes.GOTO) { - mergeControlFlowEdge(insn + 1, current) - } - mergeControlFlowEdge(insnNode.label.indexOf(), current) - } + override fun newFrame(nLocals: Int, nStack: Int): StoreLoadFrame = StoreLoadFrame(nLocals) override fun mergeControlFlowEdge(dest: Int, frame: StoreLoadFrame, canReuse: Boolean) { val oldFrame = getFrame(dest)