JVM use FastMethodAnalyzer when possible

This commit is contained in:
Dmitry Petrov
2021-07-09 13:08:13 +03:00
committed by teamcityserver
parent c54e680021
commit 68560c60f3
7 changed files with 20 additions and 15 deletions
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.codegen.coroutines package org.jetbrains.kotlin.codegen.coroutines
import org.jetbrains.kotlin.codegen.optimization.boxing.isUnitInstance import org.jetbrains.kotlin.codegen.optimization.boxing.isUnitInstance
import org.jetbrains.kotlin.codegen.optimization.common.MethodAnalyzer import org.jetbrains.kotlin.codegen.optimization.common.FastMethodAnalyzer
import org.jetbrains.kotlin.codegen.optimization.common.asSequence import org.jetbrains.kotlin.codegen.optimization.common.asSequence
import org.jetbrains.kotlin.codegen.optimization.common.removeAll import org.jetbrains.kotlin.codegen.optimization.common.removeAll
import org.jetbrains.kotlin.codegen.optimization.fixStack.top import org.jetbrains.kotlin.codegen.optimization.fixStack.top
@@ -85,7 +85,7 @@ private class UnitSourceInterpreter(private val localVariables: Set<Int>) : Basi
} }
fun run(internalClassName: String, methodNode: MethodNode): Array<Frame<BasicValue>?> { fun run(internalClassName: String, methodNode: MethodNode): Array<Frame<BasicValue>?> {
val frames = MethodAnalyzer<BasicValue>(internalClassName, methodNode, this).analyze() val frames = FastMethodAnalyzer<BasicValue>(internalClassName, methodNode, this).analyze()
// The ASM analyzer does not visit POP instructions, so we do so here. // The ASM analyzer does not visit POP instructions, so we do so here.
for ((insn, frame) in methodNode.instructions.asSequence().zip(frames.asSequence())) { for ((insn, frame) in methodNode.instructions.asSequence().zip(frames.asSequence())) {
if (frame != null && insn.opcode == Opcodes.POP) { if (frame != null && insn.opcode == Opcodes.POP) {
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.codegen.coroutines package org.jetbrains.kotlin.codegen.coroutines
import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.optimization.common.MethodAnalyzer import org.jetbrains.kotlin.codegen.optimization.common.FastMethodAnalyzer
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes
@@ -130,11 +130,11 @@ internal fun performSpilledVariableFieldTypesAnalysis(
thisName: String thisName: String
): Array<out Frame<BasicValue>?> { ): Array<out Frame<BasicValue>?> {
val interpreter = IntLikeCoerceInterpreter() val interpreter = IntLikeCoerceInterpreter()
MethodAnalyzer(thisName, methodNode, interpreter).analyze() FastMethodAnalyzer(thisName, methodNode, interpreter).analyze()
for ((insn, type) in interpreter.needsToBeCoerced) { for ((insn, type) in interpreter.needsToBeCoerced) {
methodNode.instructions.insert(insn, withInstructionAdapter { coerceInt(type, this) }) methodNode.instructions.insert(insn, withInstructionAdapter { coerceInt(type, this) })
} }
return MethodAnalyzer(thisName, methodNode, OptimizationBasicInterpreter()).analyze() return FastMethodAnalyzer(thisName, methodNode, OptimizationBasicInterpreter()).analyze()
} }
private fun coerceInt(to: Type, v: InstructionAdapter) { private fun coerceInt(to: Type, v: InstructionAdapter) {
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.codegen.inline package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.kotlin.codegen.optimization.common.FastMethodAnalyzer
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckParameterIsNotNull import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckParameterIsNotNull
@@ -136,7 +137,7 @@ internal class Aload0Interpreter(private val node: MethodNode) : BasicInterprete
internal fun AbstractInsnNode.isAload0() = opcode == Opcodes.ALOAD && (this as VarInsnNode).`var` == 0 internal fun AbstractInsnNode.isAload0() = opcode == Opcodes.ALOAD && (this as VarInsnNode).`var` == 0
internal fun analyzeMethodNodeWithInterpreter(node: MethodNode, interpreter: BasicInterpreter): Array<out Frame<BasicValue>?> { internal fun analyzeMethodNodeWithInterpreter(node: MethodNode, interpreter: BasicInterpreter): Array<out Frame<BasicValue>?> {
val analyzer = object : Analyzer<BasicValue>(interpreter) { val analyzer = object : FastMethodAnalyzer<BasicValue>("fake", node, interpreter) {
override fun newFrame(nLocals: Int, nStack: Int): Frame<BasicValue> { override fun newFrame(nLocals: Int, nStack: Int): Frame<BasicValue> {
return object : Frame<BasicValue>(nLocals, nStack) { return object : Frame<BasicValue>(nLocals, nStack) {
@@ -151,7 +152,7 @@ internal fun analyzeMethodNodeWithInterpreter(node: MethodNode, interpreter: Bas
} }
try { try {
return analyzer.analyze("fake", node) return analyzer.analyze()
} catch (e: AnalyzerException) { } catch (e: AnalyzerException) {
throw RuntimeException(e) throw RuntimeException(e)
} }
@@ -17,13 +17,16 @@
package org.jetbrains.kotlin.codegen.optimization.boxing package org.jetbrains.kotlin.codegen.optimization.boxing
import org.jetbrains.kotlin.codegen.optimization.OptimizationMethodVisitor import org.jetbrains.kotlin.codegen.optimization.OptimizationMethodVisitor
import org.jetbrains.kotlin.codegen.optimization.common.FastMethodAnalyzer
import org.jetbrains.kotlin.codegen.optimization.common.isLoadOperation import org.jetbrains.kotlin.codegen.optimization.common.isLoadOperation
import org.jetbrains.kotlin.codegen.optimization.fixStack.peekWords import org.jetbrains.kotlin.codegen.optimization.fixStack.peekWords
import org.jetbrains.kotlin.codegen.optimization.fixStack.top import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.org.objectweb.asm.Opcodes 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.analysis.Analyzer import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
import org.jetbrains.org.objectweb.asm.tree.InsnNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
import org.jetbrains.org.objectweb.asm.tree.analysis.SourceInterpreter import org.jetbrains.org.objectweb.asm.tree.analysis.SourceInterpreter
import org.jetbrains.org.objectweb.asm.tree.analysis.SourceValue import org.jetbrains.org.objectweb.asm.tree.analysis.SourceValue
@@ -52,7 +55,7 @@ class PopBackwardPropagationTransformer : MethodTransformer() {
private val dontTouchInsnIndices = BitSet(insns.size) private val dontTouchInsnIndices = BitSet(insns.size)
fun transform() { fun transform() {
val frames = Analyzer(HazardsTrackingInterpreter()).analyze("fake", methodNode) val frames = FastMethodAnalyzer("fake", methodNode, HazardsTrackingInterpreter()).analyze()
for ((i, insn) in insns.withIndex()) { for ((i, insn) in insns.withIndex()) {
val frame = frames[i] ?: continue val frame = frames[i] ?: continue
when (insn.opcode) { when (insn.opcode) {
@@ -12,8 +12,8 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
class ControlFlowGraph private constructor(private val insns: InsnList) { class ControlFlowGraph private constructor(private val insns: InsnList) {
private val edges: Array<MutableList<Int>> = Array(insns.size()) { arrayListOf<Int>() } private val edges: Array<MutableList<Int>> = Array(insns.size()) { ArrayList() }
private val backwardEdges: Array<MutableList<Int>> = Array(insns.size()) { arrayListOf<Int>() } private val backwardEdges: Array<MutableList<Int>> = Array(insns.size()) { ArrayList() }
fun getSuccessorsIndices(insn: AbstractInsnNode): List<Int> = getSuccessorsIndices(insns.indexOf(insn)) fun getSuccessorsIndices(insn: AbstractInsnNode): List<Int> = getSuccessorsIndices(insns.indexOf(insn))
fun getSuccessorsIndices(index: Int): List<Int> = edges[index] fun getSuccessorsIndices(index: Int): List<Int> = edges[index]
@@ -30,6 +30,7 @@ class ControlFlowGraph private constructor(private val insns: InsnList) {
graph.backwardEdges[to].add(from) graph.backwardEdges[to].add(from)
} }
// TODO custom analyzer, no need to analyze data flow
object : MethodAnalyzer<BasicValue>("fake", node, OptimizationBasicInterpreter()) { object : MethodAnalyzer<BasicValue>("fake", node, OptimizationBasicInterpreter()) {
override fun visitControlFlowEdge(insn: Int, successor: Int): Boolean { override fun visitControlFlowEdge(insn: Int, successor: Int): Boolean {
addEdge(insn, successor) addEdge(insn, successor)
@@ -24,6 +24,6 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Value
class CustomFramesMethodAnalyzer<V : Value>( class CustomFramesMethodAnalyzer<V : Value>(
owner: String, method: MethodNode, interpreter: Interpreter<V>, owner: String, method: MethodNode, interpreter: Interpreter<V>,
private val frameFactory: (Int, Int) -> Frame<V> private val frameFactory: (Int, Int) -> Frame<V>
) : MethodAnalyzer<V>(owner, method, interpreter) { ) : FastMethodAnalyzer<V>(owner, method, interpreter) {
override fun newFrame(nLocals: Int, nStack: Int) = frameFactory(nLocals, nStack) override fun newFrame(nLocals: Int, nStack: Int) = frameFactory(nLocals, nStack)
} }
@@ -45,7 +45,7 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
import org.jetbrains.org.objectweb.asm.tree.analysis.Value import org.jetbrains.org.objectweb.asm.tree.analysis.Value
@Suppress("DuplicatedCode") @Suppress("DuplicatedCode")
class FastMethodAnalyzer<V : Value>( open class FastMethodAnalyzer<V : Value>(
private val owner: String, private val owner: String,
val method: MethodNode, val method: MethodNode,
private val interpreter: Interpreter<V> private val interpreter: Interpreter<V>
@@ -87,7 +87,7 @@ class FastMethodAnalyzer<V : Value>(
private val queue = IntArray(nInsns) private val queue = IntArray(nInsns)
private var top = 0 private var top = 0
private fun newFrame(nLocals: Int, nStack: Int): Frame<V> = protected open fun newFrame(nLocals: Int, nStack: Int): Frame<V> =
Frame(nLocals, nStack) Frame(nLocals, nStack)
fun analyze(): Array<Frame<V>?> { fun analyze(): Array<Frame<V>?> {