Split exception table on finally insertion before non-local return

in nested try blocks without finally

 #KT-31653 Fixed
This commit is contained in:
Mikhael Bogdanov
2019-06-12 14:11:02 +02:00
parent c335015c05
commit 26032e4297
14 changed files with 368 additions and 20 deletions
@@ -64,7 +64,12 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
}
}
public static void processInlineFunFinallyBlocks(@NotNull MethodNode inlineFun, int lambdaTryCatchBlockNodes, int finallyParamOffset) {
public static void processInlineFunFinallyBlocks(
@NotNull MethodNode inlineFun,
int lambdaTryCatchBlockNodes,
int finallyParamOffset,
boolean properFinallySplit
) {
int index = 0;
List<TryCatchBlockNodeInfo> inlineFunTryBlockInfo = new ArrayList<>();
for (TryCatchBlockNode block : inlineFun.tryCatchBlocks) {
@@ -77,13 +82,14 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
}
if (hasFinallyBlocks(inlineFunTryBlockInfo)) {
new InternalFinallyBlockInliner(inlineFun, inlineFunTryBlockInfo, localVars, finallyParamOffset)
new InternalFinallyBlockInliner(inlineFun, inlineFunTryBlockInfo, localVars, finallyParamOffset, properFinallySplit)
.processInlineFunFinallyBlocks();
}
}
@NotNull
private final MethodNode inlineFun;
private final boolean properFinallySplit;
//lambdaTryCatchBlockNodes is number of TryCatchBlockNodes that was inlined with lambdas into function
@@ -92,10 +98,12 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
@NotNull MethodNode inlineFun,
@NotNull List<TryCatchBlockNodeInfo> inlineFunTryBlockInfo,
@NotNull List<LocalVarNodeWrapper> localVariableInfo,
int finallyParamOffset
int finallyParamOffset,
boolean properFinallySplit
) {
super(finallyParamOffset);
this.inlineFun = inlineFun;
this.properFinallySplit = properFinallySplit;
for (TryCatchBlockNodeInfo block : inlineFunTryBlockInfo) {
getTryBlocksMetaInfo().addNewInterval(block);
}
@@ -162,7 +170,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
checkClusterInvariant(clustersFromInnermost);
int originalDepthIndex = 0;
List<TryCatchBlockNodeInfo> nestedUnsplitBlocksWithoutFinally = new ArrayList();
while (tryCatchBlockIterator.hasNext()) {
TryBlockCluster<TryCatchBlockNodeInfo> clusterToFindFinally = tryCatchBlockIterator.next();
List<TryCatchBlockNodeInfo> clusterBlocks = clusterToFindFinally.getBlocks();
@@ -170,7 +178,10 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
FinallyBlockInfo finallyInfo =
findFinallyBlockBody(nodeWithDefaultHandlerIfExists, getTryBlocksMetaInfo().getAllIntervals());
if (finallyInfo == null) continue;
if (finallyInfo == null) {
nestedUnsplitBlocksWithoutFinally.addAll(clusterToFindFinally.getBlocks());
continue;
}
if (nodeWithDefaultHandlerIfExists.getOnlyCopyNotProcess()) {
//lambdas finally generated before non-local return instruction,
@@ -220,8 +231,13 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
//Copying finally body before non-local return instruction
insertNodeBefore(finallyBlockCopy, inlineFun, instrInsertFinallyBefore);
updateExceptionTable(clusterBlocks, newFinallyStart, newFinallyEnd,
tryCatchBlockInlinedInFinally, labelsInsideFinally, (LabelNode) insertedBlockEnd.info);
nestedUnsplitBlocksWithoutFinally.addAll(clusterBlocks);
updateExceptionTable(
properFinallySplit ? nestedUnsplitBlocksWithoutFinally : clusterBlocks, newFinallyStart, newFinallyEnd,
tryCatchBlockInlinedInFinally, labelsInsideFinally, (LabelNode) insertedBlockEnd.info
);
nestedUnsplitBlocksWithoutFinally.clear();
}
//skip just inserted finally
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.codegen.optimization.common.*
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
@@ -123,7 +124,8 @@ class MethodInliner(
if (inliningContext.isRoot) {
val remapValue = remapper.remap(parameters.argsSizeOnStack + 1).value
InternalFinallyBlockInliner.processInlineFunFinallyBlocks(
resultNode, lambdasFinallyBlocks, (remapValue as StackValue.Local).index
resultNode, lambdasFinallyBlocks, (remapValue as StackValue.Local).index,
languageVersionSettings.supportsFeature(LanguageFeature.ProperFinally)
)
}
@@ -0,0 +1,42 @@
// !LANGUAGE: +ProperFinally
// FILE: 1.kt
package test
var result = ""
inline fun a(f: () -> Any) =
try {
f()
} finally {
throw RuntimeException()
}
fun b(vararg functions: () -> Any) = a {
for (function in functions) {
try {
return function()
} catch (fail: Throwable) {
}
}
}
fun main(args: Array<String>) {
b({ result += "OK"; 1 }, { result += "fail"; 2 })
}
// FILE: 2.kt
// NO_CHECK_LAMBDA_INLINING
import test.*
fun box(): String {
try {
b({ result += "OK"; 1 }, { result += "fail"; 2 })
return "fail: expected exception"
} catch (e: RuntimeException) {
}
return result
}
@@ -0,0 +1,37 @@
// !LANGUAGE: +ProperFinally
// FILE: 1.kt
package test
var result = ""
class A {
var field = 0
inline fun a(f: () -> Any): Any {
try {
val value = f()
return value
} finally {
field--
}
}
fun c(vararg functions: () -> Any): Any = a {
for (function in functions) {
try { return function() } catch (fail: Throwable) { }
}
throw RuntimeException()
}
}
// FILE: 2.kt
// NO_CHECK_LAMBDA_INLINING
import test.*
fun box(): String {
val a = A()
a.c({ result += "OK"; 1 }, { result += "fail"; 2 })
if (a.field != -1) return "fail: -1 != ${a.field}"
return result
}
@@ -0,0 +1,44 @@
// !LANGUAGE: +ProperFinally
// FILE: 1.kt
package test
var result = ""
inline fun inlineFun(block: (String)-> String) {
try {
try {
result += block("lambda")
return
} catch (fail: Throwable) {
result += " catch"
}
} finally {
result += " finally"
throw RuntimeException()
}
}
fun test() {
inlineFun {
result += it
return
}
}
// FILE: 2.kt
import test.*
fun box(): String {
try {
test()
return "fail: expected exception"
} catch (e: RuntimeException) {
}
return if (result == "lambda finally") "OK" else "fail: $result"
}
@@ -0,0 +1,43 @@
// !LANGUAGE: +ProperFinally
// FILE: 1.kt
package test
var result = ""
inline fun inlineFun(block: (String)-> String) {
try {
try {
result += block("lambda")
} catch (fail: Throwable) {
result += " catch"
}
} finally {
result += " finally"
throw RuntimeException()
}
}
fun test() {
inlineFun {
result += it
return
}
}
// FILE: 2.kt
import test.*
fun box(): String {
try {
test()
return "fail: expected exception"
} catch (e: RuntimeException) {
}
return if (result == "lambda finally") "OK" else "fail: $result"
}
@@ -0,0 +1,45 @@
// !LANGUAGE: -ProperFinally
// TARGET_BACKEND: JVM
// FILE: 1.kt
package test
var result = ""
inline fun inlineFun(block: (String)-> String) {
try {
try {
result += block("lambda")
return
} catch (fail: Throwable) {
result += " catch"
}
} finally {
result += " finally"
throw RuntimeException()
}
}
fun test() {
inlineFun {
result += it
return
}
}
// FILE: 2.kt
import test.*
fun box(): String {
try {
test()
return "fail: expected exception"
} catch (e: RuntimeException) {
}
return if (result == "lambda finally catch finally") "OK" else "fail: $result"
}
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// !LANGUAGE: +ProperFinally
// FILE: 1.kt
package test
@@ -2472,6 +2472,31 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalSimple.kt");
}
@TestMetadata("kt31653.kt")
public void testKt31653() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31653.kt");
}
@TestMetadata("kt31653_2.kt")
public void testKt31653_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31653_2.kt");
}
@TestMetadata("kt31923.kt")
public void testKt31923() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31923.kt");
}
@TestMetadata("kt31923_2.kt")
public void testKt31923_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31923_2.kt");
}
@TestMetadata("kt31923_wrong.kt")
public void testKt31923_wrong() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31923_wrong.kt");
}
@TestMetadata("nested.kt")
public void testNested() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nested.kt");
@@ -2472,6 +2472,31 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalSimple.kt");
}
@TestMetadata("kt31653.kt")
public void testKt31653() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31653.kt");
}
@TestMetadata("kt31653_2.kt")
public void testKt31653_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31653_2.kt");
}
@TestMetadata("kt31923.kt")
public void testKt31923() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31923.kt");
}
@TestMetadata("kt31923_2.kt")
public void testKt31923_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31923_2.kt");
}
@TestMetadata("kt31923_wrong.kt")
public void testKt31923_wrong() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31923_wrong.kt");
}
@TestMetadata("nested.kt")
public void testNested() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nested.kt");
@@ -2472,6 +2472,31 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalSimple.kt");
}
@TestMetadata("kt31653.kt")
public void testKt31653() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31653.kt");
}
@TestMetadata("kt31653_2.kt")
public void testKt31653_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31653_2.kt");
}
@TestMetadata("kt31923.kt")
public void testKt31923() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31923.kt");
}
@TestMetadata("kt31923_2.kt")
public void testKt31923_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31923_2.kt");
}
@TestMetadata("kt31923_wrong.kt")
public void testKt31923_wrong() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31923_wrong.kt");
}
@TestMetadata("nested.kt")
public void testNested() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nested.kt");
@@ -2433,16 +2433,6 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
KotlinTestUtils.runTestWithCustomIgnoreDirective(this::doTest, TargetBackend.JVM_IR, testDataFilePath, "// IGNORE_BACKEND_MULTI_MODULE: ");
}
@TestMetadata("31929.kt")
public void test31929() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/31929.kt");
}
@TestMetadata("31929_2.kt")
public void test31929_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/31929_2.kt");
}
public void testAllFilesPresentInExceptionTable() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
}
@@ -2482,6 +2472,16 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalSimple.kt");
}
@TestMetadata("kt31653.kt")
public void testKt31653() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31653.kt");
}
@TestMetadata("kt31653_2.kt")
public void testKt31653_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31653_2.kt");
}
@TestMetadata("kt31923.kt")
public void testKt31923() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31923.kt");
@@ -2492,6 +2492,11 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31923_2.kt");
}
@TestMetadata("kt31923_wrong.kt")
public void testKt31923_wrong() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31923_wrong.kt");
}
@TestMetadata("nested.kt")
public void testNested() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nested.kt");
@@ -410,6 +410,26 @@ public class IrNonLocalReturnsTestGenerated extends AbstractIrNonLocalReturnsTes
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalSimple.kt");
}
@TestMetadata("kt31653.kt")
public void testKt31653() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31653.kt");
}
@TestMetadata("kt31653_2.kt")
public void testKt31653_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31653_2.kt");
}
@TestMetadata("kt31923.kt")
public void testKt31923() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31923.kt");
}
@TestMetadata("kt31923_2.kt")
public void testKt31923_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31923_2.kt");
}
@TestMetadata("nested.kt")
public void testNested() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nested.kt");
@@ -410,6 +410,26 @@ public class NonLocalReturnsTestGenerated extends AbstractNonLocalReturnsTest {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalSimple.kt");
}
@TestMetadata("kt31653.kt")
public void testKt31653() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31653.kt");
}
@TestMetadata("kt31653_2.kt")
public void testKt31653_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31653_2.kt");
}
@TestMetadata("kt31923.kt")
public void testKt31923() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31923.kt");
}
@TestMetadata("kt31923_2.kt")
public void testKt31923_2() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/kt31923_2.kt");
}
@TestMetadata("nested.kt")
public void testNested() throws Exception {
runTest("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nested.kt");