From 3a5197d1ae4ceeb714c01e2b33a0fccf9988a9f3 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Mon, 6 Jun 2016 21:10:14 +0300 Subject: [PATCH] Minor. Simplify collecting save/restore markers for FixStackMethodTransformer --- .../fixStack/AnalyzeTryCatchBlocks.kt | 67 +++++++++++-------- .../optimization/fixStack/FixStackContext.kt | 55 +++------------ 2 files changed, 49 insertions(+), 73 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/AnalyzeTryCatchBlocks.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/AnalyzeTryCatchBlocks.kt index 145fb558909..300b7ab9aa0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/AnalyzeTryCatchBlocks.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/AnalyzeTryCatchBlocks.kt @@ -19,14 +19,16 @@ package org.jetbrains.kotlin.codegen.optimization.fixStack import com.sun.xml.internal.ws.org.objectweb.asm.Opcodes import org.jetbrains.kotlin.codegen.optimization.common.findNextOrNull import org.jetbrains.kotlin.codegen.optimization.common.hasOpcode -import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn import org.jetbrains.org.objectweb.asm.Label -import org.jetbrains.org.objectweb.asm.tree.* -import org.jetbrains.org.objectweb.asm.util.Printer +import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode +import org.jetbrains.org.objectweb.asm.tree.LabelNode +import org.jetbrains.org.objectweb.asm.tree.MethodNode +import org.jetbrains.org.objectweb.asm.tree.TryCatchBlockNode import java.util.* private class DecompiledTryDescriptor(val tryStartLabel: LabelNode) { + // Only used for assertions var defaultHandlerTcb : TryCatchBlockNode? = null val handlerStartLabels = hashSetOf() } @@ -37,20 +39,17 @@ private fun TryCatchBlockNode.isDefaultHandlerNode(): Boolean = private fun MethodNode.debugString(tcb: TryCatchBlockNode): String = "TCB<${instructions.indexOf(tcb.start)}, ${instructions.indexOf(tcb.end)}, ${instructions.indexOf(tcb.handler)}>" -internal fun insertTryCatchBlocksMarkers(methodNode: MethodNode) { - if (methodNode.tryCatchBlocks.isEmpty()) return - - val decompiledTryDescriptorForStart = linkedMapOf() - val decompiledTryDescriptorForHandler = hashMapOf() - - collectDecompiledTryDescriptors(decompiledTryDescriptorForStart, decompiledTryDescriptorForHandler, methodNode) +internal fun insertTryCatchBlocksMarkers(methodNode: MethodNode): Map { + if (methodNode.tryCatchBlocks.isEmpty()) return emptyMap() + val decompiledTryDescriptorForStart = collectDecompiledTryDescriptors(methodNode) val newTryStartLabels = hashMapOf() - - insertSaveRestoreStackMarkers(decompiledTryDescriptorForStart, methodNode, newTryStartLabels) + val restoreStackToSaveStackMarker = insertSaveRestoreStackMarkers(decompiledTryDescriptorForStart, methodNode, newTryStartLabels) transformTryCatchBlocks(methodNode, newTryStartLabels) + + return restoreStackToSaveStackMarker } private fun transformTryCatchBlocks(methodNode: MethodNode, newTryStartLabels: HashMap) { @@ -67,24 +66,34 @@ private fun insertSaveRestoreStackMarkers( decompiledTryDescriptorForStart: Map, methodNode: MethodNode, newTryStartLabels: MutableMap -) { - val doneTryStartLabels = hashSetOf() +): Map { + val restoreStackToSaveMarker = hashMapOf() + val saveStackMarkerByTryLabel = hashMapOf() val doneHandlerLabels = hashSetOf() for (decompiledTryDescriptor in decompiledTryDescriptorForStart.values) { with(decompiledTryDescriptor) { - if (!doneTryStartLabels.contains(tryStartLabel)) { - doneTryStartLabels.add(tryStartLabel) + val saveStackMarker: AbstractInsnNode + if (tryStartLabel !in saveStackMarkerByTryLabel) { val nopNode = tryStartLabel.findNextOrNull { it.hasOpcode() }!! - assert(nopNode.getOpcode() == Opcodes.NOP) { "${methodNode.instructions.indexOf(nopNode)}: try block should start with NOP" } + assert(nopNode.opcode == Opcodes.NOP) { "${methodNode.instructions.indexOf(nopNode)}: try block should start with NOP" } val newTryStartLabel = LabelNode(Label()) newTryStartLabels[tryStartLabel] = newTryStartLabel - methodNode.instructions.insertBefore(nopNode, PseudoInsn.SAVE_STACK_BEFORE_TRY.createInsnNode()) + saveStackMarker = PseudoInsn.SAVE_STACK_BEFORE_TRY.createInsnNode() + val restoreStackMarker = PseudoInsn.RESTORE_STACK_IN_TRY_CATCH.createInsnNode() + + saveStackMarkerByTryLabel[tryStartLabel] = saveStackMarker + restoreStackToSaveMarker[restoreStackMarker] = saveStackMarker + + methodNode.instructions.insertBefore(nopNode, saveStackMarker) methodNode.instructions.insertBefore(nopNode, newTryStartLabel) - methodNode.instructions.insert(nopNode, PseudoInsn.RESTORE_STACK_IN_TRY_CATCH.createInsnNode()) + methodNode.instructions.insert(nopNode, restoreStackMarker) + } + else { + saveStackMarker = saveStackMarkerByTryLabel[tryStartLabel]!! } for (handlerStartLabel in handlerStartLabels) { @@ -92,20 +101,22 @@ private fun insertSaveRestoreStackMarkers( doneHandlerLabels.add(handlerStartLabel) val storeNode = handlerStartLabel.findNextOrNull { it.hasOpcode() }!! - assert(storeNode.getOpcode() == Opcodes.ASTORE) { "${methodNode.instructions.indexOf(storeNode)}: handler should start with ASTORE" } + assert(storeNode.opcode == Opcodes.ASTORE) { "${methodNode.instructions.indexOf(storeNode)}: handler should start with ASTORE" } - methodNode.instructions.insert(storeNode, PseudoInsn.RESTORE_STACK_IN_TRY_CATCH.createInsnNode()) + val restoreStackMarker = PseudoInsn.RESTORE_STACK_IN_TRY_CATCH.createInsnNode() + restoreStackToSaveMarker[restoreStackMarker] = saveStackMarker + methodNode.instructions.insert(storeNode, restoreStackMarker) } } } } + + return restoreStackToSaveMarker } -private fun collectDecompiledTryDescriptors( - decompiledTryDescriptorForStart: MutableMap, - decompiledTryDescriptorForHandler: MutableMap, - methodNode: MethodNode -) { +private fun collectDecompiledTryDescriptors(methodNode: MethodNode): Map { + val decompiledTryDescriptorForStart: MutableMap = hashMapOf() + val decompiledTryDescriptorForHandler: MutableMap = hashMapOf() for (tcb in methodNode.tryCatchBlocks) { if (tcb.isDefaultHandlerNode()) { assert(decompiledTryDescriptorForHandler.containsKey(tcb.start)) { "${methodNode.debugString(tcb)}: default handler should occur after some regular handler" } @@ -128,4 +139,6 @@ private fun collectDecompiledTryDescriptors( } } } -} \ No newline at end of file + + return decompiledTryDescriptorForStart +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackContext.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackContext.kt index 10b4bcd379b..71986dbadde 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackContext.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackContext.kt @@ -17,18 +17,14 @@ package org.jetbrains.kotlin.codegen.optimization.fixStack import com.intellij.util.SmartList -import com.intellij.util.containers.SmartHashSet import com.intellij.util.containers.Stack import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence -import org.jetbrains.kotlin.codegen.optimization.common.findPreviousOrNull -import org.jetbrains.kotlin.codegen.optimization.common.hasOpcode import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn import org.jetbrains.kotlin.codegen.pseudoInsns.parsePseudoInsnOrNull import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode import org.jetbrains.org.objectweb.asm.tree.JumpInsnNode -import org.jetbrains.org.objectweb.asm.tree.LabelNode import org.jetbrains.org.objectweb.asm.tree.MethodNode internal class FixStackContext(val methodNode: MethodNode) { @@ -36,15 +32,19 @@ internal class FixStackContext(val methodNode: MethodNode) { val fakeAlwaysTrueIfeqMarkers = arrayListOf() val fakeAlwaysFalseIfeqMarkers = arrayListOf() - val saveStackNodesForTryStartLabel = hashMapOf() - val saveStackMarkerForRestoreMarker = hashMapOf() + val isThereAnyTryCatch: Boolean + val saveStackMarkerForRestoreMarker: Map val restoreStackMarkersForSaveMarker = hashMapOf>() val openingInlineMethodMarker = hashMapOf() var consistentInlineMarkers: Boolean = true; private set init { - insertTryCatchBlocksMarkers(methodNode) + saveStackMarkerForRestoreMarker = insertTryCatchBlocksMarkers(methodNode) + isThereAnyTryCatch = saveStackMarkerForRestoreMarker.isNotEmpty() + for ((restore, save) in saveStackMarkerForRestoreMarker) { + restoreStackMarkersForSaveMarker.getOrPut(save) { SmartList() }.add(restore) + } val inlineMarkersStack = Stack() @@ -57,10 +57,6 @@ internal class FixStackContext(val methodNode: MethodNode) { visitFakeAlwaysTrueIfeq(insnNode) pseudoInsn == PseudoInsn.FAKE_ALWAYS_FALSE_IFEQ -> visitFakeAlwaysFalseIfeq(insnNode) - pseudoInsn == PseudoInsn.SAVE_STACK_BEFORE_TRY -> - visitSaveStackBeforeTry(insnNode) - pseudoInsn == PseudoInsn.RESTORE_STACK_IN_TRY_CATCH -> - visitRestoreStackInTryCatch(insnNode) InlineCodegenUtil.isBeforeInlineMarker(insnNode) -> { inlineMarkersStack.push(insnNode) } @@ -92,51 +88,18 @@ internal class FixStackContext(val methodNode: MethodNode) { fakeAlwaysFalseIfeqMarkers.add(insnNode) } - private fun visitSaveStackBeforeTry(insnNode: AbstractInsnNode) { - val tryStartLabel = insnNode.next - assert(tryStartLabel is LabelNode) { "${indexOf(insnNode)}: save should be followed by a label" } - saveStackNodesForTryStartLabel[tryStartLabel as LabelNode] = insnNode - } - - private fun visitRestoreStackInTryCatch(insnNode: AbstractInsnNode) { - val restoreLabel = insnNode.findPreviousOrNull { it.hasOpcode() }!!.findPreviousOrNull { it is LabelNode || it.hasOpcode() }!! - if (restoreLabel !is LabelNode) { - throw AssertionError("${indexOf(insnNode)}: restore should be preceded by a catch block label") - } - val saveNodes = findMatchingSaveNodes(restoreLabel) - if (saveNodes.isEmpty()) { - throw AssertionError("${indexOf(insnNode)}: in handler ${indexOf(restoreLabel)} restore is not matched with save") - } - else if (saveNodes.size > 1) { - throw AssertionError("${indexOf(insnNode)}: in handler ${indexOf(restoreLabel)} restore is matched with several saves") - } - val saveNode = saveNodes.first() - saveStackMarkerForRestoreMarker[insnNode] = saveNode - restoreStackMarkersForSaveMarker.getOrPut(saveNode, { SmartList() }).add(insnNode) - } - - private fun findMatchingSaveNodes(restoreLabel: LabelNode): List { - val saveNodes = SmartHashSet() - methodNode.tryCatchBlocks.forEach { tcb -> - if (restoreLabel == tcb.start || restoreLabel == tcb.handler) { - saveStackNodesForTryStartLabel[tcb.start]?.let { saveNodes.add(it) } - } - } - return SmartList(saveNodes) - } - private fun indexOf(node: AbstractInsnNode) = methodNode.instructions.indexOf(node) fun hasAnyMarkers(): Boolean = breakContinueGotoNodes.isNotEmpty() || fakeAlwaysTrueIfeqMarkers.isNotEmpty() || fakeAlwaysFalseIfeqMarkers.isNotEmpty() || - saveStackNodesForTryStartLabel.isNotEmpty() || + isThereAnyTryCatch || openingInlineMethodMarker.isNotEmpty() fun isAnalysisRequired(): Boolean = breakContinueGotoNodes.isNotEmpty() || - saveStackNodesForTryStartLabel.isNotEmpty() || + isThereAnyTryCatch || openingInlineMethodMarker.isNotEmpty() }