From bd25bf14df7a43ba2a18440b5c1e1ac9469d54ba Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Wed, 24 Jan 2018 14:13:36 +0300 Subject: [PATCH] Minor: reformat code in org.jetbrains.kotlin.codegen.optimization --- ...sionCallsPreprocessingMethodTransformer.kt | 48 +++--- ...pturedVarsOptimizationMethodTransformer.kt | 48 +++--- ...ntConditionEliminationMethodTransformer.kt | 73 ++++---- .../DeadCodeEliminationMethodTransformer.kt | 18 +- ...WithLabelNormalizationMethodTransformer.kt | 6 +- .../LabelNormalizationMethodTransformer.kt | 36 ++-- .../codegen/optimization/MethodVerifier.kt | 3 +- .../optimization/OptimizationMethodVisitor.kt | 44 ++--- .../RedundantCheckCastElimination.kt | 5 +- .../RedundantGotoMethodTransformer.kt | 14 +- .../RedundantNopsCleanupMethodTransformer.kt | 8 +- .../UninitializedStoresMethodTransformer.kt | 2 +- .../optimization/boxing/BoxedBasicValue.kt | 18 +- .../optimization/boxing/BoxingInterpreter.kt | 162 +++++++++--------- .../PopBackwardPropagationTransformer.kt | 68 ++++---- .../boxing/ProgressionIteratorBasicValue.java | 2 + .../boxing/RedundantBoxingInterpreter.kt | 27 ++- .../RedundantBoxingMethodTransformer.kt | 126 +++++++------- .../StackPeepholeOptimizationsTransformer.kt | 29 ++-- .../common/CustomFramesMethodAnalyzer.kt | 4 +- .../optimization/common/MethodAnalyzer.kt | 36 ++-- .../common/ReferenceTrackingInterpreter.kt | 77 ++++----- .../common/TrackedReferenceValue.kt | 27 +-- .../codegen/optimization/common/Util.kt | 49 +++--- .../optimization/common/variableLiveness.kt | 22 +-- .../fixStack/AnalyzeTryCatchBlocks.kt | 15 +- .../optimization/fixStack/FixStackAnalyzer.kt | 28 ++- .../optimization/fixStack/FixStackContext.kt | 16 +- .../fixStack/FixStackMethodTransformer.kt | 76 ++++---- .../fixStack/LocalVariablesManager.kt | 19 +- .../fixStack/StackTransformationUtils.kt | 56 +++--- .../nullCheck/NullabilityInterpreter.kt | 38 ++-- .../RedundantNullCheckMethodTransformer.kt | 82 +++++---- .../nullCheck/nullabilityValues.kt | 13 +- .../transformer/CompositeMethodTransformer.kt | 2 +- 35 files changed, 645 insertions(+), 652 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/ApiVersionCallsPreprocessingMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/ApiVersionCallsPreprocessingMethodTransformer.kt index 3d3bed400ed..836a8542934 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/ApiVersionCallsPreprocessingMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/ApiVersionCallsPreprocessingMethodTransformer.kt @@ -46,10 +46,10 @@ class ApiVersionCallsPreprocessingMethodTransformer(private val targetApiVersion val atLeastVersion = MavenComparableVersion("$epic.$major.$minor") val replacementInsn = - if (targetApiVersion.version >= atLeastVersion) - InsnNode(Opcodes.ICONST_1) - else - InsnNode(Opcodes.ICONST_0) + if (targetApiVersion.version >= atLeastVersion) + InsnNode(Opcodes.ICONST_1) + else + InsnNode(Opcodes.ICONST_0) methodNode.instructions.run { remove(prev1) @@ -65,29 +65,29 @@ class ApiVersionCallsPreprocessingMethodTransformer(private val targetApiVersion } private fun AbstractInsnNode.isApiVersionIsAtLeastCall(): Boolean = - isMethodInsnWith(Opcodes.INVOKESTATIC) { - owner.startsWith("kotlin/internal") && - name == "apiVersionIsAtLeast" && - desc == "(III)Z" - } + isMethodInsnWith(Opcodes.INVOKESTATIC) { + owner.startsWith("kotlin/internal") && + name == "apiVersionIsAtLeast" && + desc == "(III)Z" + } private fun AbstractInsnNode.getIntConstValue(): Int? = - when (this) { - is InsnNode -> - if (opcode in Opcodes.ICONST_M1..Opcodes.ICONST_5) - opcode - Opcodes.ICONST_0 - else - null + when (this) { + is InsnNode -> + if (opcode in Opcodes.ICONST_M1..Opcodes.ICONST_5) + opcode - Opcodes.ICONST_0 + else + null - is IntInsnNode -> - when (opcode) { - Opcodes.BIPUSH -> operand - Opcodes.SIPUSH -> operand - else -> null - } + is IntInsnNode -> + when (opcode) { + Opcodes.BIPUSH -> operand + Opcodes.SIPUSH -> operand + else -> null + } - is LdcInsnNode -> cst as? Int + is LdcInsnNode -> cst as? Int - else -> null - } + else -> null + } } \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/CapturedVarsOptimizationMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/CapturedVarsOptimizationMethodTransformer.kt index 5a0729cf9d9..7c6bfccc7eb 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/CapturedVarsOptimizationMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/CapturedVarsOptimizationMethodTransformer.kt @@ -17,13 +17,7 @@ package org.jetbrains.kotlin.codegen.optimization import org.jetbrains.kotlin.builtins.PrimitiveType -import org.jetbrains.kotlin.codegen.optimization.common.ProperTrackedReferenceValue -import org.jetbrains.kotlin.codegen.optimization.common.ReferenceTrackingInterpreter -import org.jetbrains.kotlin.codegen.optimization.common.ReferenceValueDescriptor -import org.jetbrains.kotlin.codegen.optimization.common.TrackedReferenceValue -import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence -import org.jetbrains.kotlin.codegen.optimization.common.removeEmptyCatchBlocks -import org.jetbrains.kotlin.codegen.optimization.common.removeUnusedLocalVariables +import org.jetbrains.kotlin.codegen.optimization.common.* import org.jetbrains.kotlin.codegen.optimization.fixStack.peek import org.jetbrains.kotlin.codegen.optimization.fixStack.top import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer @@ -71,10 +65,10 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() { var cleanVarInstruction: VarInsnNode? = null fun canRewrite(): Boolean = - !hazard && - initCallInsn != null && - localVar != null && - localVarIndex >= 0 + !hazard && + initCallInsn != null && + localVar != null && + localVarIndex >= 0 override fun onUseAsTainted() { hazard = true @@ -118,10 +112,10 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() { private inner class Interpreter : ReferenceTrackingInterpreter() { override fun newOperation(insn: AbstractInsnNode): BasicValue = - refValuesByNewInsn[insn]?.let { descriptor -> - ProperTrackedReferenceValue(descriptor.refType, descriptor) - } - ?: super.newOperation(insn) + refValuesByNewInsn[insn]?.let { descriptor -> + ProperTrackedReferenceValue(descriptor.refType, descriptor) + } + ?: super.newOperation(insn) override fun processRefValueUsage(value: TrackedReferenceValue, insn: AbstractInsnNode, position: Int) { for (descriptor in value.descriptors) { @@ -179,7 +173,7 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() { } private fun BasicValue.getCapturedVarOrNull() = - safeAs()?.descriptor?.safeAs() + safeAs()?.descriptor?.safeAs() private fun assignLocalVars() { for (localVar in methodNode.localVariables) { @@ -195,8 +189,7 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() { if (descriptor.localVar == null) { descriptor.localVar = localVar - } - else { + } else { descriptor.hazard = true } } @@ -210,8 +203,7 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() { refValue.localVarIndex = methodNode.maxLocals methodNode.maxLocals += 2 localVar.index = refValue.localVarIndex - } - else { + } else { refValue.localVarIndex = localVar.index } @@ -223,7 +215,7 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() { } val cleanInstructions = findCleanInstructions(refValue, oldVarIndex, methodNode.instructions) - if (cleanInstructions.size > 1 ) { + if (cleanInstructions.size > 1) { refValue.hazard = true continue } @@ -235,12 +227,14 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() { return InsnSequence(instructions).filterIsInstance().filter { it.opcode == Opcodes.ASTORE && it.`var` == oldVarIndex }.filter { - it.previous?.opcode == Opcodes.ACONST_NULL - }.filter { - val operationIndex = instructions.indexOf(it) - val localVariableNode = refValue.localVar!! - instructions.indexOf(localVariableNode.start) < operationIndex && operationIndex < instructions.indexOf(localVariableNode.end) - }.toList() + it.previous?.opcode == Opcodes.ACONST_NULL + }.filter { + val operationIndex = instructions.indexOf(it) + val localVariableNode = refValue.localVar!! + instructions.indexOf(localVariableNode.start) < operationIndex && operationIndex < instructions.indexOf( + localVariableNode.end + ) + }.toList() } private fun rewrite() { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/ConstantConditionEliminationMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/ConstantConditionEliminationMethodTransformer.kt index d1c145c060a..bb5dcab0323 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/ConstantConditionEliminationMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/ConstantConditionEliminationMethodTransformer.kt @@ -48,20 +48,20 @@ class ConstantConditionEliminationMethodTransformer : MethodTransformer() { } private fun collectRewriteActions(): List<() -> Unit> = - arrayListOf<() -> Unit>().also { actions -> - val frames = analyze(internalClassName, methodNode, ConstantPropagationInterpreter()) - val insns = methodNode.instructions.toArray() - for (i in frames.indices) { - val frame = frames[i] ?: continue - val insn = insns[i] as? JumpInsnNode ?: continue - when (insn.opcode) { - in Opcodes.IFEQ .. Opcodes.IFLE -> - tryRewriteComparisonWithZero(insn, frame, actions) - in Opcodes.IF_ICMPEQ .. Opcodes.IF_ICMPLE -> - tryRewriteBinaryComparison(insn, frame, actions) - } + arrayListOf<() -> Unit>().also { actions -> + val frames = analyze(internalClassName, methodNode, ConstantPropagationInterpreter()) + val insns = methodNode.instructions.toArray() + for (i in frames.indices) { + val frame = frames[i] ?: continue + val insn = insns[i] as? JumpInsnNode ?: continue + when (insn.opcode) { + in Opcodes.IFEQ..Opcodes.IFLE -> + tryRewriteComparisonWithZero(insn, frame, actions) + in Opcodes.IF_ICMPEQ..Opcodes.IF_ICMPLE -> + tryRewriteBinaryComparison(insn, frame, actions) } } + } private fun tryRewriteComparisonWithZero(insn: JumpInsnNode, frame: Frame, actions: ArrayList<() -> Unit>) { val top = frame.top()!!.safeAs() ?: return @@ -93,8 +93,7 @@ class ConstantConditionEliminationMethodTransformer : MethodTransformer() { if (arg1 is IConstValue && arg2 is IConstValue) { rewriteBinaryComparisonOfConsts(insn, arg1.value, arg2.value, actions) - } - else if (arg2 is IConstValue && arg2.value == 0) { + } else if (arg2 is IConstValue && arg2.value == 0) { rewriteBinaryComparisonWith0(insn, actions) } } @@ -144,8 +143,8 @@ class ConstantConditionEliminationMethodTransformer : MethodTransformer() { private class IConstValue private constructor(val value: Int) : StrictBasicValue(Type.INT_TYPE) { override fun equals(other: Any?): Boolean = - other === this || - other is IConstValue && other.value == this.value + other === this || + other is IConstValue && other.value == this.value override fun hashCode(): Int = value @@ -155,34 +154,34 @@ class ConstantConditionEliminationMethodTransformer : MethodTransformer() { private val ICONST_CACHE = Array(7) { IConstValue(it - 1) } fun of(value: Int) = - if (value in -1 .. 5) - ICONST_CACHE[value + 1] - else - IConstValue(value) + if (value in -1..5) + ICONST_CACHE[value + 1] + else + IConstValue(value) } } private class ConstantPropagationInterpreter : OptimizationBasicInterpreter() { override fun newOperation(insn: AbstractInsnNode): BasicValue = - when (insn.opcode) { - in Opcodes.ICONST_M1 .. Opcodes.ICONST_5 -> - IConstValue.of(insn.opcode - Opcodes.ICONST_0) - Opcodes.BIPUSH, Opcodes.SIPUSH -> - IConstValue.of(insn.cast().operand) - Opcodes.LDC -> { - val operand = insn.cast().cst - if (operand is Int) - IConstValue.of(operand) - else - super.newOperation(insn) - } - else -> super.newOperation(insn) + when (insn.opcode) { + in Opcodes.ICONST_M1..Opcodes.ICONST_5 -> + IConstValue.of(insn.opcode - Opcodes.ICONST_0) + Opcodes.BIPUSH, Opcodes.SIPUSH -> + IConstValue.of(insn.cast().operand) + Opcodes.LDC -> { + val operand = insn.cast().cst + if (operand is Int) + IConstValue.of(operand) + else + super.newOperation(insn) } + else -> super.newOperation(insn) + } override fun merge(v: BasicValue, w: BasicValue): BasicValue = - if (v is IConstValue && w is IConstValue && v == w) - v - else - super.merge(v, w) + if (v is IConstValue && w is IConstValue && v == w) + v + else + super.merge(v, w) } } \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/DeadCodeEliminationMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/DeadCodeEliminationMethodTransformer.kt index aae00a45028..2395a4ede1d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/DeadCodeEliminationMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/DeadCodeEliminationMethodTransformer.kt @@ -55,15 +55,15 @@ class DeadCodeEliminationMethodTransformer : MethodTransformer() { } private fun shouldRemove(insn: AbstractInsnNode, index: Int, frames: Array): Boolean = - when (insn) { - is LabelNode -> - // Do not remove label nodes because they can be referred by try/catch blocks or local variables table - false - is LineNumberNode -> - isDeadLineNumber(insn, index, frames) - else -> - frames[index] == null - } + when (insn) { + is LabelNode -> + // Do not remove label nodes because they can be referred by try/catch blocks or local variables table + false + is LineNumberNode -> + isDeadLineNumber(insn, index, frames) + else -> + frames[index] == null + } private fun isDeadLineNumber(insn: LineNumberNode, index: Int, frames: Array): Boolean { // Line number node is "dead" if the corresponding line number interval diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/FixStackWithLabelNormalizationMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/FixStackWithLabelNormalizationMethodTransformer.kt index 8e21e2e8b31..a1bf3aa9ec6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/FixStackWithLabelNormalizationMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/FixStackWithLabelNormalizationMethodTransformer.kt @@ -18,10 +18,8 @@ package org.jetbrains.kotlin.codegen.optimization import org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackMethodTransformer import org.jetbrains.kotlin.codegen.optimization.transformer.CompositeMethodTransformer -import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer -import org.jetbrains.org.objectweb.asm.tree.MethodNode class FixStackWithLabelNormalizationMethodTransformer : CompositeMethodTransformer( - LabelNormalizationMethodTransformer(), - FixStackMethodTransformer() + LabelNormalizationMethodTransformer(), + FixStackMethodTransformer() ) \ No newline at end of file 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 26a658a122d..e896ca7d047 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/LabelNormalizationMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/LabelNormalizationMethodTransformer.kt @@ -49,13 +49,11 @@ class LabelNormalizationMethodTransformer : MethodTransformer() { newLabelNodes[thisNode.label] = prevNode removedAnyLabels = true thisNode = instructions.removeNodeGetNext(thisNode) - } - else { + } else { newLabelNodes[thisNode.label] = thisNode thisNode = thisNode.next } - } - else { + } else { thisNode = thisNode.next } } @@ -83,19 +81,19 @@ class LabelNormalizationMethodTransformer : MethodTransformer() { } private fun rewriteLineNumberNode(oldLineNode: LineNumberNode): AbstractInsnNode? = - instructions.replaceNodeGetNext(oldLineNode, oldLineNode.rewriteLabels()) + instructions.replaceNodeGetNext(oldLineNode, oldLineNode.rewriteLabels()) private fun rewriteJumpInsn(oldJumpNode: JumpInsnNode): AbstractInsnNode? = - instructions.replaceNodeGetNext(oldJumpNode, oldJumpNode.rewriteLabels()) + instructions.replaceNodeGetNext(oldJumpNode, oldJumpNode.rewriteLabels()) private fun rewriteLookupSwitchInsn(oldSwitchNode: LookupSwitchInsnNode): AbstractInsnNode? = - instructions.replaceNodeGetNext(oldSwitchNode, oldSwitchNode.rewriteLabels()) + instructions.replaceNodeGetNext(oldSwitchNode, oldSwitchNode.rewriteLabels()) private fun rewriteTableSwitchInsn(oldSwitchNode: TableSwitchInsnNode): AbstractInsnNode? = - instructions.replaceNodeGetNext(oldSwitchNode, oldSwitchNode.rewriteLabels()) + instructions.replaceNodeGetNext(oldSwitchNode, oldSwitchNode.rewriteLabels()) private fun rewriteFrameNode(oldFrameNode: FrameNode): AbstractInsnNode? = - instructions.replaceNodeGetNext(oldFrameNode, oldFrameNode.rewriteLabels()) + instructions.replaceNodeGetNext(oldFrameNode, oldFrameNode.rewriteLabels()) private fun rewriteTryCatchBlocks() { methodNode.tryCatchBlocks = methodNode.tryCatchBlocks.map { oldTcb -> @@ -109,21 +107,21 @@ class LabelNormalizationMethodTransformer : MethodTransformer() { private fun rewriteLocalVars() { methodNode.localVariables = methodNode.localVariables.map { oldVar -> LocalVariableNode( - oldVar.name, - oldVar.desc, - oldVar.signature, - getNew(oldVar.start), - getNew(oldVar.end), - oldVar.index + oldVar.name, + oldVar.desc, + oldVar.signature, + getNew(oldVar.start), + getNew(oldVar.end), + oldVar.index ) } } private fun LineNumberNode.rewriteLabels(): AbstractInsnNode = - LineNumberNode(line, getNewOrOld(start)) + LineNumberNode(line, getNewOrOld(start)) private fun JumpInsnNode.rewriteLabels(): AbstractInsnNode = - JumpInsnNode(opcode, getNew(label)) + JumpInsnNode(opcode, getNew(label)) private fun LookupSwitchInsnNode.rewriteLabels(): AbstractInsnNode { val switchNode = LookupSwitchInsnNode(getNew(dflt), keys.toIntArray(), emptyArray()) @@ -145,10 +143,10 @@ class LabelNormalizationMethodTransformer : MethodTransformer() { } private fun getNew(oldLabelNode: LabelNode): LabelNode = - newLabelNodes[oldLabelNode.label]!! + newLabelNodes[oldLabelNode.label]!! private fun getNewOrOld(oldLabelNode: LabelNode): LabelNode = - newLabelNodes[oldLabelNode.label] ?: oldLabelNode + newLabelNodes[oldLabelNode.label] ?: oldLabelNode } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/MethodVerifier.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/MethodVerifier.kt index 27354d1e6fa..0796f110112 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/MethodVerifier.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/MethodVerifier.kt @@ -24,8 +24,7 @@ class MethodVerifier(private val checkPoint: String) : MethodTransformer() { override fun transform(internalClassName: String, methodNode: MethodNode) { try { analyze(internalClassName, methodNode, BasicVerifier()) - } - catch (e: Throwable) { + } catch (e: Throwable) { throw AssertionError("$checkPoint: incorrect bytecode", e) } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationMethodVisitor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationMethodVisitor.kt index 5e7a5c91181..79ac499c6a5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationMethodVisitor.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationMethodVisitor.kt @@ -28,17 +28,17 @@ import org.jetbrains.org.objectweb.asm.MethodVisitor import org.jetbrains.org.objectweb.asm.tree.MethodNode class OptimizationMethodVisitor( - delegate: MethodVisitor, - private val disableOptimization: Boolean, - private val constructorCallNormalizationMode: JVMConstructorCallNormalizationMode, - access: Int, - name: String, - desc: String, - signature: String?, - exceptions: Array? + delegate: MethodVisitor, + private val disableOptimization: Boolean, + private val constructorCallNormalizationMode: JVMConstructorCallNormalizationMode, + access: Int, + name: String, + desc: String, + signature: String?, + exceptions: Array? ) : TransformationMethodVisitor(delegate, access, name, desc, signature, exceptions) { private val constructorCallNormalizationTransformer = - UninitializedStoresMethodTransformer(constructorCallNormalizationMode) + UninitializedStoresMethodTransformer(constructorCallNormalizationMode) override fun performTransformations(methodNode: MethodNode) { normalizationMethodTransformer.transform("fake", methodNode) @@ -55,22 +55,22 @@ class OptimizationMethodVisitor( private val MEMORY_LIMIT_BY_METHOD_MB = 50 val normalizationMethodTransformer = CompositeMethodTransformer( - FixStackWithLabelNormalizationMethodTransformer(), - MethodVerifier("AFTER mandatory stack transformations") + FixStackWithLabelNormalizationMethodTransformer(), + MethodVerifier("AFTER mandatory stack transformations") ) val optimizationTransformer = CompositeMethodTransformer( - CapturedVarsOptimizationMethodTransformer(), - RedundantNullCheckMethodTransformer(), - RedundantCheckCastEliminationMethodTransformer(), - ConstantConditionEliminationMethodTransformer(), - RedundantBoxingMethodTransformer(), - StackPeepholeOptimizationsTransformer(), - PopBackwardPropagationTransformer(), - DeadCodeEliminationMethodTransformer(), - RedundantGotoMethodTransformer(), - RedundantNopsCleanupMethodTransformer(), - MethodVerifier("AFTER optimizations") + CapturedVarsOptimizationMethodTransformer(), + RedundantNullCheckMethodTransformer(), + RedundantCheckCastEliminationMethodTransformer(), + ConstantConditionEliminationMethodTransformer(), + RedundantBoxingMethodTransformer(), + StackPeepholeOptimizationsTransformer(), + PopBackwardPropagationTransformer(), + DeadCodeEliminationMethodTransformer(), + RedundantGotoMethodTransformer(), + RedundantNopsCleanupMethodTransformer(), + MethodVerifier("AFTER optimizations") ) fun canBeOptimized(node: MethodNode): Boolean { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/RedundantCheckCastElimination.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/RedundantCheckCastElimination.kt index 66a01e83fa7..e9175d6b794 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/RedundantCheckCastElimination.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/RedundantCheckCastElimination.kt @@ -22,7 +22,8 @@ import org.jetbrains.kotlin.codegen.optimization.fixStack.top import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type -import org.jetbrains.org.objectweb.asm.tree.* +import org.jetbrains.org.objectweb.asm.tree.MethodNode +import org.jetbrains.org.objectweb.asm.tree.TypeInsnNode class RedundantCheckCastEliminationMethodTransformer : MethodTransformer() { override fun transform(internalClassName: String, methodNode: MethodNode) { @@ -57,7 +58,7 @@ class RedundantCheckCastEliminationMethodTransformer : MethodTransformer() { } private fun isTrivialSubtype(superType: Type, subType: Type) = - superType == subType + superType == subType private fun isMultiArrayType(type: Type) = type.sort == Type.ARRAY && type.dimensions != 1 } \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/RedundantGotoMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/RedundantGotoMethodTransformer.kt index c0013505149..3d83e6ec00c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/RedundantGotoMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/RedundantGotoMethodTransformer.kt @@ -16,13 +16,13 @@ package org.jetbrains.kotlin.codegen.optimization -import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer -import org.jetbrains.org.objectweb.asm.tree.MethodNode -import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode -import org.jetbrains.org.objectweb.asm.tree.LabelNode -import org.jetbrains.org.objectweb.asm.Opcodes -import org.jetbrains.org.objectweb.asm.tree.JumpInsnNode import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful +import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer +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 class RedundantGotoMethodTransformer : MethodTransformer() { /** @@ -38,7 +38,7 @@ class RedundantGotoMethodTransformer : MethodTransformer() { insn is LabelNode -> currentLabels.add(insn) insn.opcode == Opcodes.GOTO && - (insn as JumpInsnNode).label in currentLabels -> + (insn as JumpInsnNode).label in currentLabels -> insnsToRemove.add(insn) insn.isMeaningful -> currentLabels.clear() diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/RedundantNopsCleanupMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/RedundantNopsCleanupMethodTransformer.kt index 3198348f53c..07d3475c7b8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/RedundantNopsCleanupMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/RedundantNopsCleanupMethodTransformer.kt @@ -46,8 +46,7 @@ class RedundantNopsCleanupMethodTransformer : MethodTransformer() { val toRemove = current current = current.next methodNode.instructions.remove(toRemove) - } - else { + } else { current = current.next } } @@ -84,7 +83,7 @@ class RedundantNopsCleanupMethodTransformer : MethodTransformer() { } - for (i in 0 .. localVariableLabels.size - 2) { + for (i in 0..localVariableLabels.size - 2) { val begin = localVariableLabels[i] val end = localVariableLabels[i + 1] if (InsnSequence(begin, end).any { it in requiredNops }) continue @@ -109,8 +108,7 @@ internal fun getRequiredNopInRange(firstInclusive: AbstractInsnNode, lastExclusi while (current != null && current != lastExclusive) { if (current.isMeaningful && current.opcode != Opcodes.NOP) { return null - } - else if (current.opcode == Opcodes.NOP) { + } else if (current.opcode == Opcodes.NOP) { lastNop = current } current = current.next diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/UninitializedStoresMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/UninitializedStoresMethodTransformer.kt index 663fb404da4..23e49e727dc 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/UninitializedStoresMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/UninitializedStoresMethodTransformer.kt @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.config.JVMConstructorCallNormalizationMode import org.jetbrains.org.objectweb.asm.tree.MethodNode class UninitializedStoresMethodTransformer( - private val mode: JVMConstructorCallNormalizationMode + private val mode: JVMConstructorCallNormalizationMode ) : MethodTransformer() { override fun transform(internalClassName: String, methodNode: MethodNode) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxedBasicValue.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxedBasicValue.kt index aaea372fc95..ce582dcced2 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxedBasicValue.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxedBasicValue.kt @@ -34,9 +34,9 @@ abstract class BoxedBasicValue(type: Type) : StrictBasicValue(type) { class CleanBoxedValue( - boxedType: Type, - boxingInsn: AbstractInsnNode, - progressionIterator: ProgressionIteratorBasicValue? + boxedType: Type, + boxingInsn: AbstractInsnNode, + progressionIterator: ProgressionIteratorBasicValue? ) : BoxedBasicValue(boxedType) { override val descriptor = BoxedValueDescriptor(boxedType, boxingInsn, progressionIterator) @@ -53,9 +53,9 @@ class TaintedBoxedValue(private val boxedBasicValue: CleanBoxedValue) : BoxedBas class BoxedValueDescriptor( - private val boxedType: Type, - val boxingInsn: AbstractInsnNode, - val progressionIterator: ProgressionIteratorBasicValue? + private val boxedType: Type, + val boxingInsn: AbstractInsnNode, + val progressionIterator: ProgressionIteratorBasicValue? ) { private val associatedInsns = HashSet() private val unboxingWithCastInsns = HashSet>() @@ -76,14 +76,14 @@ class BoxedValueDescriptor( } fun getVariablesIndexes(): List = - ArrayList(associatedVariables) + ArrayList(associatedVariables) fun addMergedWith(descriptor: BoxedValueDescriptor) { mergedWith.add(descriptor) } fun getMergedWith(): Iterable = - mergedWith + mergedWith fun markAsUnsafeToRemove() { isSafeToRemove = false @@ -98,7 +98,7 @@ class BoxedValueDescriptor( } fun getUnboxingWithCastInsns(): Set> = - unboxingWithCastInsns + unboxingWithCastInsns } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxingInterpreter.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxingInterpreter.kt index ceb808266ae..d9f1b2933ef 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxingInterpreter.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/BoxingInterpreter.kt @@ -36,12 +36,16 @@ import java.util.* open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasicInterpreter() { private val boxingPlaces = HashMap() - protected open fun createNewBoxing(insn: AbstractInsnNode, type: Type, progressionIterator: ProgressionIteratorBasicValue?): BasicValue = - boxingPlaces.getOrPut(insnList.indexOf(insn)) { - val boxedBasicValue = CleanBoxedValue(type, insn, progressionIterator) - onNewBoxedValue(boxedBasicValue) - boxedBasicValue - } + protected open fun createNewBoxing( + insn: AbstractInsnNode, + type: Type, + progressionIterator: ProgressionIteratorBasicValue? + ): BasicValue = + boxingPlaces.getOrPut(insnList.indexOf(insn)) { + val boxedBasicValue = CleanBoxedValue(type, insn, progressionIterator) + onNewBoxedValue(boxedBasicValue) + boxedBasicValue + } protected fun checkUsedValue(value: BasicValue) { if (value is TaintedBoxedValue) { @@ -69,7 +73,7 @@ open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasic ProgressionIteratorBasicValue.byProgressionClassType(firstArg.type) insn.isNextMethodCallOfProgressionIterator(values) -> { val progressionIterator = firstArg as? ProgressionIteratorBasicValue - ?: throw AssertionError("firstArg should be progression iterator") + ?: throw AssertionError("firstArg should be progression iterator") createNewBoxing(insn, AsmUtil.boxType(progressionIterator.valuesPrimitiveType), progressionIterator) } insn.isAreEqualIntrinsicForSameTypedBoxedValues(values) && canValuesBeUnboxedForAreEqual(values) -> { @@ -104,30 +108,30 @@ open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasic } protected open fun isExactValue(value: BasicValue) = - value is ProgressionIteratorBasicValue || - value is CleanBoxedValue || - value.type != null && isProgressionClass(value.type) + value is ProgressionIteratorBasicValue || + value is CleanBoxedValue || + value.type != null && isProgressionClass(value.type) override fun merge(v: BasicValue, w: BasicValue) = - when { - v == StrictBasicValue.UNINITIALIZED_VALUE || w == StrictBasicValue.UNINITIALIZED_VALUE -> - StrictBasicValue.UNINITIALIZED_VALUE - v is BoxedBasicValue && w is BoxedBasicValue -> { - onMergeSuccess(v, w) - when { - v is TaintedBoxedValue -> v - w is TaintedBoxedValue -> w - v.type != w.type -> v.taint() - else -> v - } + when { + v == StrictBasicValue.UNINITIALIZED_VALUE || w == StrictBasicValue.UNINITIALIZED_VALUE -> + StrictBasicValue.UNINITIALIZED_VALUE + v is BoxedBasicValue && w is BoxedBasicValue -> { + onMergeSuccess(v, w) + when { + v is TaintedBoxedValue -> v + w is TaintedBoxedValue -> w + v.type != w.type -> v.taint() + else -> v } - v is BoxedBasicValue -> - v.taint() - w is BoxedBasicValue -> - w.taint() - else -> - super.merge(v, w) } + v is BoxedBasicValue -> + v.taint() + w is BoxedBasicValue -> + w.taint() + else -> + super.merge(v, w) + } protected open fun onNewBoxedValue(value: BoxedBasicValue) {} protected open fun onUnboxing(insn: AbstractInsnNode, value: BoxedBasicValue, resultType: Type) {} @@ -140,51 +144,51 @@ open class BoxingInterpreter(private val insnList: InsnList) : OptimizationBasic } private val UNBOXING_METHOD_NAMES = - ImmutableSet.of("booleanValue", "charValue", "byteValue", "shortValue", "intValue", "floatValue", "longValue", "doubleValue") + ImmutableSet.of("booleanValue", "charValue", "byteValue", "shortValue", "intValue", "floatValue", "longValue", "doubleValue") private val KCLASS_TO_JLCLASS = Type.getMethodDescriptor(AsmTypes.JAVA_CLASS_TYPE, AsmTypes.K_CLASS_TYPE) private val JLCLASS_TO_KCLASS = Type.getMethodDescriptor(AsmTypes.K_CLASS_TYPE, AsmTypes.JAVA_CLASS_TYPE) fun AbstractInsnNode.isUnboxing() = - isPrimitiveUnboxing() || isJavaLangClassUnboxing() + isPrimitiveUnboxing() || isJavaLangClassUnboxing() fun AbstractInsnNode.isBoxing() = - isPrimitiveBoxing() || isJavaLangClassBoxing() + isPrimitiveBoxing() || isJavaLangClassBoxing() fun AbstractInsnNode.isPrimitiveUnboxing() = - isMethodInsnWith(Opcodes.INVOKEVIRTUAL) { - isWrapperClassNameOrNumber(owner) && isUnboxingMethodName(name) - } + isMethodInsnWith(Opcodes.INVOKEVIRTUAL) { + isWrapperClassNameOrNumber(owner) && isUnboxingMethodName(name) + } fun AbstractInsnNode.isJavaLangClassUnboxing() = - isMethodInsnWith(Opcodes.INVOKESTATIC) { - owner == "kotlin/jvm/JvmClassMappingKt" && - name == "getJavaClass" && - desc == KCLASS_TO_JLCLASS - } + isMethodInsnWith(Opcodes.INVOKESTATIC) { + owner == "kotlin/jvm/JvmClassMappingKt" && + name == "getJavaClass" && + desc == KCLASS_TO_JLCLASS + } inline fun AbstractInsnNode.isMethodInsnWith(opcode: Int, condition: MethodInsnNode.() -> Boolean): Boolean = - this.opcode == opcode && this is MethodInsnNode && this.condition() + this.opcode == opcode && this is MethodInsnNode && this.condition() private fun isWrapperClassNameOrNumber(internalClassName: String) = - isWrapperClassName(internalClassName) || internalClassName == Type.getInternalName(Number::class.java) + isWrapperClassName(internalClassName) || internalClassName == Type.getInternalName(Number::class.java) private fun isWrapperClassName(internalClassName: String) = - JvmPrimitiveType.isWrapperClassName(buildFqNameByInternal(internalClassName)) + JvmPrimitiveType.isWrapperClassName(buildFqNameByInternal(internalClassName)) private fun buildFqNameByInternal(internalClassName: String) = - FqName(Type.getObjectType(internalClassName).className) + FqName(Type.getObjectType(internalClassName).className) private fun isUnboxingMethodName(name: String) = - UNBOXING_METHOD_NAMES.contains(name) + UNBOXING_METHOD_NAMES.contains(name) fun AbstractInsnNode.isPrimitiveBoxing() = - isMethodInsnWith(Opcodes.INVOKESTATIC) { - isWrapperClassName(owner) && - name == "valueOf" && - isBoxingMethodDescriptor() - } + isMethodInsnWith(Opcodes.INVOKESTATIC) { + isWrapperClassName(owner) && + name == "valueOf" && + isBoxingMethodDescriptor() + } private fun MethodInsnNode.isBoxingMethodDescriptor(): Boolean { val ownerType = Type.getObjectType(owner) @@ -192,58 +196,58 @@ private fun MethodInsnNode.isBoxingMethodDescriptor(): Boolean { } fun AbstractInsnNode.isJavaLangClassBoxing() = - isMethodInsnWith(Opcodes.INVOKESTATIC) { - owner == AsmTypes.REFLECTION && - name == "getOrCreateKotlinClass" && - desc == JLCLASS_TO_KCLASS - } + isMethodInsnWith(Opcodes.INVOKESTATIC) { + owner == AsmTypes.REFLECTION && + name == "getOrCreateKotlinClass" && + desc == JLCLASS_TO_KCLASS + } fun AbstractInsnNode.isNextMethodCallOfProgressionIterator(values: List) = - values.firstOrNull() is ProgressionIteratorBasicValue && - isMethodInsnWith(Opcodes.INVOKEINTERFACE) { - name == "next" - } + values.firstOrNull() is ProgressionIteratorBasicValue && + isMethodInsnWith(Opcodes.INVOKEINTERFACE) { + name == "next" + } fun AbstractInsnNode.isIteratorMethodCallOfProgression(values: List) = - isMethodInsnWith(Opcodes.INVOKEINTERFACE) { - val firstArgType = values.firstOrNull()?.type - firstArgType != null && - isProgressionClass(firstArgType) && - name == "iterator" - } + isMethodInsnWith(Opcodes.INVOKEINTERFACE) { + val firstArgType = values.firstOrNull()?.type + firstArgType != null && + isProgressionClass(firstArgType) && + name == "iterator" + } fun isProgressionClass(type: Type) = - isRangeOrProgression(buildFqNameByInternal(type.internalName)) + isRangeOrProgression(buildFqNameByInternal(type.internalName)) fun AbstractInsnNode.isAreEqualIntrinsicForSameTypedBoxedValues(values: List) = - isAreEqualIntrinsic() && areSameTypedBoxedValues(values) + isAreEqualIntrinsic() && areSameTypedBoxedValues(values) fun areSameTypedBoxedValues(values: List): Boolean { if (values.size != 2) return false val (v1, v2) = values return v1 is BoxedBasicValue && - v2 is BoxedBasicValue && - v1.descriptor.unboxedType == v2.descriptor.unboxedType + v2 is BoxedBasicValue && + v1.descriptor.unboxedType == v2.descriptor.unboxedType } fun AbstractInsnNode.isAreEqualIntrinsic() = - isMethodInsnWith(Opcodes.INVOKESTATIC) { - name == "areEqual" && - owner == IntrinsicMethods.INTRINSICS_CLASS_NAME && - desc == "(Ljava/lang/Object;Ljava/lang/Object;)Z" - } + isMethodInsnWith(Opcodes.INVOKESTATIC) { + name == "areEqual" && + owner == IntrinsicMethods.INTRINSICS_CLASS_NAME && + desc == "(Ljava/lang/Object;Ljava/lang/Object;)Z" + } private val shouldUseEqualsForWrappers = setOf(Type.DOUBLE_TYPE, Type.FLOAT_TYPE, AsmTypes.JAVA_CLASS_TYPE) fun canValuesBeUnboxedForAreEqual(values: List): Boolean = - values.none { getUnboxedType(it.type) in shouldUseEqualsForWrappers } + values.none { getUnboxedType(it.type) in shouldUseEqualsForWrappers } fun AbstractInsnNode.isJavaLangComparableCompareToForSameTypedBoxedValues(values: List) = - isJavaLangComparableCompareTo() && areSameTypedBoxedValues(values) + isJavaLangComparableCompareTo() && areSameTypedBoxedValues(values) fun AbstractInsnNode.isJavaLangComparableCompareTo() = - isMethodInsnWith(Opcodes.INVOKEINTERFACE) { - name == "compareTo" && - owner == "java/lang/Comparable" && - desc == "(Ljava/lang/Object;)I" - } + isMethodInsnWith(Opcodes.INVOKEINTERFACE) { + name == "compareTo" && + owner == "java/lang/Comparable" && + desc == "(Ljava/lang/Object;)I" + } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/PopBackwardPropagationTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/PopBackwardPropagationTransformer.kt index 1c67d33e114..e0a45e81d29 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/PopBackwardPropagationTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/PopBackwardPropagationTransformer.kt @@ -44,11 +44,11 @@ class PopBackwardPropagationTransformer : MethodTransformer() { } private inline fun Transformation(crossinline body: (AbstractInsnNode) -> Unit): Transformation = - object : Transformation { - override fun apply(insn: AbstractInsnNode) { - body(insn) - } + object : Transformation { + override fun apply(insn: AbstractInsnNode) { + body(insn) } + } private val REPLACE_WITH_NOP = Transformation { insnList.set(it, createRemovableNopInsn()) } private val REPLACE_WITH_POP1 = Transformation { insnList.set(it, InsnNode(Opcodes.POP)) } @@ -145,7 +145,12 @@ class PopBackwardPropagationTransformer : MethodTransformer() { return super.binaryOperation(insn, value1, value2) } - override fun ternaryOperation(insn: AbstractInsnNode, value1: SourceValue, value2: SourceValue, value3: SourceValue): SourceValue { + override fun ternaryOperation( + insn: AbstractInsnNode, + value1: SourceValue, + value2: SourceValue, + value3: SourceValue + ): SourceValue { value1.insns.markAsDontTouch() value2.insns.markAsDontTouch() value3.insns.markAsDontTouch() @@ -193,8 +198,7 @@ class PopBackwardPropagationTransformer : MethodTransformer() { if (sources.all { !isDontTouch(it) } && sources.any { isTransformableCheckcastOperand(it, resultType) }) { transformations[insn] = replaceWithNopTransformation() sources.forEach { propagatePopBackwards(it, inputTop.size) } - } - else { + } else { transformations[insn] = insertPopAfterTransformation(poppedValueSize) } } @@ -214,8 +218,7 @@ class PopBackwardPropagationTransformer : MethodTransformer() { if (sources.all { !isDontTouch(it) }) { transformations[insn] = replaceWithNopTransformation() sources.forEach { propagatePopBackwards(it, inputTop.size) } - } - else { + } else { transformations[insn] = replaceWithPopTransformation(poppedValueSize) } } @@ -252,8 +255,7 @@ class PopBackwardPropagationTransformer : MethodTransformer() { while (node != null && node != end) { if (node in removableNops && !keepNop) { node = insnList.removeNodeGetNext(node) - } - else { + } else { if (node.isMeaningful) keepNop = false node = node.next } @@ -261,24 +263,24 @@ class PopBackwardPropagationTransformer : MethodTransformer() { } private fun replaceWithPopTransformation(size: Int): Transformation = - when (size) { - 1 -> REPLACE_WITH_POP1 - 2 -> REPLACE_WITH_POP2 - else -> throw AssertionError("Unexpected pop value size: $size") - } + when (size) { + 1 -> REPLACE_WITH_POP1 + 2 -> REPLACE_WITH_POP2 + else -> throw AssertionError("Unexpected pop value size: $size") + } private fun insertPopAfterTransformation(size: Int): Transformation = - when (size) { - 1 -> INSERT_POP1_AFTER - 2 -> INSERT_POP2_AFTER - else -> throw AssertionError("Unexpected pop value size: $size") - } + when (size) { + 1 -> INSERT_POP1_AFTER + 2 -> INSERT_POP2_AFTER + else -> throw AssertionError("Unexpected pop value size: $size") + } private fun replaceWithNopTransformation(): Transformation = - REPLACE_WITH_NOP + REPLACE_WITH_NOP private fun createRemovableNopInsn() = - InsnNode(Opcodes.NOP).apply { removableNops.add(this) } + InsnNode(Opcodes.NOP).apply { removableNops.add(this) } private fun getInputTop(insn: AbstractInsnNode): SourceValue { val i = insnList.indexOf(insn) @@ -287,28 +289,28 @@ class PopBackwardPropagationTransformer : MethodTransformer() { } private fun isTransformableCheckcastOperand(it: AbstractInsnNode, resultType: String) = - it.isPrimitiveBoxing() && (it as MethodInsnNode).owner == resultType + it.isPrimitiveBoxing() && (it as MethodInsnNode).owner == resultType private fun isTransformablePopOperand(insn: AbstractInsnNode) = - insn.opcode == Opcodes.CHECKCAST || insn.isPrimitiveBoxing() || insn.isPurePush() + insn.opcode == Opcodes.CHECKCAST || insn.isPrimitiveBoxing() || insn.isPurePush() private fun isDontTouch(insn: AbstractInsnNode) = - dontTouchInsnIndices[insnList.indexOf(insn)] + dontTouchInsnIndices[insnList.indexOf(insn)] } } fun AbstractInsnNode.isPurePush() = - isLoadOperation() || - opcode in Opcodes.ACONST_NULL .. Opcodes.LDC + 2 || - isUnitInstance() + isLoadOperation() || + opcode in Opcodes.ACONST_NULL..Opcodes.LDC + 2 || + isUnitInstance() fun AbstractInsnNode.isPop() = - opcode == Opcodes.POP || opcode == Opcodes.POP2 + opcode == Opcodes.POP || opcode == Opcodes.POP2 fun AbstractInsnNode.isUnitInstance() = - opcode == Opcodes.GETSTATIC && - this is FieldInsnNode && owner == "kotlin/Unit" && name == "INSTANCE" + opcode == Opcodes.GETSTATIC && + this is FieldInsnNode && owner == "kotlin/Unit" && name == "INSTANCE" fun AbstractInsnNode.isPrimitiveTypeConversion() = - opcode in Opcodes.I2L .. Opcodes.I2S \ No newline at end of file + opcode in Opcodes.I2L..Opcodes.I2S \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/ProgressionIteratorBasicValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/ProgressionIteratorBasicValue.java index 77b8f2ef866..ac5c9239312 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/ProgressionIteratorBasicValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/ProgressionIteratorBasicValue.java @@ -30,6 +30,7 @@ import org.jetbrains.org.objectweb.asm.Type; public class ProgressionIteratorBasicValue extends StrictBasicValue { private final static ImmutableMap VALUES_TYPENAME_TO_TYPE; + static { ImmutableMap.Builder builder = ImmutableMap.builder(); for (PrimitiveType primitiveType : RangeCodegenUtilKt.getSupportedRangeTypes()) { @@ -39,6 +40,7 @@ public class ProgressionIteratorBasicValue extends StrictBasicValue { } private static final ImmutableMap ITERATOR_VALUE_BY_ELEMENT_PRIMITIVE_TYPE; + static { ImmutableMap.Builder builder = ImmutableMap.builder(); for (PrimitiveType elementType : RangeCodegenUtilKt.getSupportedRangeTypes()) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/RedundantBoxingInterpreter.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/RedundantBoxingInterpreter.kt index cefd6d6ac7c..52fb5cdf6ba 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/RedundantBoxingInterpreter.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/RedundantBoxingInterpreter.kt @@ -116,8 +116,7 @@ internal class RedundantBoxingInterpreter(insnList: InsnList) : BoxingInterprete if (!PERMITTED_OPERATIONS_OPCODES.contains(insnNode.opcode)) { markValueAsDirty(value) - } - else { + } else { addAssociatedInsn(value, insnNode) } } @@ -129,22 +128,22 @@ internal class RedundantBoxingInterpreter(insnList: InsnList) : BoxingInterprete companion object { private val PERMITTED_OPERATIONS_OPCODES = - ImmutableSet.of(Opcodes.ASTORE, Opcodes.ALOAD, Opcodes.POP, Opcodes.DUP, Opcodes.CHECKCAST, Opcodes.INSTANCEOF) + ImmutableSet.of(Opcodes.ASTORE, Opcodes.ALOAD, Opcodes.POP, Opcodes.DUP, Opcodes.CHECKCAST, Opcodes.INSTANCEOF) private val PRIMITIVE_TYPES_SORTS_WITH_WRAPPER_EXTENDS_NUMBER = - ImmutableSet.of(Type.BYTE, Type.SHORT, Type.INT, Type.FLOAT, Type.LONG, Type.DOUBLE) + ImmutableSet.of(Type.BYTE, Type.SHORT, Type.INT, Type.FLOAT, Type.LONG, Type.DOUBLE) private fun isSafeCast(value: BoxedBasicValue, targetInternalName: String) = - when (targetInternalName) { - Type.getInternalName(Any::class.java) -> - true - Type.getInternalName(Number::class.java) -> - PRIMITIVE_TYPES_SORTS_WITH_WRAPPER_EXTENDS_NUMBER.contains(value.descriptor.unboxedType.sort) - "java/lang/Comparable" -> - true - else -> - value.type.internalName == targetInternalName - } + when (targetInternalName) { + Type.getInternalName(Any::class.java) -> + true + Type.getInternalName(Number::class.java) -> + PRIMITIVE_TYPES_SORTS_WITH_WRAPPER_EXTENDS_NUMBER.contains(value.descriptor.unboxedType.sort) + "java/lang/Comparable" -> + true + else -> + value.type.internalName == targetInternalName + } private fun addAssociatedInsn(value: BoxedBasicValue, insn: AbstractInsnNode) { value.descriptor.run { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/RedundantBoxingMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/RedundantBoxingMethodTransformer.kt index 23fe0e732da..27153bd4f3b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/RedundantBoxingMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/boxing/RedundantBoxingMethodTransformer.kt @@ -21,7 +21,7 @@ import org.jetbrains.kotlin.codegen.inline.insnOpcodeText import org.jetbrains.kotlin.codegen.inline.insnText import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue -import org.jetbrains.kotlin.codegen.optimization.common.* +import org.jetbrains.kotlin.codegen.optimization.common.remapLocalVariables import org.jetbrains.kotlin.codegen.optimization.fixStack.peek import org.jetbrains.kotlin.codegen.optimization.fixStack.top import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer @@ -32,7 +32,6 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter 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 java.util.* class RedundantBoxingMethodTransformer : MethodTransformer() { @@ -58,9 +57,9 @@ class RedundantBoxingMethodTransformer : MethodTransformer() { } private fun interpretPopInstructionsForBoxedValues( - interpreter: RedundantBoxingInterpreter, - node: MethodNode, - frames: Array?> + interpreter: RedundantBoxingInterpreter, + node: MethodNode, + frames: Array?> ) { for (i in frames.indices) { val insn = node.instructions[i] @@ -80,9 +79,9 @@ class RedundantBoxingMethodTransformer : MethodTransformer() { } private fun removeValuesClashingWithVariables( - values: RedundantBoxedValuesCollection, - node: MethodNode, - frames: Array> + values: RedundantBoxedValuesCollection, + node: MethodNode, + frames: Array> ) { while (removeValuesClashingWithVariablesPass(values, node, frames)) { // do nothing @@ -90,9 +89,9 @@ class RedundantBoxingMethodTransformer : MethodTransformer() { } private fun removeValuesClashingWithVariablesPass( - values: RedundantBoxedValuesCollection, - node: MethodNode, - frames: Array?> + values: RedundantBoxedValuesCollection, + node: MethodNode, + frames: Array?> ): Boolean { var needToRepeat = false @@ -123,13 +122,13 @@ class RedundantBoxingMethodTransformer : MethodTransformer() { } private fun isUnsafeToRemoveBoxingForConnectedValues(usedValues: List, unboxedType: Type): Boolean = - usedValues.any { input -> - if (input === StrictBasicValue.UNINITIALIZED_VALUE) return@any false - if (input !is BoxedBasicValue) return@any true + usedValues.any { input -> + if (input === StrictBasicValue.UNINITIALIZED_VALUE) return@any false + if (input !is BoxedBasicValue) return@any true - val descriptor = input.descriptor - !descriptor.isSafeToRemove || descriptor.unboxedType != unboxedType - } + val descriptor = input.descriptor + !descriptor.isSafeToRemove || descriptor.unboxedType != unboxedType + } private fun adaptLocalVariableTableForBoxedValues(node: MethodNode, frames: Array>) { for (localVariableNode in node.localVariables) { @@ -148,9 +147,9 @@ class RedundantBoxingMethodTransformer : MethodTransformer() { } private fun getValuesStoredOrLoadedToVariable( - localVariableNode: LocalVariableNode, - node: MethodNode, - frames: Array?> + localVariableNode: LocalVariableNode, + node: MethodNode, + frames: Array?> ): List { val values = ArrayList() val insnList = node.instructions @@ -171,8 +170,7 @@ class RedundantBoxingMethodTransformer : MethodTransformer() { (insn as VarInsnNode).`var` == localVariableNode.index) { if (insn.getOpcode() == Opcodes.ASTORE) { values.add(frame.top()!!) - } - else { + } else { values.add(frame.getLocal(insn.`var`)) } } @@ -205,8 +203,8 @@ class RedundantBoxingMethodTransformer : MethodTransformer() { } private fun adaptInstructionsForBoxedValues( - node: MethodNode, - values: RedundantBoxedValuesCollection + node: MethodNode, + values: RedundantBoxedValuesCollection ) { for (value in values) { adaptInstructionsForBoxedValue(node, value) @@ -228,8 +226,7 @@ class RedundantBoxingMethodTransformer : MethodTransformer() { private fun adaptBoxingInstruction(node: MethodNode, value: BoxedValueDescriptor) { if (!value.isFromProgressionIterator()) { node.instructions.remove(value.boxingInsn) - } - else { + } else { val iterator = value.progressionIterator ?: error("iterator should not be null because isFromProgressionIterator returns true") //add checkcast to kotlin/Iterator before next() call @@ -237,20 +234,20 @@ class RedundantBoxingMethodTransformer : MethodTransformer() { //invoke concrete method (kotlin/iterator.next()) node.instructions.set( - value.boxingInsn, - MethodInsnNode( - Opcodes.INVOKEVIRTUAL, - iterator.type.internalName, iterator.nextMethodName, iterator.nextMethodDesc, - false - ) + value.boxingInsn, + MethodInsnNode( + Opcodes.INVOKEVIRTUAL, + iterator.type.internalName, iterator.nextMethodName, iterator.nextMethodDesc, + false + ) ) } } private fun adaptCastInstruction( - node: MethodNode, - value: BoxedValueDescriptor, - castWithType: Pair + node: MethodNode, + value: BoxedValueDescriptor, + castWithType: Pair ) { val castInsn = castWithType.getFirst() val castInsnsListener = MethodNode(Opcodes.ASM5) @@ -264,7 +261,7 @@ class RedundantBoxingMethodTransformer : MethodTransformer() { } private fun adaptInstruction( - node: MethodNode, insn: AbstractInsnNode, value: BoxedValueDescriptor + node: MethodNode, insn: AbstractInsnNode, value: BoxedValueDescriptor ) { val isDoubleSize = value.isDoubleSize() @@ -286,8 +283,8 @@ class RedundantBoxingMethodTransformer : MethodTransformer() { Opcodes.INSTANCEOF -> { node.instructions.insertBefore( - insn, - InsnNode(if (isDoubleSize) Opcodes.POP2 else Opcodes.POP) + insn, + InsnNode(if (isDoubleSize) Opcodes.POP2 else Opcodes.POP) ) node.instructions.set(insn, InsnNode(Opcodes.ICONST_1)) } @@ -299,7 +296,7 @@ class RedundantBoxingMethodTransformer : MethodTransformer() { insn.isJavaLangComparableCompareTo() -> adaptJavaLangComparableCompareTo(node, insn, value) insn.isJavaLangClassBoxing() || - insn.isJavaLangClassUnboxing() -> + insn.isJavaLangClassUnboxing() -> node.instructions.remove(insn) else -> throwCannotAdaptInstruction(insn) @@ -309,8 +306,7 @@ class RedundantBoxingMethodTransformer : MethodTransformer() { Opcodes.INVOKEINTERFACE -> { if (insn.isJavaLangComparableCompareTo()) { adaptJavaLangComparableCompareTo(node, insn, value) - } - else { + } else { throwCannotAdaptInstruction(insn) } } @@ -325,12 +321,12 @@ class RedundantBoxingMethodTransformer : MethodTransformer() { } private fun throwCannotAdaptInstruction(insn: AbstractInsnNode): Nothing = - throw AssertionError("Cannot adapt instruction: ${insn.insnText}") + throw AssertionError("Cannot adapt instruction: ${insn.insnText}") private fun adaptAreEqualIntrinsic( - node: MethodNode, - insn: AbstractInsnNode, - value: BoxedValueDescriptor + node: MethodNode, + insn: AbstractInsnNode, + value: BoxedValueDescriptor ) { val unboxedType = value.unboxedType @@ -339,8 +335,8 @@ class RedundantBoxingMethodTransformer : MethodTransformer() { adaptAreEqualIntrinsicForInt(node, insn) Type.LONG -> adaptAreEqualIntrinsicForLong(node, insn) - Type.OBJECT -> - {} + Type.OBJECT -> { + } else -> throw AssertionError("Unexpected unboxed type kind: $unboxedType") } @@ -353,8 +349,7 @@ class RedundantBoxingMethodTransformer : MethodTransformer() { fuseAreEqualWithBranch(node, insn, Opcodes.IF_ICMPNE, Opcodes.IF_ICMPEQ) remove(insn) remove(next) - } - else { + } else { ifEqual1Else0(node, insn, Opcodes.IF_ICMPNE) remove(insn) } @@ -369,8 +364,7 @@ class RedundantBoxingMethodTransformer : MethodTransformer() { fuseAreEqualWithBranch(node, insn, Opcodes.IFNE, Opcodes.IFEQ) remove(insn) remove(next) - } - else { + } else { ifEqual1Else0(node, insn, Opcodes.IFNE) remove(insn) } @@ -378,10 +372,10 @@ class RedundantBoxingMethodTransformer : MethodTransformer() { } private fun fuseAreEqualWithBranch( - node: MethodNode, - insn: AbstractInsnNode, - ifEqualOpcode: Int, - ifNotEqualOpcode: Int + node: MethodNode, + insn: AbstractInsnNode, + ifEqualOpcode: Int, + ifNotEqualOpcode: Int ) { node.instructions.run { val next = insn.next @@ -412,22 +406,22 @@ class RedundantBoxingMethodTransformer : MethodTransformer() { } private fun adaptJavaLangComparableCompareTo( - node: MethodNode, - insn: AbstractInsnNode, - value: BoxedValueDescriptor + node: MethodNode, + insn: AbstractInsnNode, + value: BoxedValueDescriptor ) { val unboxedType = value.unboxedType when (unboxedType.sort) { - Type.BOOLEAN, Type.BYTE, Type.SHORT, Type.INT, Type.CHAR -> + Type.BOOLEAN, Type.BYTE, Type.SHORT, Type.INT, Type.CHAR -> adaptJavaLangComparableCompareToForInt(node, insn) - Type.LONG -> + Type.LONG -> adaptJavaLangComparableCompareToForLong(node, insn) - Type.FLOAT -> + Type.FLOAT -> adaptJavaLangComparableCompareToForFloat(node, insn) - Type.DOUBLE -> + Type.DOUBLE -> adaptJavaLangComparableCompareToForDouble(node, insn) - else -> + else -> throw AssertionError("Unexpected unboxed type kind: $unboxedType") } } @@ -438,15 +432,15 @@ class RedundantBoxingMethodTransformer : MethodTransformer() { val next2 = next?.next when { next != null && next2 != null && - next.opcode == Opcodes.ICONST_0 && - next2.opcode >= Opcodes.IF_ICMPEQ && next2.opcode <= Opcodes.IF_ICMPLE -> { + next.opcode == Opcodes.ICONST_0 && + next2.opcode >= Opcodes.IF_ICMPEQ && next2.opcode <= Opcodes.IF_ICMPLE -> { // Fuse: compareTo + ICONST_0 + IF_ICMPxx -> IF_ICMPxx remove(insn) remove(next) } next != null && - next.opcode >= Opcodes.IFEQ && next.opcode <= Opcodes.IFLE -> { + next.opcode >= Opcodes.IFEQ && next.opcode <= Opcodes.IFLE -> { // Fuse: compareTo + IFxx -> IF_ICMPxx val nextLabel = (next as JumpInsnNode).label val ifCmpOpcode = next.opcode - Opcodes.IFEQ + Opcodes.IF_ICMPEQ 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 0dbb3cbfcbb..1eeb1c532b3 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 @@ -84,8 +84,7 @@ class StackPeepholeOptimizationsTransformer : MethodTransformer() { it.set(insn, InsnNode(Opcodes.NOP)) it.remove(prevNonNop) } - } - else if (i > 1) { + } else if (i > 1) { val prevNonNop2 = prevNonNop.findPreviousOrNull { it.opcode != Opcodes.NOP } ?: continue@forInsn if (prevNonNop.isEliminatedByPop() && prevNonNop2.isEliminatedByPop()) { actions.add { @@ -112,24 +111,24 @@ class StackPeepholeOptimizationsTransformer : MethodTransformer() { } private fun AbstractInsnNode.isEliminatedByPop() = - isPurePushOfSize1() || - opcode == Opcodes.DUP + isPurePushOfSize1() || + opcode == Opcodes.DUP private fun AbstractInsnNode.isPurePushOfSize1(): Boolean = - opcode in Opcodes.ACONST_NULL..Opcodes.FCONST_2 || - opcode in Opcodes.BIPUSH..Opcodes.ILOAD || - opcode == Opcodes.FLOAD || - opcode == Opcodes.ALOAD || - isUnitInstance() + opcode in Opcodes.ACONST_NULL..Opcodes.FCONST_2 || + opcode in Opcodes.BIPUSH..Opcodes.ILOAD || + opcode == Opcodes.FLOAD || + opcode == Opcodes.ALOAD || + isUnitInstance() private fun AbstractInsnNode.isEliminatedByPop2() = - isPurePushOfSize2() || - opcode == Opcodes.DUP2 + isPurePushOfSize2() || + opcode == Opcodes.DUP2 private fun AbstractInsnNode.isPurePushOfSize2(): Boolean = - opcode == Opcodes.LCONST_0 || opcode == Opcodes.LCONST_1 || - opcode == Opcodes.DCONST_0 || opcode == Opcodes.DCONST_1 || - opcode == Opcodes.LLOAD || - opcode == Opcodes.DLOAD + opcode == Opcodes.LCONST_0 || opcode == Opcodes.LCONST_1 || + opcode == Opcodes.DCONST_0 || opcode == Opcodes.DCONST_1 || + opcode == Opcodes.LLOAD || + opcode == Opcodes.DLOAD } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/CustomFramesMethodAnalyzer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/CustomFramesMethodAnalyzer.kt index ec80501283f..73513222c4f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/CustomFramesMethodAnalyzer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/CustomFramesMethodAnalyzer.kt @@ -22,8 +22,8 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter import org.jetbrains.org.objectweb.asm.tree.analysis.Value class CustomFramesMethodAnalyzer( - owner: String, method: MethodNode, interpreter: Interpreter, - private val frameFactory: (Int, Int) -> Frame + owner: String, method: MethodNode, interpreter: Interpreter, + private val frameFactory: (Int, Int) -> Frame ) : MethodAnalyzer(owner, method, interpreter) { override fun newFrame(nLocals: Int, nStack: Int) = frameFactory(nLocals, nStack) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/MethodAnalyzer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/MethodAnalyzer.kt index 53aeb4b86df..a1af2e5e548 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/MethodAnalyzer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/MethodAnalyzer.kt @@ -62,9 +62,9 @@ import java.util.* * @author Dmitry Petrov */ open class MethodAnalyzer( - val owner: String, - val method: MethodNode, - protected val interpreter: Interpreter + val owner: String, + val method: MethodNode, + protected val interpreter: Interpreter ) { val instructions: InsnList = method.instructions private val nInsns: Int = instructions.size() @@ -91,7 +91,7 @@ open class MethodAnalyzer( protected open fun visitControlFlowExceptionEdge(insn: Int, successor: Int): Boolean = true protected open fun visitControlFlowExceptionEdge(insn: Int, tcb: TryCatchBlockNode): Boolean = - visitControlFlowExceptionEdge(insn, instructions.indexOf(tcb.handler)) + visitControlFlowExceptionEdge(insn, instructions.indexOf(tcb.handler)) fun analyze(): Array?> { if (nInsns == 0) return frames @@ -116,8 +116,7 @@ open class MethodAnalyzer( if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) { visitNopInsn(f, insn) - } - else { + } else { current.init(f).execute(insnNode, interpreter) when { @@ -129,12 +128,13 @@ open class MethodAnalyzer( visitTableSwitchInsnNode(insnNode, current, insn) insnOpcode != Opcodes.ATHROW && (insnOpcode < Opcodes.IRETURN || insnOpcode > Opcodes.RETURN) -> visitOpInsn(current, insn) - else -> {} + else -> { + } } } handlers[insn]?.forEach { tcb -> - val exnType = Type.getObjectType(tcb.type?:"java/lang/Throwable") + val exnType = Type.getObjectType(tcb.type ?: "java/lang/Throwable") val jump = instructions.indexOf(tcb.handler) if (visitControlFlowExceptionEdge(insn, tcb)) { handler.init(f) @@ -144,11 +144,9 @@ open class MethodAnalyzer( } } - } - catch (e: AnalyzerException) { + } catch (e: AnalyzerException) { throw AnalyzerException(e.node, "Error at instruction #$insn ${insnNode.insnText}: ${e.message}", e) - } - catch (e: Exception) { + } catch (e: Exception) { throw AnalyzerException(insnNode, "Error at instruction #$insn ${insnNode.insnText}: ${e.message}", e) } @@ -158,7 +156,7 @@ open class MethodAnalyzer( } fun getFrame(insn: AbstractInsnNode): Frame? = - frames[instructions.indexOf(insn)] + frames[instructions.indexOf(insn)] private fun checkAssertions() { if (instructions.toArray().any { it.opcode == Opcodes.JSR || it.opcode == Opcodes.RET }) @@ -250,12 +248,12 @@ open class MethodAnalyzer( private fun mergeControlFlowEdge(insn: Int, frame: Frame) { val oldFrame = frames[insn] val changes = - if (oldFrame != null) - oldFrame.merge(frame, interpreter) - else { - frames[insn] = newFrame(frame) - true - } + if (oldFrame != null) + oldFrame.merge(frame, interpreter) + else { + frames[insn] = newFrame(frame) + true + } if (changes && !queued[insn]) { queued[insn] = true queue[top++] = insn diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/ReferenceTrackingInterpreter.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/ReferenceTrackingInterpreter.kt index 27543bf2d5d..2b299265cb0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/ReferenceTrackingInterpreter.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/ReferenceTrackingInterpreter.kt @@ -23,61 +23,60 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue abstract class ReferenceTrackingInterpreter : OptimizationBasicInterpreter() { override fun merge(v: BasicValue, w: BasicValue): BasicValue = - when { - v is ProperTrackedReferenceValue && w is ProperTrackedReferenceValue -> - if (v.descriptor == w.descriptor) - v - else - createTaintedValue(v, w) - - v is TrackedReferenceValue && w is TrackedReferenceValue -> - createPossiblyMergedValue(v, w) - - v is TrackedReferenceValue || w is TrackedReferenceValue -> + when { + v is ProperTrackedReferenceValue && w is ProperTrackedReferenceValue -> + if (v.descriptor == w.descriptor) + v + else createTaintedValue(v, w) - else -> - super.merge(v, w) - } + v is TrackedReferenceValue && w is TrackedReferenceValue -> + createPossiblyMergedValue(v, w) - protected fun createTaintedValue(v: BasicValue, w: BasicValue) : TrackedReferenceValue = - TaintedTrackedReferenceValue( - getMergedValueType(v.type, w.type), - mergeDescriptors(v, w).also { - assert(it.isNotEmpty()) { "At least one of ($v, $w) should be a tracked reference" } - } - ) + v is TrackedReferenceValue || w is TrackedReferenceValue -> + createTaintedValue(v, w) + + else -> + super.merge(v, w) + } + + protected fun createTaintedValue(v: BasicValue, w: BasicValue): TrackedReferenceValue = + TaintedTrackedReferenceValue( + getMergedValueType(v.type, w.type), + mergeDescriptors(v, w).also { + assert(it.isNotEmpty()) { "At least one of ($v, $w) should be a tracked reference" } + } + ) protected fun createMergedValue(v: TrackedReferenceValue, w: TrackedReferenceValue): TrackedReferenceValue = - if (v is TaintedTrackedReferenceValue || w is TaintedTrackedReferenceValue) - createTaintedValue(v, w) - else - MergedTrackedReferenceValue(getMergedValueType(v.type, w.type), mergeDescriptors(v, w)) + if (v is TaintedTrackedReferenceValue || w is TaintedTrackedReferenceValue) + createTaintedValue(v, w) + else + MergedTrackedReferenceValue(getMergedValueType(v.type, w.type), mergeDescriptors(v, w)) protected open fun createPossiblyMergedValue(v: TrackedReferenceValue, w: TrackedReferenceValue): TrackedReferenceValue = - createTaintedValue(v, w) + createTaintedValue(v, w) private fun mergeDescriptors(v: BasicValue, w: BasicValue) = - v.referenceValueDescriptors + w.referenceValueDescriptors + v.referenceValueDescriptors + w.referenceValueDescriptors private val BasicValue.referenceValueDescriptors: Set get() = if (this is TrackedReferenceValue) this.descriptors else emptySet() protected fun getMergedValueType(type1: Type?, type2: Type?): Type = - when { - type1 == null || type2 == null -> AsmTypes.OBJECT_TYPE - type1 == type2 -> type1 - else -> AsmTypes.OBJECT_TYPE - } + when { + type1 == null || type2 == null -> AsmTypes.OBJECT_TYPE + type1 == type2 -> type1 + else -> AsmTypes.OBJECT_TYPE + } override fun copyOperation(insn: AbstractInsnNode, value: BasicValue): BasicValue? = - if (value is TrackedReferenceValue) { - checkRefValuesUsages(insn, listOf(value)) - value - } - else { - super.copyOperation(insn, value) - } + if (value is TrackedReferenceValue) { + checkRefValuesUsages(insn, listOf(value)) + value + } else { + super.copyOperation(insn, value) + } override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue): BasicValue? { checkRefValuesUsages(insn, listOf(value)) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/TrackedReferenceValue.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/TrackedReferenceValue.kt index 1b5ed39ff1a..78a32356a60 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/TrackedReferenceValue.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/TrackedReferenceValue.kt @@ -22,7 +22,7 @@ interface ReferenceValueDescriptor { fun onUseAsTainted() } -sealed class TrackedReferenceValue(type: Type): StrictBasicValue(type) { +sealed class TrackedReferenceValue(type: Type) : StrictBasicValue(type) { abstract val descriptors: Set } @@ -31,37 +31,38 @@ class ProperTrackedReferenceValue(type: Type, val descriptor: ReferenceValueDesc get() = setOf(descriptor) override fun equals(other: Any?): Boolean = - other === this || - other is ProperTrackedReferenceValue && other.descriptor == this.descriptor + other === this || + other is ProperTrackedReferenceValue && other.descriptor == this.descriptor override fun hashCode(): Int = - descriptor.hashCode() + descriptor.hashCode() override fun toString(): String = - "[$descriptor]" + "[$descriptor]" } class MergedTrackedReferenceValue(type: Type, override val descriptors: Set) : TrackedReferenceValue(type) { override fun equals(other: Any?): Boolean = - other === this || - other is MergedTrackedReferenceValue && other.descriptors == this.descriptors + other === this || + other is MergedTrackedReferenceValue && other.descriptors == this.descriptors override fun hashCode(): Int = - descriptors.hashCode() + descriptors.hashCode() override fun toString(): String = - descriptors.toString() + descriptors.toString() } class TaintedTrackedReferenceValue(type: Type, override val descriptors: Set) : TrackedReferenceValue(type) { override fun equals(other: Any?): Boolean = - other === this || - other is TaintedTrackedReferenceValue && other.descriptors == this.descriptors + other === this || + other is TaintedTrackedReferenceValue && other.descriptors == this.descriptors override fun hashCode(): Int = - descriptors.hashCode() + descriptors.hashCode() + override fun toString(): String = - "!$descriptors" + "!$descriptors" } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/Util.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/Util.kt index adb8fe84bcb..801cb8dd470 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/Util.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/Util.kt @@ -27,11 +27,12 @@ import org.jetbrains.org.objectweb.asm.Opcodes.* import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.tree.* -val AbstractInsnNode.isMeaningful: Boolean get() = - when (this.type) { - AbstractInsnNode.LABEL, AbstractInsnNode.LINE, AbstractInsnNode.FRAME -> false - else -> true - } +val AbstractInsnNode.isMeaningful: Boolean + get() = + when (this.type) { + AbstractInsnNode.LABEL, AbstractInsnNode.LINE, AbstractInsnNode.FRAME -> false + else -> true + } class InsnSequence(val from: AbstractInsnNode, val to: AbstractInsnNode?) : Sequence { constructor(insnList: InsnList) : this(insnList.first, null) @@ -44,6 +45,7 @@ class InsnSequence(val from: AbstractInsnNode, val to: AbstractInsnNode?) : Sequ current = current!!.next return result!! } + override fun hasNext() = current != to } } @@ -74,13 +76,15 @@ fun MethodNode.prepareForEmitting() { current = prev } maxStack = -1 - accept(MaxStackFrameSizeAndLocalsCalculator( + accept( + MaxStackFrameSizeAndLocalsCalculator( Opcodes.ASM5, access, desc, object : MethodVisitor(Opcodes.ASM5) { override fun visitMaxs(maxStack: Int, maxLocals: Int) { this@prepareForEmitting.maxStack = maxStack } - })) + }) + ) } fun MethodNode.stripOptimizationMarkers() { @@ -88,15 +92,14 @@ fun MethodNode.stripOptimizationMarkers() { while (insn != null) { if (isOptimizationMarker(insn)) { insn = instructions.removeNodeGetNext(insn) - } - else { + } else { insn = insn.next } } } private fun isOptimizationMarker(insn: AbstractInsnNode) = - PseudoInsn.STORE_NOT_NULL.isa(insn) + PseudoInsn.STORE_NOT_NULL.isa(insn) fun MethodNode.removeEmptyCatchBlocks() { tryCatchBlocks = tryCatchBlocks.filter { tcb -> @@ -143,7 +146,7 @@ fun MethodNode.removeUnusedLocalVariables() { } private fun VarInsnNode.isSize2LoadStoreOperation() = - opcode == LLOAD || opcode == DLOAD || opcode == LSTORE || opcode == DSTORE + opcode == LLOAD || opcode == DLOAD || opcode == LSTORE || opcode == DSTORE fun MethodNode.remapLocalVariables(remapping: IntArray) { for (insn in instructions.toArray()) { @@ -177,7 +180,7 @@ inline fun AbstractInsnNode.findPreviousOrNull(predicate: (AbstractInsnNode) -> } fun AbstractInsnNode.hasOpcode(): Boolean = - opcode >= 0 + opcode >= 0 // See InstructionAdapter // @@ -192,27 +195,29 @@ fun AbstractInsnNode.hasOpcode(): Boolean = // mv.visitLdcInsn(new Integer(cst)); // } // } -val AbstractInsnNode.intConstant: Int? get() = - when (opcode) { - in ICONST_M1..ICONST_5 -> opcode - ICONST_0 - BIPUSH, SIPUSH -> (this as IntInsnNode).operand - LDC -> (this as LdcInsnNode).cst as? Int - else -> null - } +val AbstractInsnNode.intConstant: Int? + get() = + when (opcode) { + in ICONST_M1..ICONST_5 -> opcode - ICONST_0 + BIPUSH, SIPUSH -> (this as IntInsnNode).operand + LDC -> (this as LdcInsnNode).cst as? Int + else -> null + } fun insnListOf(vararg insns: AbstractInsnNode) = InsnList().apply { insns.forEach { add(it) } } fun AbstractInsnNode.isStoreOperation(): Boolean = opcode in Opcodes.ISTORE..Opcodes.ASTORE fun AbstractInsnNode.isLoadOperation(): Boolean = opcode in Opcodes.ILOAD..Opcodes.ALOAD -val AbstractInsnNode?.debugText get() = +val AbstractInsnNode?.debugText + get() = if (this == null) "" else "${this::class.java.simpleName}: $insnText" internal inline fun AbstractInsnNode.isInsn(opcode: Int, condition: T.() -> Boolean): Boolean = - takeInsnIf(opcode, condition) != null + takeInsnIf(opcode, condition) != null internal inline fun AbstractInsnNode.takeInsnIf(opcode: Int, condition: T.() -> Boolean): T? = - takeIf { it.opcode == opcode }?.safeAs()?.takeIf { it.condition() } + takeIf { it.opcode == opcode }?.safeAs()?.takeIf { it.condition() } fun InsnList.removeAll(nodes: Collection) { for (node in nodes) remove(node) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/variableLiveness.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/variableLiveness.kt index df5e702238b..f34acb90f4d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/variableLiveness.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/variableLiveness.kt @@ -51,13 +51,14 @@ class VariableLivenessFrame(val maxLocals: Int) : VarFrame { val typeAnnotatedFrames = MethodTransformer.analyze("fake", node, OptimizationBasicInterpreter()) return analyze(node, object : BackwardAnalysisInterpreter { override fun newFrame(maxLocals: Int) = VariableLivenessFrame(maxLocals) override fun def(frame: VariableLivenessFrame, insn: AbstractInsnNode) = defVar(frame, insn) override fun use(frame: VariableLivenessFrame, insn: AbstractInsnNode) = - useVar(frame, insn, node, typeAnnotatedFrames[node.instructions.indexOf(insn)]) + useVar(frame, insn, node, typeAnnotatedFrames[node.instructions.indexOf(insn)]) }) } @@ -69,24 +70,23 @@ private fun defVar(frame: VariableLivenessFrame, insn: AbstractInsnNode) { } private fun useVar( - frame: VariableLivenessFrame, - insn: AbstractInsnNode, - node: MethodNode, - // May be null in case of dead code - typeAnnotatedFrame: Frame? + frame: VariableLivenessFrame, + insn: AbstractInsnNode, + node: MethodNode, + // May be null in case of dead code + typeAnnotatedFrame: Frame? ) { val index = node.instructions.indexOf(insn) node.localVariables.filter { node.instructions.indexOf(it.start) < index && index < node.instructions.indexOf(it.end) && - Type.getType(it.desc).sort == typeAnnotatedFrame?.getLocal(it.index)?.type?.sort + Type.getType(it.desc).sort == typeAnnotatedFrame?.getLocal(it.index)?.type?.sort }.forEach { - frame.markAlive(it.index) - } + frame.markAlive(it.index) + } if (insn is VarInsnNode && insn.isLoadOperation()) { frame.markAlive(insn.`var`) - } - else if (insn is IincInsnNode) { + } else if (insn is IincInsnNode) { frame.markAlive(insn.`var`) } } 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 109567613d3..37eab850fc1 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 @@ -30,15 +30,15 @@ import java.util.* private class DecompiledTryDescriptor(val tryStartLabel: LabelNode) { // Only used for assertions - var defaultHandlerTcb : TryCatchBlockNode? = null + var defaultHandlerTcb: TryCatchBlockNode? = null val handlerStartLabels = hashSetOf() } private fun TryCatchBlockNode.isDefaultHandlerNode(): Boolean = - start == handler + start == handler private fun MethodNode.debugString(tcb: TryCatchBlockNode): String = - "TCB<${instructions.indexOf(tcb.start)}, ${instructions.indexOf(tcb.end)}, ${instructions.indexOf(tcb.handler)}>" + "TCB<${instructions.indexOf(tcb.start)}, ${instructions.indexOf(tcb.end)}, ${instructions.indexOf(tcb.handler)}>" internal fun insertTryCatchBlocksMarkers(methodNode: MethodNode): Map { if (methodNode.tryCatchBlocks.isEmpty()) return emptyMap() @@ -64,9 +64,9 @@ private fun transformTryCatchBlocks(methodNode: MethodNode, newTryStartLabels: H } private fun insertSaveRestoreStackMarkers( - decompiledTryDescriptorForStart: Map, - methodNode: MethodNode, - newTryStartLabels: MutableMap + decompiledTryDescriptorForStart: Map, + methodNode: MethodNode, + newTryStartLabels: MutableMap ): Map { val restoreStackToSaveMarker = hashMapOf() val saveStackMarkerByTryLabel = hashMapOf() @@ -92,8 +92,7 @@ private fun insertSaveRestoreStackMarkers( methodNode.instructions.insertBefore(nopNode, saveStackMarker) methodNode.instructions.insertBefore(nopNode, newTryStartLabel) methodNode.instructions.insert(nopNode, restoreStackMarker) - } - else { + } else { saveStackMarker = saveStackMarkerByTryLabel[tryStartLabel]!! } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackAnalyzer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackAnalyzer.kt index 953bbccab62..9f1713363ac 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackAnalyzer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackAnalyzer.kt @@ -24,16 +24,19 @@ import org.jetbrains.kotlin.codegen.optimization.common.MethodAnalyzer import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn 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.JumpInsnNode +import org.jetbrains.org.objectweb.asm.tree.LabelNode +import org.jetbrains.org.objectweb.asm.tree.MethodNode 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 internal class FixStackAnalyzer( - owner: String, - val method: MethodNode, - val context: FixStackContext, - private val skipBreakContinueGotoEdges: Boolean = true + owner: String, + val method: MethodNode, + val context: FixStackContext, + private val skipBreakContinueGotoEdges: Boolean = true ) { companion object { // Stack size is always non-negative @@ -79,7 +82,7 @@ internal class FixStackAnalyzer( } override fun newFrame(nLocals: Int, nStack: Int): Frame = - FixStackFrame(nLocals, nStack) + FixStackFrame(nLocals, nStack) private fun indexOf(node: AbstractInsnNode) = method.instructions.indexOf(node) @@ -128,8 +131,7 @@ internal class FixStackAnalyzer( override fun push(value: BasicValue) { if (super.getStackSize() < maxStackSize) { super.push(value) - } - else { + } else { extraStack.add(value) maxExtraStackSize = Math.max(maxExtraStackSize, extraStack.size) } @@ -142,8 +144,7 @@ internal class FixStackAnalyzer( override fun pop(): BasicValue { return if (extraStack.isNotEmpty()) { extraStack.pop() - } - else { + } else { super.pop() } } @@ -151,8 +152,7 @@ internal class FixStackAnalyzer( override fun getStack(i: Int): BasicValue { return if (i < super.getMaxStackSize()) { super.getStack(i) - } - else { + } else { extraStack[i - maxStackSize] } } @@ -176,8 +176,7 @@ internal class FixStackAnalyzer( val savedValues = spilledStacks[beforeInlineMarker] pushAll(savedValues!!) push(returnValue) - } - else { + } else { val savedValues = spilledStacks[beforeInlineMarker] pushAll(savedValues!!) } @@ -197,5 +196,4 @@ internal class FixStackAnalyzer( } - } 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 cb8f1edceed..f33238605d2 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 @@ -91,15 +91,15 @@ internal class FixStackContext(val methodNode: MethodNode) { private fun indexOf(node: AbstractInsnNode) = methodNode.instructions.indexOf(node) fun hasAnyMarkers(): Boolean = - breakContinueGotoNodes.isNotEmpty() || - fakeAlwaysTrueIfeqMarkers.isNotEmpty() || - fakeAlwaysFalseIfeqMarkers.isNotEmpty() || - isThereAnyTryCatch || - openingInlineMethodMarker.isNotEmpty() + breakContinueGotoNodes.isNotEmpty() || + fakeAlwaysTrueIfeqMarkers.isNotEmpty() || + fakeAlwaysFalseIfeqMarkers.isNotEmpty() || + isThereAnyTryCatch || + openingInlineMethodMarker.isNotEmpty() fun isAnalysisRequired(): Boolean = - breakContinueGotoNodes.isNotEmpty() || - isThereAnyTryCatch || - openingInlineMethodMarker.isNotEmpty() + breakContinueGotoNodes.isNotEmpty() || + isThereAnyTryCatch || + openingInlineMethodMarker.isNotEmpty() } 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 23cfc6fb085..3d3bb861758 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 @@ -89,10 +89,10 @@ class FixStackMethodTransformer : MethodTransformer() { } private fun transformBreakContinueGotos( - methodNode: MethodNode, - fixStackContext: FixStackContext, - actions: MutableList<() -> Unit>, - analyzer: FixStackAnalyzer + methodNode: MethodNode, + fixStackContext: FixStackContext, + actions: MutableList<() -> Unit>, + analyzer: FixStackAnalyzer ) { fixStackContext.breakContinueGotoNodes.forEach { gotoNode -> val gotoIndex = methodNode.instructions.indexOf(gotoNode) @@ -106,13 +106,11 @@ class FixStackMethodTransformer : MethodTransformer() { "Label at $labelIndex, jump at $gotoIndex: stack underflow: $expectedStackSize > $actualStackSize" } val actualStackContent = analyzer.getActualStack(gotoNode) - ?: throw AssertionError("Jump at $gotoIndex should be alive") + ?: throw AssertionError("Jump at $gotoIndex should be alive") actions.add { replaceMarkerWithPops(methodNode, gotoNode.previous, expectedStackSize, actualStackContent) } - } - else if (actualStackSize >= 0 && expectedStackSize < 0) { + } else if (actualStackSize >= 0 && expectedStackSize < 0) { throw AssertionError("Live jump $gotoIndex to dead label $labelIndex") - } - else { + } else { val marker = gotoNode.previous actions.add { methodNode.instructions.remove(marker) } } @@ -120,10 +118,10 @@ class FixStackMethodTransformer : MethodTransformer() { } private fun transformSaveRestoreStackMarkers( - methodNode: MethodNode, - context: FixStackContext, - actions: MutableList<() -> Unit>, - analyzer: FixStackAnalyzer + methodNode: MethodNode, + context: FixStackContext, + actions: MutableList<() -> Unit>, + analyzer: FixStackAnalyzer ) { val localVariablesManager = LocalVariablesManager(context, methodNode) InsnSequence(methodNode.instructions).forEach { marker -> @@ -142,18 +140,17 @@ class FixStackMethodTransformer : MethodTransformer() { } private fun transformSaveStackMarker( - methodNode: MethodNode, - actions: MutableList<() -> Unit>, - analyzer: FixStackAnalyzer, - marker: AbstractInsnNode, - localVariablesManager: LocalVariablesManager + methodNode: MethodNode, + actions: MutableList<() -> Unit>, + analyzer: FixStackAnalyzer, + marker: AbstractInsnNode, + localVariablesManager: LocalVariablesManager ) { val savedStackValues = analyzer.getStackToSpill(marker) if (savedStackValues != null) { val savedStackDescriptor = localVariablesManager.allocateVariablesForSaveStackMarker(marker, savedStackValues) actions.add { saveStack(methodNode, marker, savedStackDescriptor) } - } - else { + } else { // marker is dead code localVariablesManager.allocateVariablesForSaveStackMarker(marker, emptyList()) actions.add { methodNode.instructions.remove(marker) } @@ -161,10 +158,10 @@ class FixStackMethodTransformer : MethodTransformer() { } private fun transformRestoreStackMarker( - methodNode: MethodNode, - actions: MutableList<() -> Unit>, - marker: AbstractInsnNode, - localVariablesManager: LocalVariablesManager + methodNode: MethodNode, + actions: MutableList<() -> Unit>, + marker: AbstractInsnNode, + localVariablesManager: LocalVariablesManager ) { val savedStackDescriptor = localVariablesManager.getSavedStackDescriptor(marker) actions.add { restoreStack(methodNode, marker, savedStackDescriptor) } @@ -172,11 +169,11 @@ class FixStackMethodTransformer : MethodTransformer() { } private fun transformAfterInlineCallMarker( - methodNode: MethodNode, - actions: MutableList<() -> Unit>, - analyzer: FixStackAnalyzer, - inlineMarker: AbstractInsnNode, - localVariablesManager: LocalVariablesManager + methodNode: MethodNode, + actions: MutableList<() -> Unit>, + analyzer: FixStackAnalyzer, + inlineMarker: AbstractInsnNode, + localVariablesManager: LocalVariablesManager ) { val savedStackDescriptor = localVariablesManager.getBeforeInlineDescriptor(inlineMarker) val stackContentAfterInline = analyzer.getActualStack(inlineMarker) @@ -186,8 +183,9 @@ class FixStackMethodTransformer : MethodTransformer() { val returnValue = stackContentAfterInline.last() val returnValueLocalVarIndex = localVariablesManager.createReturnValueVariable(returnValue) actions.add { - restoreStackWithReturnValue(methodNode, inlineMarker, savedStackDescriptor, - returnValue, returnValueLocalVarIndex + restoreStackWithReturnValue( + methodNode, inlineMarker, savedStackDescriptor, + returnValue, returnValueLocalVarIndex ) } } @@ -196,8 +194,7 @@ class FixStackMethodTransformer : MethodTransformer() { else -> throw AssertionError("Inline method should not leave more than 1 value on stack") } - } - else { + } else { // after inline marker is dead code actions.add { methodNode.instructions.remove(inlineMarker) } } @@ -205,18 +202,17 @@ class FixStackMethodTransformer : MethodTransformer() { } private fun transformBeforeInlineCallMarker( - methodNode: MethodNode, - actions: MutableList<() -> Unit>, - analyzer: FixStackAnalyzer, - inlineMarker: AbstractInsnNode, - localVariablesManager: LocalVariablesManager + methodNode: MethodNode, + actions: MutableList<() -> Unit>, + analyzer: FixStackAnalyzer, + inlineMarker: AbstractInsnNode, + localVariablesManager: LocalVariablesManager ) { val savedStackValues = analyzer.getStackToSpill(inlineMarker) if (savedStackValues != null) { val savedStackDescriptor = localVariablesManager.allocateVariablesForBeforeInlineMarker(inlineMarker, savedStackValues) actions.add { saveStack(methodNode, inlineMarker, savedStackDescriptor) } - } - else { + } else { // before inline marker is dead code localVariablesManager.allocateVariablesForBeforeInlineMarker(inlineMarker, emptyList()) actions.add { methodNode.instructions.remove(inlineMarker) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/LocalVariablesManager.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/LocalVariablesManager.kt index ab7dbb1b8d6..7a1d3bb5082 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/LocalVariablesManager.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/LocalVariablesManager.kt @@ -23,7 +23,7 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue internal class LocalVariablesManager(val context: FixStackContext, val methodNode: MethodNode) { private class AllocatedHandle(val savedStackDescriptor: SavedStackDescriptor, var numRestoreMarkers: Int) { fun isFullyEmitted(): Boolean = - numRestoreMarkers == 0 + numRestoreMarkers == 0 fun markRestoreNodeEmitted() { assert(numRestoreMarkers > 0) { "Emitted more restore markers than expected for $savedStackDescriptor" } @@ -43,7 +43,11 @@ internal class LocalVariablesManager(val context: FixStackContext, val methodNod return allocateNewHandle(numRestoreStackMarkers, saveStackMarker, savedStackValues) } - private fun allocateNewHandle(numRestoreStackMarkers: Int, saveStackMarker: AbstractInsnNode, savedStackValues: List): SavedStackDescriptor { + private fun allocateNewHandle( + numRestoreStackMarkers: Int, + saveStackMarker: AbstractInsnNode, + savedStackValues: List + ): SavedStackDescriptor { if (savedStackValues.any { it.type == null }) { throw AssertionError("Uninitialized value on stack at ${methodNode.instructions.indexOf(saveStackMarker)}") } @@ -62,16 +66,19 @@ internal class LocalVariablesManager(val context: FixStackContext, val methodNod } private fun getFirstUnusedLocalVariableIndex(): Int = - allocatedHandles.values.fold(initialMaxLocals) { - index, handle -> Math.max(index, handle.savedStackDescriptor.firstUnusedLocalVarIndex) - } + allocatedHandles.values.fold(initialMaxLocals) { index, handle -> + Math.max(index, handle.savedStackDescriptor.firstUnusedLocalVarIndex) + } fun markRestoreStackMarkerEmitted(restoreStackMarker: AbstractInsnNode) { val saveStackMarker = context.saveStackMarkerForRestoreMarker[restoreStackMarker] markEmitted(saveStackMarker!!) } - fun allocateVariablesForBeforeInlineMarker(beforeInlineMarker: AbstractInsnNode, savedStackValues: List): SavedStackDescriptor { + fun allocateVariablesForBeforeInlineMarker( + beforeInlineMarker: AbstractInsnNode, + savedStackValues: List + ): SavedStackDescriptor { return allocateNewHandle(1, beforeInlineMarker, savedStackValues) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/StackTransformationUtils.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/StackTransformationUtils.kt index 85a33442d69..f2a90f4db1f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/StackTransformationUtils.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/StackTransformationUtils.kt @@ -23,10 +23,10 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Frame import org.jetbrains.org.objectweb.asm.tree.analysis.Value fun Frame.top(): V? = - peek(0) + peek(0) fun Frame.peek(offset: Int): V? = - if (stackSize > offset) getStack(stackSize - offset - 1) else null + if (stackSize > offset) getStack(stackSize - offset - 1) else null private fun Frame.peekWordsTo(dest: MutableList, size: Int, offset0: Int = 0): Int { var offset = offset0 @@ -54,22 +54,22 @@ fun Frame.peekWords(size1: Int, size2: Int): List? { } class SavedStackDescriptor( - val savedValues: List, - val firstLocalVarIndex: Int + val savedValues: List, + val firstLocalVarIndex: Int ) { private val savedValuesSize = savedValues.fold(0, { size, value -> size + value.size }) val firstUnusedLocalVarIndex = firstLocalVarIndex + savedValuesSize override fun toString(): String = - "@$firstLocalVarIndex: [$savedValues]" + "@$firstLocalVarIndex: [$savedValues]" fun isNotEmpty(): Boolean = savedValues.isNotEmpty() } fun saveStack( - methodNode: MethodNode, - nodeToReplace: AbstractInsnNode, - savedStackDescriptor: SavedStackDescriptor + methodNode: MethodNode, + nodeToReplace: AbstractInsnNode, + savedStackDescriptor: SavedStackDescriptor ) { with(methodNode.instructions) { generateStoreInstructions(methodNode, nodeToReplace, savedStackDescriptor) @@ -85,11 +85,11 @@ fun restoreStack(methodNode: MethodNode, location: AbstractInsnNode, savedStackD } fun restoreStackWithReturnValue( - methodNode: MethodNode, - nodeToReplace: AbstractInsnNode, - savedStackDescriptor: SavedStackDescriptor, - returnValue: BasicValue, - returnValueLocalVarIndex: Int + methodNode: MethodNode, + nodeToReplace: AbstractInsnNode, + savedStackDescriptor: SavedStackDescriptor, + returnValue: BasicValue, + returnValueLocalVarIndex: Int ) { with(methodNode.instructions) { insertBefore(nodeToReplace, VarInsnNode(returnValue.type.getOpcode(Opcodes.ISTORE), returnValueLocalVarIndex)) @@ -102,8 +102,10 @@ fun restoreStackWithReturnValue( fun generateLoadInstructions(methodNode: MethodNode, location: AbstractInsnNode, savedStackDescriptor: SavedStackDescriptor) { var localVarIndex = savedStackDescriptor.firstLocalVarIndex for (value in savedStackDescriptor.savedValues) { - methodNode.instructions.insertBefore(location, - VarInsnNode(value.type.getOpcode(Opcodes.ILOAD), localVarIndex)) + methodNode.instructions.insertBefore( + location, + VarInsnNode(value.type.getOpcode(Opcodes.ILOAD), localVarIndex) + ) localVarIndex += value.size } } @@ -112,27 +114,31 @@ fun generateStoreInstructions(methodNode: MethodNode, location: AbstractInsnNode var localVarIndex = savedStackDescriptor.firstUnusedLocalVarIndex for (value in savedStackDescriptor.savedValues.asReversed()) { localVarIndex -= value.size - methodNode.instructions.insertBefore(location, - VarInsnNode(value.type.getOpcode(Opcodes.ISTORE), localVarIndex)) + methodNode.instructions.insertBefore( + location, + VarInsnNode(value.type.getOpcode(Opcodes.ISTORE), localVarIndex) + ) } } fun getPopInstruction(top: BasicValue) = - InsnNode(when (top.size) { - 1 -> Opcodes.POP - 2 -> Opcodes.POP2 - else -> throw AssertionError("Unexpected value type size") - }) + InsnNode( + when (top.size) { + 1 -> Opcodes.POP + 2 -> Opcodes.POP2 + else -> throw AssertionError("Unexpected value type size") + } + ) fun removeAlwaysFalseIfeq(methodNode: MethodNode, node: AbstractInsnNode) { - with (methodNode.instructions) { + with(methodNode.instructions) { remove(node.next) remove(node) } } fun replaceAlwaysTrueIfeqWithGoto(methodNode: MethodNode, node: AbstractInsnNode) { - with (methodNode.instructions) { + with(methodNode.instructions) { val next = node.next as JumpInsnNode insertBefore(node, JumpInsnNode(Opcodes.GOTO, next.label)) remove(node) @@ -141,7 +147,7 @@ fun replaceAlwaysTrueIfeqWithGoto(methodNode: MethodNode, node: AbstractInsnNode } fun replaceMarkerWithPops(methodNode: MethodNode, node: AbstractInsnNode, expectedStackSize: Int, stackContent: List) { - with (methodNode.instructions) { + with(methodNode.instructions) { for (stackValue in stackContent.subList(expectedStackSize, stackContent.size)) { insert(node, getPopInstruction(stackValue)) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/NullabilityInterpreter.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/NullabilityInterpreter.kt index 1213a3a1892..7d26d676a6f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/NullabilityInterpreter.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/NullabilityInterpreter.kt @@ -47,7 +47,7 @@ class NullabilityInterpreter : OptimizationBasicInterpreter() { } private fun Type?.isReferenceType() = - this?.sort.let { it == Type.OBJECT || it == Type.ARRAY } + this?.sort.let { it == Type.OBJECT || it == Type.ARRAY } override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue?): BasicValue? { val defaultResult = super.unaryOperation(insn, value) @@ -82,29 +82,29 @@ class NullabilityInterpreter : OptimizationBasicInterpreter() { } override fun merge(v: BasicValue, w: BasicValue): BasicValue = - when { - v is NullBasicValue && w is NullBasicValue -> - NullBasicValue - v is NullBasicValue || w is NullBasicValue -> - StrictBasicValue.REFERENCE_VALUE - v is ProgressionIteratorBasicValue && w is ProgressionIteratorBasicValue -> - mergeNotNullValuesOfSameKind(v, w) - v is ProgressionIteratorBasicValue && w is NotNullBasicValue -> - NotNullBasicValue.NOT_NULL_REFERENCE_VALUE - w is ProgressionIteratorBasicValue && v is NotNullBasicValue -> - NotNullBasicValue.NOT_NULL_REFERENCE_VALUE - v is NotNullBasicValue && w is NotNullBasicValue -> - mergeNotNullValuesOfSameKind(v, w) - else -> - super.merge(v, w) - } + when { + v is NullBasicValue && w is NullBasicValue -> + NullBasicValue + v is NullBasicValue || w is NullBasicValue -> + StrictBasicValue.REFERENCE_VALUE + v is ProgressionIteratorBasicValue && w is ProgressionIteratorBasicValue -> + mergeNotNullValuesOfSameKind(v, w) + v is ProgressionIteratorBasicValue && w is NotNullBasicValue -> + NotNullBasicValue.NOT_NULL_REFERENCE_VALUE + w is ProgressionIteratorBasicValue && v is NotNullBasicValue -> + NotNullBasicValue.NOT_NULL_REFERENCE_VALUE + v is NotNullBasicValue && w is NotNullBasicValue -> + mergeNotNullValuesOfSameKind(v, w) + else -> + super.merge(v, w) + } private fun mergeNotNullValuesOfSameKind(v: StrictBasicValue, w: StrictBasicValue) = - if (v.type == w.type) v else NotNullBasicValue.NOT_NULL_REFERENCE_VALUE + if (v.type == w.type) v else NotNullBasicValue.NOT_NULL_REFERENCE_VALUE } fun TypeInsnNode.getObjectType(): Type = - Type.getObjectType(desc) + Type.getObjectType(desc) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/RedundantNullCheckMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/RedundantNullCheckMethodTransformer.kt index 664384f9271..5c311b8aa69 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/RedundantNullCheckMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/RedundantNullCheckMethodTransformer.kt @@ -37,7 +37,8 @@ import org.jetbrains.org.objectweb.asm.tree.* class RedundantNullCheckMethodTransformer : MethodTransformer() { override fun transform(internalClassName: String, methodNode: MethodNode) { - while (TransformerPass(internalClassName, methodNode).run()) {} + while (TransformerPass(internalClassName, methodNode).run()) { + } } private class TransformerPass(val internalClassName: String, val methodNode: MethodNode) { @@ -79,10 +80,10 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() { } private fun AbstractInsnNode.isOptimizable() = - opcode == Opcodes.IFNULL || - opcode == Opcodes.IFNONNULL || - opcode == Opcodes.INSTANCEOF || - isCheckExpressionValueIsNotNull() + opcode == Opcodes.IFNULL || + opcode == Opcodes.IFNONNULL || + opcode == Opcodes.INSTANCEOF || + isCheckExpressionValueIsNotNull() private fun transformTrivialChecks(nullabilityMap: Map) { for ((insn, value) in nullabilityMap) { @@ -108,8 +109,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() { popReferenceValueBefore(insn) if (alwaysTrue) { set(insn, JumpInsnNode(Opcodes.GOTO, insn.label)) - } - else { + } else { remove(insn) } } @@ -120,8 +120,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() { if (nullability == Nullability.NULL) { changes = true transformTrivialInstanceOf(insn, false) - } - else if (nullability == Nullability.NOT_NULL && value.type.internalName == insn.desc) { + } else if (nullability == Nullability.NOT_NULL && value.type.internalName == insn.desc) { changes = true transformTrivialInstanceOf(insn, true) } @@ -160,8 +159,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() { val previous = insn.previous ?: continue@insnLoop if (previous.opcode == Opcodes.ALOAD) { addDependentCheck(insn, previous as VarInsnNode) - } - else if (previous.opcode == Opcodes.DUP) { + } else if (previous.opcode == Opcodes.DUP) { val previous2 = previous.previous ?: continue@insnLoop if (previous2.opcode == Opcodes.ALOAD) { addDependentCheck(insn, previous2 as VarInsnNode) @@ -184,8 +182,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() { val insn1 = ldcInsn.previous ?: continue@insnLoop if (insn1.opcode == Opcodes.ALOAD) { aLoadInsn = insn1 as VarInsnNode - } - else if (insn1.opcode == Opcodes.DUP) { + } else if (insn1.opcode == Opcodes.DUP) { val insn2 = insn1.previous ?: continue@insnLoop if (insn2.opcode == Opcodes.ALOAD) { aLoadInsn = insn2 as VarInsnNode @@ -227,7 +224,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() { Opcodes.INVOKESTATIC -> { when { insn.isCheckParameterIsNotNull() || - insn.isCheckExpressionValueIsNotNull() -> + insn.isCheckExpressionValueIsNotNull() -> injectAssumptionsForNotNullAssertion(varIndex, insn) insn.isPseudo(PseudoInsn.STORE_NOT_NULL) -> injectCodeForStoreNotNull(insn) @@ -318,8 +315,7 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() { methodNode.instructions.add(newLabel) next.label = newLabel insertAfterNotNull = newLabel - } - else { + } else { originalLabel = null insertAfterNotNull = next } @@ -395,41 +391,41 @@ class RedundantNullCheckMethodTransformer : MethodTransformer() { } internal fun AbstractInsnNode.isInstanceOfOrNullCheck() = - opcode == Opcodes.INSTANCEOF || - opcode == Opcodes.IFNULL || - opcode == Opcodes.IFNONNULL + opcode == Opcodes.INSTANCEOF || + opcode == Opcodes.IFNULL || + opcode == Opcodes.IFNONNULL internal fun AbstractInsnNode.isCheckParameterIsNotNull() = - isInsn(Opcodes.INVOKESTATIC) { - owner == IntrinsicMethods.INTRINSICS_CLASS_NAME && - name == "checkParameterIsNotNull" && - desc == "(Ljava/lang/Object;Ljava/lang/String;)V" - } + isInsn(Opcodes.INVOKESTATIC) { + owner == IntrinsicMethods.INTRINSICS_CLASS_NAME && + name == "checkParameterIsNotNull" && + desc == "(Ljava/lang/Object;Ljava/lang/String;)V" + } internal fun AbstractInsnNode.isCheckExpressionValueIsNotNull() = - isInsn(Opcodes.INVOKESTATIC) { - owner == IntrinsicMethods.INTRINSICS_CLASS_NAME && - name == "checkExpressionValueIsNotNull" && - desc == "(Ljava/lang/Object;Ljava/lang/String;)V" - } + isInsn(Opcodes.INVOKESTATIC) { + owner == IntrinsicMethods.INTRINSICS_CLASS_NAME && + name == "checkExpressionValueIsNotNull" && + desc == "(Ljava/lang/Object;Ljava/lang/String;)V" + } internal fun AbstractInsnNode.isThrowIntrinsic() = - isInsn(Opcodes.INVOKESTATIC) { - owner == IntrinsicMethods.INTRINSICS_CLASS_NAME && - name in THROW_INTRINSIC_METHOD_NAMES - } + isInsn(Opcodes.INVOKESTATIC) { + owner == IntrinsicMethods.INTRINSICS_CLASS_NAME && + name in THROW_INTRINSIC_METHOD_NAMES + } internal val THROW_INTRINSIC_METHOD_NAMES = - setOf( - "throwNpe", - "throwUninitializedProperty", - "throwUninitializedPropertyAccessException", - "throwAssert", - "throwIllegalArgument", - "throwIllegalState", - "throwParameterIsNullException", - "throwUndefinedForReified" - ) + setOf( + "throwNpe", + "throwUninitializedProperty", + "throwUninitializedPropertyAccessException", + "throwAssert", + "throwIllegalArgument", + "throwIllegalState", + "throwParameterIsNullException", + "throwUndefinedForReified" + ) internal fun InsnList.popReferenceValueBefore(insn: AbstractInsnNode) { val prev = insn.previous diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/nullabilityValues.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/nullabilityValues.kt index 9800b8b4d6d..a5be15050b8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/nullabilityValues.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/nullCheck/nullabilityValues.kt @@ -37,14 +37,15 @@ object NullBasicValue : StrictBasicValue(AsmTypes.OBJECT_TYPE) enum class Nullability { NULL, NOT_NULL, NULLABLE; + fun isNull() = this == NULL fun isNotNull() = this == NOT_NULL } fun BasicValue.getNullability(): Nullability = - when (this) { - is NullBasicValue -> Nullability.NULL - is NotNullBasicValue -> Nullability.NOT_NULL - is ProgressionIteratorBasicValue -> Nullability.NOT_NULL - else -> Nullability.NULLABLE - } \ No newline at end of file + when (this) { + is NullBasicValue -> Nullability.NULL + is NotNullBasicValue -> Nullability.NOT_NULL + is ProgressionIteratorBasicValue -> Nullability.NOT_NULL + else -> Nullability.NULLABLE + } \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/transformer/CompositeMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/transformer/CompositeMethodTransformer.kt index e2e40b47b59..e83938752fe 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/transformer/CompositeMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/transformer/CompositeMethodTransformer.kt @@ -27,6 +27,6 @@ open class CompositeMethodTransformer(private val transformers: List.() -> Unit) = - CompositeMethodTransformer(ArrayList().apply { builder() }) + CompositeMethodTransformer(ArrayList().apply { builder() }) } } \ No newline at end of file