Extract backward analysis framework
This commit is contained in:
+65
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.codegen.optimization.common
|
||||||
|
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||||
|
|
||||||
|
interface VarFrame<F : VarFrame<F>> {
|
||||||
|
fun mergeFrom(other: F)
|
||||||
|
override fun equals(other: Any?): Boolean
|
||||||
|
override fun hashCode(): Int
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BackwardAnalysisInterpreter<F : VarFrame<F>> {
|
||||||
|
fun newFrame(maxLocals: Int): F
|
||||||
|
fun def(frame: F, insn: AbstractInsnNode)
|
||||||
|
fun use(frame: F, insn: AbstractInsnNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <F : VarFrame<F>> analyze(node: MethodNode, interpreter: BackwardAnalysisInterpreter<F>): List<F> {
|
||||||
|
val graph = ControlFlowGraph.build(node)
|
||||||
|
val insnList = node.instructions
|
||||||
|
|
||||||
|
val frames = (1..insnList.size()).map { interpreter.newFrame(node.maxLocals) }.toMutableList()
|
||||||
|
val insnArray = insnList.toArray()
|
||||||
|
|
||||||
|
// see Figure 9.16 from Dragon book
|
||||||
|
var wereChanges: Boolean
|
||||||
|
|
||||||
|
do {
|
||||||
|
wereChanges = false
|
||||||
|
for (insn in insnArray) {
|
||||||
|
val index = insnList.indexOf(insn)
|
||||||
|
val newFrame = interpreter.newFrame(node.maxLocals)
|
||||||
|
for (successorIndex in graph.getSuccessorsIndices(insn)) {
|
||||||
|
newFrame.mergeFrom(frames[successorIndex])
|
||||||
|
}
|
||||||
|
|
||||||
|
interpreter.def(newFrame, insn)
|
||||||
|
interpreter.use(newFrame, insn)
|
||||||
|
|
||||||
|
if (frames[index] != newFrame) {
|
||||||
|
frames[index] = newFrame
|
||||||
|
wereChanges = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (wereChanges)
|
||||||
|
|
||||||
|
return frames
|
||||||
|
}
|
||||||
+11
-35
@@ -27,10 +27,10 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
class VariableLivenessFrame(val maxLocals: Int) {
|
class VariableLivenessFrame(val maxLocals: Int) : VarFrame<VariableLivenessFrame> {
|
||||||
private val bitSet = BitSet(maxLocals)
|
private val bitSet = BitSet(maxLocals)
|
||||||
|
|
||||||
fun mergeFrom(other: VariableLivenessFrame) {
|
override fun mergeFrom(other: VariableLivenessFrame) {
|
||||||
bitSet.or(other.bitSet)
|
bitSet.or(other.bitSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,48 +51,24 @@ class VariableLivenessFrame(val maxLocals: Int) {
|
|||||||
|
|
||||||
override fun hashCode() = bitSet.hashCode()
|
override fun hashCode() = bitSet.hashCode()
|
||||||
}
|
}
|
||||||
|
fun analyzeLiveness(node: MethodNode): List<VariableLivenessFrame> {
|
||||||
fun analyzeLiveness(node: MethodNode): Array<VariableLivenessFrame> {
|
|
||||||
val typeAnnotatedFrames = MethodTransformer.analyze("fake", node, OptimizationBasicInterpreter())
|
val typeAnnotatedFrames = MethodTransformer.analyze("fake", node, OptimizationBasicInterpreter())
|
||||||
|
return analyze(node, object : BackwardAnalysisInterpreter<VariableLivenessFrame> {
|
||||||
|
override fun newFrame(maxLocals: Int) = VariableLivenessFrame(maxLocals)
|
||||||
|
override fun def(frame: VariableLivenessFrame, insn: AbstractInsnNode) = defVar(frame, insn)
|
||||||
|
override fun use(frame: VariableLivenessFrame, insn: AbstractInsnNode) =
|
||||||
|
useVar(frame, insn, node, typeAnnotatedFrames[node.instructions.indexOf(insn)])
|
||||||
|
|
||||||
val graph = ControlFlowGraph.build(node)
|
})
|
||||||
val insnList = node.instructions
|
|
||||||
val frames = Array(insnList.size()) { VariableLivenessFrame(node.maxLocals) }
|
|
||||||
val insnArray = insnList.toArray()
|
|
||||||
|
|
||||||
// see Figure 9.16 from Dragon book
|
|
||||||
var wereChanges: Boolean
|
|
||||||
|
|
||||||
do {
|
|
||||||
wereChanges = false
|
|
||||||
for (insn in insnArray) {
|
|
||||||
val index = insnList.indexOf(insn)
|
|
||||||
val newFrame = VariableLivenessFrame(node.maxLocals)
|
|
||||||
for (successorIndex in graph.getSuccessorsIndices(insn)) {
|
|
||||||
newFrame.mergeFrom(frames[successorIndex])
|
|
||||||
}
|
|
||||||
|
|
||||||
def(newFrame, insn)
|
|
||||||
use(newFrame, insn, node, typeAnnotatedFrames[index])
|
|
||||||
|
|
||||||
if (frames[index] != newFrame) {
|
|
||||||
frames[index] = newFrame
|
|
||||||
wereChanges = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (wereChanges)
|
|
||||||
|
|
||||||
return frames
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun def(frame: VariableLivenessFrame, insn: AbstractInsnNode) {
|
private fun defVar(frame: VariableLivenessFrame, insn: AbstractInsnNode) {
|
||||||
if (insn is VarInsnNode && insn.isStoreOperation()) {
|
if (insn is VarInsnNode && insn.isStoreOperation()) {
|
||||||
frame.markDead(insn.`var`)
|
frame.markDead(insn.`var`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun use(
|
private fun useVar(
|
||||||
frame: VariableLivenessFrame,
|
frame: VariableLivenessFrame,
|
||||||
insn: AbstractInsnNode,
|
insn: AbstractInsnNode,
|
||||||
node: MethodNode,
|
node: MethodNode,
|
||||||
|
|||||||
Reference in New Issue
Block a user