Refactoring: extracted split method into intervals
This commit is contained in:
+38
-37
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
+7
-27
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user