KT-16245 Redundant null-check generated for a cast of already non-nullable value

KT-16194 Code with unnecessary safe call contains redundant boxing/unboxing for primitive values
KT-12839 Two null checks are generated when manually null checking platform type

Recognize some additional cases of trivial null checks and trivial instance-of checks.

A variable is "checked for null", if it is:
- a function parameter checked with 'INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull'
- checked for nullability with 'IFNULL/IFNONNULL'
- checked for nullability with 'INSTANCEOF'
  (if objectref is instance-of T, then objectref is non-null)

Before analyzing nullability, introduce synthetic assumptions for execution branches
where a variable is guaranteed to be null or not null. For example, the following bytecode:

     ALOAD 1 // Ljava/lang/String;
     IFNULL L
     <non-null branch>
  L:
     <null branch>

is transformed to

     ALOAD 1
     IFNULL L1
     NEW java/lang/String
     ASTORE 1            // tells analyzer that variable 1 is non-null
     <non-null branch>
  L:
     <null branch>
  L1:
     ACONST_NULL
     ASTORE 1            // tells analyzer that variable 1 is null
     GOTO L

After the analysis is performed on a preprocessed method,
remember the results for "interesting" instructions
and revert the preprocessing transformations.

After that, perform bytecode transformations as usual.

Do not transform INSTANCEOF to-be-reified, because reification at call site
can introduce null checks. E.g.,

    inline fun <reified T> isNullable() = null is T
    ...
    assert(isNullable<String?>())
This commit is contained in:
Dmitry Petrov
2017-02-14 17:45:45 +03:00
parent 3c09a26e16
commit ec403bfdbc
22 changed files with 506 additions and 23 deletions
@@ -1634,6 +1634,18 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/nullCheckOptimization"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("alreadyCheckedForIs.kt")
public void testAlreadyCheckedForIs() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/nullCheckOptimization/alreadyCheckedForIs.kt");
doTest(fileName);
}
@TestMetadata("alreadyCheckedForNull.kt")
public void testAlreadyCheckedForNull() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/nullCheckOptimization/alreadyCheckedForNull.kt");
doTest(fileName);
}
@TestMetadata("ifNullEqualsNull.kt")
public void testIfNullEqualsNull() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/nullCheckOptimization/ifNullEqualsNull.kt");
@@ -1657,6 +1669,36 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/nullCheckOptimization/ifUnitEqualsNullInline.kt");
doTest(fileName);
}
@TestMetadata("kt12839.kt")
public void testKt12839() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/nullCheckOptimization/kt12839.kt");
doTest(fileName);
}
@TestMetadata("notNullAsNotNullable.kt")
public void testNotNullAsNotNullable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/nullCheckOptimization/notNullAsNotNullable.kt");
doTest(fileName);
}
@TestMetadata("redundantSafeCall.kt")
public void testRedundantSafeCall() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/nullCheckOptimization/redundantSafeCall.kt");
doTest(fileName);
}
@TestMetadata("reifiedIs.kt")
public void testReifiedIs() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/nullCheckOptimization/reifiedIs.kt");
doTest(fileName);
}
@TestMetadata("reifiedNullIs.kt")
public void testReifiedNullIs() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/nullCheckOptimization/reifiedNullIs.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/bytecodeText/ranges")