[JVM] Create base FastAnalyzer class for all Fast...Analyzer
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.common
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Value
|
||||
|
||||
abstract class FastAnalyzer<V : Value, I : Interpreter<V>, F: Frame<V>>(
|
||||
protected val owner: String,
|
||||
protected val method: MethodNode,
|
||||
protected val interpreter: I,
|
||||
) {
|
||||
protected val nInsns = method.instructions.size()
|
||||
protected val handlers: Array<MutableList<TryCatchBlockNode>?> = arrayOfNulls(nInsns)
|
||||
|
||||
protected fun visitMeaningfulInstruction(insnNode: AbstractInsnNode, insnType: Int, insnOpcode: Int, current: F, insn: Int) {
|
||||
when {
|
||||
insnType == AbstractInsnNode.JUMP_INSN ->
|
||||
visitJumpInsnNode(insnNode as JumpInsnNode, current, insn, insnOpcode)
|
||||
insnType == AbstractInsnNode.LOOKUPSWITCH_INSN ->
|
||||
visitLookupSwitchInsnNode(insnNode as LookupSwitchInsnNode, current)
|
||||
insnType == AbstractInsnNode.TABLESWITCH_INSN ->
|
||||
visitTableSwitchInsnNode(insnNode as TableSwitchInsnNode, current)
|
||||
insnOpcode != Opcodes.ATHROW && (insnOpcode < Opcodes.IRETURN || insnOpcode > Opcodes.RETURN) ->
|
||||
visitOpInsn(insnNode, current, insn)
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun visitJumpInsnNode(insnNode: JumpInsnNode, current: F, insn: Int, insnOpcode: Int)
|
||||
protected abstract fun visitLookupSwitchInsnNode(insnNode: LookupSwitchInsnNode, current: F)
|
||||
protected abstract fun visitTableSwitchInsnNode(insnNode: TableSwitchInsnNode, current: F)
|
||||
protected abstract fun visitOpInsn(insnNode: AbstractInsnNode, current: F, insn: Int)
|
||||
|
||||
protected fun checkAssertions() {
|
||||
if (method.instructions.any { it.opcode == Opcodes.JSR || it.opcode == Opcodes.RET })
|
||||
throw AssertionError("Subroutines are deprecated since Java 6")
|
||||
}
|
||||
|
||||
protected fun AbstractInsnNode.indexOf() =
|
||||
method.instructions.indexOf(this)
|
||||
|
||||
protected fun F.dump(): String {
|
||||
return buildString {
|
||||
append("{\n")
|
||||
append(" locals: [\n")
|
||||
for (i in 0 until method.maxLocals) {
|
||||
append(" #$i: ${this@dump.getLocal(i)}\n")
|
||||
}
|
||||
append(" ]\n")
|
||||
val stackSize = this@dump.stackSize
|
||||
append(" stack: size=")
|
||||
append(stackSize)
|
||||
if (stackSize == 0) {
|
||||
append(" []\n")
|
||||
} else {
|
||||
append(" [\n")
|
||||
for (i in 0 until stackSize) {
|
||||
append(" #$i: ${this@dump.getStack(i)}\n")
|
||||
}
|
||||
append(" ]\n")
|
||||
}
|
||||
append("}\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-58
@@ -46,21 +46,16 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Value
|
||||
/**
|
||||
* @see org.jetbrains.kotlin.codegen.optimization.fixStack.FastStackAnalyzer
|
||||
*/
|
||||
@Suppress("DuplicatedCode")
|
||||
open class FastMethodAnalyzer<V : Value>
|
||||
@JvmOverloads constructor(
|
||||
private val owner: String,
|
||||
private val method: MethodNode,
|
||||
private val interpreter: Interpreter<V>,
|
||||
owner: String,
|
||||
method: MethodNode,
|
||||
interpreter: Interpreter<V>,
|
||||
private val pruneExceptionEdges: Boolean = false
|
||||
) {
|
||||
private val nInsns = method.instructions.size()
|
||||
|
||||
) : FastAnalyzer<V, Interpreter<V>, Frame<V>>(owner, method, interpreter) {
|
||||
private val isMergeNode = findMergeNodes(method)
|
||||
|
||||
private val frames: Array<Frame<V>?> = arrayOfNulls(nInsns)
|
||||
|
||||
private val handlers: Array<MutableList<TryCatchBlockNode>?> = arrayOfNulls(nInsns)
|
||||
private val queued = BooleanArray(nInsns)
|
||||
private val queue = IntArray(nInsns)
|
||||
private var top = 0
|
||||
@@ -102,18 +97,7 @@ open class FastMethodAnalyzer<V : Value>
|
||||
mergeControlFlowEdge(insn + 1, f, canReuse = true)
|
||||
} else {
|
||||
current.init(f).execute(insnNode, interpreter)
|
||||
when {
|
||||
insnType == AbstractInsnNode.JUMP_INSN ->
|
||||
visitJumpInsnNode(insnNode as JumpInsnNode, current, insn, insnOpcode)
|
||||
insnType == AbstractInsnNode.LOOKUPSWITCH_INSN ->
|
||||
visitLookupSwitchInsnNode(insnNode as LookupSwitchInsnNode, current)
|
||||
insnType == AbstractInsnNode.TABLESWITCH_INSN ->
|
||||
visitTableSwitchInsnNode(insnNode as TableSwitchInsnNode, current)
|
||||
insnOpcode != Opcodes.ATHROW && (insnOpcode < Opcodes.IRETURN || insnOpcode > Opcodes.RETURN) ->
|
||||
visitOpInsn(current, insn)
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
visitMeaningfulInstruction(insnNode, insnType, insnOpcode, current, insn)
|
||||
}
|
||||
|
||||
// Jump by an exception edge clears the stack, putting exception on top.
|
||||
@@ -155,7 +139,7 @@ open class FastMethodAnalyzer<V : Value>
|
||||
return frames
|
||||
}
|
||||
|
||||
internal fun initLocals(current: Frame<V>) {
|
||||
private fun initLocals(current: Frame<V>) {
|
||||
current.setReturn(interpreter.newReturnTypeValue(Type.getReturnType(method.desc)))
|
||||
val args = Type.getArgumentTypes(method.desc)
|
||||
var local = 0
|
||||
@@ -178,22 +162,14 @@ open class FastMethodAnalyzer<V : Value>
|
||||
}
|
||||
}
|
||||
|
||||
private fun AbstractInsnNode.indexOf() =
|
||||
method.instructions.indexOf(this)
|
||||
|
||||
fun getFrame(insn: AbstractInsnNode): Frame<V>? =
|
||||
frames[insn.indexOf()]
|
||||
|
||||
private fun checkAssertions() {
|
||||
if (method.instructions.any { it.opcode == Opcodes.JSR || it.opcode == Opcodes.RET })
|
||||
throw AssertionError("Subroutines are deprecated since Java 6")
|
||||
}
|
||||
|
||||
private fun visitOpInsn(current: Frame<V>, insn: Int) {
|
||||
override fun visitOpInsn(insnNode: AbstractInsnNode, current: Frame<V>, insn: Int) {
|
||||
mergeControlFlowEdge(insn + 1, current)
|
||||
}
|
||||
|
||||
private fun visitTableSwitchInsnNode(insnNode: TableSwitchInsnNode, current: Frame<V>) {
|
||||
override fun visitTableSwitchInsnNode(insnNode: TableSwitchInsnNode, current: Frame<V>) {
|
||||
mergeControlFlowEdge(insnNode.dflt.indexOf(), current)
|
||||
// In most cases order of visiting switch labels should not matter
|
||||
// The only one is a tableswitch being added in the beginning of coroutine method, these switch' labels may lead
|
||||
@@ -205,14 +181,14 @@ open class FastMethodAnalyzer<V : Value>
|
||||
}
|
||||
}
|
||||
|
||||
private fun visitLookupSwitchInsnNode(insnNode: LookupSwitchInsnNode, current: Frame<V>) {
|
||||
override fun visitLookupSwitchInsnNode(insnNode: LookupSwitchInsnNode, current: Frame<V>) {
|
||||
mergeControlFlowEdge(insnNode.dflt.indexOf(), current)
|
||||
for (label in insnNode.labels) {
|
||||
mergeControlFlowEdge(label.indexOf(), current)
|
||||
}
|
||||
}
|
||||
|
||||
private fun visitJumpInsnNode(insnNode: JumpInsnNode, current: Frame<V>, insn: Int, insnOpcode: Int) {
|
||||
override fun visitJumpInsnNode(insnNode: JumpInsnNode, current: Frame<V>, insn: Int, insnOpcode: Int) {
|
||||
mergeControlFlowEdge(insnNode.label.indexOf(), current)
|
||||
if (insnOpcode != Opcodes.GOTO) {
|
||||
mergeControlFlowEdge(insn + 1, current)
|
||||
@@ -272,30 +248,6 @@ open class FastMethodAnalyzer<V : Value>
|
||||
}
|
||||
}
|
||||
|
||||
private fun Frame<V>.dump(): String {
|
||||
return buildString {
|
||||
append("{\n")
|
||||
append(" locals: [\n")
|
||||
for (i in 0 until method.maxLocals) {
|
||||
append(" #$i: ${this@dump.getLocal(i)}\n")
|
||||
}
|
||||
append(" ]\n")
|
||||
val stackSize = this@dump.stackSize
|
||||
append(" stack: size=")
|
||||
append(stackSize)
|
||||
if (stackSize == 0) {
|
||||
append(" []\n")
|
||||
} else {
|
||||
append(" [\n")
|
||||
for (i in 0 until stackSize) {
|
||||
append(" #$i: ${this@dump.getStack(i)}\n")
|
||||
}
|
||||
append(" ]\n")
|
||||
}
|
||||
append("}\n")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun findMergeNodes(method: MethodNode): BooleanArray {
|
||||
val isMergeNode = BooleanArray(method.instructions.size())
|
||||
|
||||
+10
-32
@@ -34,6 +34,7 @@
|
||||
package org.jetbrains.kotlin.codegen.optimization.fixStack
|
||||
|
||||
import org.jetbrains.kotlin.codegen.inline.insnText
|
||||
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.*
|
||||
@@ -45,17 +46,13 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Value
|
||||
/**
|
||||
* @see org.jetbrains.kotlin.codegen.optimization.common.FastMethodAnalyzer
|
||||
*/
|
||||
@Suppress("DuplicatedCode")
|
||||
internal open class FastStackAnalyzer<V : Value>(
|
||||
private val owner: String,
|
||||
val method: MethodNode,
|
||||
protected val interpreter: Interpreter<V>
|
||||
) {
|
||||
private val nInsns = method.instructions.size()
|
||||
|
||||
owner: String,
|
||||
method: MethodNode,
|
||||
interpreter: Interpreter<V>
|
||||
) : FastAnalyzer<V, Interpreter<V>, Frame<V>>(owner, method, interpreter) {
|
||||
private val frames: Array<Frame<V>?> = arrayOfNulls(nInsns)
|
||||
|
||||
private val handlers: Array<MutableList<TryCatchBlockNode>?> = arrayOfNulls(nInsns)
|
||||
private val queued = BooleanArray(nInsns)
|
||||
private val queue = IntArray(nInsns)
|
||||
private var top = 0
|
||||
@@ -98,19 +95,7 @@ internal open class FastStackAnalyzer<V : Value>(
|
||||
// Don't care about possibly incompatible return type
|
||||
current.execute(insnNode, interpreter)
|
||||
}
|
||||
|
||||
when {
|
||||
insnType == AbstractInsnNode.JUMP_INSN ->
|
||||
visitJumpInsnNode(insnNode as JumpInsnNode, current, insn, insnOpcode)
|
||||
insnType == AbstractInsnNode.LOOKUPSWITCH_INSN ->
|
||||
visitLookupSwitchInsnNode(insnNode as LookupSwitchInsnNode, current)
|
||||
insnType == AbstractInsnNode.TABLESWITCH_INSN ->
|
||||
visitTableSwitchInsnNode(insnNode as TableSwitchInsnNode, current)
|
||||
insnOpcode != Opcodes.ATHROW && (insnOpcode < Opcodes.IRETURN || insnOpcode > Opcodes.RETURN) ->
|
||||
visitOpInsn(insnNode, current, insn)
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
visitMeaningfulInstruction(insnNode, insnType, insnOpcode, current, insn)
|
||||
}
|
||||
|
||||
handlers[insn]?.forEach { tcb ->
|
||||
@@ -135,17 +120,10 @@ internal open class FastStackAnalyzer<V : Value>(
|
||||
return frames
|
||||
}
|
||||
|
||||
private fun AbstractInsnNode.indexOf() = method.instructions.indexOf(this)
|
||||
|
||||
fun getFrame(insn: AbstractInsnNode): Frame<V>? =
|
||||
frames[insn.indexOf()]
|
||||
|
||||
private fun checkAssertions() {
|
||||
if (method.instructions.any { it.opcode == Opcodes.JSR || it.opcode == Opcodes.RET })
|
||||
throw AssertionError("Subroutines are deprecated since Java 6")
|
||||
}
|
||||
|
||||
private fun visitOpInsn(insnNode: AbstractInsnNode, current: Frame<V>, insn: Int) {
|
||||
override fun visitOpInsn(insnNode: AbstractInsnNode, current: Frame<V>, insn: Int) {
|
||||
processControlFlowEdge(current, insnNode, insn + 1)
|
||||
}
|
||||
|
||||
@@ -153,7 +131,7 @@ internal open class FastStackAnalyzer<V : Value>(
|
||||
processControlFlowEdge(f, insnNode, insn + 1)
|
||||
}
|
||||
|
||||
private fun visitTableSwitchInsnNode(insnNode: TableSwitchInsnNode, current: Frame<V>) {
|
||||
override fun visitTableSwitchInsnNode(insnNode: TableSwitchInsnNode, current: Frame<V>) {
|
||||
var jump = insnNode.dflt.indexOf()
|
||||
processControlFlowEdge(current, insnNode, jump)
|
||||
// In most cases order of visiting switch labels should not matter
|
||||
@@ -167,7 +145,7 @@ internal open class FastStackAnalyzer<V : Value>(
|
||||
}
|
||||
}
|
||||
|
||||
private fun visitLookupSwitchInsnNode(insnNode: LookupSwitchInsnNode, current: Frame<V>) {
|
||||
override fun visitLookupSwitchInsnNode(insnNode: LookupSwitchInsnNode, current: Frame<V>) {
|
||||
var jump = insnNode.dflt.indexOf()
|
||||
processControlFlowEdge(current, insnNode, jump)
|
||||
for (label in insnNode.labels) {
|
||||
@@ -176,7 +154,7 @@ internal open class FastStackAnalyzer<V : Value>(
|
||||
}
|
||||
}
|
||||
|
||||
private fun visitJumpInsnNode(insnNode: JumpInsnNode, current: Frame<V>, insn: Int, insnOpcode: Int) {
|
||||
override fun visitJumpInsnNode(insnNode: JumpInsnNode, current: Frame<V>, insn: Int, insnOpcode: Int) {
|
||||
if (insnOpcode != Opcodes.GOTO) {
|
||||
processControlFlowEdge(current, insnNode, insn + 1)
|
||||
}
|
||||
|
||||
+1
-3
@@ -103,8 +103,6 @@ internal class FixStackAnalyzer(
|
||||
override fun newFrame(nLocals: Int, nStack: Int): Frame<FixStackValue> =
|
||||
FixStackFrame(nLocals, nStack)
|
||||
|
||||
private fun indexOf(node: AbstractInsnNode) = method.instructions.indexOf(node)
|
||||
|
||||
inner class FixStackFrame(nLocals: Int, nStack: Int) : Frame<FixStackValue>(nLocals, nStack) {
|
||||
val extraStack = Stack<FixStackValue>()
|
||||
|
||||
@@ -207,7 +205,7 @@ internal class FixStackAnalyzer(
|
||||
private fun FixStackFrame.executeRestoreStackInTryCatch(insn: AbstractInsnNode) {
|
||||
val saveNode = context.saveStackMarkerForRestoreMarker[insn]
|
||||
val savedValues = spilledStacks.getOrElse(saveNode!!) {
|
||||
throw AssertionError("${indexOf(insn)}: Restore stack is unavailable for ${indexOf(saveNode)}")
|
||||
throw AssertionError("${insn.indexOf()}: Restore stack is unavailable for ${saveNode.indexOf()}")
|
||||
}
|
||||
pushAll(savedValues)
|
||||
}
|
||||
|
||||
+32
-46
@@ -34,28 +34,30 @@
|
||||
package org.jetbrains.kotlin.codegen.optimization.temporaryVals
|
||||
|
||||
import org.jetbrains.kotlin.codegen.inline.insnText
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.FastAnalyzer
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.API_VERSION
|
||||
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
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Value
|
||||
|
||||
interface StoreLoadValue
|
||||
interface StoreLoadValue : Value
|
||||
|
||||
|
||||
interface StoreLoadInterpreter<V : StoreLoadValue> {
|
||||
fun uninitialized(): V
|
||||
fun valueParameter(type: Type): V
|
||||
fun store(insn: VarInsnNode): V
|
||||
fun load(insn: VarInsnNode, value: V)
|
||||
fun iinc(insn: IincInsnNode, value: V): V
|
||||
fun merge(a: V, b: V): V
|
||||
abstract class StoreLoadInterpreter<V : StoreLoadValue> : Interpreter<V>(API_VERSION) {
|
||||
abstract fun uninitialized(): V
|
||||
abstract fun valueParameter(type: Type): V
|
||||
abstract fun store(insn: VarInsnNode): V
|
||||
abstract fun load(insn: VarInsnNode, value: V)
|
||||
abstract fun iinc(insn: IincInsnNode, value: V): V
|
||||
}
|
||||
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
class StoreLoadFrame<V : StoreLoadValue>(val maxLocals: Int) {
|
||||
class StoreLoadFrame<V : StoreLoadValue>(val maxLocals: Int) : Frame<V>(maxLocals, 0) {
|
||||
private val locals = arrayOfNulls<StoreLoadValue>(maxLocals)
|
||||
|
||||
operator fun get(index: Int): V =
|
||||
@@ -101,19 +103,14 @@ class StoreLoadFrame<V : StoreLoadValue>(val maxLocals: Int) {
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DuplicatedCode")
|
||||
class FastStoreLoadAnalyzer<V : StoreLoadValue>(
|
||||
private val owner: String,
|
||||
private val method: MethodNode,
|
||||
private val interpreter: StoreLoadInterpreter<V>
|
||||
) {
|
||||
private val nInsns = method.instructions.size()
|
||||
|
||||
owner: String,
|
||||
method: MethodNode,
|
||||
interpreter: StoreLoadInterpreter<V>
|
||||
) : FastAnalyzer<V, StoreLoadInterpreter<V>, StoreLoadFrame<V>>(owner, method, interpreter) {
|
||||
private val isMergeNode = BooleanArray(nInsns)
|
||||
|
||||
private val frames: Array<StoreLoadFrame<V>?> = arrayOfNulls(nInsns)
|
||||
|
||||
private val handlers: Array<MutableList<TryCatchBlockNode>?> = arrayOfNulls(nInsns)
|
||||
private val queued = BooleanArray(nInsns)
|
||||
private val queue = IntArray(nInsns)
|
||||
private var top = 0
|
||||
@@ -144,18 +141,7 @@ class FastStoreLoadAnalyzer<V : StoreLoadValue>(
|
||||
mergeControlFlowEdge(insn + 1, f)
|
||||
} else {
|
||||
current.init(f).execute(insnNode, interpreter)
|
||||
when {
|
||||
insnType == AbstractInsnNode.JUMP_INSN ->
|
||||
visitJumpInsnNode(insnNode as JumpInsnNode, current, insn, insnOpcode)
|
||||
insnType == AbstractInsnNode.LOOKUPSWITCH_INSN ->
|
||||
visitLookupSwitchInsnNode(insnNode as LookupSwitchInsnNode, current)
|
||||
insnType == AbstractInsnNode.TABLESWITCH_INSN ->
|
||||
visitTableSwitchInsnNode(insnNode as TableSwitchInsnNode, current)
|
||||
insnOpcode != Opcodes.ATHROW && (insnOpcode < Opcodes.IRETURN || insnOpcode > Opcodes.RETURN) ->
|
||||
mergeControlFlowEdge(insn + 1, current)
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
visitMeaningfulInstruction(insnNode, insnType, insnOpcode, current, insn)
|
||||
}
|
||||
|
||||
handlers[insn]?.forEach { tcb ->
|
||||
@@ -177,29 +163,25 @@ class FastStoreLoadAnalyzer<V : StoreLoadValue>(
|
||||
private fun newFrame(maxLocals: Int) =
|
||||
StoreLoadFrame<V>(maxLocals)
|
||||
|
||||
private fun AbstractInsnNode.indexOf() =
|
||||
method.instructions.indexOf(this)
|
||||
|
||||
private fun checkAssertions() {
|
||||
if (method.instructions.any { it.opcode == Opcodes.JSR || it.opcode == Opcodes.RET })
|
||||
throw AssertionError("Subroutines are deprecated since Java 6")
|
||||
override fun visitOpInsn(insnNode: AbstractInsnNode, current: StoreLoadFrame<V>, insn: Int) {
|
||||
mergeControlFlowEdge(insn + 1, current)
|
||||
}
|
||||
|
||||
private fun visitTableSwitchInsnNode(insnNode: TableSwitchInsnNode, current: StoreLoadFrame<V>) {
|
||||
override fun visitTableSwitchInsnNode(insnNode: TableSwitchInsnNode, current: StoreLoadFrame<V>) {
|
||||
mergeControlFlowEdge(insnNode.dflt.indexOf(), current)
|
||||
for (label in insnNode.labels) {
|
||||
mergeControlFlowEdge(label.indexOf(), current)
|
||||
}
|
||||
}
|
||||
|
||||
private fun visitLookupSwitchInsnNode(insnNode: LookupSwitchInsnNode, current: StoreLoadFrame<V>) {
|
||||
override fun visitLookupSwitchInsnNode(insnNode: LookupSwitchInsnNode, current: StoreLoadFrame<V>) {
|
||||
mergeControlFlowEdge(insnNode.dflt.indexOf(), current)
|
||||
for (label in insnNode.labels) {
|
||||
mergeControlFlowEdge(label.indexOf(), current)
|
||||
}
|
||||
}
|
||||
|
||||
private fun visitJumpInsnNode(insnNode: JumpInsnNode, current: StoreLoadFrame<V>, insn: Int, insnOpcode: Int) {
|
||||
override fun visitJumpInsnNode(insnNode: JumpInsnNode, current: StoreLoadFrame<V>, insn: Int, insnOpcode: Int) {
|
||||
if (insnOpcode != Opcodes.GOTO) {
|
||||
mergeControlFlowEdge(insn + 1, current)
|
||||
}
|
||||
@@ -254,21 +236,25 @@ class FastStoreLoadAnalyzer<V : StoreLoadValue>(
|
||||
}
|
||||
}
|
||||
|
||||
internal fun initLocals(current: StoreLoadFrame<V>) {
|
||||
private fun initLocals(current: StoreLoadFrame<V>) {
|
||||
val args = Type.getArgumentTypes(method.desc)
|
||||
var local = 0
|
||||
if ((method.access and Opcodes.ACC_STATIC) == 0) {
|
||||
val ctype = Type.getObjectType(owner)
|
||||
current[local++] = interpreter.valueParameter(ctype)
|
||||
current.setLocal(local, interpreter.newValue(ctype))
|
||||
local++
|
||||
}
|
||||
for (arg in args) {
|
||||
current[local++] = interpreter.valueParameter(arg)
|
||||
current.setLocal(local, interpreter.newValue(arg))
|
||||
local++
|
||||
if (arg.size == 2) {
|
||||
current[local++] = interpreter.uninitialized()
|
||||
current.setLocal(local, interpreter.uninitialized())
|
||||
local++
|
||||
}
|
||||
}
|
||||
while (local < method.maxLocals) {
|
||||
current[local++] = interpreter.uninitialized()
|
||||
current.setLocal(local, interpreter.uninitialized())
|
||||
local++
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+41
-5
@@ -134,6 +134,9 @@ class TemporaryValsAnalyzer {
|
||||
}
|
||||
|
||||
private sealed class StoredValue : StoreLoadValue {
|
||||
// `StoredValue` represent some abstract value that doesn't really have a definition of size.
|
||||
// `getSize` can return either 1 or 2, so we use 1 here.
|
||||
override fun getSize(): Int = 1
|
||||
|
||||
object Unknown : StoredValue()
|
||||
|
||||
@@ -156,13 +159,13 @@ class TemporaryValsAnalyzer {
|
||||
|
||||
private class StoreTrackingInterpreter(
|
||||
private val storeInsnToStoreData: Map<AbstractInsnNode, StoreData>
|
||||
) : StoreLoadInterpreter<StoredValue> {
|
||||
) : StoreLoadInterpreter<StoredValue>() {
|
||||
|
||||
override fun uninitialized(): StoredValue =
|
||||
StoredValue.Unknown
|
||||
override fun uninitialized(): StoredValue = StoredValue.Unknown
|
||||
|
||||
override fun valueParameter(type: Type): StoredValue =
|
||||
StoredValue.Unknown
|
||||
override fun newValue(type: Type?): StoredValue = StoredValue.Unknown
|
||||
|
||||
override fun valueParameter(type: Type): StoredValue = StoredValue.Unknown
|
||||
|
||||
override fun store(insn: VarInsnNode): StoredValue {
|
||||
val temporaryValData = storeInsnToStoreData[insn]
|
||||
@@ -218,5 +221,38 @@ class TemporaryValsAnalyzer {
|
||||
is StoredValue.DirtyStore -> this.temporaryVals
|
||||
else -> emptySet()
|
||||
}
|
||||
|
||||
override fun copyOperation(insn: AbstractInsnNode?, value: StoredValue?): StoredValue {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun newOperation(insn: AbstractInsnNode?): StoredValue {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun unaryOperation(insn: AbstractInsnNode?, value: StoredValue?): StoredValue {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun binaryOperation(insn: AbstractInsnNode?, value1: StoredValue?, value2: StoredValue?): StoredValue {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun ternaryOperation(
|
||||
insn: AbstractInsnNode?,
|
||||
value1: StoredValue?,
|
||||
value2: StoredValue?,
|
||||
value3: StoredValue?,
|
||||
): StoredValue {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun naryOperation(insn: AbstractInsnNode?, values: MutableList<out StoredValue>?): StoredValue {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun returnOperation(insn: AbstractInsnNode?, value: StoredValue?, expected: StoredValue?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user