[JVM] Avoid inheritance from FastMethodAnalyzer

This way it is easier to analyze code.
This commit is contained in:
Ivan Kylchik
2023-08-24 14:46:42 +02:00
committed by Space Team
parent 5f27e1a6b2
commit 6f8e243f0b
6 changed files with 63 additions and 71 deletions
@@ -86,10 +86,9 @@ class UninitializedStoresProcessor(private val methodNode: MethodNode) {
return
val interpreter = UninitializedNewValueMarkerInterpreter(methodNode.instructions)
val analyzer = object : FastMethodAnalyzer<BasicValue>("fake", methodNode, interpreter, pruneExceptionEdges = true) {
override fun newFrame(nLocals: Int, nStack: Int): Frame<BasicValue> =
UninitializedNewValueFrame(nLocals, nStack)
}
val analyzer = FastMethodAnalyzer<BasicValue>(
"fake", methodNode, interpreter, pruneExceptionEdges = true
) { nLocals, nStack -> UninitializedNewValueFrame(nLocals, nStack) }
val frames = analyzer.analyze()
interpreter.analyzePopInstructions(frames)
@@ -63,7 +63,7 @@ internal class FunctionalArgumentValue(
val BasicValue?.functionalArgument
get() = (this as? FunctionalArgumentValue)?.functionalArgument
internal class FunctionalArgumentInterpreter(private val inliner: MethodInliner) : BasicInterpreter(Opcodes.API_VERSION) {
internal class FunctionalArgumentInterpreter(private val inliner: MethodInliner) : BasicInterpreter(API_VERSION) {
override fun newParameterValue(isInstanceMethod: Boolean, local: Int, type: Type): BasicValue =
inliner.getFunctionalArgumentIfExists(local)?.let { FunctionalArgumentValue(it, newValue(type)) } ?: newValue(type)
@@ -95,11 +95,11 @@ internal class Aload0BasicValue private constructor(val indices: Set<Int>) : Bas
operator fun plus(other: Aload0BasicValue) = Aload0BasicValue(indices + other.indices)
}
internal class Aload0Interpreter(private val node: MethodNode) : BasicInterpreter(Opcodes.API_VERSION) {
internal class Aload0Interpreter(private val node: MethodNode) : BasicInterpreter(API_VERSION) {
override fun copyOperation(insn: AbstractInsnNode, value: BasicValue?): BasicValue? =
when {
insn.isAload0() -> Aload0BasicValue(node.instructions.indexOf(insn))
insn.opcode == Opcodes.ALOAD -> if (value == null) null else BasicValue(value.type)
insn.opcode == ALOAD -> if (value == null) null else BasicValue(value.type)
else -> super.copyOperation(insn, value)
}
@@ -113,19 +113,19 @@ internal fun analyzeMethodNodeWithInterpreter(
node: MethodNode,
interpreter: BasicInterpreter
): Array<out Frame<BasicValue>?> {
val analyzer = object : FastMethodAnalyzer<BasicValue>("fake", node, interpreter, pruneExceptionEdges = true) {
override fun newFrame(nLocals: Int, nStack: Int): Frame<BasicValue> {
return object : Frame<BasicValue>(nLocals, nStack) {
@Throws(AnalyzerException::class)
override fun execute(insn: AbstractInsnNode, interpreter: Interpreter<BasicValue>) {
// This can be a void non-local return from a non-void method; Frame#execute would throw and do nothing else.
if (insn.opcode == Opcodes.RETURN) return
super.execute(insn, interpreter)
}
}
class BasicValueFrame(nLocals: Int, nStack: Int) : Frame<BasicValue>(nLocals, nStack) {
@Throws(AnalyzerException::class)
override fun execute(insn: AbstractInsnNode, interpreter: Interpreter<BasicValue>) {
// This can be a void non-local return from a non-void method; Frame#execute would throw and do nothing else.
if (insn.opcode == Opcodes.RETURN) return
super.execute(insn, interpreter)
}
}
val analyzer = FastMethodAnalyzer<BasicValue>(
"fake", node, interpreter, pruneExceptionEdges = true
) { nLocals, nStack -> BasicValueFrame(nLocals, nStack) }
try {
return analyzer.analyze()
} catch (e: AnalyzerException) {
@@ -1,49 +0,0 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen.optimization.boxing
import org.jetbrains.kotlin.codegen.optimization.common.FastMethodAnalyzer
import org.jetbrains.org.objectweb.asm.tree.MethodNode
import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException
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
class BoxingAnalyzer(
owner: String,
method: MethodNode,
private val boxingInterpreter: BoxingInterpreter
) : FastMethodAnalyzer<BasicValue>(owner, method, boxingInterpreter) {
override fun newFrame(nLocals: Int, nStack: Int): Frame<BasicValue> =
BoxingFrame(nLocals, nStack)
private inner class BoxingFrame(nLocals: Int, nStack: Int) : Frame<BasicValue>(nLocals, nStack) {
override fun merge(frame: Frame<out BasicValue>, interpreter: Interpreter<BasicValue>): Boolean {
if (stackSize != frame.stackSize) {
throw AnalyzerException(null, "Incompatible stack heights")
}
var changed = false
for (i in 0 until locals) {
val local = getLocal(i)
val merged = boxingInterpreter.mergeLocalVariableValues(local, frame.getLocal(i))
if (local != merged) {
setLocal(i, merged)
changed = true
}
}
for (i in 0 until stackSize) {
val onStack = getStack(i)
val merged = boxingInterpreter.mergeStackValues(onStack, frame.getStack(i))
if (onStack != merged) {
setStack(i, merged)
changed = true
}
}
return changed
}
}
}
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen.optimization.boxing
import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException
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
class BoxingFrame(nLocals: Int, nStack: Int, private val boxingInterpreter: BoxingInterpreter) : Frame<BasicValue>(nLocals, nStack) {
override fun merge(frame: Frame<out BasicValue>, interpreter: Interpreter<BasicValue>): Boolean {
if (stackSize != frame.stackSize) {
throw AnalyzerException(null, "Incompatible stack heights")
}
var changed = false
for (i in 0 until locals) {
val local = getLocal(i)
val merged = boxingInterpreter.mergeLocalVariableValues(local, frame.getLocal(i))
if (local != merged) {
setLocal(i, merged)
changed = true
}
}
for (i in 0 until stackSize) {
val onStack = getStack(i)
val merged = boxingInterpreter.mergeStackValues(onStack, frame.getStack(i))
if (onStack != merged) {
setStack(i, merged)
changed = true
}
}
return changed
}
}
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.Pair
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.FastMethodAnalyzer
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
import org.jetbrains.kotlin.codegen.optimization.common.remapLocalVariables
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
@@ -41,7 +42,10 @@ class RedundantBoxingMethodTransformer(private val generationState: GenerationSt
return
val interpreter = RedundantBoxingInterpreter(node, generationState)
val frames = BoxingAnalyzer(internalClassName, node, interpreter).analyze()
val analyzer = FastMethodAnalyzer<BasicValue>(
internalClassName, node, interpreter, pruneExceptionEdges = false
) { nLocals, nStack -> BoxingFrame(nLocals, nStack, interpreter) }
val frames = analyzer.analyze()
interpretPopInstructionsForBoxedValues(interpreter, node, frames)
@@ -44,18 +44,18 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Value
/**
* @see org.jetbrains.kotlin.codegen.optimization.fixStack.FastStackAnalyzer
*/
open class FastMethodAnalyzer<V : Value>
class FastMethodAnalyzer<V : Value>
@JvmOverloads constructor(
owner: String,
method: MethodNode,
interpreter: Interpreter<V>,
private val pruneExceptionEdges: Boolean = false
private val pruneExceptionEdges: Boolean = false,
private val createFrame: (Int, Int) -> Frame<V> = { nLocals, nStack -> Frame<V>(nLocals, nStack) }
) : FastAnalyzer<V, Interpreter<V>, Frame<V>>(owner, method, interpreter) {
private val isMergeNode = findMergeNodes(method)
private val isTcbStart = BooleanArray(nInsns)
override fun newFrame(nLocals: Int, nStack: Int): Frame<V> =
Frame(nLocals, nStack)
override fun newFrame(nLocals: Int, nStack: Int): Frame<V> = createFrame(nLocals, nStack)
override fun beforeAnalyze() {
for (tcb in method.tryCatchBlocks) {