[JVM] Combine all analyzeInstruction methods
This commit is contained in:
+50
-12
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
+2
-46
@@ -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.
|
||||
|
||||
+1
-39
@@ -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 {
|
||||
|
||||
+1
-28
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user