[JVM] Combine all analyzeInstruction methods

This commit is contained in:
Ivan Kylchik
2023-09-06 11:22:43 +02:00
committed by Space Team
parent 58473b94a7
commit 68e4a7a318
4 changed files with 54 additions and 125 deletions
@@ -19,12 +19,14 @@ abstract class FastAnalyzer<V : Value, I : Interpreter<V>, F : Frame<V>>(
protected val owner: String,
protected val method: MethodNode,
protected val interpreter: I,
private val pruneExceptionEdges: Boolean,
) {
protected val nInsns = method.instructions.size()
protected val handlers: Array<MutableList<TryCatchBlockNode>?> = arrayOfNulls(nInsns)
private val nInsns = method.instructions.size()
private val frames: Array<Frame<V>?> = arrayOfNulls(nInsns)
protected val handlers: Array<MutableList<TryCatchBlockNode>?> = arrayOfNulls(nInsns)
protected val isTcbStart = BooleanArray(nInsns)
private val queued = BooleanArray(nInsns)
private val queue = IntArray(nInsns)
private var top = 0
@@ -56,11 +58,9 @@ abstract class FastAnalyzer<V : Value, I : Interpreter<V>, F : Frame<V>>(
queued[insn] = false
val insnNode = method.instructions[insn]
val insnOpcode = insnNode.opcode
val insnType = insnNode.type
try {
analyzeInstruction(insnNode, insn, insnType, insnOpcode, f, current, handler)
analyzeInstruction(insnNode, insn, f, current, handler)
} catch (e: AnalyzerException) {
throw AnalyzerException(
e.node,
@@ -111,15 +111,53 @@ abstract class FastAnalyzer<V : Value, I : Interpreter<V>, F : Frame<V>>(
protected abstract fun mergeControlFlowEdge(dest: Int, frame: F, canReuse: Boolean = false)
protected abstract fun analyzeInstruction(
private fun analyzeInstruction(
insnNode: AbstractInsnNode,
insnIndex: Int,
insnType: Int,
insnOpcode: Int,
currentlyAnalyzing: F,
current: F,
handler: F
)
) {
val insnOpcode = insnNode.opcode
val insnType = insnNode.type
if (insnType == AbstractInsnNode.LABEL ||
insnType == AbstractInsnNode.LINE ||
insnType == AbstractInsnNode.FRAME ||
insnOpcode == Opcodes.NOP
) {
visitNopInsn(insnNode, currentlyAnalyzing, insnIndex)
} else {
current.init(currentlyAnalyzing)
if (insnOpcode != Opcodes.RETURN) {
// Don't care about possibly incompatible return type
current.execute(insnNode, interpreter)
}
visitMeaningfulInstruction(insnNode, insnType, insnOpcode, current, insnIndex)
}
// Jump by an exception edge clears the stack, putting exception on top.
// So, unless we have a store operation, anything we change on stack would be lost,
// and there's no need to analyze exception handler again.
// Add an exception edge from TCB start to make sure handler itself is still visited.
if (!pruneExceptionEdges ||
insnOpcode in Opcodes.ISTORE..Opcodes.ASTORE ||
insnOpcode == Opcodes.IINC ||
isTcbStart[insnIndex]
) {
handlers[insnIndex]?.forEach { tcb ->
val exnType = Type.getObjectType(tcb.type ?: "java/lang/Throwable")
val jump = tcb.handler.indexOf()
handler.init(currentlyAnalyzing)
if (handler.maxStackSize > 0) {
handler.clearStack()
handler.push(interpreter.newExceptionValue(tcb, handler, exnType))
}
mergeControlFlowEdge(jump, handler)
}
}
}
protected abstract fun newFrame(nLocals: Int, nStack: Int): F
@@ -133,7 +171,7 @@ abstract class FastAnalyzer<V : Value, I : Interpreter<V>, F : Frame<V>>(
frames[index] = newFrame
}
protected fun visitMeaningfulInstruction(insnNode: AbstractInsnNode, insnType: Int, insnOpcode: Int, current: F, insn: Int) {
private fun visitMeaningfulInstruction(insnNode: AbstractInsnNode, insnType: Int, insnOpcode: Int, current: F, insn: Int) {
when {
insnType == AbstractInsnNode.JUMP_INSN ->
visitJumpInsnNode(insnNode as JumpInsnNode, current, insn, insnOpcode)
@@ -148,7 +186,7 @@ abstract class FastAnalyzer<V : Value, I : Interpreter<V>, F : Frame<V>>(
}
}
protected fun visitNopInsn(insnNode: AbstractInsnNode, current: F, insn: Int) {
private fun visitNopInsn(insnNode: AbstractInsnNode, current: F, insn: Int) {
processControlFlowEdge(current, insnNode, insn + 1, canReuse = true)
}
@@ -33,8 +33,6 @@
package org.jetbrains.kotlin.codegen.optimization.common
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.*
import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
@@ -49,11 +47,10 @@ class FastMethodAnalyzer<V : Value>
owner: String,
method: MethodNode,
interpreter: Interpreter<V>,
private val pruneExceptionEdges: Boolean = false,
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, pruneExceptionEdges) {
private val isMergeNode = findMergeNodes(method)
private val isTcbStart = BooleanArray(nInsns)
override fun newFrame(nLocals: Int, nStack: Int): Frame<V> = createFrame(nLocals, nStack)
@@ -63,47 +60,6 @@ class FastMethodAnalyzer<V : Value>
}
}
override fun analyzeInstruction(
insnNode: AbstractInsnNode,
insnIndex: Int,
insnType: Int,
insnOpcode: Int,
currentlyAnalyzing: Frame<V>,
current: Frame<V>,
handler: Frame<V>,
) {
if (insnType == AbstractInsnNode.LABEL ||
insnType == AbstractInsnNode.LINE ||
insnType == AbstractInsnNode.FRAME ||
insnOpcode == Opcodes.NOP
) {
visitNopInsn(insnNode, currentlyAnalyzing, insnIndex)
} else {
current.init(currentlyAnalyzing).execute(insnNode, interpreter)
visitMeaningfulInstruction(insnNode, insnType, insnOpcode, current, insnIndex)
}
// Jump by an exception edge clears the stack, putting exception on top.
// So, unless we have a store operation, anything we change on stack would be lost,
// and there's no need to analyze exception handler again.
// Add an exception edge from TCB start to make sure handler itself is still visited.
if (!pruneExceptionEdges ||
insnOpcode in Opcodes.ISTORE..Opcodes.ASTORE ||
insnOpcode == Opcodes.IINC ||
isTcbStart[insnIndex]
) {
handlers[insnIndex]?.forEach { tcb ->
val exnType = Type.getObjectType(tcb.type ?: "java/lang/Throwable")
val jump = tcb.handler.indexOf()
handler.init(currentlyAnalyzing)
handler.clearStack()
handler.push(interpreter.newExceptionValue(tcb, handler, exnType))
mergeControlFlowEdge(jump, handler)
}
}
}
/**
* Updates frame at the index [dest] with its old value if provided and previous control flow node frame [frame].
* Reuses old frame when possible and when [canReuse] is true.
@@ -34,9 +34,6 @@
package org.jetbrains.kotlin.codegen.optimization.fixStack
import org.jetbrains.kotlin.codegen.optimization.common.FastAnalyzer
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
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.Interpreter
@@ -51,48 +48,13 @@ internal open class FastStackAnalyzer<V : Value, F : Frame<V>>(
owner: String,
method: MethodNode,
interpreter: Interpreter<V>
) : FastAnalyzer<V, Interpreter<V>, F>(owner, method, interpreter) {
) : FastAnalyzer<V, Interpreter<V>, F>(owner, method, interpreter, pruneExceptionEdges = false) {
@Suppress("UNCHECKED_CAST")
override fun newFrame(nLocals: Int, nStack: Int): F = Frame<V>(nLocals, nStack) as F
// Don't have to visit the same exception handler multiple times - we care only about stack state at TCB start.
override fun useFastComputeExceptionHandlers(): Boolean = true
override fun analyzeInstruction(
insnNode: AbstractInsnNode,
insnIndex: Int,
insnType: Int,
insnOpcode: Int,
currentlyAnalyzing: F,
current: F,
handler: F,
) {
if (insnType == AbstractInsnNode.LABEL ||
insnType == AbstractInsnNode.LINE ||
insnType == AbstractInsnNode.FRAME ||
insnOpcode == Opcodes.NOP
) {
visitNopInsn(insnNode, currentlyAnalyzing, insnIndex)
} else {
current.init(currentlyAnalyzing)
if (insnOpcode != Opcodes.RETURN) {
// Don't care about possibly incompatible return type
current.execute(insnNode, interpreter)
}
visitMeaningfulInstruction(insnNode, insnType, insnOpcode, current, insnIndex)
}
handlers[insnIndex]?.forEach { tcb ->
val exnType = Type.getObjectType(tcb.type ?: "java/lang/Throwable")
val jump = tcb.handler.indexOf()
handler.init(currentlyAnalyzing)
handler.clearStack()
handler.push(interpreter.newExceptionValue(tcb, handler, exnType))
mergeControlFlowEdge(jump, handler)
}
}
override fun mergeControlFlowEdge(dest: Int, frame: F, canReuse: Boolean) {
val oldFrame = getFrame(dest)
val changes = when {
@@ -67,36 +67,9 @@ class FastStoreLoadAnalyzer<V : Value>(
owner: String,
method: MethodNode,
interpreter: Interpreter<V>
) : FastAnalyzer<V, Interpreter<V>, StoreLoadFrame<V>>(owner, method, interpreter) {
) : FastAnalyzer<V, Interpreter<V>, StoreLoadFrame<V>>(owner, method, interpreter, pruneExceptionEdges = false) {
private val isMergeNode = FastMethodAnalyzer.findMergeNodes(method)
override fun analyzeInstruction(
insnNode: AbstractInsnNode,
insnIndex: Int,
insnType: Int,
insnOpcode: Int,
currentlyAnalyzing: StoreLoadFrame<V>,
current: StoreLoadFrame<V>,
handler: StoreLoadFrame<V>,
) {
if (insnType == AbstractInsnNode.LABEL ||
insnType == AbstractInsnNode.LINE ||
insnType == AbstractInsnNode.FRAME ||
insnOpcode == Opcodes.NOP
) {
visitNopInsn(insnNode, currentlyAnalyzing, insnIndex)
} else {
current.init(currentlyAnalyzing).execute(insnNode, interpreter)
visitMeaningfulInstruction(insnNode, insnType, insnOpcode, current, insnIndex)
}
handlers[insnIndex]?.forEach { tcb ->
val jump = tcb.handler.indexOf()
handler.init(currentlyAnalyzing)
mergeControlFlowEdge(jump, handler)
}
}
override fun newFrame(nLocals: Int, nStack: Int): StoreLoadFrame<V> = StoreLoadFrame(nLocals)
override fun mergeControlFlowEdge(dest: Int, frame: StoreLoadFrame<V>, canReuse: Boolean) {