From dd8c3f0e499626666137ca21105741c8515d893d Mon Sep 17 00:00:00 2001 From: Michael Bogdanov Date: Thu, 23 Oct 2014 11:27:53 +0400 Subject: [PATCH] Fixes for inline fun finally block generation before lambda non-local returns --- .../inline/InternalFinallyBlockInliner.java | 208 ++++++++++++++---- .../exceptionTable/exceptionInFinally.1.kt | 64 ++++++ .../exceptionTable/exceptionInFinally.2.kt | 15 ++ .../exceptionTable/tryCatchInFinally.1.kt | 49 +++++ .../exceptionTable/tryCatchInFinally.2.kt | 36 +++ .../inline/notSplitedExceptionTable.kt | 28 +++ .../inline/splitedExceptionTable.kt | 55 +++++ .../codegen/BytecodeTextTestGenerated.java | 23 +- .../BlackBoxInlineCodegenTestGenerated.java | 12 + ...otlinAgainstInlineKotlinTestGenerated.java | 12 + 10 files changed, 462 insertions(+), 40 deletions(-) create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/exceptionInFinally.1.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/exceptionInFinally.2.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/tryCatchInFinally.1.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/tryCatchInFinally.2.kt create mode 100644 compiler/testData/codegen/bytecodeText/inline/notSplitedExceptionTable.kt create mode 100644 compiler/testData/codegen/bytecodeText/inline/splitedExceptionTable.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InternalFinallyBlockInliner.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InternalFinallyBlockInliner.java index 2c44d8f6b8a..1f30b51c812 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InternalFinallyBlockInliner.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InternalFinallyBlockInliner.java @@ -26,7 +26,11 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.codegen.AsmUtil; import org.jetbrains.org.objectweb.asm.*; import org.jetbrains.org.objectweb.asm.tree.*; +import org.jetbrains.org.objectweb.asm.util.Textifier; +import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.*; import static org.jetbrains.jet.codegen.inline.InlineCodegenUtil.*; @@ -43,6 +47,18 @@ public class InternalFinallyBlockInliner { startIns = inclusiveStart; endInsExclusive = exclusiveEnd; } + + public boolean isEmpty() { + if (!(startIns instanceof LabelNode)) { + return false; + + } + AbstractInsnNode end = endInsExclusive; + while (end != startIns && end instanceof LabelNode) { + end = end.getPrevious(); + } + return startIns == end; + } } public static void processInlineFunFinallyBlocks(@NotNull MethodNode inlineFun, int lambdaTryCatchBlockNodes) { @@ -99,7 +115,10 @@ public class InternalFinallyBlockInliner { updateCoveringTryBlocks(coveringTryCatchBlocks, curIns); //At this point only global return is possible, local one already substituted with: goto endLabel - if (!InlineCodegenUtil.isReturnOpcode(curIns.getOpcode()) || !InlineCodegenUtil.isMarkedReturn(curIns)) { + if (!InlineCodegenUtil.isReturnOpcode(curIns.getOpcode()) || + !InlineCodegenUtil.isMarkedReturn(curIns) || + coveringTryCatchBlocks.isEmpty() || + coveringTryCatchBlocks.get(0).getOnlyCopyNotProcess()) { curIns = curIns.getPrevious(); continue; } @@ -115,15 +134,26 @@ public class InternalFinallyBlockInliner { // So we split all try blocks on current instructions to groups and process them independently List> clusters = InlinePackage.doClustering(coveringTryCatchBlocks); ListIterator> tryCatchBlockIterator = clusters.listIterator(clusters.size()); - //Reverse visiting cause innermost tryCatchBlocks in the end - while (tryCatchBlockIterator.hasPrevious()) { - TryBlockCluster originalFinallyCluster = tryCatchBlockIterator.previous(); - List clusterBlocks = originalFinallyCluster.getBlocks(); - TryCatchBlockNodeInfo originalFinallyBlock = clusterBlocks.get(0); - FinallyBlockInfo finallyInfo = findFinallyBlockBody(originalFinallyBlock, inlineFunTryBlockInfo); + checkClusterInvariant(clusters); + + + //Reverse visiting cause innermost tryCatchBlocks in the end + List patched = new ArrayList(); + while (tryCatchBlockIterator.hasPrevious()) { + + TryBlockCluster clusterToFindFinally = tryCatchBlockIterator.previous(); + List clusterBlocks = clusterToFindFinally.getBlocks(); + TryCatchBlockNodeInfo originalTryCatchBlock = clusterBlocks.get(0); + + FinallyBlockInfo finallyInfo = findFinallyBlockBody(originalTryCatchBlock, inlineFunTryBlockInfo); if (finallyInfo == null) continue; + if (originalTryCatchBlock.getOnlyCopyNotProcess()) { + patched.addAll(clusterBlocks); + continue; + } + instructions.resetLabels(); List tryCatchBlockInlinedInFinally = findTryCatchBlocksInlinedInFinally(finallyInfo); @@ -138,7 +168,7 @@ public class InternalFinallyBlockInliner { Label newFinallyEnd = new Label(); Label insertedBlockEnd = new Label(); - if (nonLocalReturnType != Type.VOID_TYPE) { + if (nonLocalReturnType != Type.VOID_TYPE && !finallyInfo.isEmpty()) { finallyBlockCopy.visitVarInsn(nonLocalReturnType.getOpcode(Opcodes.ISTORE), nextTempNonLocalVarIndex); } finallyBlockCopy.visitLabel(newFinallyStart); @@ -175,7 +205,7 @@ public class InternalFinallyBlockInliner { } finallyBlockCopy.visitLabel(newFinallyEnd); - if (nonLocalReturnType != Type.VOID_TYPE) { + if (nonLocalReturnType != Type.VOID_TYPE && !finallyInfo.isEmpty()) { finallyBlockCopy.visitVarInsn(nonLocalReturnType.getOpcode(Opcodes.ILOAD), nextTempNonLocalVarIndex); nextTempNonLocalVarIndex += nonLocalReturnType.getSize(); //TODO: do more wise indexing } @@ -185,15 +215,44 @@ public class InternalFinallyBlockInliner { //Copying finally body before non-local return instruction InlineCodegenUtil.insertNodeBefore(finallyBlockCopy, inlineFun, instrInsertFinallyBefore); - nextPrev = updateExceptionTable(coveringTryCatchBlocks, nextPrev, clusterBlocks, newFinallyStart, newFinallyEnd, - tryCatchBlockInlinedInFinally, labelsInsideFinally, (LabelNode) insertedBlockEnd.info); + updateExceptionTable(clusterBlocks, newFinallyStart, newFinallyEnd, + tryCatchBlockInlinedInFinally, labelsInsideFinally, (LabelNode) insertedBlockEnd.info, patched); + + } - curIns = nextPrev; + + } + + curIns = curIns.getPrevious(); + while (curIns != null && curIns != nextPrev) { + updateCoveringTryBlocks(coveringTryCatchBlocks, curIns); + curIns = curIns.getPrevious(); + } + //curIns = nextPrev; } - inlineFun.tryCatchBlocks.clear(); - for (TryCatchBlockNodeInfo info : inlineFunTryBlockInfo) { - inlineFun.tryCatchBlocks.add(info.getNode()); + substitureTryBlockNodes(); + } + + private void checkCoveringBlocksInvariant(Stack coveringTryCatchBlocks) { + boolean isWasOnlyLocal = false; + for (TryCatchBlockNodeInfo info : coveringTryCatchBlocks) { + assert !isWasOnlyLocal || info.getOnlyCopyNotProcess(); + if (info.getOnlyCopyNotProcess()) { + isWasOnlyLocal = true; + } + } + } + + private void checkClusterInvariant(List> clusters) { + boolean isWasOnlyLocal; + isWasOnlyLocal = false; + for (TryBlockCluster cluster : clusters) { + TryCatchBlockNodeInfo info = cluster.getBlocks().get(0); + assert !isWasOnlyLocal || info.getOnlyCopyNotProcess(); + if (info.getOnlyCopyNotProcess()) { + isWasOnlyLocal = true; + } } } @@ -209,16 +268,14 @@ public class InternalFinallyBlockInliner { } @Nullable - private AbstractInsnNode updateExceptionTable( - @NotNull Stack coveringTryBlocks, - @Nullable AbstractInsnNode nextPrev, + private void updateExceptionTable( @NotNull List updatingClusterBlocks, @NotNull Label newFinallyStart, @NotNull Label newFinallyEnd, @NotNull List tryCatchBlockPresentInFinally, @NotNull Set labelsInsideFinally, - @NotNull LabelNode insertedBlockEnd - + @NotNull LabelNode insertedBlockEnd, + @NotNull List patched ) { //copy tryCatchFinallies that totally in finally block @@ -272,7 +329,7 @@ public class InternalFinallyBlockInliner { assert Objects.equal(startNode.getType(), endNode.getType()) : "Different handler types : " + startNode.getType() + " " + endNode.getType(); - patchTryBlocks((LabelNode) startNode.getStartLabel().getLabel().info, endNode, false); + patchTryBlocks((LabelNode) startNode.getStartLabel().getLabel().info, endNode); } } } @@ -284,7 +341,7 @@ public class InternalFinallyBlockInliner { //TODO rewrite to clusters for (TryCatchBlockNodePosition endBlockPosition : singleCluster.getBlocks()) { TryCatchBlockNodeInfo endNode = endBlockPosition.getNodeInfo(); - patchTryBlocks((LabelNode) insertedBlockEnd.getLabel().info, endNode, true); + patchTryBlocks((LabelNode) insertedBlockEnd.getLabel().info, endNode); //nextPrev = (AbstractInsnNode) insertedBlockEnd.getLabel().info; } @@ -293,33 +350,38 @@ public class InternalFinallyBlockInliner { } assert handler2Cluster.isEmpty() : "Unmatched clusters " + handler2Cluster.size(); + List toProcess = new ArrayList(); + toProcess.addAll(patched); + toProcess.addAll(updatingClusterBlocks); + patched.clear(); // Inserted finally shouldn't be handled by corresponding catches, // so we should split original interval by inserted finally one - for (TryCatchBlockNodeInfo block : updatingClusterBlocks) { + for (TryCatchBlockNodeInfo block : toProcess) { //update exception mapping LabelNode oldStartNode = block.getNode().start; - tryBlockStarts.remove(oldStartNode, block); block.getNode().start = (LabelNode) newFinallyEnd.info; - //tryBlockStarts.put(block.getStartLabel(), block); + tryBlockStarts.remove(oldStartNode, block); + tryBlockStarts.put(block.getStartLabel(), block); + + //if (!block.getOnlyCopyNotProcess()) { + patched.add(block); + //} TryCatchBlockNode additionalTryCatchBlock = new TryCatchBlockNode(oldStartNode, (LabelNode) newFinallyStart.info, block.getNode().handler, block.getNode().type); - TryCatchBlockNodeInfo newInfo = new TryCatchBlockNodeInfo(additionalTryCatchBlock, false); + TryCatchBlockNodeInfo newInfo = new TryCatchBlockNodeInfo(additionalTryCatchBlock, block.getOnlyCopyNotProcess()); tryBlockStarts.put(additionalTryCatchBlock.start, newInfo); tryBlockEnds.put(additionalTryCatchBlock.end, newInfo); inlineFunTryBlockInfo.add(newInfo); //TODO add assert - nextPrev = additionalTryCatchBlock.end; - coveringTryBlocks.pop(); } sortTryCatchBlocks(inlineFunTryBlockInfo); - return nextPrev; } - private void patchTryBlocks(@NotNull LabelNode newStartLabelNode, @NotNull TryCatchBlockNodeInfo endNode, boolean sort) { + private void patchTryBlocks(@NotNull LabelNode newStartLabelNode, @NotNull TryCatchBlockNodeInfo endNode) { LabelNode oldStart = endNode.getStartLabel(); endNode.getNode().start = newStartLabelNode; tryBlockStarts.remove(oldStart, endNode); @@ -355,20 +417,18 @@ public class InternalFinallyBlockInliner { List infos = tryBlockStarts.get((LabelNode) curIns); for (TryCatchBlockNodeInfo startNode : infos) { - if (!startNode.getOnlyCopyNotProcess()) { - TryCatchBlockNodeInfo pop = coveringTryBlocks.pop(); - //Temporary disabled cause during patched structure of exceptions changed - //assert startNode == pop : "Wrong try-catch structure " + startNode + " " + pop + " " + infos.size(); - } + TryCatchBlockNodeInfo pop = coveringTryBlocks.pop(); + //Temporary disabled cause during patched structure of exceptions changed + //assert startNode == pop : "Wrong try-catch structure " + startNode + " " + pop + " " + infos.size(); } //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 (TryCatchBlockNodeInfo info : Lists.reverse(tryBlockEnds.get((LabelNode) curIns))) { - if (!info.getOnlyCopyNotProcess()) { - coveringTryBlocks.add(info); - } + coveringTryBlocks.add(info); } + + checkCoveringBlocksInvariant(coveringTryBlocks); } private static boolean hasFinallyBlocks(List inlineFunTryBlockInfo) { @@ -396,6 +456,15 @@ public class InternalFinallyBlockInliner { @NotNull TryCatchBlockNodeInfo tryCatchBlock, @NotNull List tryCatchBlocks ) { + if (tryCatchBlock.getOnlyCopyNotProcess()) { + AbstractInsnNode start = new LabelNode(); + AbstractInsnNode end = new LabelNode(); + InsnList insnList = new InsnList(); + insnList.add(start); + insnList.add(end); + return new FinallyBlockInfo(start, end); + } + List sameDefaultHandler = new ArrayList(); LabelNode defaultHandler = null; boolean afterStartBlock = false; @@ -427,7 +496,16 @@ public class InternalFinallyBlockInliner { AbstractInsnNode endFinallyChainExclusive = skipLastGotoIfNeeded(nextIntervalWithSameDefaultHandler.getNode().handler, nextIntervalWithSameDefaultHandler.getNode().start); - return new FinallyBlockInfo(startFinallyChain.getNext(), endFinallyChainExclusive); + FinallyBlockInfo finallyInfo = new FinallyBlockInfo(startFinallyChain.getNext(), endFinallyChainExclusive); + + if (inlineFun.instructions.indexOf(finallyInfo.startIns) > inlineFun.instructions.indexOf(finallyInfo.endInsExclusive)) { + AbstractInsnNode startNode = finallyInfo.endInsExclusive; + AbstractInsnNode stopNode = finallyInfo.startIns; + writeNodes(startNode, stopNode); + throw new AssertionError(); + } + + return finallyInfo; } @NotNull @@ -470,6 +548,7 @@ public class InternalFinallyBlockInliner { private List findTryCatchBlocksInlinedInFinally(@NotNull FinallyBlockInfo finallyInfo) { List result = new ArrayList(); Map processedBlocks = new HashMap(); + for (AbstractInsnNode curInstr = finallyInfo.startIns; curInstr != finallyInfo.endInsExclusive; curInstr = curInstr.getNext()) { if (!(curInstr instanceof LabelNode)) continue; @@ -503,6 +582,19 @@ public class InternalFinallyBlockInliner { return result; } + private void writeNodes(AbstractInsnNode startNode, AbstractInsnNode stopNode) { + Textifier p = new Textifier(); + TraceMethodVisitor visitor = new TraceMethodVisitor(p); + while (startNode != stopNode) { + startNode.accept(visitor); + startNode = startNode.getNext(); + } + startNode.accept(visitor); + StringWriter out = new StringWriter(); + p.print(new PrintWriter(out)); + System.out.println(out.toString()); + } + private static void substituteReturnValueInFinally( int nonLocalVarIndex, @NotNull Type nonLocalReturnType, @@ -543,5 +635,43 @@ public class InternalFinallyBlockInliner { } }; Collections.sort(inlineFunTryBlockInfo, comp); + + for (TryCatchBlockNodeInfo info : inlineFunTryBlockInfo) { + TryCatchBlockNode node = info.getNode(); + assertNotEmptyTryNode(node); + } + } + + private void assertNotEmptyTryNode(TryCatchBlockNode node) { + LabelNode start = node.start; + AbstractInsnNode end = node.end; + while (end != start && end instanceof LabelNode) { + end = end.getPrevious(); + } + assert start != end; + } + + private static int counter = 0; + + private void flushCurrentState(@NotNull AbstractInsnNode curNonLocal) { + substitureTryBlockNodes(); + + System.out.println( ); + System.out.println(); + System.out.println("Iteration: " + counter++); + System.out.println("Will process instruction at : " + inlineFun.instructions.indexOf(curNonLocal) + " " + curNonLocal.toString()); + String text = getNodeText(inlineFun); + System.out.println(text); + } + + private void substitureTryBlockNodes() { + inlineFun.tryCatchBlocks.clear(); + for (TryCatchBlockNodeInfo info : inlineFunTryBlockInfo) { + inlineFun.tryCatchBlocks.add(info.getNode()); + } + } + + private int indexOf(AbstractInsnNode node) { + return inlineFun.instructions.indexOf(node) + 1; } } diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/exceptionInFinally.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/exceptionInFinally.1.kt new file mode 100644 index 00000000000..29d41c116f9 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/exceptionInFinally.1.kt @@ -0,0 +1,64 @@ +import test.* +import kotlin.test.assertEquals +import kotlin.test.assertTrue +import kotlin.test.fail + +class MyException(message: String) : Exception(message) + +class Holder(var value: String) { + public fun plusAssign(s: String?) { + value += s + if (s != "closed") { + value += "->" + } + } +} + +class Test() : MCloseable { + + val status = Holder("") + + private fun jobFun() { + status += "called" + } + + fun nonLocalWithExceptionAndFinally(): Holder { + muse { + try { + jobFun() + throw MyException("exception") + } + catch (e: MyException) { + status += e.getMessage() + return status + } + finally { + status += "finally" + } + } + return Holder("fail") + } + + override fun close() { + status += "closed" + throw MyException("error") + } +} + +fun box() : String { + assertError(1, "called->exception->finally->closed") { + nonLocalWithExceptionAndFinally() + } + + return "OK" +} + +public fun assertError(index: Int, expected: String, l: Test.()->Unit) { + val testLocal = Test() + try { + testLocal.l() + fail("fail $index: no error") + } catch (e: Exception) { + assertEquals(expected, testLocal.status.value, "failed on $index") + } +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/exceptionInFinally.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/exceptionInFinally.2.kt new file mode 100644 index 00000000000..8e0745401c9 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/exceptionInFinally.2.kt @@ -0,0 +1,15 @@ +package test + +public trait MCloseable { + public open fun close() +} + +public inline fun T.muse(block: (T) -> R): R { + try { + return block(this) + } finally { + this.close() + } +} + + diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/tryCatchInFinally.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/tryCatchInFinally.1.kt new file mode 100644 index 00000000000..575bc1fc538 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/tryCatchInFinally.1.kt @@ -0,0 +1,49 @@ +import test.* + + +fun test0( + h: Holder, + throwExternalFinEx1: Boolean = false, + res: String = "Fail" +): String { + try { + val localResult = doCall ( + { + h += "OK_NON_LOCAL" + return "OK_NON_LOCAL" + }, + { + h += "OK_FINALLY1" + "OK_FINALLY1" + }, + { + h += "innerTryBlock" + if (throwExternalFinEx1) { + throw Exception1("EXCEPTION_IN_EXTERNAL_FINALLY") + } + "innerTryBlock" + }, + { + h += "CATCHBLOCK" + "CATCHBLOCK" + }, + res) + return localResult; + } catch(e: Exception1) { + return e.getMessage()!! + } catch(e: Exception2) { + return e.getMessage()!! + } +} + +fun box(): String { + var h = Holder() + var test0 = test0(h, res = "OK") + if (test0 != "OK_NON_LOCAL" || h.value != "OK_NON_LOCAL -> OK_FINALLY1 -> innerTryBlock") return "test0_1: ${test0}, holder: ${h.value}" + + h = Holder() + test0 = test0(h, throwExternalFinEx1 = true, res = "OK") + if (test0 != "OK_NON_LOCAL" || h.value != "OK_NON_LOCAL -> OK_FINALLY1 -> innerTryBlock -> CATCHBLOCK") return "test0_2: ${test0}, holder: ${h.value}" + + return "OK" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/tryCatchInFinally.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/tryCatchInFinally.2.kt new file mode 100644 index 00000000000..c401339df38 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/tryCatchInFinally.2.kt @@ -0,0 +1,36 @@ +package test + +public class Holder(var value: String = "") { + + public fun plusAssign(s: String?) { + if (value.length != 0) { + value += " -> " + } + value += s + } + + override fun toString(): String { + return value + } + +} + +public class Exception1(message: String) : java.lang.RuntimeException(message) + +public class Exception2(message: String) : java.lang.RuntimeException(message) + +public inline fun doCall(block: ()-> String, finallyBlock: ()-> String, + tryBlock2: ()-> String, catchBlock2: ()-> String, res: String = "Fail") : String { + try { + block() + } + finally { + finallyBlock() + try { + tryBlock2() + } catch (e: Exception) { + catchBlock2() + } + } + return res +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/inline/notSplitedExceptionTable.kt b/compiler/testData/codegen/bytecodeText/inline/notSplitedExceptionTable.kt new file mode 100644 index 00000000000..7769e0fa16c --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/inline/notSplitedExceptionTable.kt @@ -0,0 +1,28 @@ +inline fun test(s: ()->Int): Int { + var i = 0; + i = s() + try { + i = i + 10 + } finally { + return i + } +} + +fun box() : String { + var p: Int = 1 + test { + try { + p = 1 + return "OK" //finally from inline fun doen't split this try + } catch(e: Exception) { + p = -1; + p + } finally { + p++ + } + + } + return "fail" +} + +// 10 TRYCATCHBLOCK \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/inline/splitedExceptionTable.kt b/compiler/testData/codegen/bytecodeText/inline/splitedExceptionTable.kt new file mode 100644 index 00000000000..2be9035a4ad --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/inline/splitedExceptionTable.kt @@ -0,0 +1,55 @@ +inline fun test(s: ()->Int): Int { + var i = 0; + try { + i = s() + i = i + 10 + } finally { + return i + } +} + +fun box() : String { + var p: Int = 1 + test { + try { + p = 1 + return "OK" //finally from inline fun doen't split this try + } catch(e: Exception) { + p = -1; + p + } finally { + p++ + } + + } + return "fail" +} + +// maybe we shouldinline fun test(s: ()->Int): Int { +var i = 0; +try { +i = s() +i = i + 10 +} finally { +return i +} +} + +fun box() : String { + var p: Int = 1 + test { + try { + p = 1 + return "OK" //finally from inline fun doen't split this try + } catch(e: Exception) { + p = -1; + p + } finally { + p++ + } + + } + return "fail" +} +check test data +// 13 TRYCATCHBLOCK diff --git a/compiler/tests/org/jetbrains/jet/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/BytecodeTextTestGenerated.java index 8d161fb0a06..fd4e7de786a 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/BytecodeTextTestGenerated.java @@ -30,7 +30,7 @@ import java.util.regex.Pattern; @SuppressWarnings("all") @TestMetadata("compiler/testData/codegen/bytecodeText") @TestDataPath("$PROJECT_ROOT") -@InnerTestClasses({BytecodeTextTestGenerated.BoxingOptimization.class, BytecodeTextTestGenerated.Constants.class, BytecodeTextTestGenerated.DirectInvoke.class, BytecodeTextTestGenerated.Statements.class, BytecodeTextTestGenerated.StoreStackBeforeInline.class, BytecodeTextTestGenerated.When.class, BytecodeTextTestGenerated.WhenEnumOptimization.class, BytecodeTextTestGenerated.WhenStringOptimization.class}) +@InnerTestClasses({BytecodeTextTestGenerated.BoxingOptimization.class, BytecodeTextTestGenerated.Constants.class, BytecodeTextTestGenerated.DirectInvoke.class, BytecodeTextTestGenerated.Inline.class, BytecodeTextTestGenerated.Statements.class, BytecodeTextTestGenerated.StoreStackBeforeInline.class, BytecodeTextTestGenerated.When.class, BytecodeTextTestGenerated.WhenEnumOptimization.class, BytecodeTextTestGenerated.WhenStringOptimization.class}) @RunWith(JUnit3RunnerWithInners.class) public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { @TestMetadata("accessorForProtected.kt") @@ -322,6 +322,27 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { } } + @TestMetadata("compiler/testData/codegen/bytecodeText/inline") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Inline extends AbstractBytecodeTextTest { + public void testAllFilesPresentInInline() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/inline"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("notSplitedExceptionTable.kt") + public void testNotSplitedExceptionTable() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inline/notSplitedExceptionTable.kt"); + doTest(fileName); + } + + @TestMetadata("splitedExceptionTable.kt") + public void testSplitedExceptionTable() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inline/splitedExceptionTable.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/codegen/bytecodeText/statements") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxInlineCodegenTestGenerated.java index aafb85af3d7..6211670f4db 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxInlineCodegenTestGenerated.java @@ -507,6 +507,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxCodegenT doTestMultiFileWithInlineCheck(fileName); } + @TestMetadata("exceptionInFinally.1.kt") + public void testExceptionInFinally() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/exceptionInFinally.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + @TestMetadata("forInFinally.1.kt") public void testForInFinally() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/forInFinally.1.kt"); @@ -578,6 +584,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxCodegenT String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/throwInFinally.1.kt"); doTestMultiFileWithInlineCheck(fileName); } + + @TestMetadata("tryCatchInFinally.1.kt") + public void testTryCatchInFinally() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/tryCatchInFinally.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } } } } diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java index cb64bfa128a..dda9a2830d5 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -507,6 +507,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi doBoxTestWithInlineCheck(fileName); } + @TestMetadata("exceptionInFinally.1.kt") + public void testExceptionInFinally() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/exceptionInFinally.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + @TestMetadata("forInFinally.1.kt") public void testForInFinally() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/forInFinally.1.kt"); @@ -578,6 +584,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/throwInFinally.1.kt"); doBoxTestWithInlineCheck(fileName); } + + @TestMetadata("tryCatchInFinally.1.kt") + public void testTryCatchInFinally() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/tryCatchInFinally.1.kt"); + doBoxTestWithInlineCheck(fileName); + } } } }