Refactoring: extracted split method into intervals

This commit is contained in:
Michael Bogdanov
2015-04-14 16:26:53 +03:00
parent 2f88baf641
commit 6465c6b680
4 changed files with 77 additions and 99 deletions
@@ -23,7 +23,7 @@ import org.jetbrains.org.objectweb.asm.tree.*
import java.util.Comparator import java.util.Comparator
import java.util.Collections import java.util.Collections
public abstract class CoveringTryCatchNodeProcessor<T: IntervalWithHandler>() { public abstract class CoveringTryCatchNodeProcessor<T : IntervalWithHandler> where T : SplittableInterval<T> {
public val tryBlocksMetaInfo: IntervalMetaInfo<T> = IntervalMetaInfo(); public val tryBlocksMetaInfo: IntervalMetaInfo<T> = IntervalMetaInfo();
@@ -32,18 +32,6 @@ public abstract class CoveringTryCatchNodeProcessor<T: IntervalWithHandler>() {
public val coveringFromInnermost: List<T> public val coveringFromInnermost: List<T>
get() = tryBlocksMetaInfo.currentIntervals.reverse() get() = tryBlocksMetaInfo.currentIntervals.reverse()
protected fun addNewTryCatchNode(newInfo: T) {
tryBlocksMetaInfo.addNewInterval(newInfo)
}
protected fun addNewLocalVar(newInfo: LocalVarNodeWrapper) {
localVarsMetaInfo.addNewInterval(newInfo)
}
fun remapStartLabel(oldStart: LabelNode, remapped: T) {
tryBlocksMetaInfo.remapStartLabel(oldStart, remapped)
}
public fun getStartNodes(label: LabelNode): List<T> { public fun getStartNodes(label: LabelNode): List<T> {
return tryBlocksMetaInfo.intervalStarts.get(label) return tryBlocksMetaInfo.intervalStarts.get(label)
} }
@@ -86,19 +74,14 @@ public abstract class CoveringTryCatchNodeProcessor<T: IntervalWithHandler>() {
public abstract fun instructionIndex(inst: AbstractInsnNode): Int public abstract fun instructionIndex(inst: AbstractInsnNode): Int
public fun getNonEmptyNodes(): List<T> {
return tryBlocksMetaInfo.getNonEmptyNodes()
}
public fun sortTryCatchBlocks() { public fun sortTryCatchBlocks() {
val comp = Comparator { t1: T, t2: T -> val comp = Comparator { t1: T, t2: T ->
var result = instructionIndex(t1.handler) - instructionIndex(t2.handler) var result = instructionIndex(t1.handler) - instructionIndex(t2.handler)
if (result == 0) { if (result == 0) {
result = instructionIndex(t1.startLabel) - instructionIndex(t2.startLabel) result = instructionIndex((t1 as Interval).startLabel) - instructionIndex((t2 as Interval).startLabel)
if (result == 0) { if (result == 0) {
assert(false, "Error: support multicatch finallies!") assert(false, "Error: support multicatch finallies!")
result = instructionIndex(t1.endLabel) - instructionIndex(t2.endLabel) result = instructionIndex((t1 as Interval).endLabel) - instructionIndex((t2 as Interval).endLabel)
} }
} }
result result
@@ -108,7 +91,7 @@ public abstract class CoveringTryCatchNodeProcessor<T: IntervalWithHandler>() {
} }
} }
class IntervalMetaInfo<T: Interval> { class IntervalMetaInfo<T : Interval> {
val intervalStarts = LinkedListMultimap.create<LabelNode, T>() val intervalStarts = LinkedListMultimap.create<LabelNode, T>()
@@ -131,7 +114,18 @@ class IntervalMetaInfo<T: Interval> {
fun remapEndLabel(oldEnd: LabelNode, remapped: T) { fun remapEndLabel(oldEnd: LabelNode, remapped: T) {
intervalEnds.remove(oldEnd, remapped) intervalEnds.remove(oldEnd, remapped)
intervalEnds.put(remapped.startLabel, remapped) intervalEnds.put(remapped.endLabel, remapped)
}
fun split(interval: SplittableInterval<T>, by : Interval, keepStart: Boolean): SplittedPair<T> {
val splittedPair = interval.split(by, keepStart)
if (!keepStart) {
remapStartLabel((splittedPair.newPart as Interval).startLabel, splittedPair.patchedPart)
} else {
remapEndLabel((splittedPair.newPart as Interval).endLabel, splittedPair.patchedPart)
}
addNewInterval(splittedPair.newPart)
return splittedPair
} }
public fun getNonEmptyNodes(): List<T> { public fun getNonEmptyNodes(): List<T> {
@@ -152,7 +146,7 @@ class IntervalMetaInfo<T: Interval> {
} }
} }
public class DefaultProcessor(val node: MethodNode) : CoveringTryCatchNodeProcessor<TryCatchBlockNodeWrapper>() { public class DefaultProcessor(val node: MethodNode) : CoveringTryCatchNodeProcessor<TryCatchBlockNodeInfo>() {
init { init {
node.tryCatchBlocks.forEach { addTryNode(it) } node.tryCatchBlocks.forEach { addTryNode(it) }
@@ -160,11 +154,11 @@ public class DefaultProcessor(val node: MethodNode) : CoveringTryCatchNodeProces
} }
fun addLocalVarNode(it: LocalVariableNode) { fun addLocalVarNode(it: LocalVariableNode) {
addNewLocalVar(LocalVarNodeWrapper(it)) localVarsMetaInfo.addNewInterval(LocalVarNodeWrapper(it))
} }
fun addTryNode(node: TryCatchBlockNode) { fun addTryNode(node: TryCatchBlockNode) {
addNewTryCatchNode(TryCatchBlockNodeWrapper(node)) tryBlocksMetaInfo.addNewInterval(TryCatchBlockNodeInfo(node, false))
} }
override fun instructionIndex(inst: AbstractInsnNode): Int { override fun instructionIndex(inst: AbstractInsnNode): Int {
@@ -172,20 +166,27 @@ public class DefaultProcessor(val node: MethodNode) : CoveringTryCatchNodeProces
} }
} }
public class LocalVarNodeWrapper(val node: LocalVariableNode) : Interval { public class LocalVarNodeWrapper(val node: LocalVariableNode) : Interval, SplittableInterval<LocalVarNodeWrapper> {
override val startLabel: LabelNode override val startLabel: LabelNode
get() = node.start get() = node.start
override val endLabel: LabelNode override val endLabel: LabelNode
get() = node.end get() = node.end
}
public class TryCatchBlockNodeWrapper(val node: TryCatchBlockNode) : IntervalWithHandler { override fun split(split: Interval, keepStart: Boolean): SplittedPair<LocalVarNodeWrapper> {
override val startLabel: LabelNode val newPartInterval = if (keepStart) {
get() = node.start val oldEnd = endLabel
override val endLabel: LabelNode node.end = split.startLabel
get() = node.end Pair(split.endLabel, oldEnd)
override val handler: LabelNode }
get() = node.handler else {
override val type: String? val oldStart = startLabel
get() = node.type node.start = split.endLabel
} Pair(oldStart, split.startLabel)
}
return SplittedPair(this, LocalVarNodeWrapper(
LocalVariableNode(node.name, node.desc, node.signature, newPartInterval.first, newPartInterval.second, node.index)
))
}
}
@@ -659,17 +659,9 @@ public class InlineCodegen extends CallGenerator {
//Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method //Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method
InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr); InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr);
List<TryCatchBlockNodeWrapper> blocks = processor.getCoveringFromInnermost(); List<TryCatchBlockNodeInfo> blocks = new ArrayList<TryCatchBlockNodeInfo>(processor.getTryBlocksMetaInfo().getCurrentIntervals());
ListIterator<TryCatchBlockNodeWrapper> iterator = blocks.listIterator(blocks.size()); for (TryCatchBlockNodeInfo block : blocks) {
while (iterator.hasPrevious()) { processor.getTryBlocksMetaInfo().split(block, new SimpleInterval((LabelNode) start.info, (LabelNode) end.info), false);
TryCatchBlockNodeWrapper previous = iterator.previous();
LabelNode oldStart = previous.getStartLabel();
TryCatchBlockNode node = previous.getNode();
node.start = (LabelNode) end.info;
processor.remapStartLabel(oldStart, previous);
TryCatchBlockNode additionalNode = new TryCatchBlockNode(oldStart, (LabelNode) start.info, node.handler, node.type);
processor.addTryNode(additionalNode);
} }
} }
@@ -677,15 +669,14 @@ public class InlineCodegen extends CallGenerator {
} }
processor.sortTryCatchBlocks(); processor.sortTryCatchBlocks();
Iterable<TryCatchBlockNodeWrapper> nodes = processor.getNonEmptyNodes(); Iterable<TryCatchBlockNodeInfo> nodes = processor.getNonEmptyNodes();
intoNode.tryCatchBlocks.clear(); intoNode.tryCatchBlocks.clear();
for (TryCatchBlockNodeWrapper node : nodes) { for (TryCatchBlockNodeInfo node : nodes) {
intoNode.tryCatchBlocks.add(node.getNode()); intoNode.tryCatchBlocks.add(node.getNode());
} }
intoNode.localVariables.clear(); intoNode.localVariables.clear();
List<LocalVarNodeWrapper> intervals = processor.getLocalVarsMetaInfo().getAllIntervals(); for (LocalVarNodeWrapper interval : processor.getLocalVarsMetaInfo().getAllIntervals()) {
for (LocalVarNodeWrapper interval : intervals) {
intoNode.localVariables.add(interval.getNode()); intoNode.localVariables.add(interval.getNode());
} }
} }
@@ -81,8 +81,9 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
//due to code generation specific they placed before function TryCatchBlockNodes //due to code generation specific they placed before function TryCatchBlockNodes
private InternalFinallyBlockInliner(@NotNull MethodNode inlineFun, List<TryCatchBlockNodeInfo> inlineFunTryBlockInfo) { private InternalFinallyBlockInliner(@NotNull MethodNode inlineFun, List<TryCatchBlockNodeInfo> inlineFunTryBlockInfo) {
this.inlineFun = inlineFun; this.inlineFun = inlineFun;
IntervalMetaInfo<TryCatchBlockNodeInfo> info = getTryBlocksMetaInfo();
for (TryCatchBlockNodeInfo block : inlineFunTryBlockInfo) { for (TryCatchBlockNodeInfo block : inlineFunTryBlockInfo) {
addNewTryCatchNode(block); info.addNewInterval(block);
} }
} }
@@ -293,6 +294,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
List<TryBlockCluster<TryCatchBlockNodePosition>> clusters = InlinePackage.doClustering(tryCatchBlockPresentInFinally); List<TryBlockCluster<TryCatchBlockNodePosition>> clusters = InlinePackage.doClustering(tryCatchBlockPresentInFinally);
Map<LabelNode, TryBlockCluster<TryCatchBlockNodePosition>> handler2Cluster = new HashMap<LabelNode, TryBlockCluster<TryCatchBlockNodePosition>>(); Map<LabelNode, TryBlockCluster<TryCatchBlockNodePosition>> handler2Cluster = new HashMap<LabelNode, TryBlockCluster<TryCatchBlockNodePosition>>();
IntervalMetaInfo<TryCatchBlockNodeInfo> tryBlocksMetaInfo = getTryBlocksMetaInfo();
for (TryBlockCluster<TryCatchBlockNodePosition> cluster : clusters) { for (TryBlockCluster<TryCatchBlockNodePosition> cluster : clusters) {
List<TryCatchBlockNodePosition> clusterBlocks = cluster.getBlocks(); List<TryCatchBlockNodePosition> clusterBlocks = cluster.getBlocks();
TryCatchBlockNodePosition block0 = clusterBlocks.get(0); TryCatchBlockNodePosition block0 = clusterBlocks.get(0);
@@ -313,8 +315,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
assert inlineFun.instructions.indexOf(additionalTryCatchBlock.start) <= inlineFun.instructions.indexOf(additionalTryCatchBlock.end); assert inlineFun.instructions.indexOf(additionalTryCatchBlock.start) <= inlineFun.instructions.indexOf(additionalTryCatchBlock.end);
TryCatchBlockNodeInfo newInfo = new TryCatchBlockNodeInfo(additionalTryCatchBlock, true); tryBlocksMetaInfo.addNewInterval(new TryCatchBlockNodeInfo(additionalTryCatchBlock, true));
addNewTryCatchNode(newInfo);
} }
} }
else if (clusterPosition == TryCatchPosition.END) { else if (clusterPosition == TryCatchPosition.END) {
@@ -367,37 +368,16 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
// so we should split original interval by inserted finally one // so we should split original interval by inserted finally one
for (TryCatchBlockNodeInfo block : toProcess) { for (TryCatchBlockNodeInfo block : toProcess) {
//update exception mapping //update exception mapping
LabelNode oldStartNode = block.getNode().start; tryBlocksMetaInfo.split(block, new SimpleInterval((LabelNode) newFinallyStart.info, (LabelNode) newFinallyEnd.info), false);
block.getNode().start = (LabelNode) newFinallyEnd.info;
remapStartLabel(oldStartNode, block);
patched.add(block); patched.add(block);
TryCatchBlockNode additionalTryCatchBlock =
new TryCatchBlockNode(oldStartNode, (LabelNode) newFinallyStart.info, block.getNode().handler, block.getNode().type);
TryCatchBlockNodeInfo newInfo = new TryCatchBlockNodeInfo(additionalTryCatchBlock, block.getOnlyCopyNotProcess());
addNewTryCatchNode(newInfo);
//TODO add assert //TODO add assert
} }
sortTryCatchBlocks(); sortTryCatchBlocks();
} }
private void patchTryBlocks(@NotNull LabelNode newStartLabelNode, @NotNull TryCatchBlockNodeInfo endNode) { private void patchTryBlocks(@NotNull LabelNode newStartLabelNode, @NotNull TryCatchBlockNodeInfo endNode) {
LabelNode oldStart = endNode.getStartLabel(); getTryBlocksMetaInfo()
endNode.getNode().start = newStartLabelNode; .split(endNode, new SimpleInterval((LabelNode) endNode.getNode().end.getLabel().info, newStartLabelNode), false);
remapStartLabel(oldStart, endNode);
TryCatchBlockNode endTryBlock = endNode.getNode();
TryCatchBlockNode additionalTryCatchBlock =
new TryCatchBlockNode(oldStart,
(LabelNode) endTryBlock.end.getLabel().info,
endTryBlock.handler,
endTryBlock.type);
TryCatchBlockNodeInfo newInfo = new TryCatchBlockNodeInfo(additionalTryCatchBlock, endNode.getOnlyCopyNotProcess());
addNewTryCatchNode(newInfo);
} }
private static LabelNode getNewOrOldLabel(LabelNode oldHandler, @NotNull Set<LabelNode> labelsInsideFinally) { private static LabelNode getNewOrOldLabel(LabelNode oldHandler, @NotNull Set<LabelNode> labelsInsideFinally) {
@@ -26,15 +26,17 @@ enum class TryCatchPosition {
INNER INNER
} }
public class SplittedPair(val patchedPart: SplittableInterval, val newPart: SplittableInterval) public class SplittedPair<T: Interval>(val patchedPart: T, val newPart: T)
class SimpleInterval(override val startLabel: LabelNode, override val endLabel: LabelNode ) : Interval
trait Interval { trait Interval {
val startLabel: LabelNode val startLabel: LabelNode
val endLabel: LabelNode val endLabel: LabelNode
} }
trait SplittableInterval : Interval { trait SplittableInterval<T: Interval> : Interval {
fun split(split: Interval, keepStart: Boolean): SplittedPair fun split(split: Interval, keepStart: Boolean): SplittedPair<T>
} }
@@ -43,31 +45,35 @@ trait IntervalWithHandler : Interval {
val type: String? val type: String?
} }
class TryCatchBlockNodeInfo(val node: TryCatchBlockNode, val onlyCopyNotProcess: Boolean) : IntervalWithHandler, SplittableInterval { class TryCatchBlockNodeInfo(val node: TryCatchBlockNode, val onlyCopyNotProcess: Boolean) : IntervalWithHandler, SplittableInterval<TryCatchBlockNodeInfo> {
override val startLabel: LabelNode override val startLabel: LabelNode
get() = node.start get() = node.start
override val endLabel: LabelNode override val endLabel: LabelNode
get() = node.end get() = node.end
override val handler: LabelNode override val handler: LabelNode
get() = node.handler get() = node.handler
override val type: String? override val type: String?
get() = node.type get() = node.type
override fun split(split: Interval, keepStart: Boolean): SplittedPair { override fun split(by: Interval, keepStart: Boolean): SplittedPair<TryCatchBlockNodeInfo> {
val newPart = if (keepStart) { val newPartInterval = if (keepStart) {
val oldEnd = endLabel val oldEnd = endLabel
node.end = split.startLabel node.end = by.startLabel
TryCatchBlockNodeInfo(TryCatchBlockNode(split.endLabel, oldEnd, handler, type), onlyCopyNotProcess) Pair(by.endLabel, oldEnd)
} else {
val oldStart = startLabel
node.start = split.endLabel
TryCatchBlockNodeInfo(TryCatchBlockNode(oldStart, split.startLabel, handler, type), onlyCopyNotProcess)
} }
return SplittedPair(this, newPart) else {
val oldStart = startLabel
node.start = by.endLabel
Pair(oldStart, by.startLabel)
}
return SplittedPair(
this,
TryCatchBlockNodeInfo(TryCatchBlockNode(newPartInterval.first, newPartInterval.second, handler, type), onlyCopyNotProcess)
)
} }
} }
class TryCatchBlockNodePosition(val nodeInfo: TryCatchBlockNodeInfo, var position: TryCatchPosition): IntervalWithHandler by nodeInfo { class TryCatchBlockNodePosition(val nodeInfo: TryCatchBlockNodeInfo, var position: TryCatchPosition) : IntervalWithHandler by nodeInfo {
} }
@@ -77,13 +83,13 @@ class TryBlockCluster<T : IntervalWithHandler>(val blocks: MutableList<T>) {
} }
fun <T: IntervalWithHandler> doClustering(blocks: List<T>) : List<TryBlockCluster<T>> { fun <T : IntervalWithHandler> doClustering(blocks: List<T>): List<TryBlockCluster<T>> {
[data] class TryBlockInterval(val startLabel: LabelNode, val endLabel: LabelNode) [data] class TryBlockInterval(val startLabel: LabelNode, val endLabel: LabelNode)
val clusters = linkedMapOf<TryBlockInterval, TryBlockCluster<T>>() val clusters = linkedMapOf<TryBlockInterval, TryBlockCluster<T>>()
blocks.forEach { block -> blocks.forEach { block ->
val interval = TryBlockInterval(firstLabelInChain(block.startLabel), firstLabelInChain(block.endLabel)) val interval = TryBlockInterval(firstLabelInChain(block.startLabel), firstLabelInChain(block.endLabel))
val cluster = clusters.getOrPut(interval, {TryBlockCluster(arrayListOf())}) val cluster = clusters.getOrPut(interval, { TryBlockCluster(arrayListOf()) })
cluster.blocks.add(block) cluster.blocks.add(block)
} }