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 630b53cd41e..28cf8f30d2f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/CoveringTryCatchNodeProcessor.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/CoveringTryCatchNodeProcessor.kt @@ -19,15 +19,19 @@ package org.jetbrains.kotlin.codegen.inline import com.google.common.collect.LinkedListMultimap import java.util.ArrayList import com.intellij.util.containers.Stack +import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.tree.* import java.util.Comparator import java.util.Collections -public abstract class CoveringTryCatchNodeProcessor { +public abstract class CoveringTryCatchNodeProcessor(parameterSize: Int) { - public val tryBlocksMetaInfo: IntervalMetaInfo = IntervalMetaInfo(); + public val tryBlocksMetaInfo: IntervalMetaInfo = IntervalMetaInfo() - public val localVarsMetaInfo: IntervalMetaInfo = IntervalMetaInfo(); + public val localVarsMetaInfo: IntervalMetaInfo = IntervalMetaInfo() + + public var nextFreeLocalIndex: Int = parameterSize + private set public val coveringFromInnermost: List get() = tryBlocksMetaInfo.currentIntervals.reverse() @@ -41,10 +45,16 @@ public abstract class CoveringTryCatchNodeProcessor { } public open fun processInstruction(curInstr: AbstractInsnNode, directOrder: Boolean) { - if (curInstr !is LabelNode) return + if (curInstr is VarInsnNode || curInstr is IincInsnNode) { + val argSize = InlineCodegenUtil.getLoadStoreArgSize(curInstr.getOpcode()) + val varIndex = if (curInstr is VarInsnNode) curInstr.`var` else (curInstr as IincInsnNode).`var` + nextFreeLocalIndex = Math.max(nextFreeLocalIndex, varIndex + argSize) + } - updateCoveringTryBlocks(curInstr, directOrder) - updateCoveringLocalVars(curInstr, directOrder) + if (curInstr is LabelNode) { + updateCoveringTryBlocks(curInstr, directOrder) + updateCoveringLocalVars(curInstr, directOrder) + } } //Keep information about try blocks that cover current instruction - @@ -164,11 +174,11 @@ class IntervalMetaInfo> { while (end != start && end is LabelNode) { end = end.getPrevious() } - return start == end; + return start == end } } -public class DefaultProcessor(val node: MethodNode) : CoveringTryCatchNodeProcessor() { +public class DefaultProcessor(val node: MethodNode, parameterSize: Int) : CoveringTryCatchNodeProcessor(parameterSize) { init { node.tryCatchBlocks.forEach { addTryNode(it) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineAdapter.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineAdapter.java index 776f92a66e1..110d194ba7b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineAdapter.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineAdapter.java @@ -25,6 +25,8 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; import java.util.ArrayList; import java.util.List; +import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.getLoadStoreArgSize; + public class InlineAdapter extends InstructionAdapter { private int nextLocalIndex = 0; @@ -51,7 +53,7 @@ public class InlineAdapter extends InstructionAdapter { @Override public void visitVarInsn(int opcode, int var) { super.visitVarInsn(opcode, var); - updateIndex(var, (opcode == Opcodes.DSTORE || opcode == Opcodes.LSTORE || opcode == Opcodes.DLOAD || opcode == Opcodes.LLOAD ? 2 : 1)); + updateIndex(var, getLoadStoreArgSize(opcode)); } private void updateIndex(int var, int varSize) { 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 bc4e60f724c..6dbcab966e3 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java @@ -53,7 +53,6 @@ import org.jetbrains.org.objectweb.asm.commons.Method; import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode; import org.jetbrains.org.objectweb.asm.tree.LabelNode; import org.jetbrains.org.objectweb.asm.tree.MethodNode; -import org.jetbrains.org.objectweb.asm.tree.TryCatchBlockNode; import java.io.IOException; import java.util.HashMap; @@ -287,7 +286,7 @@ public class InlineCodegen extends CallGenerator { } }; List infos = MethodInliner.processReturns(adapter, labelOwner, true, null); - generateAndInsertFinallyBlocks(adapter, infos); + generateAndInsertFinallyBlocks(adapter, infos, ((StackValue.Local)remapper.remap(parameters.totalSize() + 1).value).index); adapter.accept(new InliningInstructionAdapter(codegen.v)); @@ -624,7 +623,11 @@ public class InlineCodegen extends CallGenerator { } - public void generateAndInsertFinallyBlocks(MethodNode intoNode, List insertPoints) { + public void generateAndInsertFinallyBlocks( + MethodNode intoNode, + List insertPoints, + int offsetForFinallyLocalVar + ) { if (!codegen.hasFinallyBlocks()) return; Map extensionPoints = @@ -633,7 +636,7 @@ public class InlineCodegen extends CallGenerator { extensionPoints.put(insertPoint.beforeIns, insertPoint); } - DefaultProcessor processor = new DefaultProcessor(intoNode); + DefaultProcessor processor = new DefaultProcessor(intoNode, offsetForFinallyLocalVar); AbstractInsnNode curInstr = intoNode.instructions.getFirst(); while (curInstr != null) { @@ -652,6 +655,12 @@ public class InlineCodegen extends CallGenerator { codegen.getContext(), codegen.getState(), codegen.getParentCodegen()); finallyCodegen.addBlockStackElementsForNonLocalReturns(codegen.getBlockStackElements()); + FrameMap frameMap = finallyCodegen.getFrameMap(); + FrameMap.Mark mark = frameMap.mark(); + while (frameMap.getCurrentSize() < processor.getNextFreeLocalIndex()) { + frameMap.enterTemp(Type.INT_TYPE); + } + finallyCodegen.generateFinallyBlocksIfNeeded(extension.returnType); finallyNode.visitLabel(end); //Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method @@ -661,6 +670,8 @@ public class InlineCodegen extends CallGenerator { processor.getTryBlocksMetaInfo().splitCurrentIntervals(splitBy, false); processor.getLocalVarsMetaInfo().splitCurrentIntervals(splitBy, false); + + mark.dropTo(); } curInstr = curInstr.getNext(); @@ -675,4 +686,5 @@ public class InlineCodegen extends CallGenerator { private SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap) { return new NestedSourceMapper(sourceMapper, nodeAndSmap.getRanges(), nodeAndSmap.getClassSMAP().getSourceInfo()); } + } 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 156e0c236f3..00fd53ae5eb 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java @@ -455,4 +455,8 @@ public class InlineCodegenUtil { (isStartNotEnd ? INLINE_MARKER_BEFORE_METHOD_NAME : INLINE_MARKER_AFTER_METHOD_NAME), "()V", false); } + + public static int getLoadStoreArgSize(int opcode) { + return opcode == Opcodes.DSTORE || opcode == Opcodes.LSTORE || opcode == Opcodes.DLOAD || opcode == Opcodes.LLOAD ? 2 : 1; + } } 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 9c8e83eeb1a..13e145b4038 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InternalFinallyBlockInliner.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InternalFinallyBlockInliner.java @@ -62,7 +62,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor { } } - public static void processInlineFunFinallyBlocks(@NotNull MethodNode inlineFun, int lambdaTryCatchBlockNodes) { + public static void processInlineFunFinallyBlocks(@NotNull MethodNode inlineFun, int lambdaTryCatchBlockNodes, int finallyParamOffset) { int index = 0; List inlineFunTryBlockInfo = new ArrayList(); for (TryCatchBlockNode block : inlineFun.tryCatchBlocks) { @@ -75,7 +75,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor { } if (hasFinallyBlocks(inlineFunTryBlockInfo)) { - new InternalFinallyBlockInliner(inlineFun, inlineFunTryBlockInfo, localVars).processInlineFunFinallyBlocks(); + new InternalFinallyBlockInliner(inlineFun, inlineFunTryBlockInfo, localVars, finallyParamOffset).processInlineFunFinallyBlocks(); } } @@ -85,7 +85,11 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor { //lambdaTryCatchBlockNodes is number of TryCatchBlockNodes that was inlined with lambdas into function //due to code generation specific they placed before function TryCatchBlockNodes - private InternalFinallyBlockInliner(@NotNull MethodNode inlineFun, List inlineFunTryBlockInfo, List localVariableInfo) { + private InternalFinallyBlockInliner(@NotNull MethodNode inlineFun, + @NotNull List inlineFunTryBlockInfo, + @NotNull List localVariableInfo, + int finallyParamOffset) { + super(finallyParamOffset); this.inlineFun = inlineFun; for (TryCatchBlockNodeInfo block : inlineFunTryBlockInfo) { getTryBlocksMetaInfo().addNewInterval(block); @@ -97,8 +101,6 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor { } private int initAndGetVarIndexForNonLocalReturnValue() { - //sortTryCatchBlocks();/*TODO maybe remove*/ - MaxLocalsCalculator tempCalcNode = new MaxLocalsCalculator( InlineCodegenUtil.API, inlineFun.access, inlineFun.desc, null diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LocalVarRemapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LocalVarRemapper.java index 07684fa44c9..2ff2637222e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LocalVarRemapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LocalVarRemapper.java @@ -132,7 +132,7 @@ public class LocalVarRemapper { FAIL } - private static class RemapInfo { + public static class RemapInfo { public final StackValue value; public final ParameterInfo parameterInfo; public final RemapStatus status; 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 b70ea736e8e..a697e0caa16 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java @@ -128,7 +128,7 @@ public class MethodInliner { resultNode.visitLabel(end); if (inliningContext.isRoot()) { - InternalFinallyBlockInliner.processInlineFunFinallyBlocks(resultNode, lambdasFinallyBlocks); + InternalFinallyBlockInliner.processInlineFunFinallyBlocks(resultNode, lambdasFinallyBlocks, ((StackValue.Local)remapper.remap(parameters.totalSize() + 1).value).index); } processReturns(resultNode, labelOwner, remapReturn, end); diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt7273.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt7273.1.kt new file mode 100644 index 00000000000..481f251a94b --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt7273.1.kt @@ -0,0 +1,10 @@ +fun box(): String { + try { + test { + return@box "OK" + } + } finally { + } + + return "fail" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt7273.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt7273.2.kt new file mode 100644 index 00000000000..ac04e885dbd --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt7273.2.kt @@ -0,0 +1,8 @@ +inline fun test(s: () -> R): R { + var b = false + try { + return s() + } finally { + !b + } +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java index d8ca343e801..cb00dfe0459 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java @@ -477,6 +477,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally"), Pattern.compile("^(.+)\\.1.kt$"), true); } + @TestMetadata("kt7273.1.kt") + public void testKt7273() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt7273.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + @TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java index 3ece3492ba1..cb7e04c4de2 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -477,6 +477,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally"), Pattern.compile("^(.+)\\.1.kt$"), true); } + @TestMetadata("kt7273.1.kt") + public void testKt7273() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/kt7273.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + @TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)