From 641a59dcf286f82d2e2ab843af086d68fdd90e3b Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Tue, 28 Jul 2015 12:36:34 +0300 Subject: [PATCH] - Create independent instances of MandatoryMethodTrasformer. - Properly encapsulate LabelNormalizationMethodTransformer state. --- .../kotlin/codegen/inline/MethodInliner.java | 2 +- .../LabelNormalizationMethodTransformer.kt | 202 +++++++++--------- .../MandatoryMethodTransforker.kt | 9 +- .../OptimizationMethodVisitor.java | 4 +- .../fixStack/FixStackMethodTransformer.kt | 15 +- 5 files changed, 118 insertions(+), 114 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java index a7ac70d4f30..f321b5d0826 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java @@ -375,7 +375,7 @@ public class MethodInliner { node = prepareNode(node, finallyDeepShift); try { - MandatoryMethodTransformer.INSTANCE$.transform("fake", node); + new MandatoryMethodTransformer().transform("fake", node); } catch (Throwable e) { throw wrapException(e, node, "couldn't inline method call"); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/LabelNormalizationMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/LabelNormalizationMethodTransformer.kt index 7528cef9e4d..46493588d6f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/LabelNormalizationMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/LabelNormalizationMethodTransformer.kt @@ -20,136 +20,144 @@ import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.tree.* -public object LabelNormalizationMethodTransformer : MethodTransformer() { - val newLabelNodes = hashMapOf() - val removedLabelNodes = hashSetOf() - +public class LabelNormalizationMethodTransformer : MethodTransformer() { public override fun transform(internalClassName: String, methodNode: MethodNode) { - newLabelNodes.clear() - removedLabelNodes.clear() - - with(methodNode.instructions) { - insertBefore(getFirst(), LabelNode(Label())) - insert(getLast(), LabelNode(Label())) - } - - rewriteLabelInsns(methodNode) - if (removedLabelNodes.isEmpty()) return - - rewriteInsns(methodNode) - rewriteTryCatchBlocks(methodNode) - rewriteLocalVars(methodNode) + TransformerForMethod(methodNode).transform() } - private fun rewriteLabelInsns(methodNode: MethodNode) { - var prevLabelNode: LabelNode? = null - var thisNode = methodNode.instructions.getFirst() - while (thisNode != null) { - if (thisNode is LabelNode) { - if (prevLabelNode != null) { - newLabelNodes[thisNode] = prevLabelNode - removedLabelNodes.add(thisNode) - thisNode = methodNode.instructions.removeNodeGetNext(thisNode) + private class TransformerForMethod(val methodNode: MethodNode) { + val instructions = methodNode.instructions + val newLabelNodes = hashMapOf() + + public fun transform() { + if (rewriteLabelInstructions()) { + rewriteNonLabelInstructions() + rewriteTryCatchBlocks() + rewriteLocalVars() + } + } + + private fun rewriteLabelInstructions(): Boolean { + var removedAnyLabels = false + var thisNode = instructions.first + while (thisNode != null) { + if (thisNode is LabelNode) { + val prevNode = thisNode.previous + if (prevNode is LabelNode) { + newLabelNodes[thisNode.label] = prevNode + removedAnyLabels = true + thisNode = instructions.removeNodeGetNext(thisNode) + } + else { + newLabelNodes[thisNode.label] = thisNode + thisNode = thisNode.next + } } else { - prevLabelNode = thisNode - newLabelNodes[thisNode] = thisNode - thisNode = thisNode.getNext() + thisNode = thisNode.next } } - else { - prevLabelNode = null - thisNode = thisNode.getNext() + return removedAnyLabels + } + + private fun rewriteNonLabelInstructions() { + var thisNode = instructions.first + while (thisNode != null) { + thisNode = when (thisNode) { + is JumpInsnNode -> + rewriteJumpInsn(thisNode) + is LineNumberNode -> + rewriteLineNumberNode(thisNode) + is LookupSwitchInsnNode -> + rewriteLookupSwitchInsn(thisNode) + is TableSwitchInsnNode -> + rewriteTableSwitchInsn(thisNode) + is FrameNode -> + rewriteFrameNode(thisNode) + else -> + thisNode.next + } } } - } - private fun rewriteInsns(methodNode: MethodNode) { - var thisNode = methodNode.instructions.getFirst() - while (thisNode != null) { - thisNode = when (thisNode) { - is JumpInsnNode -> - rewriteJumpInsn(methodNode, thisNode) - is LineNumberNode -> - rewriteLineNumberNode(methodNode, thisNode) - is LookupSwitchInsnNode -> - rewriteLookupSwitchInsn(methodNode, thisNode) - is TableSwitchInsnNode -> - rewriteTableSwitchInsn(methodNode, thisNode) - is FrameNode -> - rewriteFrameNode(methodNode, thisNode) - else -> - thisNode.getNext() - } - } - } + private fun rewriteLineNumberNode(oldLineNode: LineNumberNode): AbstractInsnNode? = + instructions.replaceNodeGetNext(oldLineNode, oldLineNode.rewriteLabels()) - private fun rewriteLineNumberNode(methodNode: MethodNode, oldLineNode: LineNumberNode): AbstractInsnNode? { - if (isRemoved(oldLineNode.start)) { - val newLineNode = oldLineNode.clone(newLabelNodes) - return methodNode.instructions.replaceNodeGetNext(oldLineNode, newLineNode) - } - else { - return oldLineNode.getNext() - } - } + private fun rewriteJumpInsn(oldJumpNode: JumpInsnNode): AbstractInsnNode? = + instructions.replaceNodeGetNext(oldJumpNode, oldJumpNode.rewriteLabels()) - private fun rewriteJumpInsn(methodNode: MethodNode, oldJumpNode: JumpInsnNode): AbstractInsnNode? { - if (isRemoved(oldJumpNode.label)) { - val newJumpNode = oldJumpNode.clone(newLabelNodes) - return methodNode.instructions.replaceNodeGetNext(oldJumpNode, newJumpNode) - } - else { - return oldJumpNode.getNext() - } - } + private fun rewriteLookupSwitchInsn(oldSwitchNode: LookupSwitchInsnNode): AbstractInsnNode? = + instructions.replaceNodeGetNext(oldSwitchNode, oldSwitchNode.rewriteLabels()) - private fun rewriteLookupSwitchInsn(methodNode: MethodNode, oldSwitchNode: LookupSwitchInsnNode): AbstractInsnNode? = - methodNode.instructions.replaceNodeGetNext(oldSwitchNode, oldSwitchNode.clone(newLabelNodes)) + private fun rewriteTableSwitchInsn(oldSwitchNode: TableSwitchInsnNode): AbstractInsnNode? = + instructions.replaceNodeGetNext(oldSwitchNode, oldSwitchNode.rewriteLabels()) - private fun rewriteTableSwitchInsn(methodNode: MethodNode, oldSwitchNode: TableSwitchInsnNode): AbstractInsnNode? = - methodNode.instructions.replaceNodeGetNext(oldSwitchNode, oldSwitchNode.clone(newLabelNodes)) + private fun rewriteFrameNode(oldFrameNode: FrameNode): AbstractInsnNode? = + instructions.replaceNodeGetNext(oldFrameNode, oldFrameNode.rewriteLabels()) - private fun rewriteFrameNode(methodNode: MethodNode, oldFrameNode: FrameNode): AbstractInsnNode? = - methodNode.instructions.replaceNodeGetNext(oldFrameNode, oldFrameNode.clone(newLabelNodes)) - - private fun rewriteTryCatchBlocks(methodNode: MethodNode) { - methodNode.tryCatchBlocks = methodNode.tryCatchBlocks.map { oldTcb -> - if (isRemoved(oldTcb.start) || isRemoved(oldTcb.end) || isRemoved(oldTcb.handler)) { + private fun rewriteTryCatchBlocks() { + methodNode.tryCatchBlocks = methodNode.tryCatchBlocks.map { oldTcb -> val newTcb = TryCatchBlockNode(getNew(oldTcb.start), getNew(oldTcb.end), getNew(oldTcb.handler), oldTcb.type) newTcb.visibleTypeAnnotations = oldTcb.visibleTypeAnnotations newTcb.invisibleTypeAnnotations = oldTcb.invisibleTypeAnnotations newTcb } - else { - oldTcb + } + + private fun rewriteLocalVars() { + methodNode.localVariables = methodNode.localVariables.map { oldVar -> + LocalVariableNode( + oldVar.name, + oldVar.desc, + oldVar.signature, + getNew(oldVar.start), + getNew(oldVar.end), + oldVar.index + ) } } - } - private fun rewriteLocalVars(methodNode: MethodNode) { - methodNode.localVariables = methodNode.localVariables.map { oldVar -> - if (isRemoved(oldVar.start) || isRemoved(oldVar.end)) { - LocalVariableNode(oldVar.name, oldVar.desc, oldVar.signature, getNew(oldVar.start), getNew(oldVar.end), oldVar.index) - } - else { - oldVar - } + private fun LineNumberNode.rewriteLabels(): AbstractInsnNode = + LineNumberNode(line, getNewOrOld(start)) + + private fun JumpInsnNode.rewriteLabels(): AbstractInsnNode = + JumpInsnNode(opcode, getNew(label)) + + private fun LookupSwitchInsnNode.rewriteLabels(): AbstractInsnNode { + val switchNode = LookupSwitchInsnNode(getNew(dflt), keys.toIntArray(), emptyArray()) + switchNode.labels = labels.map { getNew(it) } + return switchNode } - } - private fun isRemoved(labelNode: LabelNode): Boolean = removedLabelNodes.contains(labelNode) - private fun getNew(oldLabelNode: LabelNode): LabelNode = newLabelNodes[oldLabelNode]!! + private fun TableSwitchInsnNode.rewriteLabels(): AbstractInsnNode { + val switchNode = TableSwitchInsnNode(min, max, getNew(dflt)) + switchNode.labels = labels.map { getNew(it) } + return switchNode + } + + private fun FrameNode.rewriteLabels(): AbstractInsnNode { + val frameNode = FrameNode(type, 0, emptyArray(), 0, emptyArray()) + frameNode.local = local.map { if (it is LabelNode) getNewOrOld(it) else it } + frameNode.stack = stack.map { if (it is LabelNode) getNewOrOld(it) else it } + return frameNode + } + + private fun getNew(oldLabelNode: LabelNode): LabelNode = + newLabelNodes[oldLabelNode.label]!! + + private fun getNewOrOld(oldLabelNode: LabelNode): LabelNode = + newLabelNodes[oldLabelNode.label] ?: oldLabelNode + } } private fun InsnList.replaceNodeGetNext(oldNode: AbstractInsnNode, newNode: AbstractInsnNode): AbstractInsnNode? { insertBefore(oldNode, newNode) remove(oldNode) - return newNode.getNext() + return newNode.next } private fun InsnList.removeNodeGetNext(oldNode: AbstractInsnNode): AbstractInsnNode? { - val next = oldNode.getNext() + val next = oldNode.next remove(oldNode) return next } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/MandatoryMethodTransforker.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/MandatoryMethodTransforker.kt index 2772abf06c2..ccf606a6042 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/MandatoryMethodTransforker.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/MandatoryMethodTransforker.kt @@ -20,9 +20,12 @@ import org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackMethodTransfor import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer import org.jetbrains.org.objectweb.asm.tree.MethodNode -public object MandatoryMethodTransformer : MethodTransformer() { +public class MandatoryMethodTransformer : MethodTransformer() { + private val labelNormalization = LabelNormalizationMethodTransformer() + private val fixStack = FixStackMethodTransformer() + public override fun transform(internalClassName: String, methodNode: MethodNode) { - LabelNormalizationMethodTransformer.transform(internalClassName, methodNode) - FixStackMethodTransformer.transform(internalClassName, methodNode) + labelNormalization.transform(internalClassName, methodNode) + fixStack.transform(internalClassName, methodNode) } } \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationMethodVisitor.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationMethodVisitor.java index 8027d2e79e3..a80ca87939b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationMethodVisitor.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationMethodVisitor.java @@ -37,6 +37,8 @@ import java.util.List; public class OptimizationMethodVisitor extends MethodVisitor { private static final int MEMORY_LIMIT_BY_METHOD_MB = 50; + private static final MethodTransformer MANDATORY_METHOD_TRANSFORMER = new MandatoryMethodTransformer(); + private static final MethodTransformer[] OPTIMIZATION_TRANSFORMERS = new MethodTransformer[] { new RedundantNullCheckMethodTransformer(), new RedundantBoxingMethodTransformer(), @@ -75,7 +77,7 @@ public class OptimizationMethodVisitor extends MethodVisitor { super.visitEnd(); if (shouldBeTransformed(methodNode)) { - MandatoryMethodTransformer.INSTANCE$.transform("fake", methodNode); + MANDATORY_METHOD_TRANSFORMER.transform("fake", methodNode); if (canBeOptimized(methodNode) && !disableOptimization) { for (MethodTransformer transformer : OPTIMIZATION_TRANSFORMERS) { transformer.transform("fake", methodNode); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackMethodTransformer.kt index aa610fb0e5c..cd1d17d0906 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackMethodTransformer.kt @@ -16,24 +16,15 @@ package org.jetbrains.kotlin.codegen.optimization.fixStack -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.MethodAnalyzer -import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter -import org.jetbrains.kotlin.codegen.optimization.fixStack.forEachPseudoInsn import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer 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.* -import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue -import org.jetbrains.org.objectweb.asm.tree.analysis.Frame -import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter -import java.util.* -import kotlin.properties.Delegates +import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode +import org.jetbrains.org.objectweb.asm.tree.MethodNode -public object FixStackMethodTransformer : MethodTransformer() { +public class FixStackMethodTransformer : MethodTransformer() { public override fun transform(internalClassName: String, methodNode: MethodNode) { val context = FixStackContext(methodNode)