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