[JVM] Avoid inheritance from FastMethodAnalyzer
This way it is easier to analyze code.
This commit is contained in:
+3
-4
@@ -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) {
|
||||
|
||||
-49
@@ -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
|
||||
}
|
||||
}
|
||||
+5
-1
@@ -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)
|
||||
|
||||
|
||||
+4
-4
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user