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.Collections
public abstract class CoveringTryCatchNodeProcessor<T: IntervalWithHandler>() {
public abstract class CoveringTryCatchNodeProcessor<T : IntervalWithHandler> where T : SplittableInterval<T> {
public val tryBlocksMetaInfo: IntervalMetaInfo<T> = IntervalMetaInfo();
@@ -32,18 +32,6 @@ public abstract class CoveringTryCatchNodeProcessor<T: IntervalWithHandler>() {
public val coveringFromInnermost: List<T>
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> {
return tryBlocksMetaInfo.intervalStarts.get(label)
}
@@ -86,19 +74,14 @@ public abstract class CoveringTryCatchNodeProcessor<T: IntervalWithHandler>() {
public abstract fun instructionIndex(inst: AbstractInsnNode): Int
public fun getNonEmptyNodes(): List<T> {
return tryBlocksMetaInfo.getNonEmptyNodes()
}
public fun sortTryCatchBlocks() {
val comp = Comparator { t1: T, t2: T ->
var result = instructionIndex(t1.handler) - instructionIndex(t2.handler)
if (result == 0) {
result = instructionIndex(t1.startLabel) - instructionIndex(t2.startLabel)
result = instructionIndex((t1 as Interval).startLabel) - instructionIndex((t2 as Interval).startLabel)
if (result == 0) {
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
@@ -108,7 +91,7 @@ public abstract class CoveringTryCatchNodeProcessor<T: IntervalWithHandler>() {
}
}
class IntervalMetaInfo<T: Interval> {
class IntervalMetaInfo<T : Interval> {
val intervalStarts = LinkedListMultimap.create<LabelNode, T>()
@@ -131,7 +114,18 @@ class IntervalMetaInfo<T: Interval> {
fun remapEndLabel(oldEnd: LabelNode, remapped: T) {
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> {
@@ -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 {
node.tryCatchBlocks.forEach { addTryNode(it) }
@@ -160,11 +154,11 @@ public class DefaultProcessor(val node: MethodNode) : CoveringTryCatchNodeProces
}
fun addLocalVarNode(it: LocalVariableNode) {
addNewLocalVar(LocalVarNodeWrapper(it))
localVarsMetaInfo.addNewInterval(LocalVarNodeWrapper(it))
}
fun addTryNode(node: TryCatchBlockNode) {
addNewTryCatchNode(TryCatchBlockNodeWrapper(node))
tryBlocksMetaInfo.addNewInterval(TryCatchBlockNodeInfo(node, false))
}
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
get() = node.start
override val endLabel: LabelNode
get() = node.end
}
public class TryCatchBlockNodeWrapper(val node: TryCatchBlockNode) : IntervalWithHandler {
override val startLabel: LabelNode
get() = node.start
override val endLabel: LabelNode
get() = node.end
override val handler: LabelNode
get() = node.handler
override val type: String?
get() = node.type
}
override fun split(split: Interval, keepStart: Boolean): SplittedPair<LocalVarNodeWrapper> {
val newPartInterval = if (keepStart) {
val oldEnd = endLabel
node.end = split.startLabel
Pair(split.endLabel, oldEnd)
}
else {
val oldStart = startLabel
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
InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr);
List<TryCatchBlockNodeWrapper> blocks = processor.getCoveringFromInnermost();
ListIterator<TryCatchBlockNodeWrapper> iterator = blocks.listIterator(blocks.size());
while (iterator.hasPrevious()) {
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);
List<TryCatchBlockNodeInfo> blocks = new ArrayList<TryCatchBlockNodeInfo>(processor.getTryBlocksMetaInfo().getCurrentIntervals());
for (TryCatchBlockNodeInfo block : blocks) {
processor.getTryBlocksMetaInfo().split(block, new SimpleInterval((LabelNode) start.info, (LabelNode) end.info), false);
}
}
@@ -677,15 +669,14 @@ public class InlineCodegen extends CallGenerator {
}
processor.sortTryCatchBlocks();
Iterable<TryCatchBlockNodeWrapper> nodes = processor.getNonEmptyNodes();
Iterable<TryCatchBlockNodeInfo> nodes = processor.getNonEmptyNodes();
intoNode.tryCatchBlocks.clear();
for (TryCatchBlockNodeWrapper node : nodes) {
for (TryCatchBlockNodeInfo node : nodes) {
intoNode.tryCatchBlocks.add(node.getNode());
}
intoNode.localVariables.clear();
List<LocalVarNodeWrapper> intervals = processor.getLocalVarsMetaInfo().getAllIntervals();
for (LocalVarNodeWrapper interval : intervals) {
for (LocalVarNodeWrapper interval : processor.getLocalVarsMetaInfo().getAllIntervals()) {
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
private InternalFinallyBlockInliner(@NotNull MethodNode inlineFun, List<TryCatchBlockNodeInfo> inlineFunTryBlockInfo) {
this.inlineFun = inlineFun;
IntervalMetaInfo<TryCatchBlockNodeInfo> info = getTryBlocksMetaInfo();
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);
Map<LabelNode, TryBlockCluster<TryCatchBlockNodePosition>> handler2Cluster = new HashMap<LabelNode, TryBlockCluster<TryCatchBlockNodePosition>>();
IntervalMetaInfo<TryCatchBlockNodeInfo> tryBlocksMetaInfo = getTryBlocksMetaInfo();
for (TryBlockCluster<TryCatchBlockNodePosition> cluster : clusters) {
List<TryCatchBlockNodePosition> clusterBlocks = cluster.getBlocks();
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);
TryCatchBlockNodeInfo newInfo = new TryCatchBlockNodeInfo(additionalTryCatchBlock, true);
addNewTryCatchNode(newInfo);
tryBlocksMetaInfo.addNewInterval(new TryCatchBlockNodeInfo(additionalTryCatchBlock, true));
}
}
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
for (TryCatchBlockNodeInfo block : toProcess) {
//update exception mapping
LabelNode oldStartNode = block.getNode().start;
block.getNode().start = (LabelNode) newFinallyEnd.info;
remapStartLabel(oldStartNode, block);
tryBlocksMetaInfo.split(block, new SimpleInterval((LabelNode) newFinallyStart.info, (LabelNode) newFinallyEnd.info), false);
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
}
sortTryCatchBlocks();
}
private void patchTryBlocks(@NotNull LabelNode newStartLabelNode, @NotNull TryCatchBlockNodeInfo endNode) {
LabelNode oldStart = endNode.getStartLabel();
endNode.getNode().start = newStartLabelNode;
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);
getTryBlocksMetaInfo()
.split(endNode, new SimpleInterval((LabelNode) endNode.getNode().end.getLabel().info, newStartLabelNode), false);
}
private static LabelNode getNewOrOldLabel(LabelNode oldHandler, @NotNull Set<LabelNode> labelsInsideFinally) {
@@ -26,15 +26,17 @@ enum class TryCatchPosition {
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 {
val startLabel: LabelNode
val endLabel: LabelNode
}
trait SplittableInterval : Interval {
fun split(split: Interval, keepStart: Boolean): SplittedPair
trait SplittableInterval<T: Interval> : Interval {
fun split(split: Interval, keepStart: Boolean): SplittedPair<T>
}
@@ -43,31 +45,35 @@ trait IntervalWithHandler : Interval {
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
get() = node.start
get() = node.start
override val endLabel: LabelNode
get() = node.end
get() = node.end
override val handler: LabelNode
get() = node.handler
get() = node.handler
override val type: String?
get() = node.type
get() = node.type
override fun split(split: Interval, keepStart: Boolean): SplittedPair {
val newPart = if (keepStart) {
override fun split(by: Interval, keepStart: Boolean): SplittedPair<TryCatchBlockNodeInfo> {
val newPartInterval = 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)
node.end = by.startLabel
Pair(by.endLabel, oldEnd)
}
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)
val clusters = linkedMapOf<TryBlockInterval, TryBlockCluster<T>>()
blocks.forEach { block ->
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)
}