diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/StackPeepholeOptimizationsTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/StackPeepholeOptimizationsTransformer.kt index 931871af16a..d3821c73eec 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/StackPeepholeOptimizationsTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/StackPeepholeOptimizationsTransformer.kt @@ -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 { 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 0c3d742b773..b16cffa0fb0 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 @@ -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, F : Frame>( - 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, F : Frame>( protected val handlers: Array?> = 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, F : Frame>( } } - 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, F : Frame>( 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 + } + } } \ No newline at end of file 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 accbc9501cb..3449d0602c8 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 @@ -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 pruneExceptionEdges: Boolean = false, private val createFrame: (Int, Int) -> Frame = { nLocals, nStack -> Frame(nLocals, nStack) } ) : FastAnalyzer, Frame>(owner, method, interpreter, pruneExceptionEdges) { - private val isMergeNode = findMergeNodes(method) - override fun newFrame(nLocals: Int, nStack: Int): Frame = createFrame(nLocals, nStack) override fun beforeAnalyze() { @@ -59,66 +56,4 @@ class FastMethodAnalyzer 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, 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 - } - } } 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 0abe45cb297..c55da6a9ad5 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,18 +54,5 @@ internal open class FastStackAnalyzer>( // 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 } 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 7362057bdf5..05943f3f0f7 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 @@ -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( method: MethodNode, interpreter: Interpreter ) : FastAnalyzer, StoreLoadFrame>(owner, method, interpreter, pruneExceptionEdges = false) { - private val isMergeNode = FastMethodAnalyzer.findMergeNodes(method) - override fun newFrame(nLocals: Int, nStack: Int): StoreLoadFrame = StoreLoadFrame(nLocals) - - override fun mergeControlFlowEdge(dest: Int, frame: StoreLoadFrame, 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) - } } \ No newline at end of file