[JVM] Create base FastAnalyzer class for all Fast...Analyzer

This commit is contained in:
Ivan Kylchik
2023-08-23 19:16:51 +02:00
committed by Space Team
parent 7853256c02
commit 98cc2c839f
6 changed files with 167 additions and 144 deletions
@@ -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")
}
}
}
@@ -46,21 +46,16 @@ 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
*/ */
@Suppress("DuplicatedCode")
open class FastMethodAnalyzer<V : Value> open class FastMethodAnalyzer<V : Value>
@JvmOverloads constructor( @JvmOverloads constructor(
private val owner: String, owner: String,
private val method: MethodNode, method: MethodNode,
private val interpreter: Interpreter<V>, interpreter: Interpreter<V>,
private val pruneExceptionEdges: Boolean = false private val pruneExceptionEdges: Boolean = false
) { ) : FastAnalyzer<V, Interpreter<V>, Frame<V>>(owner, method, interpreter) {
private val nInsns = method.instructions.size()
private val isMergeNode = findMergeNodes(method) private val isMergeNode = findMergeNodes(method)
private val frames: Array<Frame<V>?> = arrayOfNulls(nInsns) private val frames: Array<Frame<V>?> = arrayOfNulls(nInsns)
private val handlers: Array<MutableList<TryCatchBlockNode>?> = arrayOfNulls(nInsns)
private val queued = BooleanArray(nInsns) private val queued = BooleanArray(nInsns)
private val queue = IntArray(nInsns) private val queue = IntArray(nInsns)
private var top = 0 private var top = 0
@@ -102,18 +97,7 @@ open class FastMethodAnalyzer<V : Value>
mergeControlFlowEdge(insn + 1, f, canReuse = true) mergeControlFlowEdge(insn + 1, f, canReuse = true)
} else { } else {
current.init(f).execute(insnNode, interpreter) current.init(f).execute(insnNode, interpreter)
when { visitMeaningfulInstruction(insnNode, insnType, insnOpcode, current, insn)
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 -> {
}
}
} }
// Jump by an exception edge clears the stack, putting exception on top. // Jump by an exception edge clears the stack, putting exception on top.
@@ -155,7 +139,7 @@ open class FastMethodAnalyzer<V : Value>
return frames return frames
} }
internal fun initLocals(current: Frame<V>) { private fun initLocals(current: Frame<V>) {
current.setReturn(interpreter.newReturnTypeValue(Type.getReturnType(method.desc))) current.setReturn(interpreter.newReturnTypeValue(Type.getReturnType(method.desc)))
val args = Type.getArgumentTypes(method.desc) val args = Type.getArgumentTypes(method.desc)
var local = 0 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>? = fun getFrame(insn: AbstractInsnNode): Frame<V>? =
frames[insn.indexOf()] frames[insn.indexOf()]
private fun checkAssertions() { override fun visitOpInsn(insnNode: AbstractInsnNode, current: Frame<V>, insn: Int) {
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) {
mergeControlFlowEdge(insn + 1, current) 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) mergeControlFlowEdge(insnNode.dflt.indexOf(), current)
// In most cases order of visiting switch labels should not matter // 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 // 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) mergeControlFlowEdge(insnNode.dflt.indexOf(), current)
for (label in insnNode.labels) { for (label in insnNode.labels) {
mergeControlFlowEdge(label.indexOf(), current) 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) mergeControlFlowEdge(insnNode.label.indexOf(), current)
if (insnOpcode != Opcodes.GOTO) { if (insnOpcode != Opcodes.GOTO) {
mergeControlFlowEdge(insn + 1, current) 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 { companion object {
fun findMergeNodes(method: MethodNode): BooleanArray { fun findMergeNodes(method: MethodNode): BooleanArray {
val isMergeNode = BooleanArray(method.instructions.size()) val isMergeNode = BooleanArray(method.instructions.size())
@@ -34,6 +34,7 @@
package org.jetbrains.kotlin.codegen.optimization.fixStack package org.jetbrains.kotlin.codegen.optimization.fixStack
import org.jetbrains.kotlin.codegen.inline.insnText 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.Opcodes
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.* 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 * @see org.jetbrains.kotlin.codegen.optimization.common.FastMethodAnalyzer
*/ */
@Suppress("DuplicatedCode")
internal open class FastStackAnalyzer<V : Value>( internal open class FastStackAnalyzer<V : Value>(
private val owner: String, owner: String,
val method: MethodNode, method: MethodNode,
protected val interpreter: Interpreter<V> interpreter: Interpreter<V>
) { ) : FastAnalyzer<V, Interpreter<V>, Frame<V>>(owner, method, interpreter) {
private val nInsns = method.instructions.size()
private val frames: Array<Frame<V>?> = arrayOfNulls(nInsns) private val frames: Array<Frame<V>?> = arrayOfNulls(nInsns)
private val handlers: Array<MutableList<TryCatchBlockNode>?> = arrayOfNulls(nInsns)
private val queued = BooleanArray(nInsns) private val queued = BooleanArray(nInsns)
private val queue = IntArray(nInsns) private val queue = IntArray(nInsns)
private var top = 0 private var top = 0
@@ -98,19 +95,7 @@ internal open class FastStackAnalyzer<V : Value>(
// Don't care about possibly incompatible return type // Don't care about possibly incompatible return type
current.execute(insnNode, interpreter) current.execute(insnNode, interpreter)
} }
visitMeaningfulInstruction(insnNode, insnType, insnOpcode, current, insn)
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 -> {
}
}
} }
handlers[insn]?.forEach { tcb -> handlers[insn]?.forEach { tcb ->
@@ -135,17 +120,10 @@ internal open class FastStackAnalyzer<V : Value>(
return frames return frames
} }
private fun AbstractInsnNode.indexOf() = method.instructions.indexOf(this)
fun getFrame(insn: AbstractInsnNode): Frame<V>? = fun getFrame(insn: AbstractInsnNode): Frame<V>? =
frames[insn.indexOf()] frames[insn.indexOf()]
private fun checkAssertions() { override fun visitOpInsn(insnNode: AbstractInsnNode, current: Frame<V>, insn: Int) {
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) {
processControlFlowEdge(current, insnNode, insn + 1) processControlFlowEdge(current, insnNode, insn + 1)
} }
@@ -153,7 +131,7 @@ internal open class FastStackAnalyzer<V : Value>(
processControlFlowEdge(f, insnNode, insn + 1) 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() var jump = insnNode.dflt.indexOf()
processControlFlowEdge(current, insnNode, jump) processControlFlowEdge(current, insnNode, jump)
// In most cases order of visiting switch labels should not matter // 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() var jump = insnNode.dflt.indexOf()
processControlFlowEdge(current, insnNode, jump) processControlFlowEdge(current, insnNode, jump)
for (label in insnNode.labels) { 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) { if (insnOpcode != Opcodes.GOTO) {
processControlFlowEdge(current, insnNode, insn + 1) processControlFlowEdge(current, insnNode, insn + 1)
} }
@@ -103,8 +103,6 @@ internal class FixStackAnalyzer(
override fun newFrame(nLocals: Int, nStack: Int): Frame<FixStackValue> = override fun newFrame(nLocals: Int, nStack: Int): Frame<FixStackValue> =
FixStackFrame(nLocals, nStack) FixStackFrame(nLocals, nStack)
private fun indexOf(node: AbstractInsnNode) = method.instructions.indexOf(node)
inner class FixStackFrame(nLocals: Int, nStack: Int) : Frame<FixStackValue>(nLocals, nStack) { inner class FixStackFrame(nLocals: Int, nStack: Int) : Frame<FixStackValue>(nLocals, nStack) {
val extraStack = Stack<FixStackValue>() val extraStack = Stack<FixStackValue>()
@@ -207,7 +205,7 @@ internal class FixStackAnalyzer(
private fun FixStackFrame.executeRestoreStackInTryCatch(insn: AbstractInsnNode) { private fun FixStackFrame.executeRestoreStackInTryCatch(insn: AbstractInsnNode) {
val saveNode = context.saveStackMarkerForRestoreMarker[insn] val saveNode = context.saveStackMarkerForRestoreMarker[insn]
val savedValues = spilledStacks.getOrElse(saveNode!!) { 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) pushAll(savedValues)
} }
@@ -34,28 +34,30 @@
package org.jetbrains.kotlin.codegen.optimization.temporaryVals package org.jetbrains.kotlin.codegen.optimization.temporaryVals
import org.jetbrains.kotlin.codegen.inline.insnText 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.codegen.optimization.common.isMeaningful
import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.org.objectweb.asm.Opcodes 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.Type
import org.jetbrains.org.objectweb.asm.tree.* import org.jetbrains.org.objectweb.asm.tree.*
import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException 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
abstract class StoreLoadInterpreter<V : StoreLoadValue> : Interpreter<V>(API_VERSION) {
interface StoreLoadInterpreter<V : StoreLoadValue> { abstract fun uninitialized(): V
fun uninitialized(): V abstract fun valueParameter(type: Type): V
fun valueParameter(type: Type): V abstract fun store(insn: VarInsnNode): V
fun store(insn: VarInsnNode): V abstract fun load(insn: VarInsnNode, value: V)
fun load(insn: VarInsnNode, value: V) abstract fun iinc(insn: IincInsnNode, value: V): V
fun iinc(insn: IincInsnNode, value: V): V
fun merge(a: V, b: V): V
} }
@Suppress("UNCHECKED_CAST") @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) private val locals = arrayOfNulls<StoreLoadValue>(maxLocals)
operator fun get(index: Int): V = operator fun get(index: Int): V =
@@ -101,19 +103,14 @@ class StoreLoadFrame<V : StoreLoadValue>(val maxLocals: Int) {
} }
} }
@Suppress("DuplicatedCode")
class FastStoreLoadAnalyzer<V : StoreLoadValue>( class FastStoreLoadAnalyzer<V : StoreLoadValue>(
private val owner: String, owner: String,
private val method: MethodNode, method: MethodNode,
private val interpreter: StoreLoadInterpreter<V> interpreter: StoreLoadInterpreter<V>
) { ) : FastAnalyzer<V, StoreLoadInterpreter<V>, StoreLoadFrame<V>>(owner, method, interpreter) {
private val nInsns = method.instructions.size()
private val isMergeNode = BooleanArray(nInsns) private val isMergeNode = BooleanArray(nInsns)
private val frames: Array<StoreLoadFrame<V>?> = arrayOfNulls(nInsns) private val frames: Array<StoreLoadFrame<V>?> = arrayOfNulls(nInsns)
private val handlers: Array<MutableList<TryCatchBlockNode>?> = arrayOfNulls(nInsns)
private val queued = BooleanArray(nInsns) private val queued = BooleanArray(nInsns)
private val queue = IntArray(nInsns) private val queue = IntArray(nInsns)
private var top = 0 private var top = 0
@@ -144,18 +141,7 @@ class FastStoreLoadAnalyzer<V : StoreLoadValue>(
mergeControlFlowEdge(insn + 1, f) mergeControlFlowEdge(insn + 1, f)
} else { } else {
current.init(f).execute(insnNode, interpreter) current.init(f).execute(insnNode, interpreter)
when { visitMeaningfulInstruction(insnNode, insnType, insnOpcode, current, insn)
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 -> {
}
}
} }
handlers[insn]?.forEach { tcb -> handlers[insn]?.forEach { tcb ->
@@ -177,29 +163,25 @@ class FastStoreLoadAnalyzer<V : StoreLoadValue>(
private fun newFrame(maxLocals: Int) = private fun newFrame(maxLocals: Int) =
StoreLoadFrame<V>(maxLocals) StoreLoadFrame<V>(maxLocals)
private fun AbstractInsnNode.indexOf() = override fun visitOpInsn(insnNode: AbstractInsnNode, current: StoreLoadFrame<V>, insn: Int) {
method.instructions.indexOf(this) mergeControlFlowEdge(insn + 1, current)
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 visitTableSwitchInsnNode(insnNode: TableSwitchInsnNode, current: StoreLoadFrame<V>) { override fun visitTableSwitchInsnNode(insnNode: TableSwitchInsnNode, current: StoreLoadFrame<V>) {
mergeControlFlowEdge(insnNode.dflt.indexOf(), current) mergeControlFlowEdge(insnNode.dflt.indexOf(), current)
for (label in insnNode.labels) { for (label in insnNode.labels) {
mergeControlFlowEdge(label.indexOf(), current) 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) mergeControlFlowEdge(insnNode.dflt.indexOf(), current)
for (label in insnNode.labels) { for (label in insnNode.labels) {
mergeControlFlowEdge(label.indexOf(), current) 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) { if (insnOpcode != Opcodes.GOTO) {
mergeControlFlowEdge(insn + 1, current) 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) val args = Type.getArgumentTypes(method.desc)
var local = 0 var local = 0
if ((method.access and Opcodes.ACC_STATIC) == 0) { if ((method.access and Opcodes.ACC_STATIC) == 0) {
val ctype = Type.getObjectType(owner) val ctype = Type.getObjectType(owner)
current[local++] = interpreter.valueParameter(ctype) current.setLocal(local, interpreter.newValue(ctype))
local++
} }
for (arg in args) { for (arg in args) {
current[local++] = interpreter.valueParameter(arg) current.setLocal(local, interpreter.newValue(arg))
local++
if (arg.size == 2) { if (arg.size == 2) {
current[local++] = interpreter.uninitialized() current.setLocal(local, interpreter.uninitialized())
local++
} }
} }
while (local < method.maxLocals) { while (local < method.maxLocals) {
current[local++] = interpreter.uninitialized() current.setLocal(local, interpreter.uninitialized())
local++
} }
} }
@@ -134,6 +134,9 @@ class TemporaryValsAnalyzer {
} }
private sealed class StoredValue : StoreLoadValue { 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() object Unknown : StoredValue()
@@ -156,13 +159,13 @@ class TemporaryValsAnalyzer {
private class StoreTrackingInterpreter( private class StoreTrackingInterpreter(
private val storeInsnToStoreData: Map<AbstractInsnNode, StoreData> private val storeInsnToStoreData: Map<AbstractInsnNode, StoreData>
) : StoreLoadInterpreter<StoredValue> { ) : StoreLoadInterpreter<StoredValue>() {
override fun uninitialized(): StoredValue = override fun uninitialized(): StoredValue = StoredValue.Unknown
StoredValue.Unknown
override fun valueParameter(type: Type): StoredValue = override fun newValue(type: Type?): StoredValue = StoredValue.Unknown
StoredValue.Unknown
override fun valueParameter(type: Type): StoredValue = StoredValue.Unknown
override fun store(insn: VarInsnNode): StoredValue { override fun store(insn: VarInsnNode): StoredValue {
val temporaryValData = storeInsnToStoreData[insn] val temporaryValData = storeInsnToStoreData[insn]
@@ -218,5 +221,38 @@ class TemporaryValsAnalyzer {
is StoredValue.DirtyStore -> this.temporaryVals is StoredValue.DirtyStore -> this.temporaryVals
else -> emptySet() 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")
}
} }
} }