Refactoring: added Interval abstraction to represent TryCatchBlock and LocalVar nodes
This commit is contained in:
+87
-37
@@ -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) {
|
||||
|
||||
+1
-1
@@ -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?
|
||||
|
||||
Reference in New Issue
Block a user