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
|
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 com.google.common.collect.LinkedListMultimap
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
import com.intellij.util.containers.Stack
|
import com.intellij.util.containers.Stack
|
||||||
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
|
import org.jetbrains.org.objectweb.asm.tree.*
|
||||||
import org.jetbrains.org.objectweb.asm.tree.TryCatchBlockNode
|
|
||||||
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>() {
|
||||||
|
|
||||||
private val tryBlockStarts = LinkedListMultimap.create<LabelNode, T>()
|
public val tryBlocksMetaInfo: IntervalMetaInfo<T> = IntervalMetaInfo();
|
||||||
|
|
||||||
private val tryBlockEnds = LinkedListMultimap.create<LabelNode, T>()
|
public val localVarsMetaInfo: IntervalMetaInfo<LocalVarNodeWrapper> = IntervalMetaInfo();
|
||||||
|
|
||||||
public val allTryCatchNodes: ArrayList<T> = arrayListOf()
|
|
||||||
|
|
||||||
private val currentCoveringBlocks: Stack<T> = Stack()
|
|
||||||
|
|
||||||
public val coveringFromInnermost: List<T>
|
public val coveringFromInnermost: List<T>
|
||||||
get() = currentCoveringBlocks.reverse()
|
get() = tryBlocksMetaInfo.currentIntervals.reverse()
|
||||||
|
|
||||||
fun addNewTryCatchNode(newInfo: T) {
|
protected fun addNewTryCatchNode(newInfo: T) {
|
||||||
tryBlockStarts.put(newInfo.startLabel, newInfo)
|
tryBlocksMetaInfo.addNewInterval(newInfo)
|
||||||
tryBlockEnds.put(newInfo.endLabel, newInfo)
|
}
|
||||||
allTryCatchNodes.add(newInfo)
|
|
||||||
|
protected fun addNewLocalVar(newInfo: LocalVarNodeWrapper) {
|
||||||
|
localVarsMetaInfo.addNewInterval(newInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun remapStartLabel(oldStart: LabelNode, remapped: T) {
|
fun remapStartLabel(oldStart: LabelNode, remapped: T) {
|
||||||
tryBlockStarts.remove(oldStart, remapped)
|
tryBlocksMetaInfo.remapStartLabel(oldStart, remapped)
|
||||||
tryBlockStarts.put(remapped.startLabel, remapped)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun getStartNodes(label: LabelNode): List<T> {
|
public fun getStartNodes(label: LabelNode): List<T> {
|
||||||
return tryBlockStarts.get(label)
|
return tryBlocksMetaInfo.intervalStarts.get(label)
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun getEndNodes(label: LabelNode): List<T> {
|
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 -
|
//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) {
|
public open fun updateCoveringTryBlocks(curIns: AbstractInsnNode, directOrder: Boolean) {
|
||||||
if (curIns !is LabelNode) return
|
if (curIns !is LabelNode) return
|
||||||
|
|
||||||
val infosToClose = if (!directOrder) getStartNodes(curIns) else getEndNodes(curIns)
|
for (startNode in tryBlocksMetaInfo.infoToClose(curIns, directOrder)) {
|
||||||
for (startNode in infosToClose) {
|
val pop = tryBlocksMetaInfo.currentIntervals.pop()
|
||||||
val pop = currentCoveringBlocks.pop()
|
|
||||||
//Temporary disabled cause during patched structure of exceptions changed
|
//Temporary disabled cause during patched structure of exceptions changed
|
||||||
// if (startNode != pop) {
|
// if (startNode != pop) {
|
||||||
// throw RuntimeException("Wrong try-catch structure " + startNode + " " + pop + " " + infosToClose.size())
|
// 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
|
//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)
|
// (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 tryBlocksMetaInfo.infoToOpen(curIns, directOrder).reverse()) {
|
||||||
for (info in infoToOpen.reverse()) {
|
tryBlocksMetaInfo.currentIntervals.add(info)
|
||||||
currentCoveringBlocks.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
|
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> {
|
public fun getNonEmptyNodes(): List<T> {
|
||||||
return allTryCatchNodes.filterNot { isEmptyInterval(it) }
|
return tryBlocksMetaInfo.getNonEmptyNodes()
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun sortTryCatchBlocks() {
|
public fun sortTryCatchBlocks() {
|
||||||
@@ -108,25 +104,79 @@ public abstract class CoveringTryCatchNodeProcessor<T: IntervalWithHandler>() {
|
|||||||
result
|
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>() {
|
public class DefaultProcessor(val node: MethodNode) : CoveringTryCatchNodeProcessor<TryCatchBlockNodeWrapper>() {
|
||||||
|
|
||||||
init {
|
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))
|
addNewTryCatchNode(TryCatchBlockNodeWrapper(node))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun instructionIndex(inst: AbstractInsnNode): Int {
|
override fun instructionIndex(inst: AbstractInsnNode): Int {
|
||||||
return node.instructions.indexOf(inst)
|
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 {
|
public class TryCatchBlockNodeWrapper(val node: TryCatchBlockNode) : IntervalWithHandler {
|
||||||
|
|||||||
@@ -638,6 +638,7 @@ public class InlineCodegen extends CallGenerator {
|
|||||||
AbstractInsnNode curInstr = intoNode.instructions.getFirst();
|
AbstractInsnNode curInstr = intoNode.instructions.getFirst();
|
||||||
while (curInstr != null) {
|
while (curInstr != null) {
|
||||||
processor.updateCoveringTryBlocks(curInstr, true);
|
processor.updateCoveringTryBlocks(curInstr, true);
|
||||||
|
processor.updateCoveringLocalVars(curInstr, true);
|
||||||
|
|
||||||
MethodInliner.PointForExternalFinallyBlocks extension = extensionPoints.get(curInstr);
|
MethodInliner.PointForExternalFinallyBlocks extension = extensionPoints.get(curInstr);
|
||||||
if (extension != null) {
|
if (extension != null) {
|
||||||
@@ -668,7 +669,7 @@ public class InlineCodegen extends CallGenerator {
|
|||||||
processor.remapStartLabel(oldStart, previous);
|
processor.remapStartLabel(oldStart, previous);
|
||||||
|
|
||||||
TryCatchBlockNode additionalNode = new TryCatchBlockNode(oldStart, (LabelNode) start.info, node.handler, node.type);
|
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) {
|
for (TryCatchBlockNodeWrapper node : nodes) {
|
||||||
intoNode.tryCatchBlocks.add(node.getNode());
|
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) {
|
private SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap) {
|
||||||
|
|||||||
+1
-1
@@ -144,7 +144,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor<T
|
|||||||
List<TryCatchBlockNodeInfo> clusterBlocks = clusterToFindFinally.getBlocks();
|
List<TryCatchBlockNodeInfo> clusterBlocks = clusterToFindFinally.getBlocks();
|
||||||
TryCatchBlockNodeInfo nodeWithDefaultHandlerIfExists = clusterBlocks.get(clusterBlocks.size() - 1);
|
TryCatchBlockNodeInfo nodeWithDefaultHandlerIfExists = clusterBlocks.get(clusterBlocks.size() - 1);
|
||||||
|
|
||||||
FinallyBlockInfo finallyInfo = findFinallyBlockBody(nodeWithDefaultHandlerIfExists, getAllTryCatchNodes());
|
FinallyBlockInfo finallyInfo = findFinallyBlockBody(nodeWithDefaultHandlerIfExists, getTryBlocksMetaInfo().getAllIntervals());
|
||||||
if (finallyInfo == null) continue;
|
if (finallyInfo == null) continue;
|
||||||
|
|
||||||
if (nodeWithDefaultHandlerIfExists.getOnlyCopyNotProcess()) {
|
if (nodeWithDefaultHandlerIfExists.getOnlyCopyNotProcess()) {
|
||||||
|
|||||||
@@ -26,14 +26,24 @@ enum class TryCatchPosition {
|
|||||||
INNER
|
INNER
|
||||||
}
|
}
|
||||||
|
|
||||||
trait IntervalWithHandler {
|
public class SplittedPair(val patchedPart: SplittableInterval, val newPart: SplittableInterval)
|
||||||
|
|
||||||
|
trait Interval {
|
||||||
val startLabel: LabelNode
|
val startLabel: LabelNode
|
||||||
val endLabel: LabelNode
|
val endLabel: LabelNode
|
||||||
|
}
|
||||||
|
|
||||||
|
trait SplittableInterval : Interval {
|
||||||
|
fun split(split: Interval, keepStart: Boolean): SplittedPair
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
trait IntervalWithHandler : Interval {
|
||||||
val handler: LabelNode
|
val handler: LabelNode
|
||||||
val type: String?
|
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
|
override val startLabel: LabelNode
|
||||||
get() = node.start
|
get() = node.start
|
||||||
override val endLabel: LabelNode
|
override val endLabel: LabelNode
|
||||||
@@ -42,9 +52,24 @@ class TryCatchBlockNodeInfo(val node: TryCatchBlockNode, val onlyCopyNotProcess:
|
|||||||
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 {
|
||||||
|
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>) {
|
class TryBlockCluster<T : IntervalWithHandler>(val blocks: MutableList<T>) {
|
||||||
val defaultHandler: T?
|
val defaultHandler: T?
|
||||||
|
|||||||
Reference in New Issue
Block a user