From a018e4e12a8dbb4d79acf0bebb8bc9dadfa7b4ef Mon Sep 17 00:00:00 2001 From: Michael Bogdanov Date: Wed, 10 Jun 2015 15:38:09 +0300 Subject: [PATCH] Updated exception table generation: support new exception table in non-local returns --- .../kotlin/codegen/ExpressionCodegen.java | 25 ++- .../inline/CoveringTryCatchNodeProcessor.kt | 25 ++- .../kotlin/codegen/inline/InlineCodegen.java | 14 +- .../codegen/inline/InlineCodegenUtil.java | 52 ++++-- .../inline/InternalFinallyBlockInliner.java | 161 ++++++++---------- .../kotlin/codegen/inline/InvokeCall.java | 4 +- .../kotlin/codegen/inline/MethodInliner.java | 54 +++++- .../tryFinally/callSite/callSiteComplex.1.kt | 94 ++++++++++ .../tryFinally/callSite/callSiteComplex.2.kt | 13 ++ .../tryFinally/callSite/finallyInFinally.1.kt | 69 ++++++++ .../tryFinally/callSite/finallyInFinally.2.kt | 9 + .../tryFinally/chained/finallyInFinally.1.kt | 53 ++++++ .../tryFinally/chained/finallyInFinally.2.kt | 40 +++++ .../tryFinally/chained/finallyInFinally2.1.kt | 53 ++++++ .../tryFinally/chained/finallyInFinally2.2.kt | 38 +++++ .../tryFinally/chained/intReturn.1.kt | 30 ++++ .../tryFinally/chained/intReturn.2.kt | 32 ++++ .../tryFinally/chained/intReturnComplex.1.kt | 30 ++++ .../tryFinally/chained/intReturnComplex.2.kt | 36 ++++ .../tryFinally/chained/intReturnComplex2.1.kt | 30 ++++ .../tryFinally/chained/intReturnComplex2.2.kt | 44 +++++ .../tryFinally/chained/intReturnComplex3.1.kt | 34 ++++ .../tryFinally/chained/intReturnComplex3.2.kt | 44 +++++ .../tryFinally/chained/intReturnComplex4.1.kt | 34 ++++ .../tryFinally/chained/intReturnComplex4.2.kt | 48 ++++++ .../tryFinally/chained/nestedLambda.1.kt | 68 ++++++++ .../tryFinally/chained/nestedLambda.2.kt | 13 ++ .../tryFinally/declSite/intReturnComplex.1.kt | 127 ++++++++++++++ .../tryFinally/declSite/intReturnComplex.2.kt | 39 +++++ .../tryFinally/declSite/severalInTry.1.kt | 75 ++++++++ .../tryFinally/declSite/severalInTry.2.kt | 10 ++ .../declSite/severalInTryComplex.1.kt | 72 ++++++++ .../declSite/severalInTryComplex.2.kt | 19 +++ .../nonLocalReturns/tryFinally/kt6956.1.kt | 19 +++ .../nonLocalReturns/tryFinally/kt6956.2.kt | 13 ++ .../inline/notSplitedExceptionTable.kt | 2 +- .../inline/splitedExceptionTable.kt | 5 +- .../BlackBoxInlineCodegenTestGenerated.java | 93 ++++++++++ ...otlinAgainstInlineKotlinTestGenerated.java | 93 ++++++++++ .../src/kotlin/jvm/internal/InlineMarker.java | 10 ++ 40 files changed, 1586 insertions(+), 138 deletions(-) create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/callSiteComplex.1.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/callSiteComplex.2.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/finallyInFinally.1.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/finallyInFinally.2.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/finallyInFinally.1.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/finallyInFinally.2.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/finallyInFinally2.1.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/finallyInFinally2.2.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturn.1.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturn.2.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex.1.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex.2.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex2.1.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex2.2.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex3.1.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex3.2.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex4.1.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex4.2.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/nestedLambda.1.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/nestedLambda.2.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/intReturnComplex.1.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/intReturnComplex.2.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/severalInTry.1.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/severalInTry.2.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/severalInTryComplex.1.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/severalInTryComplex.2.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt6956.1.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt6956.2.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 9fb2d608c2f..55b76b8aa6f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -129,6 +129,7 @@ public class ExpressionCodegen extends JetVisitor implem private int myLastLineNumber = -1; private boolean shouldMarkLineNumbers = true; + private int finallyDeep = 0; public ExpressionCodegen( @NotNull MethodVisitor mv, @@ -1759,7 +1760,7 @@ public class ExpressionCodegen extends JetVisitor implem } } - private void doFinallyOnReturn(Label afterReturnLabel) { + private void doFinallyOnReturn(@NotNull Label afterReturnLabel) { if(!blockStackElements.isEmpty()) { BlockStackElement stackElement = blockStackElements.peek(); if (stackElement instanceof FinallyBlockStackElement) { @@ -1790,9 +1791,10 @@ public class ExpressionCodegen extends JetVisitor implem private void genFinallyBlockOrGoto( @Nullable FinallyBlockStackElement finallyBlockStackElement, @Nullable Label tryCatchBlockEnd, - @Nullable Label afterReturnLabel + @Nullable Label afterJumpLabel ) { if (finallyBlockStackElement != null) { + finallyDeep++; assert finallyBlockStackElement.gaps.size() % 2 == 0 : "Finally block gaps are inconsistent"; BlockStackElement topOfStack = blockStackElements.pop(); @@ -1802,21 +1804,25 @@ public class ExpressionCodegen extends JetVisitor implem Label finallyStart = new Label(); v.mark(finallyStart); finallyBlockStackElement.addGapLabel(finallyStart); - + if (context.isInlineFunction() || context.isInliningLambda()) { + InlineCodegenUtil.generateFinallyMarker(v, finallyDeep, true); + } //noinspection ConstantConditions gen(jetTryExpression.getFinallyBlock().getFinalExpression(), Type.VOID_TYPE); + + if (context.isInlineFunction() || context.isInliningLambda()) { + InlineCodegenUtil.generateFinallyMarker(v, finallyDeep, false); + } } if (tryCatchBlockEnd != null) { - if (context.isInlineFunction()) { - InlineCodegenUtil.generateGoToTryCatchBlockEndMarker(v); - } v.goTo(tryCatchBlockEnd); } if (finallyBlockStackElement != null) { - Label finallyEnd = afterReturnLabel != null ? afterReturnLabel : new Label(); - if (afterReturnLabel == null) { + finallyDeep--; + Label finallyEnd = afterJumpLabel != null ? afterJumpLabel : new Label(); + if (afterJumpLabel == null) { v.mark(finallyEnd); } finallyBlockStackElement.addGapLabel(finallyEnd); @@ -4000,8 +4006,9 @@ The "returned" value of try expression with no finally is either the last expres return new Stack(blockStackElements); } - public void addBlockStackElementsForNonLocalReturns(@NotNull Stack elements) { + public void addBlockStackElementsForNonLocalReturns(@NotNull Stack elements, int finallyDeepIndex) { blockStackElements.addAll(elements); + this.finallyDeep = finallyDeepIndex; } private static class NonLocalReturnInfo { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/CoveringTryCatchNodeProcessor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/CoveringTryCatchNodeProcessor.kt index 8be21ccd75f..92394ec1c8d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/CoveringTryCatchNodeProcessor.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/CoveringTryCatchNodeProcessor.kt @@ -63,7 +63,7 @@ public abstract class CoveringTryCatchNodeProcessor(parameterSize: Int) { if (result == 0) { result = instructionIndex(t1.startLabel) - instructionIndex(t2.startLabel) if (result == 0) { - assert(false, "Error: support multicatch finallies!") + assert(false, "Error: support multicatch finallies: ${t1.handler}, ${t2.handler}") result = instructionIndex(t1.endLabel) - instructionIndex(t2.endLabel) } } @@ -123,13 +123,15 @@ class IntervalMetaInfo> { fun processCurrent(curIns: LabelNode, directOrder: Boolean) { getInterval(curIns, directOrder).forEach { - val b = currentIntervals.add(it) - assert(b, "Wrong interval structure: $curIns, $it") + val added = currentIntervals.add(it) + if (!added) { + assert(added, "Wrong interval structure: $curIns, $it") + } } getInterval(curIns, !directOrder).forEach { - val b = currentIntervals.remove(it) - assert(b, "Wrong interval structure: $curIns, $it") + val removed = currentIntervals.remove(it) + assert(removed, "Wrong interval structure: $curIns, $it") } } @@ -144,6 +146,19 @@ class IntervalMetaInfo> { return splittedPair } + fun splitAndRemoveInterval(interval: T, by : Interval, keepStart: Boolean): SplittedPair { + val splittedPair = interval.split(by, keepStart) + if (!keepStart) { + remapStartLabel(splittedPair.newPart.startLabel, splittedPair.patchedPart) + } else { + remapEndLabel(splittedPair.newPart.endLabel, splittedPair.patchedPart) + } + val removed = currentIntervals.remove(splittedPair.patchedPart) + assert(removed, "Wrong interval structure: $splittedPair") + addNewInterval(splittedPair.newPart) + return splittedPair + } + fun getInterval(curIns: LabelNode, isOpen: Boolean) = if (isOpen) intervalStarts.get(curIns) else intervalEnds.get(curIns) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java index 67b160ac61e..389ccedcc55 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java @@ -661,14 +661,18 @@ public class InlineCodegen extends CallGenerator { DefaultProcessor processor = new DefaultProcessor(intoNode, offsetForFinallyLocalVar); + int curFinallyDeep = 0; AbstractInsnNode curInstr = intoNode.instructions.getFirst(); while (curInstr != null) { processor.processInstruction(curInstr, true); + if (InlineCodegenUtil.isFinallyStart(curInstr)) { + //TODO deep index calc could be more precise + curFinallyDeep = InlineCodegenUtil.getConstant(curInstr.getPrevious()); + } MethodInliner.PointForExternalFinallyBlocks extension = extensionPoints.get(curInstr); if (extension != null) { Label start = new Label(); - //Label end = new Label(); MethodNode finallyNode = InlineCodegenUtil.createEmptyMethodNode(); finallyNode.visitLabel(start); @@ -676,7 +680,7 @@ public class InlineCodegen extends CallGenerator { ExpressionCodegen finallyCodegen = new ExpressionCodegen(finallyNode, codegen.getFrameMap(), codegen.getReturnType(), codegen.getContext(), codegen.getState(), codegen.getParentCodegen()); - finallyCodegen.addBlockStackElementsForNonLocalReturns(codegen.getBlockStackElements()); + finallyCodegen.addBlockStackElementsForNonLocalReturns(codegen.getBlockStackElements(), curFinallyDeep); FrameMap frameMap = finallyCodegen.getFrameMap(); FrameMap.Mark mark = frameMap.mark(); @@ -685,14 +689,14 @@ public class InlineCodegen extends CallGenerator { } finallyCodegen.generateFinallyBlocksIfNeeded(extension.returnType, extension.labelNode.getLabel()); - //finallyNode.visitLabel(end); + //Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr); SimpleInterval splitBy = new SimpleInterval((LabelNode) start.info, extension.labelNode); - processor.getTryBlocksMetaInfo().splitCurrentIntervals(splitBy, false); + processor.getTryBlocksMetaInfo().splitCurrentIntervals(splitBy, true); - processor.getLocalVarsMetaInfo().splitCurrentIntervals(splitBy, false); + processor.getLocalVarsMetaInfo().splitCurrentIntervals(splitBy, true); mark.dropTo(); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java index 6d5d3672363..8b64ad1d317 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java @@ -33,9 +33,9 @@ import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.JetTypeMapper; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.load.java.JvmAbi; +import org.jetbrains.kotlin.load.kotlin.JvmVirtualFileFinder; import org.jetbrains.kotlin.load.kotlin.PackageClassUtils; import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils; -import org.jetbrains.kotlin.load.kotlin.JvmVirtualFileFinder; import org.jetbrains.kotlin.name.ClassId; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.Name; @@ -77,7 +77,8 @@ public class InlineCodegenUtil { public static final String INLINE_MARKER_CLASS_NAME = "kotlin/jvm/internal/InlineMarker"; public static final String INLINE_MARKER_BEFORE_METHOD_NAME = "beforeInlineCall"; public static final String INLINE_MARKER_AFTER_METHOD_NAME = "afterInlineCall"; - public static final String INLINE_MARKER_GOTO_TRY_CATCH_BLOCK_END = "goToTryCatchBlockEnd"; + public static final String INLINE_MARKER_FINALLY_START = "finallyStart"; + public static final String INLINE_MARKER_FINALLY_END = "finallyEnd"; @Nullable public static SMAPAndMethodNode getMethodNode( @@ -321,7 +322,9 @@ public class InlineCodegenUtil { //marked return could be either non-local or local in case of labeled lambda self-returns public static boolean isMarkedReturn(@NotNull AbstractInsnNode returnIns) { - assert isReturnOpcode(returnIns.getOpcode()) : "Should be called on return instruction, but " + returnIns; + if (!isReturnOpcode(returnIns.getOpcode())) { + return false; + } AbstractInsnNode globalFlag = returnIns.getPrevious(); return globalFlag instanceof MethodInsnNode && NON_LOCAL_RETURN.equals(((MethodInsnNode)globalFlag).owner); } @@ -355,10 +358,6 @@ public class InlineCodegenUtil { return new MethodNode(API, 0, "fake", "()V", null, null); } - static boolean isLineNumberOrLabel(@Nullable AbstractInsnNode node) { - return node instanceof LineNumberNode || node instanceof LabelNode; - } - @NotNull public static LabelNode firstLabelInChain(@NotNull LabelNode node) { LabelNode curNode = node; @@ -405,16 +404,39 @@ public class InlineCodegenUtil { } } - public static void generateGoToTryCatchBlockEndMarker(@NotNull InstructionAdapter v) { - v.invokestatic(INLINE_MARKER_CLASS_NAME, INLINE_MARKER_GOTO_TRY_CATCH_BLOCK_END, "()V", false); + public static void generateFinallyMarker(@NotNull InstructionAdapter v, int deep, boolean start) { + v.iconst(deep); + v.invokestatic(INLINE_MARKER_CLASS_NAME, start ? INLINE_MARKER_FINALLY_START : INLINE_MARKER_FINALLY_END, "(I)V", false); } - public static boolean isGoToTryCatchBlockEnd(@NotNull AbstractInsnNode node) { - if (!(node.getPrevious() instanceof MethodInsnNode)) return false; - MethodInsnNode previous = (MethodInsnNode) node.getPrevious(); - return node.getOpcode() == Opcodes.GOTO && - INLINE_MARKER_CLASS_NAME.equals(previous.owner) && - INLINE_MARKER_GOTO_TRY_CATCH_BLOCK_END.equals(previous.name); + public static boolean isFinallyEnd(@NotNull AbstractInsnNode node) { + return isFinallyMarker(node, INLINE_MARKER_FINALLY_END); + } + + public static boolean isFinallyStart(@NotNull AbstractInsnNode node) { + return isFinallyMarker(node, INLINE_MARKER_FINALLY_START); + } + + public static boolean isFinallyMarker(@Nullable AbstractInsnNode node) { + return isFinallyMarker(node, INLINE_MARKER_FINALLY_END) || isFinallyMarker(node, INLINE_MARKER_FINALLY_START); + } + + public static boolean isFinallyMarker(@Nullable AbstractInsnNode node, String name) { + if (!(node instanceof MethodInsnNode)) return false; + MethodInsnNode method = (MethodInsnNode) node; + return INLINE_MARKER_CLASS_NAME.equals(method.owner) && name.equals(method.name); + } + + public static int getConstant(AbstractInsnNode ins) { + int opcode = ins.getOpcode(); + Integer value; + if (opcode >= Opcodes.ICONST_0 && opcode <= Opcodes.ICONST_5) { + value = opcode - Opcodes.ICONST_0; + } else { + LdcInsnNode index = (LdcInsnNode) ins; + value = (Integer) index.cst; + } + return value; } public static class LabelTextifier extends Textifier { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InternalFinallyBlockInliner.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InternalFinallyBlockInliner.java index e63069f5e0f..daf2231a031 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InternalFinallyBlockInliner.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InternalFinallyBlockInliner.java @@ -22,7 +22,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.ReadOnly; import org.jetbrains.annotations.TestOnly; -import org.jetbrains.kotlin.codegen.AsmUtil; +import org.jetbrains.kotlin.codegen.optimization.common.CommonPackage; import org.jetbrains.org.objectweb.asm.Label; import org.jetbrains.org.objectweb.asm.Opcodes; import org.jetbrains.org.objectweb.asm.Type; @@ -44,7 +44,10 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor { final AbstractInsnNode endInsExclusive; - private FinallyBlockInfo(@NotNull AbstractInsnNode inclusiveStart, @NotNull AbstractInsnNode exclusiveEnd) { + private FinallyBlockInfo( + @NotNull AbstractInsnNode inclusiveStart, + @NotNull AbstractInsnNode exclusiveEnd + ) { startIns = inclusiveStart; endInsExclusive = exclusiveEnd; } @@ -139,8 +142,9 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor { } AbstractInsnNode markedReturn = curIns; - final AbstractInsnNode instrInsertFinallyBefore = markedReturn.getPrevious(); - AbstractInsnNode nextPrev = instrInsertFinallyBefore.getPrevious(); + AbstractInsnNode instrInsertFinallyBefore = markedReturn.getPrevious(); + AbstractInsnNode nextPrev = instrInsertFinallyBefore.getPrevious().getPrevious(); + LabelNode newFinallyEnd = (LabelNode) markedReturn.getNext(); Type nonLocalReturnType = InlineCodegenUtil.getReturnType(markedReturn.getOpcode()); //Generally there could be several tryCatch blocks (group) on one code interval (same start and end labels, but maybe different handlers) - @@ -148,25 +152,33 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor { // Each group that corresponds to try/*catches*/finally contains tryCatch block with default handler. // For each such group we should insert corresponding finally before non-local return. // So we split all try blocks on current instructions to groups and process them independently - List> clustersFromInnermost = InlinePackage.doClustering(currentCoveringNodesFromInnermost); + List> clustersFromInnermost = InlinePackage.doClustering( + currentCoveringNodesFromInnermost); Iterator> tryCatchBlockIterator = clustersFromInnermost.iterator(); checkClusterInvariant(clustersFromInnermost); - List additionalNodesToSplit = new ArrayList(); + int originalDeepIndex = 0; + while (tryCatchBlockIterator.hasNext()) { TryBlockCluster clusterToFindFinally = tryCatchBlockIterator.next(); List clusterBlocks = clusterToFindFinally.getBlocks(); TryCatchBlockNodeInfo nodeWithDefaultHandlerIfExists = clusterBlocks.get(clusterBlocks.size() - 1); - FinallyBlockInfo finallyInfo = findFinallyBlockBody(nodeWithDefaultHandlerIfExists, getTryBlocksMetaInfo().getAllIntervals()); - if (finallyInfo == null) continue; if (nodeWithDefaultHandlerIfExists.getOnlyCopyNotProcess()) { - additionalNodesToSplit.addAll(clusterBlocks); - continue; + //lambdas finally generated before non-local return instruction, + //so it's a gap in try/catch handlers + throw new RuntimeException("Lambda try blocks should be skipped"); } + FinallyBlockInfo finallyInfo = findFinallyBlockBody(nodeWithDefaultHandlerIfExists, getTryBlocksMetaInfo().getAllIntervals()); + if (finallyInfo == null) continue; + TryCatchBlockNodeInfo defaultHandlerBlock = clusterToFindFinally.getDefaultHandler(); + assert defaultHandlerBlock != null; + + originalDeepIndex++; + instructions.resetLabels(); List tryCatchBlockInlinedInFinally = findTryCatchBlocksInlinedInFinally(finallyInfo); @@ -174,7 +186,6 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor { //Creating temp node for finally block copy with some additional instruction MethodNode finallyBlockCopy = createEmptyMethodNode(); Label newFinallyStart = new Label(); - Label newFinallyEnd = new Label(); Label insertedBlockEnd = new Label(); boolean generateAloadAstore = nonLocalReturnType != Type.VOID_TYPE && !finallyInfo.isEmpty(); @@ -193,13 +204,11 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor { !(currentIns instanceof JumpInsnNode) || labelsInsideFinally.contains(((JumpInsnNode) currentIns).label); - copyInstruction(nextTempNonLocalVarIndex, markedReturn, instrInsertFinallyBefore, nonLocalReturnType, finallyBlockCopy, - currentIns, isInsOrJumpInsideFinally); + copyInstruction(finallyBlockCopy, currentIns, isInsOrJumpInsideFinally, originalDeepIndex); currentIns = currentIns.getNext(); } - finallyBlockCopy.visitLabel(newFinallyEnd); if (generateAloadAstore) { finallyBlockCopy.visitVarInsn(nonLocalReturnType.getOpcode(Opcodes.ILOAD), nextTempNonLocalVarIndex); nextTempNonLocalVarIndex += nonLocalReturnType.getSize(); //TODO: do more wise indexing @@ -211,7 +220,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor { InlineCodegenUtil.insertNodeBefore(finallyBlockCopy, inlineFun, instrInsertFinallyBefore); updateExceptionTable(clusterBlocks, newFinallyStart, newFinallyEnd, - tryCatchBlockInlinedInFinally, labelsInsideFinally, (LabelNode) insertedBlockEnd.info, additionalNodesToSplit); + tryCatchBlockInlinedInFinally, labelsInsideFinally, (LabelNode) insertedBlockEnd.info); } //skip just inserted finally @@ -237,38 +246,22 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor { } private static void copyInstruction( - int nextTempNonLocalVarIndex, - @NotNull AbstractInsnNode curIns, - @NotNull AbstractInsnNode instrInsertFinallyBefore, - @NotNull Type nonLocalReturnType, @NotNull MethodNode finallyBlockCopy, @NotNull AbstractInsnNode currentIns, - boolean isInsOrJumpInsideFinally + boolean isInsOrJumpInsideFinally, + int deep ) { - //This condition allows another model for non-local returns processing - if (false) { - boolean isReturnForSubstitution = - InlineCodegenUtil.isReturnOpcode(currentIns.getOpcode()) && !InlineCodegenUtil.isMarkedReturn(currentIns); - if (!isInsOrJumpInsideFinally || isReturnForSubstitution) { - //substitute all local returns and jumps outside finally with non-local return - Type localReturnType = InlineCodegenUtil.getReturnType(currentIns.getOpcode()); - substituteReturnValueInFinally(nextTempNonLocalVarIndex, nonLocalReturnType, finallyBlockCopy, - localReturnType, isReturnForSubstitution); - - instrInsertFinallyBefore.accept(finallyBlockCopy); - curIns.accept(finallyBlockCopy); + if (isInsOrJumpInsideFinally) { + if (InlineCodegenUtil.isFinallyMarker(currentIns.getNext())) { + Integer constant = getConstant(currentIns); + finallyBlockCopy.visitLdcInsn(constant + deep); } else { currentIns.accept(finallyBlockCopy); //VISIT } } else { - if (isInsOrJumpInsideFinally) { - currentIns.accept(finallyBlockCopy); //VISIT - } - else { - //keep original jump: add currentIns clone - finallyBlockCopy.instructions.add(new JumpInsnNode(currentIns.getOpcode(), ((JumpInsnNode) currentIns).label)); - } + //keep original jump: add currentIns clone + finallyBlockCopy.instructions.add(new JumpInsnNode(currentIns.getOpcode(), ((JumpInsnNode) currentIns).label)); } } @@ -306,11 +299,10 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor { private void updateExceptionTable( @NotNull List updatingClusterBlocks, @NotNull Label newFinallyStart, - @NotNull Label newFinallyEnd, + @NotNull LabelNode newFinallyEnd, @NotNull List tryCatchBlockPresentInFinally, @NotNull Set labelsInsideFinally, - @NotNull LabelNode insertedBlockEnd, - @NotNull List patched + @NotNull LabelNode insertedBlockEnd ) { //copy tryCatchFinallies that totally in finally block @@ -379,7 +371,6 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor { getTryBlocksMetaInfo() .split(endNode, new SimpleInterval((LabelNode) endNode.getNode().end.getLabel().info, (LabelNode) insertedBlockEnd.getLabel().info), false); - //nextPrev = (AbstractInsnNode) insertedBlockEnd.getLabel().info; } handler2Cluster.clear(); @@ -387,19 +378,16 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor { } assert handler2Cluster.isEmpty() : "Unmatched clusters " + handler2Cluster.size(); - List toProcess = new ArrayList(); - toProcess.addAll(patched); - toProcess.addAll(updatingClusterBlocks); - patched.clear(); - SimpleInterval splitBy = new SimpleInterval((LabelNode) newFinallyStart.info, (LabelNode) newFinallyEnd.info); + SimpleInterval splitBy = new SimpleInterval((LabelNode) newFinallyStart.info, newFinallyEnd); // Inserted finally shouldn't be handled by corresponding catches, // so we should split original interval by inserted finally one - for (TryCatchBlockNodeInfo block : toProcess) { + for (TryCatchBlockNodeInfo block : updatingClusterBlocks) { //update exception mapping - tryBlocksMetaInfo.split(block, splitBy, false); + SplittedPair split = tryBlocksMetaInfo.splitAndRemoveInterval(block, splitBy, false); + checkFinally(split.getNewPart()); + checkFinally(split.getPatchedPart()); //block patched in split method assert !block.isEmpty() : "Finally block should be non-empty"; - patched.add(block); //TODO add assert } @@ -432,15 +420,6 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor { @NotNull TryCatchBlockNodeInfo tryCatchBlock, @ReadOnly @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; @@ -469,29 +448,42 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor { TryCatchBlockNodeInfo nextIntervalWithSameDefaultHandler = sameDefaultHandler.get(1); AbstractInsnNode startFinallyChain = tryCatchBlock.getNode().end; - AbstractInsnNode endFinallyChainExclusive = skipLastGotoIfNeeded(nextIntervalWithSameDefaultHandler.getNode().start); + AbstractInsnNode meaningful = getNextMeaningful(startFinallyChain); + assert meaningful != null : "Can't find meaningful in finally block" + startFinallyChain; + + Integer finallyDeep = getConstant(meaningful); + AbstractInsnNode endFinallyChainExclusive = nextIntervalWithSameDefaultHandler.getNode().start; + AbstractInsnNode current = meaningful.getNext(); + while (endFinallyChainExclusive != current) { + current = current.getNext(); + if (InlineCodegenUtil.isFinallyEnd(current)) { + Integer currentDeep = getConstant(current.getPrevious()); + if (currentDeep.equals(finallyDeep)) { + endFinallyChainExclusive = current.getNext(); + break; + } + } + } FinallyBlockInfo finallyInfo = new FinallyBlockInfo(startFinallyChain.getNext(), endFinallyChainExclusive); - if (inlineFun.instructions.indexOf(finallyInfo.startIns) > inlineFun.instructions.indexOf(finallyInfo.endInsExclusive)) { - throw new AssertionError("Inconsistent finally: block end occurs before start " + traceInterval(finallyInfo.endInsExclusive, finallyInfo.startIns)); - } + checkFinally(finallyInfo); return finallyInfo; } - @NotNull - private static AbstractInsnNode skipLastGotoIfNeeded( - @NotNull AbstractInsnNode lastFinallyInsExclusive - ) { + private void checkFinally(FinallyBlockInfo finallyInfo) { + checkFinally(finallyInfo.startIns, finallyInfo.endInsExclusive); + } - AbstractInsnNode prevLast = getPrevNoLineNumberOrLabel(lastFinallyInsExclusive, true); - assert prevLast != null : "Empty finally block: " + lastFinallyInsExclusive; + private void checkFinally(IntervalWithHandler intervalWithHandler) { + checkFinally(intervalWithHandler.getStartLabel(), intervalWithHandler.getEndLabel()); + } - if (InlineCodegenUtil.isGoToTryCatchBlockEnd(prevLast)) { - return prevLast.getPrevious(); + private void checkFinally(AbstractInsnNode startIns, AbstractInsnNode endInsExclusive) { + if (inlineFun.instructions.indexOf(startIns) >= inlineFun.instructions.indexOf(endInsExclusive)) { + throw new AssertionError("Inconsistent finally: block end occurs before start " + traceInterval(endInsExclusive, startIns)); } - return lastFinallyInsExclusive; } @NotNull @@ -529,26 +521,11 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor { return result; } - private static void substituteReturnValueInFinally( - int nonLocalVarIndex, - @NotNull Type nonLocalReturnType, - @NotNull MethodNode finallyBlockCopy, - @NotNull Type localReturnType, - boolean doPop - ) { - if (doPop && localReturnType != Type.VOID_TYPE) { - AsmUtil.pop(finallyBlockCopy, localReturnType); - } - if (nonLocalReturnType != Type.VOID_TYPE) { - finallyBlockCopy.visitVarInsn(nonLocalReturnType.getOpcode(Opcodes.ILOAD), nonLocalVarIndex); - } - } - @Nullable - private static AbstractInsnNode getPrevNoLineNumberOrLabel(@NotNull AbstractInsnNode node, boolean strict) { - AbstractInsnNode result = strict ? node.getPrevious() : node; - while (isLineNumberOrLabel(result)) { - result = result.getPrevious(); + private static AbstractInsnNode getNextMeaningful(@NotNull AbstractInsnNode node) { + AbstractInsnNode result = node.getNext(); + while (result != null && !CommonPackage.getIsMeaningful(result)) { + result = result.getNext(); } return result; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InvokeCall.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InvokeCall.java index 4f62d9932d4..d70333fe45f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InvokeCall.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InvokeCall.java @@ -21,9 +21,11 @@ import org.jetbrains.annotations.Nullable; class InvokeCall { private final int index; public final LambdaInfo lambdaInfo; + public final int finallyDeep; - InvokeCall(int index, @Nullable LambdaInfo lambdaInfo) { + InvokeCall(int index, @Nullable LambdaInfo lambdaInfo, int finallyDeep) { this.index = index; this.lambdaInfo = lambdaInfo; + this.finallyDeep = finallyDeep; } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java index 6e677c19751..52f86282e3d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java @@ -104,9 +104,19 @@ public class MethodInliner { @NotNull LocalVarRemapper remapper, boolean remapReturn, @NotNull LabelOwner labelOwner + ) { + return doInline(adapter, remapper, remapReturn, labelOwner, 0); + } + + private InlineResult doInline( + @NotNull MethodVisitor adapter, + @NotNull LocalVarRemapper remapper, + boolean remapReturn, + @NotNull LabelOwner labelOwner, + int finallyDeepShift ) { //analyze body - MethodNode transformedNode = markPlacesForInlineAndRemoveInlinable(node); + MethodNode transformedNode = markPlacesForInlineAndRemoveInlinable(node, finallyDeepShift); //substitute returns with "goto end" instruction to keep non local returns in lambdas Label end = new Label(); @@ -234,7 +244,7 @@ public class MethodInliner { mapper); LocalVarRemapper remapper = new LocalVarRemapper(lambdaParameters, valueParamShift); - InlineResult lambdaResult = inliner.doInline(this.mv, remapper, true, info);//TODO add skipped this and receiver + InlineResult lambdaResult = inliner.doInline(this.mv, remapper, true, info, invokeCall.finallyDeep);//TODO add skipped this and receiver result.addAllClassesToRemove(lambdaResult); //return value boxing/unboxing @@ -301,7 +311,7 @@ public class MethodInliner { } @NotNull - public MethodNode prepareNode(@NotNull MethodNode node) { + public MethodNode prepareNode(@NotNull MethodNode node, int finallyDeepShift) { final int capturedParamsSize = parameters.getCaptured().size(); final int realParametersSize = parameters.getReal().size(); Type[] types = Type.getArgumentTypes(node.desc); @@ -354,13 +364,14 @@ public class MethodInliner { node.accept(transformedNode); transformCaptured(transformedNode); + transformFinallyDeepIndex(transformedNode, finallyDeepShift); return transformedNode; } @NotNull - protected MethodNode markPlacesForInlineAndRemoveInlinable(@NotNull MethodNode node) { - node = prepareNode(node); + protected MethodNode markPlacesForInlineAndRemoveInlinable(@NotNull MethodNode node, int finallyDeepShift) { + node = prepareNode(node, finallyDeepShift); Analyzer analyzer = new Analyzer(new SourceInterpreter()) { @NotNull @@ -395,6 +406,7 @@ public class MethodInliner { int index = 0; boolean awaitClassReification = false; + int currentFinallyDeep = 0; while (cur != null) { Frame frame = sources[index]; @@ -404,6 +416,11 @@ public class MethodInliner { awaitClassReification = true; } else if (cur.getType() == AbstractInsnNode.METHOD_INSN) { + if (InlineCodegenUtil.isFinallyStart(cur)) { + //TODO deep index calc could be more precise + currentFinallyDeep = InlineCodegenUtil.getConstant(cur.getPrevious()); + } + MethodInsnNode methodInsnNode = (MethodInsnNode) cur; String owner = methodInsnNode.owner; String desc = methodInsnNode.desc; @@ -426,7 +443,7 @@ public class MethodInliner { } } - invokeCalls.add(new InvokeCall(varIndex, lambdaInfo)); + invokeCalls.add(new InvokeCall(varIndex, lambdaInfo, currentFinallyDeep)); } else if (isAnonymousConstructorCall(owner, name)) { Map lambdaMapping = new HashMap(); @@ -585,6 +602,23 @@ public class MethodInliner { } } + private void transformFinallyDeepIndex(@NotNull MethodNode node, int finallyDeepShift) { + if (finallyDeepShift == 0) { + return; + } + + AbstractInsnNode cur = node.instructions.getFirst(); + while (cur != null) { + if (cur instanceof MethodInsnNode && InlineCodegenUtil.isFinallyMarker(cur)) { + AbstractInsnNode constant = cur.getPrevious(); + int curDeep = InlineCodegenUtil.getConstant(constant); + node.instructions.insert(constant, new LdcInsnNode(curDeep + finallyDeepShift)); + node.instructions.remove(constant); + } + cur = cur.getNext(); + } + } + @NotNull public static List getCapturedFieldAccessChain(@NotNull VarInsnNode aload0) { List fieldAccessChain = new ArrayList(); @@ -701,7 +735,8 @@ public class MethodInliner { //genetate finally block before nonLocalReturn flag/return/goto LabelNode label = new LabelNode(); instructions.insert(insnNode, label); - result.add(new PointForExternalFinallyBlocks(isLocalReturn ? insnNode : insnNode.getPrevious(), getReturnType(insnNode.getOpcode()), + result.add(new PointForExternalFinallyBlocks(getInstructionToInsertFinallyBefore(insnNode, isLocalReturn), + getReturnType(insnNode.getOpcode()), label)); } insnNode = insnNode.getNext(); @@ -709,6 +744,11 @@ public class MethodInliner { return result; } + @NotNull + private static AbstractInsnNode getInstructionToInsertFinallyBefore(@NotNull AbstractInsnNode nonLocalReturnOrJump, boolean isLocal) { + return isLocal ? nonLocalReturnOrJump : nonLocalReturnOrJump.getPrevious(); + } + //Place to insert finally blocks from try blocks that wraps inline fun call public static class PointForExternalFinallyBlocks { diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/callSiteComplex.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/callSiteComplex.1.kt new file mode 100644 index 00000000000..f9fa9820692 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/callSiteComplex.1.kt @@ -0,0 +1,94 @@ +import test.* +import Kind.* + +enum class Kind { + LOCAL + EXTERNAL + GLOBAL +} + +val FINALLY_CHAIN = "in local finally, in doCall finally, in external finally, in doCall finally, in global finally" + +class Internal(val value: String) + +class External(val value: String) + +class Global(val value: String) + +fun test1(intKind: Kind, extKind: Kind, holder: Holder): Global { + holder.value = "" + try { + var externalResult = doCall (ext@ { + try { + + val internalResult = doCall (int@ { + try { + if (intKind == Kind.GLOBAL) { + return@test1 Global("internal -> global") + } + else if (intKind == EXTERNAL) { + return@ext External("internal -> external") + } + return@int Internal("internal -> local") + } + finally { + holder.value += "in local finally" + } + }, holder) + + if (extKind == GLOBAL || extKind == EXTERNAL) { + return Global("external -> global") + } + + External(internalResult.value + ": external -> local"); + + } + finally { + holder.value += ", in external finally" + } + }, holder) + + return Global(externalResult.value + ": exit") + } + finally { + holder.value += ", in global finally" + } + + +} + +fun box(): String { + var holder = Holder() + + var test1 = test1(LOCAL, LOCAL, holder).value + if (holder.value != FINALLY_CHAIN || test1 != "internal -> local: external -> local: exit") return "test1: ${test1}, finally = ${holder.value}" + + test1 = test1(EXTERNAL, LOCAL, holder).value + if (holder.value != FINALLY_CHAIN || test1 != "internal -> external: exit") return "test2: ${test1}, finally = ${holder.value}" + + test1 = test1(GLOBAL, LOCAL, holder).value + if (holder.value != FINALLY_CHAIN || test1 != "internal -> global") return "test3: ${test1}, finally = ${holder.value}" + + + test1 = test1(LOCAL, EXTERNAL, holder).value + if (holder.value != FINALLY_CHAIN || test1 != "external -> global") return "test4: ${test1}, finally = ${holder.value}" + + test1 = test1(EXTERNAL, EXTERNAL, holder).value + if (holder.value != FINALLY_CHAIN || test1 != "internal -> external: exit") return "test5: ${test1}, finally = ${holder.value}" + + test1 = test1(GLOBAL, EXTERNAL, holder).value + if (holder.value != FINALLY_CHAIN || test1 != "internal -> global") return "test6: ${test1}, finally = ${holder.value}" + + + test1 = test1(LOCAL, GLOBAL, holder).value + if (holder.value != FINALLY_CHAIN || test1 != "external -> global") return "test7: ${test1}, finally = ${holder.value}" + + test1 = test1(EXTERNAL, GLOBAL, holder).value + if (holder.value != FINALLY_CHAIN || test1 != "internal -> external: exit") return "test8: ${test1}, finally = ${holder.value}" + + test1 = test1(GLOBAL, GLOBAL, holder).value + if (holder.value != FINALLY_CHAIN || test1 != "internal -> global") return "test9: ${test1}, finally = ${holder.value}" + + + return "OK" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/callSiteComplex.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/callSiteComplex.2.kt new file mode 100644 index 00000000000..57acd9c0a8f --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/callSiteComplex.2.kt @@ -0,0 +1,13 @@ +package test + +class Holder { + var value: String = "" +} + +inline fun doCall(block: ()-> R, h: Holder) : R { + try { + return block() + } finally { + h.value += ", in doCall finally" + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/finallyInFinally.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/finallyInFinally.1.kt new file mode 100644 index 00000000000..a8bcadcffba --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/finallyInFinally.1.kt @@ -0,0 +1,69 @@ +import test.* + +class Holder { + var value: String = "" +} + + +fun test1(h: Holder, doReturn: Int): String { + doCall ( + { + if (doReturn < 1) { + h.value += "OK_NONLOCAL" + return "OK_NONLOCAL" + } + h.value += "LOCAL" + "OK_LOCAL" + }, + { + h.value += ", OF_FINALLY1" + return "OF_FINALLY1" + } + ) + + return "LOCAL"; +} + + +fun test2(h: Holder, doReturn: Int): String { + doCall ( + { + if (doReturn < 1) { + h.value += "OK_NONLOCAL" + return "OK_NONLOCAL" + } + h.value += "LOCAL" + "OK_LOCAL" + }, + { + try { + h.value += ", OF_FINALLY1" + return "OF_FINALLY1" + } finally { + h.value += ", OF_FINALLY1_FINALLY" + } + } + ) + + return "FAIL"; +} + +fun box(): String { + var h = Holder() + val test10 = test1(h, 0) + if (test10 != "OF_FINALLY1" || h.value != "OK_NONLOCAL, OF_FINALLY1") return "test10: ${test10}, holder: ${h.value}" + + h = Holder() + val test11 = test1(h, 1) + if (test11 != "OF_FINALLY1" || h.value != "LOCAL, OF_FINALLY1") return "test11: ${test11}, holder: ${h.value}" + + h = Holder() + val test2 = test2(h, 0) + if (test2 != "OF_FINALLY1" || h.value != "OK_NONLOCAL, OF_FINALLY1, OF_FINALLY1_FINALLY") return "test20: ${test2}, holder: ${h.value}" + + h = Holder() + val test21 = test2(h, 1) + if (test21 != "OF_FINALLY1" || h.value != "LOCAL, OF_FINALLY1, OF_FINALLY1_FINALLY") return "test21: ${test21}, holder: ${h.value}" + + return "OK" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/finallyInFinally.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/finallyInFinally.2.kt new file mode 100644 index 00000000000..a8e1b0fd426 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/finallyInFinally.2.kt @@ -0,0 +1,9 @@ +package test + +public inline fun doCall(block: ()-> Unit, finallyBlock1: ()-> Unit) { + try { + block() + } finally { + finallyBlock1() + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/finallyInFinally.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/finallyInFinally.1.kt new file mode 100644 index 00000000000..bcfcc3be977 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/finallyInFinally.1.kt @@ -0,0 +1,53 @@ +import test.* + +fun test1(h: Holder, doReturn: Int): String { + doCall_1 ( + { + if (doReturn < 1) { + h.value += "OK_NONLOCAL" + return "OK_NONLOCAL" + } + h.value += "LOCAL" + "OK_LOCAL" + }, + h + ) + + return "TEST1"; +} + +fun test2(h: Holder, doReturn: Int): String { + doCall_2 ( + { + if (doReturn < 1) { + h.value += "OK_NONLOCAL" + return "OK_NONLOCAL" + } + h.value += "LOCAL" + "OK_LOCAL" + }, + h + ) + + return "TEST2"; +} + +fun box(): String { + var h = Holder() + val test10 = test1(h, 0) + if (test10 != "TEST1" || h.value != "OK_NONLOCAL, OF_FINALLY1, DO_CALL_1_FINALLY") return "test10: ${test10}, holder: ${h.value}" + + h = Holder() + val test11 = test1(h, 1) + if (test11 != "TEST1" || h.value != "LOCAL, OF_FINALLY1, DO_CALL_1_FINALLY") return "test11: ${test11}, holder: ${h.value}" + + h = Holder() + val test2 = test2(h, 0) + if (test2 != "TEST2" || h.value != "OK_NONLOCAL, OF_FINALLY1, OF_FINALLY1_FINALLY, DO_CALL_1_FINALLY") return "test20: ${test2}, holder: ${h.value}" + + h = Holder() + val test21 = test2(h, 1) + if (test21 != "TEST2" || h.value != "LOCAL, OF_FINALLY1, OF_FINALLY1_FINALLY, DO_CALL_1_FINALLY") return "test21: ${test21}, holder: ${h.value}" + + return "OK" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/finallyInFinally.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/finallyInFinally.2.kt new file mode 100644 index 00000000000..6ddaaa09276 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/finallyInFinally.2.kt @@ -0,0 +1,40 @@ +package test + +class Holder { + var value: String = "" +} + +inline fun doCall_1(block: ()-> Unit, h: Holder) { + try { + doCall(block) { + h.value += ", OF_FINALLY1" + return + } + } finally { + h.value += ", DO_CALL_1_FINALLY" + } +} + +inline fun doCall_2(block: ()-> Unit, h: Holder) { + try { + doCall(block) { + try { + h.value += ", OF_FINALLY1" + return + } + finally { + h.value += ", OF_FINALLY1_FINALLY" + } + } + } finally { + h.value += ", DO_CALL_1_FINALLY" + } +} + +inline fun doCall(block: ()-> Unit, finallyBlock1: ()-> Unit) { + try { + block() + } finally { + finallyBlock1() + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/finallyInFinally2.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/finallyInFinally2.1.kt new file mode 100644 index 00000000000..870851ced5f --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/finallyInFinally2.1.kt @@ -0,0 +1,53 @@ +import test.* + +fun test1(h: Holder, doReturn: Int): String { + doCall_1 ( + { + if (doReturn < 1) { + h.value += "OK_NONLOCAL" + return "OK_NONLOCAL" + } + h.value += "LOCAL" + "OK_LOCAL" + }, + h + ) + + return "TEST1"; +} + +fun test2(h: Holder, doReturn: Int): String { + doCall_2 ( + { + if (doReturn < 1) { + h.value += "OK_NONLOCAL" + return "OK_NONLOCAL" + } + h.value += "LOCAL" + "OK_LOCAL" + }, + h + ) + + return "TEST2"; +} + +fun box(): String { + var h = Holder() + val test10 = test1(h, 0) + if (test10 != "OK_NONLOCAL" || h.value != "OK_NONLOCAL, OF_FINALLY1, DO_CALL_1_FINALLY") return "test10: ${test10}, holder: ${h.value}" + + h = Holder() + val test11 = test1(h, 1) + if (test11 != "TEST1" || h.value != "LOCAL, OF_FINALLY1, DO_CALL_1_FINALLY") return "test11: ${test11}, holder: ${h.value}" + + h = Holder() + val test2 = test2(h, 0) + if (test2 != "OK_NONLOCAL" || h.value != "OK_NONLOCAL, OF_FINALLY1, OF_FINALLY1_FINALLY, DO_CALL_1_FINALLY") return "test20: ${test2}, holder: ${h.value}" + + h = Holder() + val test21 = test2(h, 1) + if (test21 != "TEST2" || h.value != "LOCAL, OF_FINALLY1, OF_FINALLY1_FINALLY, DO_CALL_1_FINALLY") return "test21: ${test21}, holder: ${h.value}" + + return "OK" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/finallyInFinally2.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/finallyInFinally2.2.kt new file mode 100644 index 00000000000..68bc35262cc --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/finallyInFinally2.2.kt @@ -0,0 +1,38 @@ +package test + +class Holder { + var value: String = "" +} + +inline fun doCall_1(block: ()-> Unit, h: Holder) { + try { + doCall(block) { + h.value += ", OF_FINALLY1" + } + } finally { + h.value += ", DO_CALL_1_FINALLY" + } +} + +inline fun doCall_2(block: ()-> Unit, h: Holder) { + try { + doCall(block) { + try { + h.value += ", OF_FINALLY1" + } + finally { + h.value += ", OF_FINALLY1_FINALLY" + } + } + } finally { + h.value += ", DO_CALL_1_FINALLY" + } +} + +inline fun doCall(block: ()-> Unit, finallyBlock1: ()-> Unit) { + try { + block() + } finally { + finallyBlock1() + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturn.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturn.1.kt new file mode 100644 index 00000000000..a525517486f --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturn.1.kt @@ -0,0 +1,30 @@ +import test.* + + +fun test0(h: Holder, throwException: Boolean): Int { + val localResult = doCall2_2 ( + { + h.value += "OK_NONLOCAL" + if (throwException) { + throw java.lang.RuntimeException() + } + return 1 + }, + "FAIL", + h + ) + + return -1; +} + +fun box(): String { + var h = Holder() + val test0 = test0(h, true) + if (test0 != -1 || h.value != "OK_NONLOCAL, OK_EXCEPTION, OK_FINALLY") return "test0: ${test0}, holder: ${h.value}" + + h = Holder() + val test1 = test0(h, false) + if (test1 != 1 || h.value != "OK_NONLOCAL, OK_FINALLY") return "test1: ${test1}, holder: ${h.value}" + + return "OK" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturn.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturn.2.kt new file mode 100644 index 00000000000..17de22a90b1 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturn.2.kt @@ -0,0 +1,32 @@ +package test + +public class Holder { + public var value: String = "" +} + +public inline fun doCall2_2(block: () -> R, res: R, h: Holder): R { + return doCall2_1(block, { + h.value += ", OK_EXCEPTION" + "OK_EXCEPTION" + }, res, h) +} + +public inline fun doCall2_1(block: () -> R, exception: (e: Exception) -> Unit, res: R, h: Holder): R { + return doCall2(block, exception, { + h.value += ", OK_FINALLY" + "OK_FINALLY" + }, res) +} + +public inline fun doCall2(block: () -> R, exception: (e: Exception) -> Unit, finallyBlock: () -> Unit, res: R): R { + try { + return block() + } + catch (e: Exception) { + exception(e) + } + finally { + finallyBlock() + } + return res +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex.1.kt new file mode 100644 index 00000000000..6d5ad3e8b06 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex.1.kt @@ -0,0 +1,30 @@ +import test.* + + +fun test0(h: Holder, throwException: Boolean): Int { + val localResult = doCall2_2 ( + { + h.value += "OK_NONLOCAL" + if (throwException) { + throw java.lang.RuntimeException() + } + return 1 + }, + "FAIL", + h + ) + + return -1; +} + +fun box(): String { + var h = Holder() + val test0 = test0(h, true) + if (test0 != -1 || h.value != "OK_NONLOCAL, OK_EXCEPTION, OK_FINALLY, DO_CALL_2_FINALLY") return "test0: ${test0}, holder: ${h.value}" + + h = Holder() + val test1 = test0(h, false) + if (test1 != 1 || h.value != "OK_NONLOCAL, OK_FINALLY, DO_CALL_2_FINALLY") return "test1: ${test1}, holder: ${h.value}" + + return "OK" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex.2.kt new file mode 100644 index 00000000000..bb41944b577 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex.2.kt @@ -0,0 +1,36 @@ +package test + +public class Holder { + public var value: String = "" +} + +public inline fun doCall2_2(block: () -> R, res: R, h: Holder): R { + return doCall2_1(block, { + h.value += ", OK_EXCEPTION" + "OK_EXCEPTION" + }, res, h) +} + +public inline fun doCall2_1(block: () -> R, exception: (e: Exception) -> Unit, res: R, h: Holder): R { + return doCall2(block, exception, { + h.value += ", OK_FINALLY" + "OK_FINALLY" + }, res, h) +} + +public inline fun doCall2(block: () -> R, exception: (e: Exception) -> Unit, finallyBlock: () -> Unit, res: R, h: Holder): R { + try { + try { + return block() + } + catch (e: Exception) { + exception(e) + } + finally { + finallyBlock() + } + } finally { + h.value += ", DO_CALL_2_FINALLY" + } + return res +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex2.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex2.1.kt new file mode 100644 index 00000000000..af2903eecc4 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex2.1.kt @@ -0,0 +1,30 @@ +import test.* + + +fun test0(h: Holder, throwException: Boolean): Int { + val localResult = doCall2_2 ( + { + h.value += "OK_NONLOCAL" + if (throwException) { + throw java.lang.RuntimeException() + } + return 1 + }, + "FAIL", + h + ) + + return -1; +} + +fun box(): String { + var h = Holder() + val test0 = test0(h, true) + if (test0 != -1 || h.value != "OK_NONLOCAL, OK_EXCEPTION, OK_FINALLY, DO_CALL_2_FINALLY, DO_CALL_2_1_FINALLY, DO_CALL_2_2_FINALLY") return "test0: ${test0}, holder: ${h.value}" + + h = Holder() + val test1 = test0(h, false) + if (test1 != 1 || h.value != "OK_NONLOCAL, OK_FINALLY, DO_CALL_2_FINALLY, DO_CALL_2_1_FINALLY, DO_CALL_2_2_FINALLY") return "test1: ${test1}, holder: ${h.value}" + + return "OK" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex2.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex2.2.kt new file mode 100644 index 00000000000..0bb63b2c465 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex2.2.kt @@ -0,0 +1,44 @@ +package test + +public class Holder { + public var value: String = "" +} + +public inline fun doCall2_2(block: () -> R, res: R, h: Holder): R { + try { + return doCall2_1(block, { + h.value += ", OK_EXCEPTION" + "OK_EXCEPTION" + }, res, h) + } finally{ + h.value += ", DO_CALL_2_2_FINALLY" + } +} + +public inline fun doCall2_1(block: () -> R, exception: (e: Exception) -> Unit, res: R, h: Holder): R { + try { + return doCall2(block, exception, { + h.value += ", OK_FINALLY" + "OK_FINALLY" + }, res, h) + } finally { + h.value += ", DO_CALL_2_1_FINALLY" + } +} + +public inline fun doCall2(block: () -> R, exception: (e: Exception) -> Unit, finallyBlock: () -> Unit, res: R, h: Holder): R { + try { + try { + return block() + } + catch (e: Exception) { + exception(e) + } + finally { + finallyBlock() + } + } finally { + h.value += ", DO_CALL_2_FINALLY" + } + return res +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex3.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex3.1.kt new file mode 100644 index 00000000000..1f5af18cd38 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex3.1.kt @@ -0,0 +1,34 @@ +import test.* + + +fun test0(h: Holder, throwException: Boolean): Int { + val localResult = doCall2_2 ( + { + h.value += "OK_NONLOCAL" + if (throwException) { + throw java.lang.RuntimeException() + } + return 1 + }, + "FAIL", + h + ) + + return -1; +} + +fun box(): String { + var h = Holder() + val test0 = test0(h, true) + if (test0 != -1 || h.value != "OK_NONLOCAL, OK_EXCEPTION, OK_FINALLY, DO_CALL_2_FINALLY, DO_CALL_2_1_FINALLY, DO_CALL_2_2_FINALLY") + return "test0: ${test0}, holder: ${h.value}" + + h = Holder() + val test1 = test0(h, false) + if (test1 != 1 || h.value != "OK_NONLOCAL, OK_FINALLY, DO_CALL_2_FINALLY, DO_CALL_2_1_FINALLY, DO_CALL_2_2_FINALLY") + return "test1: ${test1}, holder: ${h.value}" + + return "OK" +} + + diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex3.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex3.2.kt new file mode 100644 index 00000000000..548ea14c1fb --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex3.2.kt @@ -0,0 +1,44 @@ +package test + +public class Holder { + public var value: String = "" +} + +public inline fun doCall2_2(block: () -> String, res: String, h: Holder): String { + try { + return doCall2_1(block, { + h.value += ", OK_EXCEPTION" + return "OK_EXCEPTION" + }, res, h) + } finally{ + h.value += ", DO_CALL_2_2_FINALLY" + } +} + +public inline fun doCall2_1(block: () -> R, exception: (e: Exception) -> Unit, res: R, h: Holder): R { + try { + return doCall2(block, exception, { + h.value += ", OK_FINALLY" + "OK_FINALLY" + }, res, h) + } finally { + h.value += ", DO_CALL_2_1_FINALLY" + } +} + +public inline fun doCall2(block: () -> R, exception: (e: Exception) -> Unit, finallyBlock: () -> Unit, res: R, h: Holder): R { + try { + try { + return block() + } + catch (e: Exception) { + exception(e) + } + finally { + finallyBlock() + } + } finally { + h.value += ", DO_CALL_2_FINALLY" + } + return res +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex4.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex4.1.kt new file mode 100644 index 00000000000..b2dbc91e39f --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex4.1.kt @@ -0,0 +1,34 @@ +import test.* + + +fun test0(h: Holder, throwException: Boolean): Int { + val localResult = doCall2_2 ( + { + h.value += "OK_NONLOCAL" + if (throwException) { + throw java.lang.RuntimeException() + } + return 1 + }, + "FAIL", + h + ) + + return -1; +} + + +fun box(): String { + var h = Holder() + val test0 = test0(h, true) + + if (test0 != -1 || h.value != "OK_NONLOCAL, OK_EXCEPTION, OK_FINALLY, OK_FINALLY_NESTED, DO_CALL_2_FINALLY, DO_CALL_2_1_FINALLY, DO_CALL_2_2_FINALLY") return "test0: ${test0}, holder: ${h.value}" + + h = Holder() + val test1 = test0(h, false) + if (test1 != 1 || h.value != "OK_NONLOCAL, OK_FINALLY, OK_FINALLY_NESTED, DO_CALL_2_FINALLY, DO_CALL_2_1_FINALLY, DO_CALL_2_2_FINALLY") return "test1: ${test1}, holder: ${h.value}" + + return "OK" +} + + diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex4.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex4.2.kt new file mode 100644 index 00000000000..1155a4cc47c --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex4.2.kt @@ -0,0 +1,48 @@ +package test + +public class Holder { + public var value: String = "" +} + +public inline fun doCall2_2(block: () -> String, res: String, h: Holder): String { + try { + return doCall2_1(block, { + h.value += ", OK_EXCEPTION" + return "OK_EXCEPTION" + }, res, h) + } finally{ + h.value += ", DO_CALL_2_2_FINALLY" + } +} + +public inline fun doCall2_1(block: () -> R, exception: (e: Exception) -> Unit, res: R, h: Holder): R { + try { + return doCall2(block, exception, { + try { + h.value += ", OK_FINALLY" + "OK_FINALLY" + } finally { + h.value += ", OK_FINALLY_NESTED" + } + }, res, h) + } finally { + h.value += ", DO_CALL_2_1_FINALLY" + } +} + +public inline fun doCall2(block: () -> R, exception: (e: Exception) -> Unit, finallyBlock: () -> Unit, res: R, h: Holder): R { + try { + try { + return block() + } + catch (e: Exception) { + exception(e) + } + finally { + finallyBlock() + } + } finally { + h.value += ", DO_CALL_2_FINALLY" + } + return res +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/nestedLambda.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/nestedLambda.1.kt new file mode 100644 index 00000000000..dddbcde969c --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/nestedLambda.1.kt @@ -0,0 +1,68 @@ +import test.* + +val FINALLY_CHAIN = "in local finally, in doCall finally, in external finally, in doCall finally, in global finally" + +fun test1(holder: Holder, p: Int): String { + holder.value = "start" + return test2(holder) { i -> + if (p == i) { + return "call $i" + } + } +} + +inline fun test2(holder: Holder, l: (s: Int) -> Unit): String { + try { + l(0) + var externalResult = doCall (ext@ { + l(1) + try { + l(2) + val internalResult = doCall (int@ { + l(3) + try { + l(4) + return "fail" + } + finally { + holder.value += ", in local finally" + } + }, holder) + } + finally { + holder.value += ", in external finally" + } + }, holder) + + return "fail" + } + finally { + holder.value += ", in global finally" + } +} + +fun box(): String { + var holder = Holder() + + var test1 = test1(holder, 0) + if (holder.value != "start, in global finally" || test1 != "call 0") return "test1: ${test1}, finally = ${holder.value}" + + test1 = test1(holder, 1) + if (holder.value != "start, in doCall finally, in global finally" || test1 != "call 1") + return "test2: ${test1}, finally = ${holder.value}" + + test1 = test1(holder, 2) + if (holder.value != "start, in external finally, in doCall finally, in global finally" || test1 != "call 2") + return "test3: ${test1}, finally = ${holder.value}" + + + test1 = test1(holder, 3) + if (holder.value != "start, in doCall finally, in external finally, in doCall finally, in global finally" || test1 != "call 3") + return "test4: ${test1}, finally = ${holder.value}" + + test1 = test1(holder, 4) + if (holder.value != "start, in local finally, in doCall finally, in external finally, in doCall finally, in global finally" || test1 != "call 4") + return "test5: ${test1}, finally = ${holder.value}" + + return "OK" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/nestedLambda.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/nestedLambda.2.kt new file mode 100644 index 00000000000..57acd9c0a8f --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/nestedLambda.2.kt @@ -0,0 +1,13 @@ +package test + +class Holder { + var value: String = "" +} + +inline fun doCall(block: ()-> R, h: Holder) : R { + try { + return block() + } finally { + h.value += ", in doCall finally" + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/intReturnComplex.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/intReturnComplex.1.kt new file mode 100644 index 00000000000..9dfa097b028 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/intReturnComplex.1.kt @@ -0,0 +1,127 @@ +import test.* + + + +fun test0(h: Holder): Int { + val localResult = doCall2 ( + { + h.value += "OK_NONLOCAL" + if (true) { + throw java.lang.RuntimeException() + } + return 1 + }, + { + h.value += ", OK_EXCEPTION" + return 2 + }, + { + h.value += ", OK_FINALLY" + "OK_FINALLY" + }, "FAIL", h) + + return -1; +} + +fun test1(h: Holder): Int { + val localResult = doCall2 ( + { + h.value += "OK_NONLOCAL" + return 1 + }, + { + h.value += ", OK_EXCEPTION" + "OK_EXCEPTION" + }, + { + h.value += ", OK_FINALLY" + "OK_FINALLY" + }, "FAIL", h) + + return -1; +} + +fun test2(h: Holder): String { + val localResult = doCall ( + { + h.value += "OK_NONLOCAL" + return "OK_NONLOCAL" + }, + { + h.value += ", OK_EXCEPTION" + 2 + }, + { + h.value += ", OK_FINALLY" + 3 + }, h) + + return "" + localResult; +} + +fun test3(h: Holder): String { + val localResult = doCall ( + { + h.value += "OK_NONLOCAL" + if (true) { + throw java.lang.RuntimeException() + } + return "OK_NONLOCAL" + }, + { + h.value += ", OK_EXCEPTION" + return "OK_EXCEPTION" + }, + { + h.value += ", OK_FINALLY" + 3 + }, h) + + return "" + localResult; +} + +fun test4(h: Holder): String { + val localResult = doCall ( + { + h.value += "OK_NONLOCAL" + if (true) { + throw java.lang.RuntimeException() + } + h.value += "fail" + return "OK_NONLOCAL" + }, + { + h.value += ", OK_EXCEPTION" + return "OK_EXCEPTION" + }, + { + h.value += ", OK_FINALLY" + return "OK_FINALLY" + }, h) + + return "" + localResult; +} + +fun box(): String { + var h = Holder() + val test0 = test0(h) + if (test0 != 2 || h.value != "OK_NONLOCAL, OK_EXCEPTION, OK_FINALLY, INLINE_CALL_FINALLY") return "test0: ${test0}, holder: ${h.value}" + + h = Holder() + val test1 = test1(h) + if (test1 != 1 || h.value != "OK_NONLOCAL, OK_FINALLY, INLINE_CALL_FINALLY") return "test1: ${test1}, holder: ${h.value}" + + h = Holder() + val test2 = test2(h) + if (test2 != "OK_NONLOCAL" || h.value != "OK_NONLOCAL, OK_FINALLY, INLINE_CALL_FINALLY") return "test2: ${test2}, holder: ${h.value}" + + h = Holder() + val test3 = test3(h) + if (test3 != "OK_EXCEPTION" || h.value != "OK_NONLOCAL, OK_EXCEPTION, OK_FINALLY, INLINE_CALL_FINALLY") return "test3: ${test3}, holder: ${h.value}" + + h = Holder() + val test4 = test4(h) + if (test4 != "OK_FINALLY" || h.value != "OK_NONLOCAL, OK_EXCEPTION, OK_FINALLY, INLINE_CALL_FINALLY") return "test4: ${test4}, holder: ${h.value}" + + return "OK" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/intReturnComplex.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/intReturnComplex.2.kt new file mode 100644 index 00000000000..bdff0c06fbc --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/intReturnComplex.2.kt @@ -0,0 +1,39 @@ +package test + +public class Holder { + public var value: String = "" +} + +public inline fun doCall(block: ()-> Int, exception: (e: Exception)-> Unit, finallyBlock: ()-> Int, h : Holder, res: Int = -111) : Int { + try { + try { + return block() + } + catch (e: Exception) { + exception(e) + } + finally { + finallyBlock() + } + } finally { + h.value += ", INLINE_CALL_FINALLY" + } + return res +} + +public inline fun doCall2(block: ()-> R, exception: (e: Exception)-> Unit, finallyBlock: ()-> R, res: R, h : Holder) : R { + try { + try { + return block() + } + catch (e: Exception) { + exception(e) + } + finally { + finallyBlock() + } + } finally { + h.value += ", INLINE_CALL_FINALLY" + } + return res +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/severalInTry.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/severalInTry.1.kt new file mode 100644 index 00000000000..dec671397b8 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/severalInTry.1.kt @@ -0,0 +1,75 @@ +import test.* + +class Holder { + var value: String = "" +} + + +fun test1(h: Holder, doReturn: Int): String { + doCall ( + { + if (doReturn < 1) { + h.value += "OK_NONLOCAL" + return "OK_NONLOCAL" + } + h.value += "LOCAL" + "OK_LOCAL" + }, + { + h.value += ", OK_NONLOCAL2" + return "OK_NONLOCAL2" + }, + { + h.value += ", OK_FINALLY" + } + ) + + return "LOCAL"; +} + + +fun test2(h: Holder, doReturn: Int): String { + doCall ( + { + if (doReturn < 1) { + h.value += "OK_NONLOCAL" + return "OK_NONLOCAL" + } + h.value += "LOCAL" + "OK_LOCAL" + }, + { + try { + h.value += ", OK_NONLOCAL2" + return "OK_NONLOCAL2" + } finally { + h.value += ", OK_NONLOCAL2_FINALLY" + } + }, + { + h.value += ", OK_FINALLY" + } + ) + + return "FAIL"; +} + +fun box(): String { + var h = Holder() + val test10 = test1(h, 0) + if (test10 != "OK_NONLOCAL" || h.value != "OK_NONLOCAL, OK_FINALLY") return "test10: ${test10}, holder: ${h.value}" + + h = Holder() + val test11 = test1(h, 1) + if (test11 != "OK_NONLOCAL2" || h.value != "LOCAL, OK_NONLOCAL2, OK_FINALLY") return "test11: ${test11}, holder: ${h.value}" + + h = Holder() + val test2 = test2(h, 0) + if (test2 != "OK_NONLOCAL" || h.value != "OK_NONLOCAL, OK_FINALLY") return "test20: ${test2}, holder: ${h.value}" + + h = Holder() + val test21 = test2(h, 1) + if (test21 != "OK_NONLOCAL2" || h.value != "LOCAL, OK_NONLOCAL2, OK_NONLOCAL2_FINALLY, OK_FINALLY") return "test21: ${test21}, holder: ${h.value}" + + return "OK" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/severalInTry.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/severalInTry.2.kt new file mode 100644 index 00000000000..c1f9c28949a --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/severalInTry.2.kt @@ -0,0 +1,10 @@ +package test + +public inline fun doCall(block: ()-> Unit, block2: ()-> Unit, finallyBlock2: ()-> Unit) { + try { + block() + block2() + } finally { + finallyBlock2() + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/severalInTryComplex.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/severalInTryComplex.1.kt new file mode 100644 index 00000000000..ab27272abb9 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/severalInTryComplex.1.kt @@ -0,0 +1,72 @@ +import test.* + +fun test1(h: Holder, doReturn: Int): String { + doCall ( + { + if (doReturn < 1) { + h.value += "OK_NONLOCAL" + return "OK_NONLOCAL" + } + h.value += "LOCAL" + "OK_LOCAL" + }, + { + h.value += ", OK_NONLOCAL2" + return "OK_NONLOCAL2" + }, + { + h.value += ", OK_FINALLY" + }, + h + ) + + return "LOCAL"; +} + + +fun test2(h: Holder, doReturn: Int): String { + doCall ( + { + if (doReturn < 1) { + h.value += "OK_NONLOCAL" + return "OK_NONLOCAL" + } + h.value += "LOCAL" + "OK_LOCAL" + }, + { + try { + h.value += ", OK_NONLOCAL2" + return "OK_NONLOCAL2" + } finally { + h.value += ", OK_NONLOCAL2_FINALLY" + } + }, + { + h.value += ", OK_FINALLY" + }, + h + ) + + return "FAIL"; +} + +fun box(): String { + var h = Holder() + val test10 = test1(h, 0) + if (test10 != "OK_NONLOCAL" || h.value != "OK_NONLOCAL, OK_FINALLY, DO_CALL_EXT_FINALLY") return "test10: ${test10}, holder: ${h.value}" + + h = Holder() + val test11 = test1(h, 1) + if (test11 != "OK_NONLOCAL2" || h.value != "LOCAL, OK_NONLOCAL2, OK_FINALLY, DO_CALL_EXT_FINALLY") return "test11: ${test11}, holder: ${h.value}" + + h = Holder() + val test2 = test2(h, 0) + if (test2 != "OK_NONLOCAL" || h.value != "OK_NONLOCAL, OK_FINALLY, DO_CALL_EXT_FINALLY") return "test20: ${test2}, holder: ${h.value}" + + h = Holder() + val test21 = test2(h, 1) + if (test21 != "OK_NONLOCAL2" || h.value != "LOCAL, OK_NONLOCAL2, OK_NONLOCAL2_FINALLY, OK_FINALLY, DO_CALL_EXT_FINALLY") return "test21: ${test21}, holder: ${h.value}" + + return "OK" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/severalInTryComplex.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/severalInTryComplex.2.kt new file mode 100644 index 00000000000..79866ead52b --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/severalInTryComplex.2.kt @@ -0,0 +1,19 @@ +package test + +class Holder { + var value: String = "" +} + +inline fun doCall(block: ()-> Unit, block2: ()-> Unit, finallyBlock2: ()-> Unit, res: Holder) { + try { + try { + block() + block2() + } + finally { + finallyBlock2() + } + } finally { + res.value += ", DO_CALL_EXT_FINALLY" + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt6956.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt6956.1.kt new file mode 100644 index 00000000000..74cc23ecbff --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt6956.1.kt @@ -0,0 +1,19 @@ +import test.* + +inline fun bar(arg: String, action: () -> T) { + try { + action() + } finally { + arg.length() + } +} + +fun box(): String { + foo() { + bar("") { + return "OK" + } + } + + return "fail" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt6956.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt6956.2.kt new file mode 100644 index 00000000000..cfce790625d --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt6956.2.kt @@ -0,0 +1,13 @@ +package test + +inline fun baz(x: Int) {} + +inline fun foo(action: () -> T): T { + baz(0) + try { + return action() + } finally { + baz(1) + } +} + diff --git a/compiler/testData/codegen/bytecodeText/inline/notSplitedExceptionTable.kt b/compiler/testData/codegen/bytecodeText/inline/notSplitedExceptionTable.kt index ec2c5e98108..140c199c4ec 100644 --- a/compiler/testData/codegen/bytecodeText/inline/notSplitedExceptionTable.kt +++ b/compiler/testData/codegen/bytecodeText/inline/notSplitedExceptionTable.kt @@ -25,4 +25,4 @@ fun box() : String { return "fail" } -// 10 TRYCATCHBLOCK \ No newline at end of file +// 8 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 index 7fca76a49d6..6d1d15a047e 100644 --- a/compiler/testData/codegen/bytecodeText/inline/splitedExceptionTable.kt +++ b/compiler/testData/codegen/bytecodeText/inline/splitedExceptionTable.kt @@ -24,6 +24,5 @@ fun box() : String { } return "fail" } - -// maybe we should check test data -// 13 TRYCATCHBLOCK +/* 8 + 1 see notSplitedExceptionTable.kt*/ +// 9 TRYCATCHBLOCK diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java index 290c6642849..c9b132e29d0 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java @@ -558,6 +558,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally"), Pattern.compile("^(.+)\\.1.kt$"), true); } + @TestMetadata("kt6956.1.kt") + public void testKt6956() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt6956.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + @TestMetadata("kt7273.1.kt") public void testKt7273() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt7273.1.kt"); @@ -584,6 +590,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo doTestMultiFileWithInlineCheck(fileName); } + @TestMetadata("callSiteComplex.1.kt") + public void testCallSiteComplex() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/callSiteComplex.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + @TestMetadata("exceptionTableSplit.1.kt") public void testExceptionTableSplit() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/exceptionTableSplit.1.kt"); @@ -595,6 +607,69 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/exceptionTableSplitNoReturn.1.kt"); doTestMultiFileWithInlineCheck(fileName); } + + @TestMetadata("finallyInFinally.1.kt") + public void testFinallyInFinally() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/finallyInFinally.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + } + + @TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Chained extends AbstractBlackBoxInlineCodegenTest { + public void testAllFilesPresentInChained() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained"), Pattern.compile("^(.+)\\.1.kt$"), true); + } + + @TestMetadata("finallyInFinally.1.kt") + public void testFinallyInFinally() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/finallyInFinally.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + + @TestMetadata("finallyInFinally2.1.kt") + public void testFinallyInFinally2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/finallyInFinally2.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + + @TestMetadata("intReturn.1.kt") + public void testIntReturn() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturn.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + + @TestMetadata("intReturnComplex.1.kt") + public void testIntReturnComplex() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + + @TestMetadata("intReturnComplex2.1.kt") + public void testIntReturnComplex2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex2.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + + @TestMetadata("intReturnComplex3.1.kt") + public void testIntReturnComplex3() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex3.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + + @TestMetadata("intReturnComplex4.1.kt") + public void testIntReturnComplex4() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex4.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + + @TestMetadata("nestedLambda.1.kt") + public void testNestedLambda() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/nestedLambda.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } } @TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite") @@ -617,6 +692,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo doTestMultiFileWithInlineCheck(fileName); } + @TestMetadata("intReturnComplex.1.kt") + public void testIntReturnComplex() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/intReturnComplex.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + @TestMetadata("longReturn.1.kt") public void testLongReturn() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/longReturn.1.kt"); @@ -647,6 +728,18 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo doTestMultiFileWithInlineCheck(fileName); } + @TestMetadata("severalInTry.1.kt") + public void testSeveralInTry() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/severalInTry.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + + @TestMetadata("severalInTryComplex.1.kt") + public void testSeveralInTryComplex() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/severalInTryComplex.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + @TestMetadata("voidInlineFun.1.kt") public void testVoidInlineFun() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/voidInlineFun.1.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java index 0e80b6a696a..9b55099e8f8 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -558,6 +558,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally"), Pattern.compile("^(.+)\\.1.kt$"), true); } + @TestMetadata("kt6956.1.kt") + public void testKt6956() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt6956.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + @TestMetadata("kt7273.1.kt") public void testKt7273() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt7273.1.kt"); @@ -584,6 +590,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi doBoxTestWithInlineCheck(fileName); } + @TestMetadata("callSiteComplex.1.kt") + public void testCallSiteComplex() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/callSiteComplex.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + @TestMetadata("exceptionTableSplit.1.kt") public void testExceptionTableSplit() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/exceptionTableSplit.1.kt"); @@ -595,6 +607,69 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/exceptionTableSplitNoReturn.1.kt"); doBoxTestWithInlineCheck(fileName); } + + @TestMetadata("finallyInFinally.1.kt") + public void testFinallyInFinally() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/finallyInFinally.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + } + + @TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Chained extends AbstractCompileKotlinAgainstInlineKotlinTest { + public void testAllFilesPresentInChained() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained"), Pattern.compile("^(.+)\\.1.kt$"), true); + } + + @TestMetadata("finallyInFinally.1.kt") + public void testFinallyInFinally() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/finallyInFinally.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + + @TestMetadata("finallyInFinally2.1.kt") + public void testFinallyInFinally2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/finallyInFinally2.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + + @TestMetadata("intReturn.1.kt") + public void testIntReturn() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturn.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + + @TestMetadata("intReturnComplex.1.kt") + public void testIntReturnComplex() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + + @TestMetadata("intReturnComplex2.1.kt") + public void testIntReturnComplex2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex2.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + + @TestMetadata("intReturnComplex3.1.kt") + public void testIntReturnComplex3() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex3.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + + @TestMetadata("intReturnComplex4.1.kt") + public void testIntReturnComplex4() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/intReturnComplex4.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + + @TestMetadata("nestedLambda.1.kt") + public void testNestedLambda() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/chained/nestedLambda.1.kt"); + doBoxTestWithInlineCheck(fileName); + } } @TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite") @@ -617,6 +692,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi doBoxTestWithInlineCheck(fileName); } + @TestMetadata("intReturnComplex.1.kt") + public void testIntReturnComplex() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/intReturnComplex.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + @TestMetadata("longReturn.1.kt") public void testLongReturn() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/longReturn.1.kt"); @@ -647,6 +728,18 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi doBoxTestWithInlineCheck(fileName); } + @TestMetadata("severalInTry.1.kt") + public void testSeveralInTry() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/severalInTry.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + + @TestMetadata("severalInTryComplex.1.kt") + public void testSeveralInTryComplex() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/severalInTryComplex.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + @TestMetadata("voidInlineFun.1.kt") public void testVoidInlineFun() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/voidInlineFun.1.kt"); diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/InlineMarker.java b/core/runtime.jvm/src/kotlin/jvm/internal/InlineMarker.java index 2623dce7f13..0b3f813737f 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/InlineMarker.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/InlineMarker.java @@ -26,7 +26,17 @@ public class InlineMarker { } + //TODO: remove on ABI increment, kept only for compability + @Deprecated public static void goToTryCatchBlockEnd() { } + + public static void finallyStart(int finallyDeep) { + + } + + public static void finallyEnd(int finallyDeep) { + + } } \ No newline at end of file