From e1731373d8fc85e518bc624a7a168e9749148c85 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Tue, 25 Apr 2017 12:25:32 +0300 Subject: [PATCH] Do not restore stack in default handler for try-finally It never terminates, so the corresponding value on stack can't be used. However, if this happens in an inlined lambda argument, the inliner is unable to remove the corresponding ALOAD instruction (because default handler never terminates, and thus corresponding ALOAD is not used for lambda invocation). KT-17573 try-finally expression in inlined function parameter argument fails with VerifyError --- .../fixStack/AnalyzeTryCatchBlocks.kt | 13 +++++++++++-- .../optimization/fixStack/FixStackContext.kt | 3 +-- .../tryCatchInExpressions/kt17573.kt | 6 ++++++ .../tryCatchInExpressions/kt17573_nested.kt | 17 +++++++++++++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 12 ++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 12 ++++++++++++ .../codegen/LightAnalysisModeTestGenerated.java | 12 ++++++++++++ .../semantics/JsCodegenBoxTestGenerated.java | 12 ++++++++++++ 8 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/kt17573.kt create mode 100644 compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/kt17573_nested.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/AnalyzeTryCatchBlocks.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/AnalyzeTryCatchBlocks.kt index ce3f1ef91be..109567613d3 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/AnalyzeTryCatchBlocks.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/AnalyzeTryCatchBlocks.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen.optimization.fixStack import org.jetbrains.kotlin.codegen.optimization.common.findNextOrNull import org.jetbrains.kotlin.codegen.optimization.common.hasOpcode import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn +import org.jetbrains.kotlin.utils.SmartSet import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode @@ -117,6 +118,11 @@ private fun insertSaveRestoreStackMarkers( private fun collectDecompiledTryDescriptors(methodNode: MethodNode): Map { val decompiledTryDescriptorForStart: MutableMap = hashMapOf() val decompiledTryDescriptorForHandler: MutableMap = hashMapOf() + + val defaultHandlers = methodNode.tryCatchBlocks.mapNotNullTo(SmartSet.create()) { + if (it.isDefaultHandlerNode()) it.handler else null + } + for (tcb in methodNode.tryCatchBlocks) { if (tcb.isDefaultHandlerNode()) { assert(decompiledTryDescriptorForHandler.containsKey(tcb.start)) { "${methodNode.debugString(tcb)}: default handler should occur after some regular handler" } @@ -127,9 +133,8 @@ private fun collectDecompiledTryDescriptors(methodNode: MethodNode): Map() val isThereAnyTryCatch: Boolean - val saveStackMarkerForRestoreMarker: Map + val saveStackMarkerForRestoreMarker = insertTryCatchBlocksMarkers(methodNode) val restoreStackMarkersForSaveMarker = hashMapOf>() val openingInlineMethodMarker = hashMapOf() var consistentInlineMarkers: Boolean = true; private set init { - saveStackMarkerForRestoreMarker = insertTryCatchBlocksMarkers(methodNode) isThereAnyTryCatch = saveStackMarkerForRestoreMarker.isNotEmpty() for ((restore, save) in saveStackMarkerForRestoreMarker) { restoreStackMarkersForSaveMarker.getOrPut(save) { SmartList() }.add(restore) diff --git a/compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/kt17573.kt b/compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/kt17573.kt new file mode 100644 index 00000000000..de1d0b45cbc --- /dev/null +++ b/compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/kt17573.kt @@ -0,0 +1,6 @@ +fun zap(s: String) = s + +inline fun tryZap(string: String, fn: (String) -> String) = + fn(try { zap(string) } finally {}) + +fun box(): String = tryZap("OK") { it } \ No newline at end of file diff --git a/compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/kt17573_nested.kt b/compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/kt17573_nested.kt new file mode 100644 index 00000000000..e241aec5239 --- /dev/null +++ b/compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/kt17573_nested.kt @@ -0,0 +1,17 @@ +fun zap(s: String) = s + +inline fun tryZap1(string: String, fn: (String) -> String) = + fn( + try { zap(string) } finally { + try { zap(string) } finally { } + } + ) + +inline fun tryZap2(string: String, fn: (String) -> String) = + fn( + try { zap(string) } finally { + try { zap(string) } catch (e: Exception) { } + } + ) + +fun box(): String = tryZap1("O") { it } + tryZap2("K") { it } \ No newline at end of file diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 4253730625e..dbe87dc1f27 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -4810,6 +4810,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("kt17573.kt") + public void testKt17573() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/kt17573.kt"); + doTest(fileName); + } + + @TestMetadata("kt17573_nested.kt") + public void testKt17573_nested() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/kt17573_nested.kt"); + doTest(fileName); + } + @TestMetadata("kt8608.kt") public void testKt8608() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/kt8608.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index ba266db2fce..a4dceae7f2e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -4810,6 +4810,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("kt17573.kt") + public void testKt17573() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/kt17573.kt"); + doTest(fileName); + } + + @TestMetadata("kt17573_nested.kt") + public void testKt17573_nested() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/kt17573_nested.kt"); + doTest(fileName); + } + @TestMetadata("kt8608.kt") public void testKt8608() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/kt8608.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index ca47e24ca37..5afd28373e9 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -4810,6 +4810,18 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("kt17573.kt") + public void testKt17573() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/kt17573.kt"); + doTest(fileName); + } + + @TestMetadata("kt17573_nested.kt") + public void testKt17573_nested() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/kt17573_nested.kt"); + doTest(fileName); + } + @TestMetadata("kt8608.kt") public void testKt8608() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/kt8608.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index fde80488cf0..9aafb072d5f 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -5525,6 +5525,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("kt17573.kt") + public void testKt17573() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/kt17573.kt"); + doTest(fileName); + } + + @TestMetadata("kt17573_nested.kt") + public void testKt17573_nested() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/kt17573_nested.kt"); + doTest(fileName); + } + @TestMetadata("kt8608.kt") public void testKt8608() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/kt8608.kt");