JVM: consider casts of null to be redundant

These should only have ever been necessary for field type inference in
coroutines, which should have been fixed by 0fc676a20c.

Unlike 903a5d69a4, this time the change is in an optimization pass.
Advantage: optimization passes have a closer to the JVM view of the
bytecode, which makes this change significantly more likely to be correct.
Disadvantage: technically we don't really guarantee optimization passes
other than FixStack will run at all. For KT-54581 this is 100% fine
since the problem itself is caused by redundant checkcast elimination in
the first place (otherwise there would've been a redundant cast to
String), but for KT-53146 this means the fix is somewhat incidental and
not necessarily guaranteed.

^KT-53146 Fixed
^KT-54581 Fixed
This commit is contained in:
pyos
2022-10-20 10:20:11 +02:00
committed by Ilmir Usmanov
parent 6f4a60ac91
commit 65c153a722
7 changed files with 73 additions and 3 deletions
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
import org.jetbrains.kotlin.codegen.optimization.common.FastMethodAnalyzer
import org.jetbrains.kotlin.codegen.optimization.common.InstructionLivenessAnalyzer
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.org.objectweb.asm.Opcodes
@@ -52,13 +53,12 @@ class RedundantCheckCastEliminationMethodTransformer : MethodTransformer() {
val frames = FastMethodAnalyzer(internalClassName, methodNode, interpreter, pruneExceptionEdges = true).analyze()
for (i in insns.indices) {
val valueType = frames[i]?.top()?.type ?: continue
val insn = insns[i]
if (insn.opcode == Opcodes.CHECKCAST) {
val value = frames[i]?.top() ?: continue
val typeInsn = insn as TypeInsnNode
val insnType = Type.getObjectType(typeInsn.desc)
if (!isTrivialSubtype(insnType, valueType)) continue
if (value !== StrictBasicValue.NULL_VALUE && !isTrivialSubtype(insnType, value.type)) continue
//Keep casts to multiarray types cause dex doesn't recognize ANEWARRAY [Ljava/lang/Object; as Object [][], but Object [] type
//It's not clear is it bug in dex or not and maybe best to distinguish such types from MULTINEWARRRAY ones in method analyzer
@@ -4787,6 +4787,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/casts/kt50577.kt");
}
@Test
@TestMetadata("kt53146.kt")
public void testKt53146() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt53146.kt");
}
@Test
@TestMetadata("kt53677.kt")
public void testKt53677() throws Exception {
@@ -4799,6 +4805,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/casts/kt54318.kt");
}
@Test
@TestMetadata("kt54581.kt")
public void testKt54581() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt54581.kt");
}
@Test
@TestMetadata("lambdaToUnitCast.kt")
public void testLambdaToUnitCast() throws Exception {
+18
View File
@@ -0,0 +1,18 @@
// TARGET_BACKEND: JVM_IR
// WITH_STDLIB
// FULL_JDK
// CHECK_BYTECODE_TEXT
class A
fun box(): String {
val a = try {
A()
} catch (e: NoClassDefFoundError) {
null
}
return "OK"
}
// 0 CHECKCAST
+17
View File
@@ -0,0 +1,17 @@
// TARGET_BACKEND: JVM
fun box(): String {
val k = tryOrNull { "K" }
return "O$k"
}
private inline fun <T> tryOrNull(action: () -> T): T? =
try {
action()
} catch (e: Throwable) {
when {
else -> {
null
}
}
}
@@ -4673,6 +4673,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/casts/kt50577.kt");
}
@Test
@TestMetadata("kt54581.kt")
public void testKt54581() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt54581.kt");
}
@Test
@TestMetadata("lambdaToUnitCast.kt")
public void testLambdaToUnitCast() throws Exception {
@@ -4787,6 +4787,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/casts/kt50577.kt");
}
@Test
@TestMetadata("kt53146.kt")
public void testKt53146() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt53146.kt");
}
@Test
@TestMetadata("kt53677.kt")
public void testKt53677() throws Exception {
@@ -4799,6 +4805,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/casts/kt54318.kt");
}
@Test
@TestMetadata("kt54581.kt")
public void testKt54581() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt54581.kt");
}
@Test
@TestMetadata("lambdaToUnitCast.kt")
public void testLambdaToUnitCast() throws Exception {
@@ -4076,6 +4076,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/casts/kt50577.kt");
}
@TestMetadata("kt54581.kt")
public void testKt54581() throws Exception {
runTest("compiler/testData/codegen/box/casts/kt54581.kt");
}
@TestMetadata("lambdaToUnitCast.kt")
public void testLambdaToUnitCast() throws Exception {
runTest("compiler/testData/codegen/box/casts/lambdaToUnitCast.kt");