Remove external finally block interval on splitting during inline

#KT-20433 Fixed
This commit is contained in:
Mikhael Bogdanov
2017-11-03 14:08:10 +01:00
parent f51709e61c
commit 800cc63347
12 changed files with 330 additions and 4 deletions
@@ -22,8 +22,8 @@ import org.jetbrains.org.objectweb.asm.tree.*
import java.util.*
abstract class CoveringTryCatchNodeProcessor(parameterSize: Int) {
val tryBlocksMetaInfo: IntervalMetaInfo<TryCatchBlockNodeInfo> = IntervalMetaInfo()
val localVarsMetaInfo: IntervalMetaInfo<LocalVarNodeWrapper> = IntervalMetaInfo()
val tryBlocksMetaInfo: IntervalMetaInfo<TryCatchBlockNodeInfo> = IntervalMetaInfo(this)
val localVarsMetaInfo: IntervalMetaInfo<LocalVarNodeWrapper> = IntervalMetaInfo(this)
var nextFreeLocalIndex: Int = parameterSize
private set
@@ -84,24 +84,27 @@ abstract class CoveringTryCatchNodeProcessor(parameterSize: Int) {
}
}
class IntervalMetaInfo<T : SplittableInterval<T>> {
class IntervalMetaInfo<T : SplittableInterval<T>>(private val processor: CoveringTryCatchNodeProcessor) {
val intervalStarts = LinkedListMultimap.create<LabelNode, T>()
val intervalEnds = LinkedListMultimap.create<LabelNode, T>()
val allIntervals: ArrayList<T> = arrayListOf()
val currentIntervals: MutableSet<T> = linkedSetOf()
fun addNewInterval(newInfo: T) {
newInfo.verify(processor)
intervalStarts.put(newInfo.startLabel, newInfo)
intervalEnds.put(newInfo.endLabel, newInfo)
allIntervals.add(newInfo)
}
private fun remapStartLabel(oldStart: LabelNode, remapped: T) {
remapped.verify(processor)
intervalStarts.remove(oldStart, remapped)
intervalStarts.put(remapped.startLabel, remapped)
}
private fun remapEndLabel(oldEnd: LabelNode, remapped: T) {
remapped.verify(processor)
intervalEnds.remove(oldEnd, remapped)
intervalEnds.put(remapped.endLabel, remapped)
}
@@ -110,6 +113,10 @@ class IntervalMetaInfo<T : SplittableInterval<T>> {
return currentIntervals.map { split(it, by, keepStart) }
}
fun splitAndRemoveCurrentIntervals(by: Interval, keepStart: Boolean) {
currentIntervals.map { splitAndRemoveInterval(it, by, keepStart) }
}
fun processCurrent(curIns: LabelNode, directOrder: Boolean) {
getInterval(curIns, directOrder).forEach {
val added = currentIntervals.add(it)
@@ -366,7 +366,7 @@ class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, overrid
insertNodeBefore(finallyNode, intoNode, curInstr)
val splitBy = SimpleInterval(start.info as LabelNode, extension.finallyIntervalEnd)
processor.tryBlocksMetaInfo.splitCurrentIntervals(splitBy, true)
processor.tryBlocksMetaInfo.splitAndRemoveCurrentIntervals(splitBy, true)
//processor.getLocalVarsMetaInfo().splitAndRemoveIntervalsFromCurrents(splitBy);
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
import org.jetbrains.org.objectweb.asm.tree.LabelNode
import org.jetbrains.org.objectweb.asm.tree.TryCatchBlockNode
@@ -35,6 +36,12 @@ interface Interval {
/*note that some intervals are mutable */
fun isEmpty(): Boolean = startLabel == endLabel
fun verify(processor: CoveringTryCatchNodeProcessor) {
assert (processor.instructionIndex(startLabel) <= processor.instructionIndex(endLabel)) {
"Try block body starts after body end: ${processor.instructionIndex(startLabel)} > ${processor.instructionIndex(endLabel)}"
}
}
}
interface SplittableInterval<out T : Interval> : Interval {
@@ -77,6 +84,9 @@ class TryCatchBlockNodeInfo(
}
}
val TryCatchBlockNodeInfo.bodyInstuctions
get() = InsnSequence(startLabel, endLabel)
class TryCatchBlockNodePosition(
val nodeInfo: TryCatchBlockNodeInfo,
var position: TryCatchPosition
@@ -0,0 +1,47 @@
// FILE: 1.kt
//WITH_RUNTIME
package test
public inline fun <T, R> T.mylet(block: (T) -> R): R {
return block(this)
}
// FILE: 2.kt
import test.*
var message = ""
fun foo(root: String): String {
try {
return root.let { _ ->
try {
if (!random()) {
return root
}
return "fail $root"
} catch (e: Exception) {
message += "${e.message} "
}
"fail"
}
} finally {
message += "Finally block"
}
}
var exception = false
fun random() = if (exception) error("Exception") else false
fun box(): String {
var okResult = foo("OK")
if (okResult != "OK") return "fail 1: $okResult"
if (message != "Finally block") return "fail 2: $message"
message = ""
exception = true
if (foo("OK") != "fail") return "fail 3: ${foo("OK")}"
if (message != "Exception Finally block" ) return "fail 4: $message"
return okResult
}
@@ -0,0 +1,47 @@
// FILE: 1.kt
//WITH_RUNTIME
package test
public inline fun <T, R> T.mylet(block: (T) -> R): R {
return block(this)
}
// FILE: 2.kt
import test.*
var message = ""
fun foo(root: String): String {
try {
return root.let { _ ->
try {
if (!random()) {
return root
}
return "fail $root"
} catch (e: Exception) {
message += "Exception $e"
}
"fail"
}
} finally {
message += "Finally block"
}
}
var fail = false
fun random() = fail
fun box(): String {
var okResult = foo("OK")
if (okResult != "OK") return "fail 1: $okResult"
if (message != "Finally block") return "fail 2: $message"
message = ""
fail = true
if (foo("OK") != "fail OK") return "fail 3: ${foo("OK")}"
if (message != "Finally block" ) return "fail 4: $message"
return okResult
}
@@ -0,0 +1,47 @@
// FILE: 1.kt
//WITH_RUNTIME
package test
public inline fun <T, R> T.mylet(block: (T) -> R): R {
return block(this)
}
// FILE: 2.kt
import test.*
var message = ""
fun foo(root: String) {
try {
return root.let { _ ->
try {
if (!random()) {
message += root
return
}
message += "fail $root"
} catch (e: Exception) {
message += "Exception $e"
}
"fail"
}
} finally {
message += " Finally block"
}
}
var fail = false
fun random() = fail
fun box(): String {
foo("OK")
if (message != "OK Finally block") return "fail 1: $message"
message = ""
fail = true
foo("OK")
if (message != "fail OK Finally block" ) return "fail 2: $message"
return "OK"
}
@@ -0,0 +1,48 @@
// FILE: 1.kt
//WITH_RUNTIME
package test
public inline fun <T, R> T.mylet(block: (T) -> R): R {
return block(this)
}
// FILE: 2.kt
import test.*
var message = ""
fun foo(root: String) {
try {
root.let { _ ->
try {
if (!random()) {
message += root
return
}
message += "fail $root"
return
} catch (e: Exception) {
message += "${e.message}"
}
"fail"
}
} finally {
message += " Finally block"
}
}
var exception = false
fun random() = if (exception) error("Exception") else false
fun box(): String {
foo("OK")
if (message != "OK Finally block") return "fail 1: $message"
message = ""
exception = true
foo("OK")
if (message != "Exception Finally block" ) return "fail 2: $message"
return "OK"
}
@@ -1876,6 +1876,30 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("kt20433.kt")
public void testKt20433() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt20433.kt");
doTest(fileName);
}
@TestMetadata("kt20433_2.kt")
public void testKt20433_2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt20433_2.kt");
doTest(fileName);
}
@TestMetadata("kt20433_2_void.kt")
public void testKt20433_2_void() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt20433_2_void.kt");
doTest(fileName);
}
@TestMetadata("kt20433_void.kt")
public void testKt20433_void() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt20433_void.kt");
doTest(fileName);
}
@TestMetadata("kt6956.kt")
public void testKt6956() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt6956.kt");
@@ -1876,6 +1876,30 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("kt20433.kt")
public void testKt20433() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt20433.kt");
doTest(fileName);
}
@TestMetadata("kt20433_2.kt")
public void testKt20433_2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt20433_2.kt");
doTest(fileName);
}
@TestMetadata("kt20433_2_void.kt")
public void testKt20433_2_void() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt20433_2_void.kt");
doTest(fileName);
}
@TestMetadata("kt20433_void.kt")
public void testKt20433_void() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt20433_void.kt");
doTest(fileName);
}
@TestMetadata("kt6956.kt")
public void testKt6956() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt6956.kt");
@@ -1876,6 +1876,30 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("kt20433.kt")
public void testKt20433() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt20433.kt");
doTest(fileName);
}
@TestMetadata("kt20433_2.kt")
public void testKt20433_2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt20433_2.kt");
doTest(fileName);
}
@TestMetadata("kt20433_2_void.kt")
public void testKt20433_2_void() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt20433_2_void.kt");
doTest(fileName);
}
@TestMetadata("kt20433_void.kt")
public void testKt20433_void() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt20433_void.kt");
doTest(fileName);
}
@TestMetadata("kt6956.kt")
public void testKt6956() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt6956.kt");
@@ -1876,6 +1876,30 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("kt20433.kt")
public void testKt20433() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt20433.kt");
doTest(fileName);
}
@TestMetadata("kt20433_2.kt")
public void testKt20433_2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt20433_2.kt");
doTest(fileName);
}
@TestMetadata("kt20433_2_void.kt")
public void testKt20433_2_void() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt20433_2_void.kt");
doTest(fileName);
}
@TestMetadata("kt20433_void.kt")
public void testKt20433_void() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt20433_void.kt");
doTest(fileName);
}
@TestMetadata("kt6956.kt")
public void testKt6956() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt6956.kt");
@@ -143,6 +143,30 @@ public class NonLocalReturnsTestGenerated extends AbstractNonLocalReturnsTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("kt20433.kt")
public void testKt20433() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt20433.kt");
doTest(fileName);
}
@TestMetadata("kt20433_2.kt")
public void testKt20433_2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt20433_2.kt");
doTest(fileName);
}
@TestMetadata("kt20433_2_void.kt")
public void testKt20433_2_void() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt20433_2_void.kt");
doTest(fileName);
}
@TestMetadata("kt20433_void.kt")
public void testKt20433_void() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt20433_void.kt");
doTest(fileName);
}
@TestMetadata("kt6956.kt")
public void testKt6956() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt6956.kt");