refactorings

This commit is contained in:
Michael Bogdanov
2015-04-15 13:35:26 +03:00
parent 6465c6b680
commit 51d5b52f69
4 changed files with 102 additions and 84 deletions
@@ -23,29 +23,34 @@ import org.jetbrains.org.objectweb.asm.tree.*
import java.util.Comparator
import java.util.Collections
public abstract class CoveringTryCatchNodeProcessor<T : IntervalWithHandler> where T : SplittableInterval<T> {
public abstract class CoveringTryCatchNodeProcessor {
public val tryBlocksMetaInfo: IntervalMetaInfo<T> = IntervalMetaInfo();
public val tryBlocksMetaInfo: IntervalMetaInfo<TryCatchBlockNodeInfo> = IntervalMetaInfo();
public val localVarsMetaInfo: IntervalMetaInfo<LocalVarNodeWrapper> = IntervalMetaInfo();
public val coveringFromInnermost: List<T>
public val coveringFromInnermost: List<TryCatchBlockNodeInfo>
get() = tryBlocksMetaInfo.currentIntervals.reverse()
public fun getStartNodes(label: LabelNode): List<T> {
public fun getStartNodes(label: LabelNode): List<TryCatchBlockNodeInfo> {
return tryBlocksMetaInfo.intervalStarts.get(label)
}
public fun getEndNodes(label: LabelNode): List<T> {
public fun getEndNodes(label: LabelNode): List<TryCatchBlockNodeInfo> {
return tryBlocksMetaInfo.intervalEnds.get(label)
}
public open fun processInstruction(curInstr: AbstractInsnNode, directOrder: Boolean) {
if (curInstr !is LabelNode) return
updateCoveringTryBlocks(curInstr, directOrder)
updateCoveringLocalVars(curInstr, directOrder)
}
//Keep information about try blocks that cover current instruction -
// pushing and popping it to stack entering and exiting tryCatchBlock start and end labels
public open fun updateCoveringTryBlocks(curIns: AbstractInsnNode, directOrder: Boolean) {
if (curIns !is LabelNode) return
for (startNode in tryBlocksMetaInfo.infoToClose(curIns, directOrder)) {
protected open fun updateCoveringTryBlocks(curIns: LabelNode, directOrder: Boolean) {
for (startNode in tryBlocksMetaInfo.closeIntervals(curIns, directOrder)) {
val pop = tryBlocksMetaInfo.currentIntervals.pop()
//Temporary disabled cause during patched structure of exceptions changed
// if (startNode != pop) {
@@ -55,19 +60,17 @@ public abstract class CoveringTryCatchNodeProcessor<T : IntervalWithHandler> wh
//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)
for (info in tryBlocksMetaInfo.infoToOpen(curIns, directOrder).reverse()) {
for (info in tryBlocksMetaInfo.openIntervals(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 {
protected open fun updateCoveringLocalVars(curIns: LabelNode, directOrder: Boolean) {
localVarsMetaInfo.closeIntervals(curIns, directOrder).forEach {
localVarsMetaInfo.currentIntervals.pop()
}
localVarsMetaInfo.infoToOpen(curIns, directOrder).forEach {
localVarsMetaInfo.openIntervals(curIns, directOrder).forEach {
localVarsMetaInfo.currentIntervals.add(it)
}
}
@@ -75,23 +78,38 @@ public abstract class CoveringTryCatchNodeProcessor<T : IntervalWithHandler> wh
public abstract fun instructionIndex(inst: AbstractInsnNode): Int
public fun sortTryCatchBlocks() {
val comp = Comparator { t1: T, t2: T ->
val comp = Comparator { t1: TryCatchBlockNodeInfo, t2: TryCatchBlockNodeInfo ->
var result = instructionIndex(t1.handler) - instructionIndex(t2.handler)
if (result == 0) {
result = instructionIndex((t1 as Interval).startLabel) - instructionIndex((t2 as Interval).startLabel)
result = instructionIndex(t1.startLabel) - instructionIndex(t2.startLabel)
if (result == 0) {
assert(false, "Error: support multicatch finallies!")
result = instructionIndex((t1 as Interval).endLabel) - instructionIndex((t2 as Interval).endLabel)
result = instructionIndex(t1.endLabel) - instructionIndex(t2.endLabel)
}
}
result
}
Collections.sort<T>(tryBlocksMetaInfo.allIntervals, comp)
Collections.sort<TryCatchBlockNodeInfo>(tryBlocksMetaInfo.allIntervals, comp)
}
protected fun substituteTryBlockNodes(node: MethodNode) {
node.tryCatchBlocks.clear()
for (info in tryBlocksMetaInfo.getNonEmptyNodes()) {
node.tryCatchBlocks.add(info.node)
}
}
public fun substituteLocalVarTable(node: MethodNode) {
node.localVariables.clear()
for (info in localVarsMetaInfo.getNonEmptyNodes()) {
node.localVariables.add(info.node)
}
}
}
class IntervalMetaInfo<T : Interval> {
class IntervalMetaInfo<T : SplittableInterval<T>> {
val intervalStarts = LinkedListMultimap.create<LabelNode, T>()
@@ -107,22 +125,26 @@ class IntervalMetaInfo<T : Interval> {
allIntervals.add(newInfo)
}
fun remapStartLabel(oldStart: LabelNode, remapped: T) {
private fun remapStartLabel(oldStart: LabelNode, remapped: T) {
intervalStarts.remove(oldStart, remapped)
intervalStarts.put(remapped.startLabel, remapped)
}
fun remapEndLabel(oldEnd: LabelNode, remapped: T) {
private fun remapEndLabel(oldEnd: LabelNode, remapped: T) {
intervalEnds.remove(oldEnd, remapped)
intervalEnds.put(remapped.endLabel, remapped)
}
fun split(interval: SplittableInterval<T>, by : Interval, keepStart: Boolean): SplittedPair<T> {
fun splitCurrentIntervals(by : Interval, keepStart: Boolean): List<SplittedPair<T>> {
return currentIntervals.map { split(it, by, keepStart) }
}
fun split(interval: T, by : Interval, keepStart: Boolean): SplittedPair<T> {
val splittedPair = interval.split(by, keepStart)
if (!keepStart) {
remapStartLabel((splittedPair.newPart as Interval).startLabel, splittedPair.patchedPart)
remapStartLabel(splittedPair.newPart.startLabel, splittedPair.patchedPart)
} else {
remapEndLabel((splittedPair.newPart as Interval).endLabel, splittedPair.patchedPart)
remapEndLabel(splittedPair.newPart.endLabel, splittedPair.patchedPart)
}
addNewInterval(splittedPair.newPart)
return splittedPair
@@ -132,9 +154,9 @@ class IntervalMetaInfo<T : Interval> {
return allIntervals.filterNot { isEmptyInterval(it) }
}
fun infoToClose(curIns: LabelNode, directOrder: Boolean) = if (!directOrder) intervalStarts.get(curIns) else intervalEnds.get(curIns)
fun closeIntervals(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)
fun openIntervals(curIns: LabelNode, directOrder: Boolean) = if (directOrder) intervalStarts.get(curIns) else intervalEnds.get(curIns)
private fun isEmptyInterval(node: T): Boolean {
val start = node.startLabel
@@ -146,7 +168,7 @@ class IntervalMetaInfo<T : Interval> {
}
}
public class DefaultProcessor(val node: MethodNode) : CoveringTryCatchNodeProcessor<TryCatchBlockNodeInfo>() {
public class DefaultProcessor(val node: MethodNode) : CoveringTryCatchNodeProcessor() {
init {
node.tryCatchBlocks.forEach { addTryNode(it) }
@@ -637,8 +637,7 @@ public class InlineCodegen extends CallGenerator {
AbstractInsnNode curInstr = intoNode.instructions.getFirst();
while (curInstr != null) {
processor.updateCoveringTryBlocks(curInstr, true);
processor.updateCoveringLocalVars(curInstr, true);
processor.processInstruction(curInstr, true);
MethodInliner.PointForExternalFinallyBlocks extension = extensionPoints.get(curInstr);
if (extension != null) {
@@ -655,34 +654,25 @@ public class InlineCodegen extends CallGenerator {
finallyCodegen.generateFinallyBlocksIfNeeded(extension.returnType);
finallyNode.visitLabel(end);
//Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method
InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr);
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);
}
SimpleInterval splitBy = new SimpleInterval((LabelNode) start.info, (LabelNode) end.info);
processor.getTryBlocksMetaInfo().splitCurrentIntervals(splitBy, false);
processor.getLocalVarsMetaInfo().splitCurrentIntervals(splitBy, false);
}
curInstr = curInstr.getNext();
}
processor.sortTryCatchBlocks();
Iterable<TryCatchBlockNodeInfo> nodes = processor.getNonEmptyNodes();
intoNode.tryCatchBlocks.clear();
for (TryCatchBlockNodeInfo node : nodes) {
intoNode.tryCatchBlocks.add(node.getNode());
}
processor.substituteTryBlockNodes(intoNode);
intoNode.localVariables.clear();
for (LocalVarNodeWrapper interval : processor.getLocalVarsMetaInfo().getAllIntervals()) {
intoNode.localVariables.add(interval.getNode());
}
//processor.substituteLocalVarTable(intoNode);
}
private SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap) {
return new NestedSourceMapper(sourceMapper, nodeAndSmap.getRanges(), nodeAndSmap.getClassSMAP().getSourceInfo());
}
}
@@ -20,6 +20,7 @@ import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.ReadOnly;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.kotlin.codegen.AsmUtil;
import org.jetbrains.org.objectweb.asm.Label;
@@ -35,7 +36,7 @@ import java.util.*;
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.*;
public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<TryCatchBlockNodeInfo> {
public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
private static class FinallyBlockInfo {
@@ -68,8 +69,13 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
inlineFunTryBlockInfo.add(new TryCatchBlockNodeInfo(block, index++ < lambdaTryCatchBlockNodes));
}
List<LocalVarNodeWrapper> localVars = new ArrayList<LocalVarNodeWrapper>();
for (LocalVariableNode var : inlineFun.localVariables) {
localVars.add(new LocalVarNodeWrapper(var));
}
if (hasFinallyBlocks(inlineFunTryBlockInfo)) {
new InternalFinallyBlockInliner(inlineFun, inlineFunTryBlockInfo).processInlineFunFinallyBlocks();
new InternalFinallyBlockInliner(inlineFun, inlineFunTryBlockInfo, localVars).processInlineFunFinallyBlocks();
}
}
@@ -79,11 +85,14 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
//lambdaTryCatchBlockNodes is number of TryCatchBlockNodes that was inlined with lambdas into function
//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, List<LocalVarNodeWrapper> localVariableInfo) {
this.inlineFun = inlineFun;
IntervalMetaInfo<TryCatchBlockNodeInfo> info = getTryBlocksMetaInfo();
for (TryCatchBlockNodeInfo block : inlineFunTryBlockInfo) {
info.addNewInterval(block);
getTryBlocksMetaInfo().addNewInterval(block);
}
for (LocalVarNodeWrapper wrapper : localVariableInfo) {
getLocalVarsMetaInfo().addNewInterval(wrapper);
}
}
@@ -108,7 +117,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
// So we do instruction processing in reverse order!
AbstractInsnNode curIns = instructions.getLast();
while (curIns != null) {
updateCoveringTryBlocks(curIns);
processInstruction(curIns, false);
//At this point only global return is possible, local one already substituted with: goto endLabel
if (!InlineCodegenUtil.isReturnOpcode(curIns.getOpcode()) ||
@@ -117,10 +126,10 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
continue;
}
List<TryCatchBlockNodeInfo> currentCoveringNodes = getCoveringFromInnermost();
checkCoveringBlocksInvariant(currentCoveringNodes);
if (currentCoveringNodes.isEmpty() ||
currentCoveringNodes.get(currentCoveringNodes.size() - 1).getOnlyCopyNotProcess()) {
List<TryCatchBlockNodeInfo> currentCoveringNodesFromOuterMost = getTryBlocksMetaInfo().getCurrentIntervals();
checkCoveringBlocksInvariant(currentCoveringNodesFromOuterMost);
if (currentCoveringNodesFromOuterMost.isEmpty() ||
currentCoveringNodesFromOuterMost.get(0).getOnlyCopyNotProcess()) {
curIns = curIns.getPrevious();
continue;
}
@@ -134,7 +143,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
// Each group that corresponds to try/*catches*/finally contains tryCatch block with default handler.
// For each such group we should insert corresponding finally before non-local return.
// So we split all try blocks on current instructions to groups and process them independently
List<TryBlockCluster<TryCatchBlockNodeInfo>> clustersFromInnermost = InlinePackage.doClustering(currentCoveringNodes);
List<TryBlockCluster<TryCatchBlockNodeInfo>> clustersFromInnermost = InlinePackage.doClustering(getCoveringFromInnermost());
Iterator<TryBlockCluster<TryCatchBlockNodeInfo>> tryCatchBlockIterator = clustersFromInnermost.iterator();
checkClusterInvariant(clustersFromInnermost);
@@ -203,12 +212,13 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
//skip just inserted finally
curIns = curIns.getPrevious();
while (curIns != null && curIns != nextPrev) {
updateCoveringTryBlocks(curIns);
processInstruction(curIns, false);
curIns = curIns.getPrevious();
}
}
substituteTryBlockNodes();
substituteTryBlockNodes(inlineFun);
//substituteLocalVarTable(inlineFun);
}
private static void copyInstruction(
@@ -247,13 +257,11 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
}
}
private static void checkCoveringBlocksInvariant(List<TryCatchBlockNodeInfo> coveringTryCatchBlocks) {
private static void checkCoveringBlocksInvariant(@ReadOnly @NotNull List<TryCatchBlockNodeInfo> currentCoveringNodesFromOuterMost) {
boolean isWasOnlyLocal = false;
for (TryCatchBlockNodeInfo info : Lists.reverse(coveringTryCatchBlocks)) {
assert !isWasOnlyLocal || info.getOnlyCopyNotProcess();
if (info.getOnlyCopyNotProcess()) {
isWasOnlyLocal = true;
}
for (TryCatchBlockNodeInfo info : currentCoveringNodesFromOuterMost) {
assert !isWasOnlyLocal || info.getOnlyCopyNotProcess() : "There are some problems with try-catch structure";
isWasOnlyLocal = info.getOnlyCopyNotProcess();
}
}
@@ -339,7 +347,9 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
assert Objects.equal(startNode.getType(), endNode.getType()) : "Different handler types : " + startNode.getType() + " " + endNode.getType();
patchTryBlocks((LabelNode) startNode.getStartLabel().getLabel().info, endNode);
getTryBlocksMetaInfo()
.split(endNode, new SimpleInterval((LabelNode) endNode.getNode().end.getLabel().info,
(LabelNode) startNode.getStartLabel().getLabel().info), false);
}
}
}
@@ -351,7 +361,9 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
//TODO rewrite to clusters
for (TryCatchBlockNodePosition endBlockPosition : singleCluster.getBlocks()) {
TryCatchBlockNodeInfo endNode = endBlockPosition.getNodeInfo();
patchTryBlocks((LabelNode) insertedBlockEnd.getLabel().info, endNode);
getTryBlocksMetaInfo()
.split(endNode, new SimpleInterval((LabelNode) endNode.getNode().end.getLabel().info,
(LabelNode) insertedBlockEnd.getLabel().info), false);
//nextPrev = (AbstractInsnNode) insertedBlockEnd.getLabel().info;
}
@@ -369,15 +381,15 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
for (TryCatchBlockNodeInfo block : toProcess) {
//update exception mapping
tryBlocksMetaInfo.split(block, new SimpleInterval((LabelNode) newFinallyStart.info, (LabelNode) newFinallyEnd.info), false);
//block patched in split method
patched.add(block);
//TODO add assert
}
sortTryCatchBlocks();
}
private void patchTryBlocks(@NotNull LabelNode newStartLabelNode, @NotNull TryCatchBlockNodeInfo endNode) {
getTryBlocksMetaInfo()
.split(endNode, new SimpleInterval((LabelNode) endNode.getNode().end.getLabel().info, newStartLabelNode), false);
getLocalVarsMetaInfo().splitCurrentIntervals(new SimpleInterval((LabelNode) newFinallyStart.info, (LabelNode) newFinallyEnd.info),
false);
sortTryCatchBlocks();
}
private static LabelNode getNewOrOldLabel(LabelNode oldHandler, @NotNull Set<LabelNode> labelsInsideFinally) {
@@ -390,9 +402,10 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
//Keep information about try blocks that cover current instruction -
// pushing and popping it to stack entering and exiting tryCatchBlock start and end labels
public void updateCoveringTryBlocks(@NotNull AbstractInsnNode curIns) {
super.updateCoveringTryBlocks(curIns, false);
checkCoveringBlocksInvariant(getCoveringFromInnermost());
@Override
protected void updateCoveringTryBlocks(@NotNull LabelNode curIns, boolean directOrder) {
super.updateCoveringTryBlocks(curIns, directOrder);
checkCoveringBlocksInvariant(getTryBlocksMetaInfo().getCurrentIntervals());
}
private static boolean hasFinallyBlocks(List<TryCatchBlockNodeInfo> inlineFunTryBlockInfo) {
@@ -411,7 +424,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
@Nullable
private FinallyBlockInfo findFinallyBlockBody(
@NotNull TryCatchBlockNodeInfo tryCatchBlock,
@NotNull List<TryCatchBlockNodeInfo> tryCatchBlocks
@ReadOnly @NotNull List<TryCatchBlockNodeInfo> tryCatchBlocks
) {
if (tryCatchBlock.getOnlyCopyNotProcess()) {
AbstractInsnNode start = new LabelNode();
@@ -539,13 +552,6 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
return inlineFun.instructions.indexOf(inst);
}
private void substituteTryBlockNodes() {
inlineFun.tryCatchBlocks.clear();
for (TryCatchBlockNodeInfo info : getNonEmptyNodes()) {
inlineFun.tryCatchBlocks.add(info.getNode());
}
}
private static String traceInterval(AbstractInsnNode startNode, AbstractInsnNode stopNode) {
Textifier p = new Textifier();
TraceMethodVisitor visitor = new TraceMethodVisitor(p);
@@ -562,7 +568,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
@SuppressWarnings({"UnusedDeclaration", "UseOfSystemOutOrSystemErr"})
@TestOnly
private void flushCurrentState(@NotNull AbstractInsnNode curNonLocal) {
substituteTryBlockNodes();
substituteTryBlockNodes(inlineFun);
System.out.println("Will process instruction at : " + inlineFun.instructions.indexOf(curNonLocal) + " " + curNonLocal.toString());
String text = getNodeText(inlineFun);
System.out.println(text);
@@ -45,7 +45,7 @@ trait IntervalWithHandler : Interval {
val type: String?
}
class TryCatchBlockNodeInfo(val node: TryCatchBlockNode, val onlyCopyNotProcess: Boolean) : IntervalWithHandler, SplittableInterval<TryCatchBlockNodeInfo> {
open class TryCatchBlockNodeInfo(val node: TryCatchBlockNode, val onlyCopyNotProcess: Boolean) : IntervalWithHandler, SplittableInterval<TryCatchBlockNodeInfo> {
override val startLabel: LabelNode
get() = node.start
override val endLabel: LabelNode