From a30d0aeeb0a17f05429b2d92bdd0bc2f9b1e5267 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Wed, 23 Aug 2023 15:55:56 +0200 Subject: [PATCH] [JVM] Replace `AbstractInsnNode.getType` with new util function This change speeds up backend by approximately 0.96%. --- .../kotlin/codegen/inline/MethodInliner.kt | 8 ++-- .../codegen/inline/inlineCodegenUtils.kt | 3 +- .../NegatedJumpsMethodTransformer.kt | 3 +- .../optimization/OptimizationMethodVisitor.kt | 6 ++- .../StackPeepholeOptimizationsTransformer.kt | 5 ++- .../optimization/common/ControlFlowGraph.kt | 2 +- .../optimization/common/FastAnalyzer.kt | 4 +- .../common/InstructionLivenessAnalyzer.kt | 2 +- .../codegen/optimization/common/Util.kt | 40 +++++++++++++++++-- .../temporaryVals/TemporaryVals.kt | 3 +- ...emporaryVariablesEliminationTransformer.kt | 5 ++- 11 files changed, 61 insertions(+), 20 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt index 9f27b365067..3330dcf5d0e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt @@ -647,7 +647,7 @@ class MethodInliner( } else { //given frame is null if and only if the corresponding instruction cannot be reached (dead code). //clean dead code otherwise there is problems in unreachable finally block, don't touch label it cause try/catch/finally problems - if (cur.type == AbstractInsnNode.LABEL) { + if (cur.nodeType == AbstractInsnNode.LABEL) { //NB: Cause we generate exception table for default handler using gaps (see ExpressionCodegen.visitTryExpression) //it may occurs that interval for default handler starts before catch start label, so this label seems as dead, //but as result all this labels will be merged into one (see KT-5863) @@ -856,9 +856,9 @@ class MethodInliner( // - there's a local variable table entry for this variable val usedIntegerVar = BooleanArray(node.maxLocals) for (insn in insnArray) { - if (insn.type == AbstractInsnNode.VAR_INSN && insn.opcode == Opcodes.ILOAD) { + if (insn.nodeType == AbstractInsnNode.VAR_INSN && insn.opcode == Opcodes.ILOAD) { usedIntegerVar[(insn as VarInsnNode).`var`] = true - } else if (insn.type == AbstractInsnNode.IINC_INSN) { + } else if (insn.nodeType == AbstractInsnNode.IINC_INSN) { usedIntegerVar[(insn as IincInsnNode).`var`] = true } } @@ -883,7 +883,7 @@ class MethodInliner( if (p1.opcode != Opcodes.ISTORE) continue val p2 = p1.next ?: break - if (p2.type != AbstractInsnNode.LABEL) continue + if (p2.nodeType != AbstractInsnNode.LABEL) continue val varIndex = (p1 as VarInsnNode).`var` if (!usedIntegerVar[varIndex]) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt index 8da1c9268b1..8981c336036 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspend import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence import org.jetbrains.kotlin.codegen.optimization.common.asSequence import org.jetbrains.kotlin.codegen.optimization.common.intConstant +import org.jetbrains.kotlin.codegen.optimization.common.nodeType import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.codegen.state.KotlinTypeMapperBase @@ -375,7 +376,7 @@ fun MethodNode.dumpBody(): String { } for ((i, insn) in this.instructions.toArray().withIndex()) { - when (insn.type) { + when (insn.nodeType) { AbstractInsnNode.INSN -> pw.println("$i\t${Printer.OPCODES[insn.opcode]}") AbstractInsnNode.INT_INSN -> diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/NegatedJumpsMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/NegatedJumpsMethodTransformer.kt index 80f7e86b602..fe8d78f7f9b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/NegatedJumpsMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/NegatedJumpsMethodTransformer.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.codegen.optimization +import org.jetbrains.kotlin.codegen.optimization.common.nodeType import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode @@ -23,7 +24,7 @@ class NegatedJumpsMethodTransformer : MethodTransformer() { // IF_ICMPGE L2 = negatedJumpInsn // L1: = next2 for (insn in insnList.toArray()) { - if (insn.type != AbstractInsnNode.JUMP_INSN || insn.opcode == Opcodes.GOTO) continue + if (insn.nodeType != AbstractInsnNode.JUMP_INSN || insn.opcode == Opcodes.GOTO) continue val next1 = insn.next ?: continue if (next1.opcode != Opcodes.GOTO) continue val next2 = next1.next ?: continue 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 5da9b3a8db3..e2f179fbab6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationMethodVisitor.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/OptimizationMethodVisitor.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.codegen.optimization.boxing.PopBackwardPropagationTr import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantBoxingMethodTransformer import org.jetbrains.kotlin.codegen.optimization.boxing.StackPeepholeOptimizationsTransformer import org.jetbrains.kotlin.codegen.optimization.common.prepareForEmitting +import org.jetbrains.kotlin.codegen.optimization.common.nodeType import org.jetbrains.kotlin.codegen.optimization.nullCheck.RedundantNullCheckMethodTransformer import org.jetbrains.kotlin.codegen.optimization.temporaryVals.TemporaryVariablesEliminationTransformer import org.jetbrains.kotlin.codegen.optimization.transformer.CompositeMethodTransformer @@ -107,8 +108,9 @@ class OptimizationMethodVisitor( // by anything other than a jump-targeted label, so those instructions consume no extra memory. // To avoid checking all jumps, here we assume all labels are potentially targeted. // (Effectively, all of this means that adding line numbers should not inhibit optimization.) - if ((it.type != AbstractInsnNode.LINE && it.type != AbstractInsnNode.FRAME && it.type != AbstractInsnNode.LABEL && - it.opcode != Opcodes.NOP) || it.next?.type == AbstractInsnNode.LABEL + val type = it.nodeType + if ((type != AbstractInsnNode.LINE && type != AbstractInsnNode.FRAME && type != AbstractInsnNode.LABEL && + it.opcode != Opcodes.NOP) || it.next?.nodeType == AbstractInsnNode.LABEL ) result++ it = it.next } 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 d3821c73eec..48154760ebc 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 @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.codegen.optimization.boxing import org.jetbrains.kotlin.codegen.optimization.common.FastAnalyzer import org.jetbrains.kotlin.codegen.optimization.common.findPreviousOrNull +import org.jetbrains.kotlin.codegen.optimization.common.nodeType import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode @@ -40,8 +41,8 @@ class StackPeepholeOptimizationsTransformer : MethodTransformer() { fun AbstractInsnNode.previousMeaningful() = findPreviousOrNull { - it.opcode != Opcodes.NOP && it.type != AbstractInsnNode.LINE && - (it.type != AbstractInsnNode.LABEL || isMergeNode[instructions.indexOf(it)]) + it.opcode != Opcodes.NOP && it.nodeType != AbstractInsnNode.LINE && + (it.nodeType != AbstractInsnNode.LABEL || isMergeNode[instructions.indexOf(it)]) } var insn: AbstractInsnNode? diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/ControlFlowGraph.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/ControlFlowGraph.kt index 3a89a1ef9ce..0c7e2a0c774 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/ControlFlowGraph.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/ControlFlowGraph.kt @@ -60,7 +60,7 @@ class ControlFlowGraph private constructor(private val insns: InsnList) { val insnNode = method.instructions[insn] val insnOpcode = insnNode.opcode - when (insnNode.type) { + when (insnNode.nodeType) { AbstractInsnNode.LABEL, AbstractInsnNode.LINE, AbstractInsnNode.FRAME -> visitOpInsn(insn) AbstractInsnNode.JUMP_INSN -> diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FastAnalyzer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FastAnalyzer.kt index a1e763ab56d..bb6a233654f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FastAnalyzer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/FastAnalyzer.kt @@ -96,7 +96,7 @@ abstract class FastAnalyzer>( handler: F ) { val insnOpcode = insnNode.opcode - val insnType = insnNode.type + val insnType = insnNode.nodeType if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || @@ -349,7 +349,7 @@ abstract class FastAnalyzer>( fun findMergeNodes(method: MethodNode): BooleanArray { val isMergeNode = BooleanArray(method.instructions.size()) for (insn in method.instructions) { - when (insn.type) { + when (insn.nodeType) { AbstractInsnNode.JUMP_INSN -> { val jumpInsn = insn as JumpInsnNode isMergeNode[method.instructions.indexOf(jumpInsn.label)] = true diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/InstructionLivenessAnalyzer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/InstructionLivenessAnalyzer.kt index dfc2ea3ce1d..bef0b3e97f9 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/InstructionLivenessAnalyzer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/InstructionLivenessAnalyzer.kt @@ -79,7 +79,7 @@ class InstructionLivenessAnalyzer( val insnNode = method.instructions[insn] val insnOpcode = insnNode.opcode - when (insnNode.type) { + when (insnNode.nodeType) { AbstractInsnNode.LABEL, AbstractInsnNode.LINE, AbstractInsnNode.FRAME -> visitOpInsn(insn) AbstractInsnNode.JUMP_INSN -> 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 6eaff8eb88a..3c272cd2b08 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,14 +27,14 @@ import org.jetbrains.org.objectweb.asm.tree.* val AbstractInsnNode.isMeaningful: Boolean get() = - when (this.type) { + when (this.nodeType) { AbstractInsnNode.LABEL, AbstractInsnNode.LINE, AbstractInsnNode.FRAME -> false else -> true } val AbstractInsnNode.isBranchOrCall: Boolean get() = - when (this.type) { + when (this.nodeType) { AbstractInsnNode.JUMP_INSN, AbstractInsnNode.TABLESWITCH_INSN, AbstractInsnNode.LOOKUPSWITCH_INSN, @@ -42,6 +42,40 @@ val AbstractInsnNode.isBranchOrCall: Boolean else -> false } +private val opcodeToNodeType = IntArray(IFNONNULL + 1) { + when (it) { + in NOP..DCONST_1, in IALOAD..SALOAD, in IASTORE..LXOR, in I2L..DCMPG, in IRETURN..RETURN, + ARRAYLENGTH, ATHROW, MONITORENTER, MONITOREXIT -> AbstractInsnNode.INSN + in BIPUSH..SIPUSH, NEWARRAY -> AbstractInsnNode.INT_INSN + in ILOAD..ALOAD, in ISTORE..ASTORE, RET -> AbstractInsnNode.VAR_INSN + NEW, ANEWARRAY, CHECKCAST, INSTANCEOF -> AbstractInsnNode.TYPE_INSN + in GETSTATIC..PUTFIELD -> AbstractInsnNode.FIELD_INSN + in INVOKEVIRTUAL..INVOKEINTERFACE -> AbstractInsnNode.METHOD_INSN + INVOKEDYNAMIC -> AbstractInsnNode.INVOKE_DYNAMIC_INSN + in IFEQ..JSR, IFNULL, IFNONNULL -> AbstractInsnNode.JUMP_INSN + LDC -> AbstractInsnNode.LDC_INSN + IINC -> AbstractInsnNode.IINC_INSN + TABLESWITCH -> AbstractInsnNode.TABLESWITCH_INSN + LOOKUPSWITCH -> AbstractInsnNode.LOOKUPSWITCH_INSN + MULTIANEWARRAY -> AbstractInsnNode.MULTIANEWARRAY_INSN + else -> -1 + } +} + +// Faster version of `AbstractInsnNode.getType` +val AbstractInsnNode.nodeType: Int + get() { + return when (val opcode = this.opcode) { + -1 -> when (this) { + is LabelNode -> AbstractInsnNode.LABEL + is FrameNode -> AbstractInsnNode.FRAME + is LineNumberNode -> AbstractInsnNode.LINE + else -> -1 + } + else -> opcodeToNodeType.getOrElse(opcode) { -1 } + } + } + class InsnSequence(val from: AbstractInsnNode, val to: AbstractInsnNode?) : Sequence { constructor(insnList: InsnList) : this(insnList.first, null) @@ -77,7 +111,7 @@ fun MethodNode.prepareForEmitting() { while (!current.isMeaningful) { val prev = current.previous - if (current.type == AbstractInsnNode.LINE) { + if (current.nodeType == AbstractInsnNode.LINE) { instructions.remove(current) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/temporaryVals/TemporaryVals.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/temporaryVals/TemporaryVals.kt index 33671c129fa..4157acc9093 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/temporaryVals/TemporaryVals.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/temporaryVals/TemporaryVals.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.codegen.optimization.temporaryVals import org.jetbrains.kotlin.codegen.optimization.OptimizationMethodVisitor import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful import org.jetbrains.kotlin.codegen.optimization.common.isStoreOperation +import org.jetbrains.kotlin.codegen.optimization.common.nodeType import org.jetbrains.kotlin.utils.SmartSet import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes.API_VERSION @@ -53,7 +54,7 @@ class TemporaryValsAnalyzer { potentiallyTemporaryStores.remove(p) break } else if ( - p.type == AbstractInsnNode.LABEL || + p.nodeType == AbstractInsnNode.LABEL || p.opcode in Opcodes.IRETURN..Opcodes.RETURN || p.opcode == Opcodes.GOTO || p.opcode == Opcodes.ATHROW diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/temporaryVals/TemporaryVariablesEliminationTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/temporaryVals/TemporaryVariablesEliminationTransformer.kt index f4fa3cdc9b8..aad2ecdaba7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/temporaryVals/TemporaryVariablesEliminationTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/temporaryVals/TemporaryVariablesEliminationTransformer.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.codegen.inline.isSuspendInlineMarker import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful import org.jetbrains.kotlin.codegen.optimization.common.removeUnusedLocalVariables +import org.jetbrains.kotlin.codegen.optimization.common.nodeType import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckExpressionValueIsNotNull import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckNotNullWithMessage import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer @@ -168,7 +169,7 @@ class TemporaryVariablesEliminationTransformer(private val state: GenerationStat } for (insn in insnList) { - when (insn.type) { + when (insn.nodeType) { AbstractInsnNode.LINE -> { usedLabels.add((insn as LineNumberNode).start) } @@ -570,7 +571,7 @@ class TemporaryVariablesEliminationTransformer(private val state: GenerationStat } private fun AbstractInsnNode.isIntervening(context: ControlFlowGraph): Boolean = - when (this.type) { + when (this.nodeType) { AbstractInsnNode.LINE, AbstractInsnNode.FRAME -> false AbstractInsnNode.LABEL ->