[JVM] Extract unique code in Fast...Analyzer into analyzeInstruction

This commit is contained in:
Ivan Kylchik
2023-08-23 20:08:11 +02:00
committed by Space Team
parent bf53268453
commit e0dd3a33c0
3 changed files with 104 additions and 72 deletions
@@ -84,41 +84,11 @@ open class FastMethodAnalyzer<V : Value>
queued[insn] = false
val insnNode = method.instructions[insn]
try {
val insnOpcode = insnNode.opcode
val insnOpcode = insnNode.opcode
val insnType = insnNode.type
if (insnType == AbstractInsnNode.LABEL ||
insnType == AbstractInsnNode.LINE ||
insnType == AbstractInsnNode.FRAME ||
insnOpcode == Opcodes.NOP
) {
mergeControlFlowEdge(insn + 1, f, canReuse = true)
} else {
current.init(f).execute(insnNode, interpreter)
visitMeaningfulInstruction(insnNode, insnType, insnOpcode, current, insn)
}
// 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[insn]
) {
handlers[insn]?.forEach { tcb ->
val exnType = Type.getObjectType(tcb.type ?: "java/lang/Throwable")
val jump = tcb.handler.indexOf()
handler.init(f)
handler.clearStack()
handler.push(interpreter.newExceptionValue(tcb, handler, exnType))
mergeControlFlowEdge(jump, handler)
}
}
try {
analyzeInstruction(insnType, insnOpcode, insn, f, current, insnNode, isTcbStart, handler)
} catch (e: AnalyzerException) {
throw AnalyzerException(
e.node,
@@ -132,12 +102,53 @@ open class FastMethodAnalyzer<V : Value>
e
)
}
}
return frames
}
private fun analyzeInstruction(
insnType: Int,
insnOpcode: Int,
insn: Int,
f: Frame<V>,
current: Frame<V>,
insnNode: AbstractInsnNode,
isTcbStart: BooleanArray,
handler: Frame<V>,
) {
if (insnType == AbstractInsnNode.LABEL ||
insnType == AbstractInsnNode.LINE ||
insnType == AbstractInsnNode.FRAME ||
insnOpcode == Opcodes.NOP
) {
mergeControlFlowEdge(insn + 1, f, canReuse = true)
} else {
current.init(f).execute(insnNode, interpreter)
visitMeaningfulInstruction(insnNode, insnType, insnOpcode, current, insn)
}
// 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[insn]
) {
handlers[insn]?.forEach { tcb ->
val exnType = Type.getObjectType(tcb.type ?: "java/lang/Throwable")
val jump = tcb.handler.indexOf()
handler.init(f)
handler.clearStack()
handler.push(interpreter.newExceptionValue(tcb, handler, exnType))
mergeControlFlowEdge(jump, handler)
}
}
}
private fun initLocals(current: Frame<V>) {
current.setReturn(interpreter.newReturnTypeValue(Type.getReturnType(method.desc)))
val args = Type.getArgumentTypes(method.desc)
@@ -88,39 +88,49 @@ internal open class FastStackAnalyzer<V : Value>(
val insnType = insnNode.type
try {
if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) {
visitNopInsn(insnNode, f, insn)
} else {
current.init(f)
if (insnOpcode != Opcodes.RETURN) {
// Don't care about possibly incompatible return type
current.execute(insnNode, interpreter)
}
visitMeaningfulInstruction(insnNode, insnType, insnOpcode, current, insn)
}
handlers[insn]?.forEach { tcb ->
val exnType = Type.getObjectType(tcb.type ?: "java/lang/Throwable")
val jump = tcb.handler.indexOf()
if (visitControlFlowExceptionEdge(insn, tcb.handler.indexOf())) {
handler.init(f)
handler.clearStack()
handler.push(interpreter.newValue(exnType))
mergeControlFlowEdge(jump, handler)
}
}
analyzeInstruction(insnType, insnNode, f, insn, current, insnOpcode, handler)
} catch (e: AnalyzerException) {
throw AnalyzerException(e.node, "Error at instruction #$insn ${insnNode.insnText}: ${e.message}", e)
} catch (e: Exception) {
throw AnalyzerException(insnNode, "Error at instruction #$insn ${insnNode.insnText}: ${e.message}", e)
}
}
return frames
}
private fun analyzeInstruction(
insnType: Int,
insnNode: AbstractInsnNode,
f: Frame<V>,
insn: Int,
current: Frame<V>,
insnOpcode: Int,
handler: Frame<V>,
) {
if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) {
visitNopInsn(insnNode, f, insn)
} else {
current.init(f)
if (insnOpcode != Opcodes.RETURN) {
// Don't care about possibly incompatible return type
current.execute(insnNode, interpreter)
}
visitMeaningfulInstruction(insnNode, insnType, insnOpcode, current, insn)
}
handlers[insn]?.forEach { tcb ->
val exnType = Type.getObjectType(tcb.type ?: "java/lang/Throwable")
val jump = tcb.handler.indexOf()
if (visitControlFlowExceptionEdge(insn, tcb.handler.indexOf())) {
handler.init(f)
handler.clearStack()
handler.push(interpreter.newValue(exnType))
mergeControlFlowEdge(jump, handler)
}
}
}
fun getFrame(insn: AbstractInsnNode): Frame<V>? =
frames[insn.indexOf()]
@@ -131,33 +131,44 @@ class FastStoreLoadAnalyzer<V : StoreLoadValue>(
queued[insn] = false
val insnNode = method.instructions[insn]
try {
val insnOpcode = insnNode.opcode
val insnOpcode = insnNode.opcode
val insnType = insnNode.type
if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) {
mergeControlFlowEdge(insn + 1, f)
} else {
current.init(f).execute(insnNode, interpreter)
visitMeaningfulInstruction(insnNode, insnType, insnOpcode, current, insn)
}
handlers[insn]?.forEach { tcb ->
val jump = tcb.handler.indexOf()
handler.init(f)
mergeControlFlowEdge(jump, handler)
}
try {
analyzeInstruction(insnType, insn, f, current, insnNode, insnOpcode, handler)
} catch (e: AnalyzerException) {
throw AnalyzerException(e.node, "Error at instruction #$insn ${insnNode.insnText(method.instructions)}: ${e.message}", e)
} catch (e: Exception) {
throw AnalyzerException(insnNode, "Error at instruction #$insn ${insnNode.insnText(method.instructions)}: ${e.message}", e)
}
}
return frames
}
private fun analyzeInstruction(
insnType: Int,
insn: Int,
f: StoreLoadFrame<V>,
current: StoreLoadFrame<V>,
insnNode: AbstractInsnNode,
insnOpcode: Int,
handler: StoreLoadFrame<V>,
) {
if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) {
mergeControlFlowEdge(insn + 1, f)
} else {
current.init(f).execute(insnNode, interpreter)
visitMeaningfulInstruction(insnNode, insnType, insnOpcode, current, insn)
}
handlers[insn]?.forEach { tcb ->
val jump = tcb.handler.indexOf()
handler.init(f)
mergeControlFlowEdge(jump, handler)
}
}
private fun newFrame(maxLocals: Int) =
StoreLoadFrame<V>(maxLocals)