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
This commit is contained in:
+11
-2
@@ -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<LabelNode, DecompiledTryDescriptor> {
|
||||
val decompiledTryDescriptorForStart: MutableMap<LabelNode, DecompiledTryDescriptor> = hashMapOf()
|
||||
val decompiledTryDescriptorForHandler: MutableMap<LabelNode, DecompiledTryDescriptor> = 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<LabelNo
|
||||
DecompiledTryDescriptor(tcb.start)
|
||||
}
|
||||
}
|
||||
with(decompiledTryDescriptor) {
|
||||
handlerStartLabels.add(tcb.handler)
|
||||
|
||||
with(decompiledTryDescriptor) {
|
||||
if (tcb.isDefaultHandlerNode()) {
|
||||
assert(defaultHandlerTcb == null) {
|
||||
"${methodNode.debugString(tcb)}: default handler is already found: ${methodNode.debugString(defaultHandlerTcb!!)}"
|
||||
@@ -137,6 +142,10 @@ private fun collectDecompiledTryDescriptors(methodNode: MethodNode): Map<LabelNo
|
||||
|
||||
defaultHandlerTcb = tcb
|
||||
}
|
||||
|
||||
if (tcb.handler !in defaultHandlers) {
|
||||
handlerStartLabels.add(tcb.handler)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -33,14 +33,13 @@ internal class FixStackContext(val methodNode: MethodNode) {
|
||||
val fakeAlwaysFalseIfeqMarkers = arrayListOf<AbstractInsnNode>()
|
||||
|
||||
val isThereAnyTryCatch: Boolean
|
||||
val saveStackMarkerForRestoreMarker: Map<AbstractInsnNode, AbstractInsnNode>
|
||||
val saveStackMarkerForRestoreMarker = insertTryCatchBlocksMarkers(methodNode)
|
||||
val restoreStackMarkersForSaveMarker = hashMapOf<AbstractInsnNode, MutableList<AbstractInsnNode>>()
|
||||
|
||||
val openingInlineMethodMarker = hashMapOf<AbstractInsnNode, AbstractInsnNode>()
|
||||
var consistentInlineMarkers: Boolean = true; private set
|
||||
|
||||
init {
|
||||
saveStackMarkerForRestoreMarker = insertTryCatchBlocksMarkers(methodNode)
|
||||
isThereAnyTryCatch = saveStackMarkerForRestoreMarker.isNotEmpty()
|
||||
for ((restore, save) in saveStackMarkerForRestoreMarker) {
|
||||
restoreStackMarkersForSaveMarker.getOrPut(save) { SmartList() }.add(restore)
|
||||
|
||||
+6
@@ -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 }
|
||||
+17
@@ -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 }
|
||||
+12
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
+12
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user