Merge commit '51dd41e7e6a7d6b00cfd621fb5156a87a11cff14' into dev-release

Change-Id: I1f5e30801109f8ae5a0102bd3c2eb9b8698756c4
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index e95af33..02835ae 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -86,6 +86,8 @@
       "Landroid/media/MediaMetadataRetriever;";
   public static final String androidResourcesDescriptorString = "Landroid/content/res/Resources;";
   public static final String androidContextDescriptorString = "Landroid/content/Context;";
+  public static final String kotlinJvmInternalIntrinsicsDescriptor =
+      "Lkotlin/jvm/internal/Intrinsics;";
 
   /** Set of types that may be synthesized during compilation. */
   private final Set<DexType> possibleCompilerSynthesizedTypes = Sets.newIdentityHashSet();
@@ -649,6 +651,8 @@
 
   public final DexType kotlinMetadataType = createStaticallyKnownType(kotlinMetadataDescriptor);
   public final DexType kotlinJvmNameType = createStaticallyKnownType(kotlinJvmNameDescriptor);
+  public final DexType kotlinJvmInternalIntrinsicsType =
+      createStaticallyKnownType(kotlinJvmInternalIntrinsicsDescriptor);
 
   public final DexType kotlinEnumEntriesList =
       createStaticallyKnownType("Lkotlin/enums/EnumEntriesList;");
@@ -944,6 +948,8 @@
   public final IteratorMethods iteratorMethods = new IteratorMethods();
   public final StringConcatFactoryMembers stringConcatFactoryMembers =
       new StringConcatFactoryMembers();
+  public final KotlinJvmInternalIntrinsicsMethods kotlinJvmInternalIntrinsicsMethods =
+      new KotlinJvmInternalIntrinsicsMethods();
 
   private final SyntheticNaming syntheticNaming = new SyntheticNaming();
 
@@ -3035,6 +3041,91 @@
         createMethod(javaUtilIteratorType, createProto(objectType), nextName);
   }
 
+  public class KotlinJvmInternalIntrinsicsMethods {
+    /*
+     From javap:
+
+     public class kotlin.jvm.internal.Intrinsics {
+       public static void checkNotNull(java.lang.Object);
+       public static void checkNotNull(java.lang.Object, java.lang.String);
+       public static void checkExpressionValueIsNotNull(java.lang.Object, java.lang.String);
+       public static void checkNotNullExpressionValue(java.lang.Object, java.lang.String);
+       public static void checkReturnedValueIsNotNull(
+           java.lang.Object, java.lang.String, java.lang.String);
+       public static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String);
+       public static void checkFieldIsNotNull(
+           java.lang.Object, java.lang.String, java.lang.String);
+       public static void checkFieldIsNotNull(java.lang.Object, java.lang.String);
+       public static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
+       public static void checkNotNullParameter(java.lang.Object, java.lang.String);
+     }
+    */
+    public final DexMethod checkNotNullObject =
+        createMethod(
+            kotlinJvmInternalIntrinsicsType, createProto(voidType, objectType), "checkNotNull");
+    public final DexMethod checkNotNullObjectString =
+        createMethod(
+            kotlinJvmInternalIntrinsicsType,
+            createProto(voidType, objectType, stringType),
+            "checkNotNull");
+    public final DexMethod checkExpressionValueIsNotNull =
+        createMethod(
+            kotlinJvmInternalIntrinsicsType,
+            createProto(voidType, objectType, stringType),
+            "checkExpressionValueIsNotNull");
+    public final DexMethod checkNotNullExpressionValue =
+        createMethod(
+            kotlinJvmInternalIntrinsicsType,
+            createProto(voidType, objectType, stringType),
+            "checkNotNullExpressionValue");
+    public final DexMethod checkReturnedValueIsNotNullObjectStringString =
+        createMethod(
+            kotlinJvmInternalIntrinsicsType,
+            createProto(voidType, objectType, stringType, stringType),
+            "checkReturnedValueIsNotNull");
+    public final DexMethod checkReturnedValueIsNotNullObjectString =
+        createMethod(
+            kotlinJvmInternalIntrinsicsType,
+            createProto(voidType, objectType, stringType),
+            "checkReturnedValueIsNotNull");
+    public final DexMethod checkFieldIsNotNullObjectStringString =
+        createMethod(
+            kotlinJvmInternalIntrinsicsType,
+            createProto(voidType, objectType, stringType, stringType),
+            "checkFieldIsNotNull");
+    public final DexMethod checkFieldIsNotNullObjectString =
+        createMethod(
+            kotlinJvmInternalIntrinsicsType,
+            createProto(voidType, objectType, stringType),
+            "checkFieldIsNotNull");
+    public final DexMethod checkParameterIsNotNull =
+        createMethod(
+            kotlinJvmInternalIntrinsicsType,
+            createProto(voidType, objectType, stringType),
+            "checkParameterIsNotNull");
+    public final DexMethod checkNotNullParameter =
+        createMethod(
+            kotlinJvmInternalIntrinsicsType,
+            createProto(voidType, objectType, stringType),
+            "checkNotNullParameter");
+
+    public boolean isNullCheck(DexMethod method) {
+      if (!method.getHolderType().isIdenticalTo(kotlinJvmInternalIntrinsicsType)) {
+        return false;
+      }
+      return method.isIdenticalTo(checkNotNullObject)
+          || method.isIdenticalTo(checkNotNullObjectString)
+          || method.isIdenticalTo(checkExpressionValueIsNotNull)
+          || method.isIdenticalTo(checkNotNullExpressionValue)
+          || method.isIdenticalTo(checkReturnedValueIsNotNullObjectString)
+          || method.isIdenticalTo(checkReturnedValueIsNotNullObjectStringString)
+          || method.isIdenticalTo(checkFieldIsNotNullObjectString)
+          || method.isIdenticalTo(checkFieldIsNotNullObjectStringString)
+          || method.isIdenticalTo(checkParameterIsNotNull)
+          || method.isIdenticalTo(checkNotNullParameter);
+    }
+  }
+
   private static <T extends DexItem> T canonicalize(
       Map<T, T> committedMap, Map<T, T> pendingMap, T item) {
     assert item != null;
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
index 653bdaa..dd2cdac 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
@@ -178,6 +178,14 @@
       return true;
     }
 
+    if (appView.options().getProguardConfiguration().getProcessKotlinNullChecks().isRemove()
+        && appView
+            .dexItemFactory()
+            .kotlinJvmInternalIntrinsicsMethods
+            .isNullCheck(getInvokedMethod())) {
+      return false;
+    }
+
     AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
     SingleResolutionResult<?> resolutionResult =
         appViewWithLiveness
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CheckNotNullConverter.java b/src/main/java/com/android/tools/r8/ir/optimize/CheckNotNullConverter.java
index ded9ac0..7bbe9a1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CheckNotNullConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CheckNotNullConverter.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.BasicBlockIterator;
@@ -46,6 +47,22 @@
     }
   }
 
+  static boolean kotlinNullCheckLedgibleForMessageRemoval(
+      AppView<? extends AppInfoWithClassHierarchy> appView, DexMethod method) {
+    return appView
+            .options()
+            .getProguardConfiguration()
+            .getProcessKotlinNullChecks()
+            .isRemoveMessage()
+        && appView.dexItemFactory().kotlinJvmInternalIntrinsicsMethods.isNullCheck(method);
+  }
+
+  private static boolean canConvertNullCheck(
+      AppView<? extends AppInfoWithClassHierarchy> appView, DexClassAndMethod singleTarget) {
+    return singleTarget.getOptimizationInfo().isConvertCheckNotNull()
+        || kotlinNullCheckLedgibleForMessageRemoval(appView, singleTarget.getReference());
+  }
+
   private static void rewriteInvoke(
       AppView<? extends AppInfoWithClassHierarchy> appView,
       IRCode code,
@@ -53,7 +70,7 @@
       InvokeMethod invoke) {
     ProgramMethod context = code.context();
     DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, context);
-    if (singleTarget == null || !singleTarget.getOptimizationInfo().isConvertCheckNotNull()) {
+    if (singleTarget == null || !canConvertNullCheck(appView, singleTarget)) {
       return;
     }
     Value checkNotNullValue = invoke.getFirstNonReceiverArgument();
diff --git a/src/main/java/com/android/tools/r8/processkeeprules/FilteredKeepRulesBuilder.java b/src/main/java/com/android/tools/r8/processkeeprules/FilteredKeepRulesBuilder.java
index 9ba68e1..504cfe1 100644
--- a/src/main/java/com/android/tools/r8/processkeeprules/FilteredKeepRulesBuilder.java
+++ b/src/main/java/com/android/tools/r8/processkeeprules/FilteredKeepRulesBuilder.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.position.TextPosition;
 import com.android.tools.r8.shaking.FilteredClassPath;
 import com.android.tools.r8.shaking.ProguardClassNameList;
+import com.android.tools.r8.shaking.ProguardConfiguration.ProcessKotlinNullChecks;
 import com.android.tools.r8.shaking.ProguardConfigurationParser.ProguardConfigurationSourceParser;
 import com.android.tools.r8.shaking.ProguardConfigurationParserConsumer;
 import com.android.tools.r8.shaking.ProguardConfigurationRule;
@@ -214,6 +215,15 @@
   }
 
   @Override
+  public void addProcessKotlinNullChecks(
+      ProcessKotlinNullChecks value,
+      ProguardConfigurationSourceParser parser,
+      Position position,
+      TextPosition positionStart) {
+    writeComment(parser, positionStart);
+  }
+
+  @Override
   public void addKeepPackageNamesPattern(
       ProguardClassNameList proguardClassNameList,
       ProguardConfigurationSourceParser parser,
diff --git a/src/main/java/com/android/tools/r8/processkeeprules/ValidateLibraryConsumerRulesKeepRuleProcessor.java b/src/main/java/com/android/tools/r8/processkeeprules/ValidateLibraryConsumerRulesKeepRuleProcessor.java
index e0bbeab..4b9b4bf 100644
--- a/src/main/java/com/android/tools/r8/processkeeprules/ValidateLibraryConsumerRulesKeepRuleProcessor.java
+++ b/src/main/java/com/android/tools/r8/processkeeprules/ValidateLibraryConsumerRulesKeepRuleProcessor.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.position.TextPosition;
 import com.android.tools.r8.shaking.FilteredClassPath;
 import com.android.tools.r8.shaking.ProguardClassNameList;
+import com.android.tools.r8.shaking.ProguardConfiguration.ProcessKotlinNullChecks;
 import com.android.tools.r8.shaking.ProguardConfigurationParser.ProguardConfigurationSourceParser;
 import com.android.tools.r8.shaking.ProguardConfigurationParserConsumer;
 import com.android.tools.r8.shaking.ProguardConfigurationRule;
@@ -154,6 +155,15 @@
       ProguardConfigurationSourceParser parser, Position position, TextPosition positionStart) {}
 
   @Override
+  public void addProcessKotlinNullChecks(
+      ProcessKotlinNullChecks value,
+      ProguardConfigurationSourceParser parser,
+      Position position,
+      TextPosition positionStart) {
+    handleRule(parser, positionStart, "-processkotlinnullchecks");
+  }
+
+  @Override
   public void addKeepPackageNamesPattern(
       ProguardClassNameList proguardClassNameList,
       ProguardConfigurationSourceParser parser,
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
index ad2a5a2..8450bce 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.shaking;
 
+import static com.android.tools.r8.shaking.ProguardConfiguration.ProcessKotlinNullChecks.DEFAULT;
 import static com.android.tools.r8.shaking.ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS;
 
 import com.android.tools.r8.errors.dontwarn.DontWarnConfiguration;
@@ -28,6 +29,26 @@
 
 public class ProguardConfiguration {
 
+  public enum ProcessKotlinNullChecks {
+    DEFAULT,
+    KEEP,
+    REMOVE_MESSAGE,
+    REMOVE;
+
+    public boolean isRemoveMessage() {
+      return this == DEFAULT || this == REMOVE_MESSAGE;
+    }
+
+    public boolean isRemove() {
+      return this == REMOVE;
+    }
+
+    public ProcessKotlinNullChecks meet(ProcessKotlinNullChecks other) {
+      assert other != DEFAULT;
+      return other.ordinal() > ordinal() ? other : this;
+    }
+  }
+
   public static class Builder implements ProguardConfigurationParserConsumer {
 
     private final StringBuilder parsedConfiguration = new StringBuilder();
@@ -74,6 +95,7 @@
     private boolean forceProguardCompatibility = false;
     private boolean protoShrinking = false;
     private int maxRemovedAndroidLogLevel = MaximumRemovedAndroidLogLevelRule.NOT_SET;
+    private ProcessKotlinNullChecks processKotlinNullChecks = DEFAULT;
     PackageObfuscationMode packageObfuscationMode = PackageObfuscationMode.NONE;
     String packagePrefix = "";
 
@@ -274,6 +296,15 @@
           Collections.singletonList(RUNTIME_VISIBLE_ANNOTATIONS), parser, position, positionStart);
     }
 
+    @Override
+    public void addProcessKotlinNullChecks(
+        ProcessKotlinNullChecks value,
+        ProguardConfigurationSourceParser parser,
+        Position position,
+        TextPosition positionStart) {
+      processKotlinNullChecks = processKotlinNullChecks.meet(value);
+    }
+
     public Builder addKeepAttributePatterns(List<String> keepAttributePatterns) {
       this.keepAttributePatterns.addAll(keepAttributePatterns);
       return this;
@@ -499,7 +530,8 @@
               adaptResourceFileContents.build(),
               keepDirectories.build(),
               protoShrinking,
-              getMaxRemovedAndroidLogLevel());
+              getMaxRemovedAndroidLogLevel(),
+              processKotlinNullChecks);
 
       reporter.failIfPendingErrors();
 
@@ -554,6 +586,7 @@
   private final int maxRemovedAndroidLogLevel;
   private final boolean hasWhyAreYouNotInliningRule;
   private final boolean hasWhyAreYouNotObfuscatingRule;
+  private final ProcessKotlinNullChecks processKotlinNullChecks;
 
   private ProguardConfiguration(
       String parsedConfiguration,
@@ -591,7 +624,8 @@
       ProguardPathFilter adaptResourceFileContents,
       ProguardPathFilter keepDirectories,
       boolean protoShrinking,
-      int maxRemovedAndroidLogLevel) {
+      int maxRemovedAndroidLogLevel,
+      ProcessKotlinNullChecks processKotlinNullChecks) {
     this.parsedConfiguration = parsedConfiguration;
     this.dexItemFactory = factory;
     this.injars = ImmutableList.copyOf(injars);
@@ -632,6 +666,7 @@
         Iterables.any(rules, rule -> rule instanceof WhyAreYouNotInliningRule);
     this.hasWhyAreYouNotObfuscatingRule =
         Iterables.any(rules, rule -> rule instanceof WhyAreYouNotObfuscatingRule);
+    this.processKotlinNullChecks = processKotlinNullChecks;
   }
 
   /**
@@ -811,6 +846,10 @@
     return hasWhyAreYouNotObfuscatingRule;
   }
 
+  public ProcessKotlinNullChecks getProcessKotlinNullChecks() {
+    return processKotlinNullChecks;
+  }
+
   @Override
   public String toString() {
     StringBuilder builder = new StringBuilder();
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index f67ed82..0060f9d3 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -3,6 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.shaking;
 
+import static com.android.tools.r8.shaking.ProguardConfiguration.ProcessKotlinNullChecks.KEEP;
+import static com.android.tools.r8.shaking.ProguardConfiguration.ProcessKotlinNullChecks.REMOVE;
+import static com.android.tools.r8.shaking.ProguardConfiguration.ProcessKotlinNullChecks.REMOVE_MESSAGE;
 import static com.android.tools.r8.utils.DescriptorUtils.javaTypeToDescriptor;
 
 import com.android.tools.r8.InputDependencyGraphConsumer;
@@ -18,6 +21,7 @@
 import com.android.tools.r8.position.TextPosition;
 import com.android.tools.r8.position.TextRange;
 import com.android.tools.r8.shaking.InlineRule.InlineRuleType;
+import com.android.tools.r8.shaking.ProguardConfiguration.ProcessKotlinNullChecks;
 import com.android.tools.r8.shaking.ProguardTypeMatcher.ClassOrType;
 import com.android.tools.r8.shaking.ProguardWildcard.BackReference;
 import com.android.tools.r8.shaking.ProguardWildcard.Pattern;
@@ -296,6 +300,8 @@
         // Intentionally left empty.
       } else if (acceptString("keepkotlinmetadata")) {
         configurationConsumer.addKeepKotlinMetadata(this, getPosition(optionStart), optionStart);
+      } else if (acceptString("processkotlinnullchecks")) {
+        parseProcessKotlinNullChecks(optionStart);
       } else if (acceptString("renamesourcefileattribute")) {
         skipWhitespace();
         String renameSourceFileAttribute =
@@ -712,6 +718,30 @@
           attributesPatterns, this, getPosition(start), start);
     }
 
+    private void parseProcessKotlinNullChecks(TextPosition start)
+        throws ProguardRuleParserException {
+      skipWhitespace();
+      TextPosition argumentStart = getPosition();
+      String processKotlinNullChecksValue =
+          isOptionalArgumentGiven() ? acceptQuotedOrUnquotedString() : "";
+      ProcessKotlinNullChecks value = REMOVE_MESSAGE;
+      switch (processKotlinNullChecksValue) {
+        case "keep":
+          value = KEEP;
+          break;
+        case "":
+        case "remove_message":
+          value = REMOVE_MESSAGE;
+          break;
+        case "remove":
+          value = REMOVE;
+          break;
+        default:
+          throw parseError("Illegal value for -processkotlinnullchecks", argumentStart);
+      }
+      configurationConsumer.addProcessKotlinNullChecks(value, this, getPosition(start), start);
+    }
+
     private boolean skipFlag(String name) {
       if (acceptString(name)) {
         return true;
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParserConsumer.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParserConsumer.java
index b3067da..4ea4043 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParserConsumer.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParserConsumer.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.position.Position;
 import com.android.tools.r8.position.TextPosition;
+import com.android.tools.r8.shaking.ProguardConfiguration.ProcessKotlinNullChecks;
 import com.android.tools.r8.shaking.ProguardConfigurationParser.ProguardConfigurationSourceParser;
 import com.android.tools.r8.utils.InternalOptions.PackageObfuscationMode;
 import java.nio.file.Path;
@@ -39,6 +40,12 @@
   void addKeepKotlinMetadata(
       ProguardConfigurationSourceParser parser, Position position, TextPosition positionStart);
 
+  void addProcessKotlinNullChecks(
+      ProcessKotlinNullChecks value,
+      ProguardConfigurationSourceParser parser,
+      Position position,
+      TextPosition positionStart);
+
   void addKeepPackageNamesPattern(
       ProguardClassNameList proguardClassNameList,
       ProguardConfigurationSourceParser parser,
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
index 10d8bbc..be552b1 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
@@ -4,14 +4,12 @@
 
 package com.android.tools.r8.kotlin;
 
-import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_3_72;
 import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_5_0;
 import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_9_21;
 import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_2_0_20;
 import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_2_1_10;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentIf;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -31,7 +29,6 @@
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import com.google.common.collect.Lists;
 import com.google.common.collect.Streams;
 import java.util.Collections;
 import java.util.List;
@@ -110,9 +107,9 @@
                 return;
               }
               if (testParameters.isCfRuntime() && !hasKotlinCGeneratedLambdaClasses) {
-                assertEquals(5, inspector.allClasses().size());
+                assertEquals(4, inspector.allClasses().size());
               } else {
-                assertEquals(7, inspector.allClasses().size());
+                assertEquals(6, inspector.allClasses().size());
               }
             });
   }
@@ -138,9 +135,9 @@
                 return;
               }
               if (testParameters.isCfRuntime() && !hasKotlinCGeneratedLambdaClasses) {
-                assertEquals(5, inspector.allClasses().size());
+                assertEquals(4, inspector.allClasses().size());
               } else {
-                assertEquals(7, inspector.allClasses().size());
+                assertEquals(6, inspector.allClasses().size());
               }
             });
   }
@@ -264,14 +261,14 @@
                 assertThat(
                     inspector.clazz(
                         "class_inliner_lambda_k_style.MainKt$testKotlinSequencesStateless$1"),
-                    isPresentIf(testParameters.isDexRuntime()));
+                    isPresent());
                 assertThat(
                     inspector.clazz(
                         "class_inliner_lambda_k_style.MainKt$testKotlinSequencesStateful$1"),
                     isAbsent());
                 assertThat(
                     inspector.clazz("class_inliner_lambda_k_style.MainKt$testBigExtraMethod$1"),
-                    isPresentIf(testParameters.isCfRuntime()));
+                    isAbsent());
               }
             });
   }
@@ -298,15 +295,8 @@
                       clazz,
                       "main",
                       String[].class.getCanonicalName()));
-              String kotlinIntrinsics = "void kotlin.jvm.internal.Intrinsics";
               assertEquals(
-                  Lists.newArrayList(
-                      kotlinIntrinsics
-                          + (kotlinc.is(KOTLINC_1_3_72)
-                              ? ".checkParameterIsNotNull"
-                              : ".checkNotNullParameter")
-                          + "(java.lang.Object, java.lang.String)"),
-                  collectStaticCalls(clazz, "main", String[].class.getCanonicalName()));
+                  0, collectStaticCalls(clazz, "main", String[].class.getCanonicalName()).size());
             });
   }
 
diff --git a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinNullChecksTest.java b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinNullChecksTest.java
index 965918d..4dc5c4e 100644
--- a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinNullChecksTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinNullChecksTest.java
@@ -9,11 +9,13 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.google.common.collect.ImmutableMap;
 import java.io.IOException;
+import java.nio.file.Path;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -31,9 +33,10 @@
     return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  private static final String EXPECTED_OUTPUT_D8 =
+  private static final String EXPECTED_OUTPUT_WITH_INVOKE_OF_INTRINSICS =
       StringUtils.lines("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Hello, world!");
-  private static final String EXPECTED_OUTPUT = StringUtils.lines("Hello, world!");
+  private static final String EXPECTED_OUTPUT_WITHOUT_INVOKE_OF_INTRINSICS =
+      StringUtils.lines("Hello, world!");
   private static final String[] RUN_ARGUMENTS =
       new String[] {"", "", "", "", "", "", "", "", "", ""};
 
@@ -86,7 +89,7 @@
         .run(parameters.getRuntime(), TestClass.class, RUN_ARGUMENTS)
         .inspect(inspector -> assertKotlinIntrinsicsInvokes(inspector, 10))
         .inspect(inspector -> assertObjectGetClassInvokes(inspector, 0))
-        .assertSuccessWithOutput(EXPECTED_OUTPUT_D8);
+        .assertSuccessWithOutput(EXPECTED_OUTPUT_WITH_INVOKE_OF_INTRINSICS);
   }
 
   @Test
@@ -97,22 +100,64 @@
         .run(parameters.getRuntime(), TestClass.class, RUN_ARGUMENTS)
         .inspect(inspector -> assertKotlinIntrinsicsInvokes(inspector, 10))
         .inspect(inspector -> assertObjectGetClassInvokes(inspector, 0))
-        .assertSuccessWithOutput(EXPECTED_OUTPUT_D8);
+        .assertSuccessWithOutput(EXPECTED_OUTPUT_WITH_INVOKE_OF_INTRINSICS);
   }
 
   @Test
   public void testR8() throws Exception {
-    parameters.assumeDexRuntime();
     testForR8(parameters)
         .addProgramClassFileData(getTransformedMain())
         .addClasspathClassFileData(getTransformedKotlinIntrinsics())
         .addKeepMainRule(TestClass.class)
-        .compile()
-        .addRunClasspathClassFileData(getTransformedKotlinIntrinsics())
+        .run(parameters.getRuntime(), TestClass.class, RUN_ARGUMENTS)
+        .inspect(inspector -> assertKotlinIntrinsicsInvokes(inspector, 0))
+        .inspect(inspector -> assertObjectGetClassInvokes(inspector, 10))
+        .assertSuccessWithOutput(EXPECTED_OUTPUT_WITHOUT_INVOKE_OF_INTRINSICS);
+  }
+
+  @Test
+  public void testR8ProcessKotlinNullChecksLeave() throws Exception {
+    Path fakeKotlinIntrinsicsLibrary =
+        testForD8(parameters)
+            .addProgramClassFileData(getTransformedKotlinIntrinsics())
+            .compile()
+            .writeToZip();
+    testForR8(parameters)
+        .addProgramClassFileData(getTransformedMain())
+        .addClasspathClassFileData(getTransformedKotlinIntrinsics())
+        .addKeepMainRule(TestClass.class)
+        .addKeepRules("-processkotlinnullchecks keep")
+        .addRunClasspathFiles(fakeKotlinIntrinsicsLibrary)
         .run(parameters.getRuntime(), TestClass.class, RUN_ARGUMENTS)
         .inspect(inspector -> assertKotlinIntrinsicsInvokes(inspector, 10))
         .inspect(inspector -> assertObjectGetClassInvokes(inspector, 0))
-        .assertSuccessWithOutput(EXPECTED_OUTPUT_D8);
+        .assertSuccessWithOutput(EXPECTED_OUTPUT_WITH_INVOKE_OF_INTRINSICS);
+  }
+
+  @Test
+  public void testR8ProcessKotlinNullChecksRemoveMessage() throws Exception {
+    testForR8(parameters)
+        .addProgramClassFileData(getTransformedMain())
+        .addClasspathClassFileData(getTransformedKotlinIntrinsics())
+        .addKeepMainRule(TestClass.class)
+        .addKeepRules("-processkotlinnullchecks remove_message")
+        .run(parameters.getRuntime(), TestClass.class, RUN_ARGUMENTS)
+        .inspect(inspector -> assertKotlinIntrinsicsInvokes(inspector, 0))
+        .inspect(inspector -> assertObjectGetClassInvokes(inspector, 10))
+        .assertSuccessWithOutput(EXPECTED_OUTPUT_WITHOUT_INVOKE_OF_INTRINSICS);
+  }
+
+  @Test
+  public void testR8ProcessKotlinNullChecksRemove() throws Exception {
+    testForR8(parameters)
+        .addProgramClassFileData(getTransformedMain())
+        .addClasspathClassFileData(getTransformedKotlinIntrinsics())
+        .addKeepMainRule(TestClass.class)
+        .addKeepRules("-processkotlinnullchecks remove")
+        .run(parameters.getRuntime(), TestClass.class, RUN_ARGUMENTS)
+        .inspect(inspector -> assertKotlinIntrinsicsInvokes(inspector, 0))
+        .inspect(inspector -> assertObjectGetClassInvokes(inspector, 0))
+        .assertSuccessWithOutput(EXPECTED_OUTPUT_WITHOUT_INVOKE_OF_INTRINSICS);
   }
 
   private void addRuleForKotlinIntrinsics(String rule, R8TestBuilder<?, ?, ?> builder) {
@@ -137,12 +182,13 @@
     testForR8(parameters)
         .addProgramClassFileData(getTransformedMain())
         .addClasspathClassFileData(getTransformedKotlinIntrinsics())
+        .addKeepRules("-processkotlinnullchecks keep")
         .apply(b -> addRuleForKotlinIntrinsics("-convertchecknotnull", b))
         .addKeepMainRule(TestClass.class)
         .run(parameters.getRuntime(), TestClass.class, RUN_ARGUMENTS)
         .inspect(inspector -> assertKotlinIntrinsicsInvokes(inspector, 0))
         .inspect(inspector -> assertObjectGetClassInvokes(inspector, 10))
-        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+        .assertSuccessWithOutput(EXPECTED_OUTPUT_WITHOUT_INVOKE_OF_INTRINSICS);
   }
 
   @Test
@@ -150,12 +196,13 @@
     testForR8(parameters)
         .addProgramClassFileData(getTransformedMain())
         .addClasspathClassFileData(getTransformedKotlinIntrinsics())
+        .addKeepRules("-processkotlinnullchecks remove_message")
         .apply(b -> addRuleForKotlinIntrinsics("-assumenosideeffects", b))
         .addKeepMainRule(TestClass.class)
         .run(parameters.getRuntime(), TestClass.class, RUN_ARGUMENTS)
         .inspect(inspector -> assertKotlinIntrinsicsInvokes(inspector, 0))
         .inspect(inspector -> assertObjectGetClassInvokes(inspector, 0))
-        .assertSuccessWithOutput(EXPECTED_OUTPUT);
+        .assertSuccessWithOutput(EXPECTED_OUTPUT_WITHOUT_INVOKE_OF_INTRINSICS);
   }
 
   private byte[] getTransformedMain() throws IOException {
@@ -163,13 +210,13 @@
         .replaceClassDescriptorInMethodInstructions(
             ImmutableMap.of(
                 descriptor(KotlinJvmInternalIntrinsicsStub.class),
-                "Lkotlin/jvm/internal/Intrinsics;"))
+                DexItemFactory.kotlinJvmInternalIntrinsicsDescriptor))
         .transform();
   }
 
   private byte[] getTransformedKotlinIntrinsics() throws IOException {
     return transformer(KotlinJvmInternalIntrinsicsStub.class)
-        .setClassDescriptor("Lkotlin/jvm/internal/Intrinsics;")
+        .setClassDescriptor(DexItemFactory.kotlinJvmInternalIntrinsicsDescriptor)
         .transform();
   }
 
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
index 45aad76..cc2b6c5 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
@@ -129,6 +129,14 @@
                 testBuilder
                     .addKeepRules(keepClassMethod(mainClassName, testMethodSignature))
                     .addOptionsModification(disableClassInliner))
-        .inspect(inspector -> checkClassIsRemoved(inspector, TEST_DATA_CLASS.getClassName()));
+        .applyIf(
+            testParameters.isCfRuntime(),
+            b ->
+                b.inspect(
+                    inspector -> checkClassIsRemoved(inspector, TEST_DATA_CLASS.getClassName())),
+            // TODO(b/461691875): Why is the class not removed (it is unused).
+            b ->
+                b.inspect(
+                    inspector -> checkClassIsKept(inspector, TEST_DATA_CLASS.getClassName())));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java
index eb55f31..071df42 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java
@@ -49,7 +49,9 @@
             "intrinsics",
             "intrinsics.IntrinsicsKt",
             testBuilder ->
-                testBuilder.addKeepRules(extraRules).noHorizontalClassMerging(Intrinsics.class))
+                testBuilder
+                    .addKeepRules(extraRules, "-processkotlinnullchecks keep")
+                    .noHorizontalClassMerging(Intrinsics.class))
         .inspect(
             inspector -> {
               ClassSubject intrinsicsClass =
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingCapturesKotlinStyleTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingCapturesKotlinStyleTest.java
index ea1031a..1ee6b63 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingCapturesKotlinStyleTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingCapturesKotlinStyleTest.java
@@ -87,8 +87,7 @@
         .addHorizontallyMergedClassesInspector(
             inspector -> {
               if (parameters.isDexRuntime()
-                  && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.L)
-                  && kotlinParameters.getLambdaGeneration().isInvokeDynamic()) {
+                  && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.L)) {
                 SyntheticItemsTestUtils syntheticItems = testBuilder.getState().getSyntheticItems();
                 inspector
                     .assertIsCompleteMergeGroup(
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java
index 8f4d567..e22c378 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java
@@ -146,10 +146,7 @@
       if (kotlinParameters.getLambdaGeneration().isClass()) {
         inspector
             .assertIsCompleteMergeGroup(
-                lambdasInInput.getKStyleLambdaReferenceFromTypeName(getTestName(), "MainKt$main$1"),
-                lambdasInInput.getKStyleLambdaReferenceFromTypeName(getTestName(), "MainKt$main$2"),
                 lambdasInInput.getKStyleLambdaReferenceFromTypeName(getTestName(), "MainKt$main$3"),
-                lambdasInInput.getKStyleLambdaReferenceFromTypeName(getTestName(), "MainKt$main$4"),
                 lambdasInInput.getKStyleLambdaReferenceFromTypeName(
                     getTestName(), "MainKt$testFirst$1"),
                 lambdasInInput.getKStyleLambdaReferenceFromTypeName(
@@ -195,31 +192,8 @@
         ClassReference mainKt = Reference.classFromTypeName(getMainClassName());
         List<ClassReference> mergeGroup =
             ImmutableList.of(
-                syntheticItems.syntheticLambdaClass(mainKt, 1),
-                syntheticItems.syntheticLambdaClass(mainKt, 2),
-                syntheticItems.syntheticLambdaClass(mainKt, 3),
-                syntheticItems.syntheticLambdaClass(mainKt, 4),
-                syntheticItems.syntheticLambdaClass(mainKt, 5),
-                syntheticItems.syntheticLambdaClass(mainKt, 6),
-                syntheticItems.syntheticLambdaClass(mainKt, 7),
-                syntheticItems.syntheticLambdaClass(mainKt, 8),
-                syntheticItems.syntheticLambdaClass(mainKt, 9),
-                syntheticItems.syntheticLambdaClass(mainKt, 10),
-                syntheticItems.syntheticLambdaClass(mainKt, 11),
-                syntheticItems.syntheticLambdaClass(mainKt, 12),
-                syntheticItems.syntheticLambdaClass(mainKt, 13),
-                syntheticItems.syntheticLambdaClass(mainKt, 14),
-                syntheticItems.syntheticLambdaClass(mainKt, 15),
-                syntheticItems.syntheticLambdaClass(mainKt, 16),
-                syntheticItems.syntheticLambdaClass(mainKt, 17),
-                syntheticItems.syntheticLambdaClass(mainKt, 18),
-                syntheticItems.syntheticLambdaClass(mainKt, 19),
-                syntheticItems.syntheticLambdaClass(mainKt, 20),
-                syntheticItems.syntheticLambdaClass(mainKt, 21),
-                syntheticItems.syntheticLambdaClass(mainKt, 22),
-                syntheticItems.syntheticLambdaClass(mainKt, 23),
-                syntheticItems.syntheticLambdaClass(mainKt, 24),
-                syntheticItems.syntheticBottomUpOutlineClass(mainKt, 0));
+                syntheticItems.syntheticBottomUpOutlineClass(mainKt, 0),
+                syntheticItems.syntheticBottomUpOutlineClass(mainKt, 1));
         inspector.assertIsCompleteMergeGroup(mergeGroup).assertNoOtherClassesMerged();
       }
     }
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingSingletonTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingSingletonTest.java
index c4a70db..6ee7339 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingSingletonTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingSingletonTest.java
@@ -13,7 +13,6 @@
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.references.ClassReference;
-import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -95,9 +94,7 @@
     if (kotlinParameters.getCompilerVersion().isLessThanOrEqualTo(KOTLINC_1_9_21)) {
       inspector.assertIsCompleteMergeGroup(lambdasInInput.getJStyleLambdas());
     } else {
-      assertEquals(
-          parameters.isCfRuntime() || parameters.getApiLevel() == AndroidApiLevel.B ? 3 : 4,
-          inspector.getMergeGroups().size());
+      assertEquals(3, inspector.getMergeGroups().size());
     }
 
     // The remaining lambdas are not merged.
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialKotlinStyleTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialKotlinStyleTest.java
index 483460c..6c76091 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialKotlinStyleTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialKotlinStyleTest.java
@@ -153,7 +153,7 @@
     assertEquals(
         kotlinParameters.getLambdaGeneration().isInvokeDynamic()
             ? 0
-            : allowAccessModification && parameters.isCfRuntime() ? 1 : 1,
+            : parameters.isDexRuntime() ? 1 : 0,
         lambdasInOutput.size());
   }
 
diff --git a/src/test/java/com/android/tools/r8/kotlin/optimize/defaultarguments/KotlinDefaultArgumentsTest.java b/src/test/java/com/android/tools/r8/kotlin/optimize/defaultarguments/KotlinDefaultArgumentsTest.java
index 4a39c83..aaed8b1 100644
--- a/src/test/java/com/android/tools/r8/kotlin/optimize/defaultarguments/KotlinDefaultArgumentsTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/optimize/defaultarguments/KotlinDefaultArgumentsTest.java
@@ -95,6 +95,29 @@
         .addProgramFiles(kotlinc.getKotlinStdlibJar())
         .addProgramFiles(kotlinc.getKotlinAnnotationJar())
         .addKeepMainRule(MAIN)
+        // With default -processkotlinnullchecks inlining of "unrelated" Kotlin intrinsics cause
+        // an ArrayLength instruction to enter read$default
+        .enableProguardTestOptions()
+        .addKeepRules(
+            "-neverinline class kotlin.jvm.internal.Intrinsics { java.lang.Throwable"
+                + " sanitizeStackTrace(java.lang.Throwable); }")
+        .allowAccessModification()
+        .setMinApi(parameters)
+        .compile()
+        .inspect(inspector -> inspect(inspector, true))
+        .run(parameters.getRuntime(), MAIN)
+        .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
+  }
+
+  @Test
+  public void testR8KeepKotlinNullChecks()
+      throws ExecutionException, CompilationFailedException, IOException {
+    testForR8(parameters.getBackend())
+        .addProgramFiles(compilationResults.getForConfiguration(kotlinParameters))
+        .addProgramFiles(kotlinc.getKotlinStdlibJar())
+        .addProgramFiles(kotlinc.getKotlinAnnotationJar())
+        .addKeepMainRule(MAIN)
+        .addKeepRules("-processkotlinnullchecks keep")
         .allowAccessModification()
         .setMinApi(parameters)
         .compile()
diff --git a/src/test/java/com/android/tools/r8/processkeeprules/ProcessKeepRulesCommandTest.java b/src/test/java/com/android/tools/r8/processkeeprules/ProcessKeepRulesCommandTest.java
index f784755..e3b6656 100644
--- a/src/test/java/com/android/tools/r8/processkeeprules/ProcessKeepRulesCommandTest.java
+++ b/src/test/java/com/android/tools/r8/processkeeprules/ProcessKeepRulesCommandTest.java
@@ -95,6 +95,18 @@
           .put(
               "-whyareyounotinlining class * { *; }",
               "-whyareyounotinlining not allowed in library consumer rules.")
+          .put(
+              "-processkotlinnullchecks",
+              "-processkotlinnullchecks not allowed in library consumer rules.")
+          .put(
+              "-processkotlinnullchecks keep",
+              "-processkotlinnullchecks not allowed in library consumer rules.")
+          .put(
+              "-processkotlinnullchecks remove_message",
+              "-processkotlinnullchecks not allowed in library consumer rules.")
+          .put(
+              "-processkotlinnullchecks remove",
+              "-processkotlinnullchecks not allowed in library consumer rules.")
           .build();
 
   @Parameter(1)
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
index 24490f3..91e3aa5 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -27,6 +27,7 @@
 import com.android.tools.r8.position.Position;
 import com.android.tools.r8.position.TextRange;
 import com.android.tools.r8.shaking.ProguardClassNameList.SingleClassNameList;
+import com.android.tools.r8.shaking.ProguardConfiguration.ProcessKotlinNullChecks;
 import com.android.tools.r8.shaking.ProguardConfigurationParser.IdentifierPatternWithWildcards;
 import com.android.tools.r8.shaking.ProguardTypeMatcher.MatchSpecificType;
 import com.android.tools.r8.shaking.constructor.InitMatchingTest;
@@ -3020,6 +3021,83 @@
   }
 
   @Test
+  public void parseProcessKotlinNullChecks() {
+    {
+      String configuration = StringUtils.lines("");
+      parser.parse(createConfigurationForTesting(configuration));
+      verifyParserEndsCleanly();
+
+      ProguardConfiguration config = builder.build();
+      assertEquals(ProcessKotlinNullChecks.DEFAULT, config.getProcessKotlinNullChecks());
+      assertEquals(0, config.getRules().size());
+    }
+    reset();
+
+    {
+      String configuration = StringUtils.lines("-processkotlinnullchecks");
+      parser.parse(createConfigurationForTesting(configuration));
+      verifyParserEndsCleanly();
+
+      ProguardConfiguration config = builder.build();
+      assertEquals(ProcessKotlinNullChecks.REMOVE_MESSAGE, config.getProcessKotlinNullChecks());
+      assertEquals(0, config.getRules().size());
+    }
+    reset();
+
+    {
+      String configuration = StringUtils.lines("-processkotlinnullchecks keep");
+      parser.parse(createConfigurationForTesting(configuration));
+      verifyParserEndsCleanly();
+
+      ProguardConfiguration config = builder.build();
+      assertEquals(ProcessKotlinNullChecks.KEEP, config.getProcessKotlinNullChecks());
+      assertEquals(0, config.getRules().size());
+    }
+    for (String configuration :
+        ImmutableList.of(
+            StringUtils.lines("-processkotlinnullchecks remove_message"),
+            StringUtils.lines(
+                "-processkotlinnullchecks remove_message", "-processkotlinnullchecks keep"),
+            StringUtils.lines(
+                "-processkotlinnullchecks keep", "-processkotlinnullchecks remove_message"))) {
+      reset();
+
+      parser.parse(createConfigurationForTesting(configuration));
+      verifyParserEndsCleanly();
+
+      ProguardConfiguration config = builder.build();
+      assertEquals(ProcessKotlinNullChecks.REMOVE_MESSAGE, config.getProcessKotlinNullChecks());
+      assertEquals(0, config.getRules().size());
+    }
+
+    for (String configuration :
+        ImmutableList.of(
+            StringUtils.lines("-processkotlinnullchecks remove"),
+            StringUtils.lines(
+                "-processkotlinnullchecks remove", "-processkotlinnullchecks remove_message"),
+            StringUtils.lines(
+                "-processkotlinnullchecks remove", "-processkotlinnullchecks keep"))) {
+      reset();
+      parser.parse(createConfigurationForTesting(configuration));
+      verifyParserEndsCleanly();
+
+      ProguardConfiguration config = builder.build();
+      assertEquals(ProcessKotlinNullChecks.REMOVE, config.getProcessKotlinNullChecks());
+      assertEquals(0, config.getRules().size());
+    }
+
+    reset();
+
+    try {
+      String configuration = StringUtils.lines("-processkotlinnullchecks leave");
+      parser.parse(createConfigurationForTesting(configuration));
+      fail("Expect to fail due to unsupported value.");
+    } catch (RuntimeException e) {
+      checkDiagnostics(handler.errors, null, 1, 26, "Illegal value for -processkotlinnullchecks");
+    }
+  }
+
+  @Test
   public void testParsedConfigurationWithInclude() throws Exception {
     Path config = temp.newFile("config.txt").toPath().toAbsolutePath();
     Path include1 = temp.newFile("include1.txt").toPath().toAbsolutePath();
diff --git a/tools/download_kotlin.py b/tools/download_kotlin.py
index e07c86c..11576c5 100755
--- a/tools/download_kotlin.py
+++ b/tools/download_kotlin.py
@@ -14,8 +14,8 @@
 
 
 JETBRAINS_KOTLIN_STABLE_URL = "https://github.com/JetBrains/kotlin/releases/download"
-JETBRAINS_KOTLIN_MAVEN_URL = "https://packages.jetbrains.team/maven/p/" \
-                             "kt/bootstrap/org/jetbrains/kotlin/"
+JETBRAINS_KOTLIN_MAVEN_URL = "https://redirector.kotlinlang.org/maven/" \
+                             "bootstrap/org/jetbrains/kotlin/"
 
 KOTLIN_RELEASE_URL = JETBRAINS_KOTLIN_MAVEN_URL + "kotlin-compiler/"
 KOTLINC_LIB = os.path.join(utils.THIRD_PARTY, "kotlin",
@@ -92,7 +92,7 @@
 
     if (top_most_version_and_build is None):
         raise Exception('Url: %s \n returned %s' %
-                        (KOTLIN_RELEASE_URL, response.getcode()))
+                        (response.geturl(), response.getcode()))
 
     # Download checked in kotlin dev compiler before owerlaying with the new.
     # TODO(sgjesse): This should just ensure an empty directory instead of