[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
|
return
|
||||||
|
|
||||||
val interpreter = UninitializedNewValueMarkerInterpreter(methodNode.instructions)
|
val interpreter = UninitializedNewValueMarkerInterpreter(methodNode.instructions)
|
||||||
val analyzer = object : FastMethodAnalyzer<BasicValue>("fake", methodNode, interpreter, pruneExceptionEdges = true) {
|
val analyzer = FastMethodAnalyzer<BasicValue>(
|
||||||
override fun newFrame(nLocals: Int, nStack: Int): Frame<BasicValue> =
|
"fake", methodNode, interpreter, pruneExceptionEdges = true
|
||||||
UninitializedNewValueFrame(nLocals, nStack)
|
) { nLocals, nStack -> UninitializedNewValueFrame(nLocals, nStack) }
|
||||||
}
|
|
||||||
val frames = analyzer.analyze()
|
val frames = analyzer.analyze()
|
||||||
interpreter.analyzePopInstructions(frames)
|
interpreter.analyzePopInstructions(frames)
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ internal class FunctionalArgumentValue(
|
|||||||
val BasicValue?.functionalArgument
|
val BasicValue?.functionalArgument
|
||||||
get() = (this as? FunctionalArgumentValue)?.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 =
|
override fun newParameterValue(isInstanceMethod: Boolean, local: Int, type: Type): BasicValue =
|
||||||
inliner.getFunctionalArgumentIfExists(local)?.let { FunctionalArgumentValue(it, newValue(type)) } ?: newValue(type)
|
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)
|
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? =
|
override fun copyOperation(insn: AbstractInsnNode, value: BasicValue?): BasicValue? =
|
||||||
when {
|
when {
|
||||||
insn.isAload0() -> Aload0BasicValue(node.instructions.indexOf(insn))
|
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)
|
else -> super.copyOperation(insn, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,19 +113,19 @@ internal fun analyzeMethodNodeWithInterpreter(
|
|||||||
node: MethodNode,
|
node: MethodNode,
|
||||||
interpreter: BasicInterpreter
|
interpreter: BasicInterpreter
|
||||||
): Array<out Frame<BasicValue>?> {
|
): Array<out Frame<BasicValue>?> {
|
||||||
val analyzer = object : FastMethodAnalyzer<BasicValue>("fake", node, interpreter, pruneExceptionEdges = true) {
|
class BasicValueFrame(nLocals: Int, nStack: Int) : Frame<BasicValue>(nLocals, nStack) {
|
||||||
override fun newFrame(nLocals: Int, nStack: Int): Frame<BasicValue> {
|
@Throws(AnalyzerException::class)
|
||||||
return object : Frame<BasicValue>(nLocals, nStack) {
|
override fun execute(insn: AbstractInsnNode, interpreter: Interpreter<BasicValue>) {
|
||||||
@Throws(AnalyzerException::class)
|
// This can be a void non-local return from a non-void method; Frame#execute would throw and do nothing else.
|
||||||
override fun execute(insn: AbstractInsnNode, interpreter: Interpreter<BasicValue>) {
|
if (insn.opcode == Opcodes.RETURN) return
|
||||||
// This can be a void non-local return from a non-void method; Frame#execute would throw and do nothing else.
|
super.execute(insn, interpreter)
|
||||||
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 {
|
try {
|
||||||
return analyzer.analyze()
|
return analyzer.analyze()
|
||||||
} catch (e: AnalyzerException) {
|
} 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.insnOpcodeText
|
||||||
import org.jetbrains.kotlin.codegen.inline.insnText
|
import org.jetbrains.kotlin.codegen.inline.insnText
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
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.StrictBasicValue
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.remapLocalVariables
|
import org.jetbrains.kotlin.codegen.optimization.common.remapLocalVariables
|
||||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
|
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
|
||||||
@@ -41,7 +42,10 @@ class RedundantBoxingMethodTransformer(private val generationState: GenerationSt
|
|||||||
return
|
return
|
||||||
|
|
||||||
val interpreter = RedundantBoxingInterpreter(node, generationState)
|
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)
|
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
|
* @see org.jetbrains.kotlin.codegen.optimization.fixStack.FastStackAnalyzer
|
||||||
*/
|
*/
|
||||||
open class FastMethodAnalyzer<V : Value>
|
class FastMethodAnalyzer<V : Value>
|
||||||
@JvmOverloads constructor(
|
@JvmOverloads constructor(
|
||||||
owner: String,
|
owner: String,
|
||||||
method: MethodNode,
|
method: MethodNode,
|
||||||
interpreter: Interpreter<V>,
|
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) {
|
) : FastAnalyzer<V, Interpreter<V>, Frame<V>>(owner, method, interpreter) {
|
||||||
private val isMergeNode = findMergeNodes(method)
|
private val isMergeNode = findMergeNodes(method)
|
||||||
private val isTcbStart = BooleanArray(nInsns)
|
private val isTcbStart = BooleanArray(nInsns)
|
||||||
|
|
||||||
override fun newFrame(nLocals: Int, nStack: Int): Frame<V> =
|
override fun newFrame(nLocals: Int, nStack: Int): Frame<V> = createFrame(nLocals, nStack)
|
||||||
Frame(nLocals, nStack)
|
|
||||||
|
|
||||||
override fun beforeAnalyze() {
|
override fun beforeAnalyze() {
|
||||||
for (tcb in method.tryCatchBlocks) {
|
for (tcb in method.tryCatchBlocks) {
|
||||||
|
|||||||
Reference in New Issue
Block a user