[JVM] Use composition instead of inheritance in FixStackAnalyzer
This way we will be able to pass `createFrame` argument directly to `FastAnalyzer`.
This commit is contained in:
+1
-1
@@ -35,7 +35,7 @@ abstract class FastAnalyzer<V : Value, F : Frame<V>>(
|
||||
protected abstract fun newFrame(nLocals: Int, nStack: Int): F
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
protected fun getFrame(insn: AbstractInsnNode): F? = frames[insn.indexOf()] as? F
|
||||
fun getFrame(insn: AbstractInsnNode): F? = frames[insn.indexOf()] as? F
|
||||
|
||||
fun analyze(): Array<Frame<V>?> {
|
||||
if (nInsns == 0) return frames
|
||||
|
||||
+3
-2
@@ -47,10 +47,11 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Value
|
||||
internal open class FastStackAnalyzer<V : Value, F : Frame<V>>(
|
||||
owner: String,
|
||||
method: MethodNode,
|
||||
interpreter: Interpreter<V>
|
||||
interpreter: Interpreter<V>,
|
||||
private val createFrame: (Int, Int) -> Frame<V> = { nLocals, nStack -> Frame<V>(nLocals, nStack) }
|
||||
) : FastAnalyzer<V, F>(owner, method, interpreter, pruneExceptionEdges = false) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun newFrame(nLocals: Int, nStack: Int): F = Frame<V>(nLocals, nStack) as F
|
||||
override fun newFrame(nLocals: Int, nStack: Int): F = createFrame(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
|
||||
|
||||
+22
-19
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.codegen.optimization.fixStack
|
||||
|
||||
import com.intellij.util.containers.Stack
|
||||
import org.jetbrains.kotlin.codegen.inline.insnText
|
||||
import org.jetbrains.kotlin.codegen.inline.isAfterInlineMarker
|
||||
import org.jetbrains.kotlin.codegen.inline.isBeforeInlineMarker
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
|
||||
@@ -34,26 +35,40 @@ internal class FixStackAnalyzer(
|
||||
owner: String,
|
||||
method: MethodNode,
|
||||
val context: FixStackContext,
|
||||
private val skipBreakContinueGotoEdges: Boolean = true
|
||||
) : FastStackAnalyzer<FixStackValue, FixStackAnalyzer.FixStackFrame>(owner, method, FixStackInterpreter()) {
|
||||
private val skipBreakContinueGotoEdges: Boolean
|
||||
) {
|
||||
companion object {
|
||||
// Stack size is always non-negative
|
||||
const val DEAD_CODE_STACK_SIZE = -1
|
||||
}
|
||||
|
||||
private val analyzer = object : FastStackAnalyzer<FixStackValue, FixStackAnalyzer.FixStackFrame>(
|
||||
owner, method, FixStackInterpreter(), { nLocals, nStack -> FixStackFrame(nLocals, nStack) }
|
||||
) {
|
||||
override fun visitControlFlowEdge(insnNode: AbstractInsnNode, successor: Int): Boolean {
|
||||
if (!skipBreakContinueGotoEdges) return true
|
||||
return !(insnNode is JumpInsnNode && context.breakContinueGotoNodes.contains(insnNode))
|
||||
}
|
||||
}
|
||||
|
||||
private val loopEntryPointMarkers = hashMapOf<LabelNode, SmartList<AbstractInsnNode>>()
|
||||
|
||||
var maxExtraStackSize = 0; private set
|
||||
private val spilledStacks = hashMapOf<AbstractInsnNode, List<FixStackValue>>()
|
||||
|
||||
fun analyze() {
|
||||
recordLoopEntryPointMarkers()
|
||||
analyzer.analyze()
|
||||
}
|
||||
|
||||
fun getStackToSpill(location: AbstractInsnNode): List<FixStackValue>? =
|
||||
spilledStacks[location]
|
||||
|
||||
fun getActualStack(location: AbstractInsnNode): List<FixStackValue>? =
|
||||
getFrame(location)?.getStackContent()
|
||||
analyzer.getFrame(location)?.getStackContent()
|
||||
|
||||
fun getActualStackSize(location: AbstractInsnNode): Int =
|
||||
getFrame(location)?.stackSizeWithExtra ?: DEAD_CODE_STACK_SIZE
|
||||
analyzer.getFrame(location)?.stackSizeWithExtra ?: DEAD_CODE_STACK_SIZE
|
||||
|
||||
fun getExpectedStackSize(location: AbstractInsnNode): Int {
|
||||
// We should look for expected stack size at loop entry point markers if available,
|
||||
@@ -62,7 +77,7 @@ internal class FixStackAnalyzer(
|
||||
|
||||
// Find 1st live node among expected stack size nodes and return corresponding stack size
|
||||
for (node in expectedStackSizeNodes) {
|
||||
val frame = getFrame(node) ?: continue
|
||||
val frame = analyzer.getFrame(node) ?: continue
|
||||
return frame.stackSizeWithExtra
|
||||
}
|
||||
|
||||
@@ -71,10 +86,6 @@ internal class FixStackAnalyzer(
|
||||
return DEAD_CODE_STACK_SIZE
|
||||
}
|
||||
|
||||
override fun beforeAnalyze() {
|
||||
recordLoopEntryPointMarkers()
|
||||
}
|
||||
|
||||
private fun recordLoopEntryPointMarkers() {
|
||||
// NB JVM_IR can generate nested loops with same exit labels (see kt37370.kt)
|
||||
for (marker in context.fakeAlwaysFalseIfeqMarkers) {
|
||||
@@ -85,14 +96,6 @@ internal class FixStackAnalyzer(
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitControlFlowEdge(insnNode: AbstractInsnNode, successor: Int): Boolean {
|
||||
if (!skipBreakContinueGotoEdges) return true
|
||||
return !(insnNode is JumpInsnNode && context.breakContinueGotoNodes.contains(insnNode))
|
||||
}
|
||||
|
||||
override fun newFrame(nLocals: Int, nStack: Int): FixStackFrame =
|
||||
FixStackFrame(nLocals, nStack)
|
||||
|
||||
inner class FixStackFrame(nLocals: Int, nStack: Int) : Frame<FixStackValue>(nLocals, nStack) {
|
||||
private val extraStack = Stack<FixStackValue>()
|
||||
|
||||
@@ -144,7 +147,7 @@ internal class FixStackAnalyzer(
|
||||
}
|
||||
}
|
||||
|
||||
fun pushAll(values: Collection<FixStackValue>) {
|
||||
private fun pushAll(values: Collection<FixStackValue>) {
|
||||
values.forEach { push(it) }
|
||||
}
|
||||
|
||||
@@ -194,7 +197,7 @@ internal class FixStackAnalyzer(
|
||||
private fun executeRestoreStackInTryCatch(insn: AbstractInsnNode) {
|
||||
val saveNode = context.saveStackMarkerForRestoreMarker[insn]
|
||||
val savedValues = spilledStacks.getOrElse(saveNode!!) {
|
||||
throw AssertionError("${insn.indexOf()}: Restore stack is unavailable for ${saveNode.indexOf()}")
|
||||
throw AssertionError("${insn.insnText}: Restore stack is unavailable for ${saveNode.insnText}")
|
||||
}
|
||||
pushAll(savedValues)
|
||||
}
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ class FixStackMethodTransformer : MethodTransformer() {
|
||||
}
|
||||
|
||||
private fun analyzeAndTransformBreakContinueGotos(context: FixStackContext, internalClassName: String, methodNode: MethodNode) {
|
||||
val analyzer = FixStackAnalyzer(internalClassName, methodNode, context)
|
||||
val analyzer = FixStackAnalyzer(internalClassName, methodNode, context, skipBreakContinueGotoEdges = true)
|
||||
analyzer.analyze()
|
||||
|
||||
methodNode.maxStack = methodNode.maxStack + analyzer.maxExtraStackSize
|
||||
|
||||
Reference in New Issue
Block a user