Refactoring: added Interval abstraction to represent TryCatchBlock and LocalVar nodes

This commit is contained in:
Michael Bogdanov
2015-04-14 14:41:40 +03:00
parent 45428895ad
commit 2f88baf641
4 changed files with 124 additions and 42 deletions
@@ -16,46 +16,40 @@
package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.org.objectweb.asm.tree.MethodNode
import org.jetbrains.org.objectweb.asm.tree.LabelNode
import com.google.common.collect.LinkedListMultimap
import java.util.ArrayList
import com.intellij.util.containers.Stack
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
import org.jetbrains.org.objectweb.asm.tree.TryCatchBlockNode
import org.jetbrains.org.objectweb.asm.tree.*
import java.util.Comparator
import java.util.Collections
public abstract class CoveringTryCatchNodeProcessor<T: IntervalWithHandler>() {
private val tryBlockStarts = LinkedListMultimap.create<LabelNode, T>()
public val tryBlocksMetaInfo: IntervalMetaInfo<T> = IntervalMetaInfo();
private val tryBlockEnds = LinkedListMultimap.create<LabelNode, T>()
public val allTryCatchNodes: ArrayList<T> = arrayListOf()
private val currentCoveringBlocks: Stack<T> = Stack()
public val localVarsMetaInfo: IntervalMetaInfo<LocalVarNodeWrapper> = IntervalMetaInfo();
public val coveringFromInnermost: List<T>
get() = currentCoveringBlocks.reverse()
get() = tryBlocksMetaInfo.currentIntervals.reverse()
fun addNewTryCatchNode(newInfo: T) {
tryBlockStarts.put(newInfo.startLabel, newInfo)
tryBlockEnds.put(newInfo.endLabel, newInfo)
allTryCatchNodes.add(newInfo)
protected fun addNewTryCatchNode(newInfo: T) {
tryBlocksMetaInfo.addNewInterval(newInfo)
}
protected fun addNewLocalVar(newInfo: LocalVarNodeWrapper) {
localVarsMetaInfo.addNewInterval(newInfo)
}
fun remapStartLabel(oldStart: LabelNode, remapped: T) {
tryBlockStarts.remove(oldStart, remapped)
tryBlockStarts.put(remapped.startLabel, remapped)
tryBlocksMetaInfo.remapStartLabel(oldStart, remapped)
}
public fun getStartNodes(label: LabelNode): List<T> {
return tryBlockStarts.get(label)
return tryBlocksMetaInfo.intervalStarts.get(label)
}
public fun getEndNodes(label: LabelNode): List<T> {
return tryBlockEnds.get(label)
return tryBlocksMetaInfo.intervalEnds.get(label)
}
//Keep information about try blocks that cover current instruction -
@@ -63,9 +57,8 @@ public abstract class CoveringTryCatchNodeProcessor<T: IntervalWithHandler>() {
public open fun updateCoveringTryBlocks(curIns: AbstractInsnNode, directOrder: Boolean) {
if (curIns !is LabelNode) return
val infosToClose = if (!directOrder) getStartNodes(curIns) else getEndNodes(curIns)
for (startNode in infosToClose) {
val pop = currentCoveringBlocks.pop()
for (startNode in tryBlocksMetaInfo.infoToClose(curIns, directOrder)) {
val pop = tryBlocksMetaInfo.currentIntervals.pop()
//Temporary disabled cause during patched structure of exceptions changed
// if (startNode != pop) {
// throw RuntimeException("Wrong try-catch structure " + startNode + " " + pop + " " + infosToClose.size())
@@ -74,25 +67,28 @@ public abstract class CoveringTryCatchNodeProcessor<T: IntervalWithHandler>() {
//Reversing list order cause we should pop external block before internal one
// (originally internal blocks goes before external one, such invariant preserved via sortTryCatchBlocks method)
val infoToOpen = if (!directOrder) getEndNodes(curIns) else getStartNodes(curIns)
for (info in infoToOpen.reverse()) {
currentCoveringBlocks.add(info)
for (info in tryBlocksMetaInfo.infoToOpen(curIns, directOrder).reverse()) {
tryBlocksMetaInfo.currentIntervals.add(info)
}
}
public open fun updateCoveringLocalVars(curIns: AbstractInsnNode, directOrder: Boolean) {
if (curIns !is LabelNode) return
localVarsMetaInfo.infoToClose(curIns, directOrder).forEach {
localVarsMetaInfo.currentIntervals.pop()
}
localVarsMetaInfo.infoToOpen(curIns, directOrder).forEach {
localVarsMetaInfo.currentIntervals.add(it)
}
}
public abstract fun instructionIndex(inst: AbstractInsnNode): Int
private fun isEmptyInterval(node: T): Boolean {
val start = node.startLabel
var end: AbstractInsnNode = node.endLabel
while (end != start && end is LabelNode) {
end = end.getPrevious()
}
return start == end;
}
public fun getNonEmptyNodes(): List<T> {
return allTryCatchNodes.filterNot { isEmptyInterval(it) }
return tryBlocksMetaInfo.getNonEmptyNodes()
}
public fun sortTryCatchBlocks() {
@@ -108,25 +104,79 @@ public abstract class CoveringTryCatchNodeProcessor<T: IntervalWithHandler>() {
result
}
Collections.sort<T>(allTryCatchNodes, comp)
Collections.sort<T>(tryBlocksMetaInfo.allIntervals, comp)
}
}
class IntervalMetaInfo<T: Interval> {
val intervalStarts = LinkedListMultimap.create<LabelNode, T>()
val intervalEnds = LinkedListMultimap.create<LabelNode, T>()
val allIntervals: ArrayList<T> = arrayListOf()
val currentIntervals: Stack<T> = Stack()
fun addNewInterval(newInfo: T) {
intervalStarts.put(newInfo.startLabel, newInfo)
intervalEnds.put(newInfo.endLabel, newInfo)
allIntervals.add(newInfo)
}
fun remapStartLabel(oldStart: LabelNode, remapped: T) {
intervalStarts.remove(oldStart, remapped)
intervalStarts.put(remapped.startLabel, remapped)
}
fun remapEndLabel(oldEnd: LabelNode, remapped: T) {
intervalEnds.remove(oldEnd, remapped)
intervalEnds.put(remapped.startLabel, remapped)
}
public fun getNonEmptyNodes(): List<T> {
return allIntervals.filterNot { isEmptyInterval(it) }
}
fun infoToClose(curIns: LabelNode, directOrder: Boolean) = if (!directOrder) intervalStarts.get(curIns) else intervalEnds.get(curIns)
fun infoToOpen(curIns: LabelNode, directOrder: Boolean) = if (directOrder) intervalStarts.get(curIns) else intervalEnds.get(curIns)
private fun isEmptyInterval(node: T): Boolean {
val start = node.startLabel
var end: AbstractInsnNode = node.endLabel
while (end != start && end is LabelNode) {
end = end.getPrevious()
}
return start == end;
}
}
public class DefaultProcessor(val node: MethodNode) : CoveringTryCatchNodeProcessor<TryCatchBlockNodeWrapper>() {
init {
node.tryCatchBlocks.forEach { addNode(it) }
node.tryCatchBlocks.forEach { addTryNode(it) }
node.localVariables.forEach { addLocalVarNode(it) }
}
fun addNode(node: TryCatchBlockNode) {
fun addLocalVarNode(it: LocalVariableNode) {
addNewLocalVar(LocalVarNodeWrapper(it))
}
fun addTryNode(node: TryCatchBlockNode) {
addNewTryCatchNode(TryCatchBlockNodeWrapper(node))
}
override fun instructionIndex(inst: AbstractInsnNode): Int {
return node.instructions.indexOf(inst)
}
}
public class LocalVarNodeWrapper(val node: LocalVariableNode) : Interval {
override val startLabel: LabelNode
get() = node.start
override val endLabel: LabelNode
get() = node.end
}
public class TryCatchBlockNodeWrapper(val node: TryCatchBlockNode) : IntervalWithHandler {
@@ -638,6 +638,7 @@ public class InlineCodegen extends CallGenerator {
AbstractInsnNode curInstr = intoNode.instructions.getFirst();
while (curInstr != null) {
processor.updateCoveringTryBlocks(curInstr, true);
processor.updateCoveringLocalVars(curInstr, true);
MethodInliner.PointForExternalFinallyBlocks extension = extensionPoints.get(curInstr);
if (extension != null) {
@@ -668,7 +669,7 @@ public class InlineCodegen extends CallGenerator {
processor.remapStartLabel(oldStart, previous);
TryCatchBlockNode additionalNode = new TryCatchBlockNode(oldStart, (LabelNode) start.info, node.handler, node.type);
processor.addNode(additionalNode);
processor.addTryNode(additionalNode);
}
}
@@ -681,6 +682,12 @@ public class InlineCodegen extends CallGenerator {
for (TryCatchBlockNodeWrapper node : nodes) {
intoNode.tryCatchBlocks.add(node.getNode());
}
intoNode.localVariables.clear();
List<LocalVarNodeWrapper> intervals = processor.getLocalVarsMetaInfo().getAllIntervals();
for (LocalVarNodeWrapper interval : intervals) {
intoNode.localVariables.add(interval.getNode());
}
}
private SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap) {
@@ -144,7 +144,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
List<TryCatchBlockNodeInfo> clusterBlocks = clusterToFindFinally.getBlocks();
TryCatchBlockNodeInfo nodeWithDefaultHandlerIfExists = clusterBlocks.get(clusterBlocks.size() - 1);
FinallyBlockInfo finallyInfo = findFinallyBlockBody(nodeWithDefaultHandlerIfExists, getAllTryCatchNodes());
FinallyBlockInfo finallyInfo = findFinallyBlockBody(nodeWithDefaultHandlerIfExists, getTryBlocksMetaInfo().getAllIntervals());
if (finallyInfo == null) continue;
if (nodeWithDefaultHandlerIfExists.getOnlyCopyNotProcess()) {
@@ -26,14 +26,24 @@ enum class TryCatchPosition {
INNER
}
trait IntervalWithHandler {
public class SplittedPair(val patchedPart: SplittableInterval, val newPart: SplittableInterval)
trait Interval {
val startLabel: LabelNode
val endLabel: LabelNode
}
trait SplittableInterval : Interval {
fun split(split: Interval, keepStart: Boolean): SplittedPair
}
trait IntervalWithHandler : Interval {
val handler: LabelNode
val type: String?
}
class TryCatchBlockNodeInfo(val node: TryCatchBlockNode, val onlyCopyNotProcess: Boolean) : IntervalWithHandler {
class TryCatchBlockNodeInfo(val node: TryCatchBlockNode, val onlyCopyNotProcess: Boolean) : IntervalWithHandler, SplittableInterval {
override val startLabel: LabelNode
get() = node.start
override val endLabel: LabelNode
@@ -42,9 +52,24 @@ class TryCatchBlockNodeInfo(val node: TryCatchBlockNode, val onlyCopyNotProcess:
get() = node.handler
override val type: String?
get() = node.type
override fun split(split: Interval, keepStart: Boolean): SplittedPair {
val newPart = if (keepStart) {
val oldEnd = endLabel
node.end = split.startLabel
TryCatchBlockNodeInfo(TryCatchBlockNode(split.endLabel, oldEnd, handler, type), onlyCopyNotProcess)
} else {
val oldStart = startLabel
node.start = split.endLabel
TryCatchBlockNodeInfo(TryCatchBlockNode(oldStart, split.startLabel, handler, type), onlyCopyNotProcess)
}
return SplittedPair(this, newPart)
}
}
class TryCatchBlockNodePosition(val nodeInfo: TryCatchBlockNodeInfo, var position: TryCatchPosition): IntervalWithHandler by nodeInfo
class TryCatchBlockNodePosition(val nodeInfo: TryCatchBlockNodeInfo, var position: TryCatchPosition): IntervalWithHandler by nodeInfo {
}
class TryBlockCluster<T : IntervalWithHandler>(val blocks: MutableList<T>) {
val defaultHandler: T?