Enable dynamic type optimization

Bug: 127461806
Change-Id: I8cc40901ea5cf4b977ba55b7b23caeaa43ab93b1
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index dfeaf74..4b53365 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -676,7 +676,7 @@
             ? LineNumberOptimization.ON
             : LineNumberOptimization.OFF;
 
-    assert !internal.enableDynamicTypeOptimization;
+    assert internal.enableDynamicTypeOptimization || !proguardConfiguration.isOptimizing();
     assert internal.enableHorizontalClassMerging || !proguardConfiguration.isOptimizing();
     assert !internal.enableTreeShakingOfLibraryMethodOverrides;
     assert internal.enableVerticalClassMerging || !proguardConfiguration.isOptimizing();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index f214373..334bfb2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -2094,7 +2094,9 @@
         if (aliasedValue != null) {
           TypeLatticeElement dynamicType =
               aliasedValue.definition.asAssumeDynamicType().getAssumption().getType();
-          if (dynamicType.lessThanOrEqual(instanceOfType, appView)
+          if (dynamicType.isDefinitelyNull()) {
+            result = InstanceOfResult.FALSE;
+          } else if (dynamicType.lessThanOrEqual(instanceOfType, appView)
               && (!inType.isNullable() || !dynamicType.isNullable())) {
             result = InstanceOfResult.TRUE;
           }
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index c1b199c..022a58d 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -136,7 +136,7 @@
   public boolean passthroughDexCode = false;
 
   // Optimization-related flags. These should conform to -dontoptimize and disableAllOptimizations.
-  public boolean enableDynamicTypeOptimization = false;
+  public boolean enableDynamicTypeOptimization = true;
   public boolean enableHorizontalClassMerging = true;
   public boolean enableVerticalClassMerging = true;
   public boolean enableArgumentRemoval = true;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/InstanceOfRemovalTest.java b/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/InstanceOfRemovalTest.java
index efd4766..1cbeaae 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/InstanceOfRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/instanceofremoval/InstanceOfRemovalTest.java
@@ -8,7 +8,8 @@
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -16,6 +17,7 @@
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.Streams;
 import java.util.Iterator;
+import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -109,15 +111,17 @@
     }
   }
 
-  @Parameters(name = "Backend: {0}")
-  public static Backend[] data() {
-    return ToolHelper.getBackends();
+  @Parameters(name = "{1}, enable dynamic type optimization: {0}")
+  public static List<Object[]> data() {
+    return buildParameters(BooleanUtils.values(), getTestParameters().withAllRuntimes().build());
   }
 
-  private final Backend backend;
+  private final boolean enableDynamicTypeOptimization;
+  private final TestParameters parameters;
 
-  public InstanceOfRemovalTest(Backend backend) {
-    this.backend = backend;
+  public InstanceOfRemovalTest(boolean enableDynamicTypeOptimization, TestParameters parameters) {
+    this.enableDynamicTypeOptimization = enableDynamicTypeOptimization;
+    this.parameters = parameters;
   }
 
   @Test
@@ -146,14 +150,22 @@
             "B[] instanceof B[]: true",
             "");
 
-    testForJvm().addTestClasspath().run(TestClass.class).assertSuccessWithOutput(expected);
+    if (parameters.isCfRuntime()) {
+      testForJvm()
+          .addTestClasspath()
+          .run(parameters.getRuntime(), TestClass.class)
+          .assertSuccessWithOutput(expected);
+    }
 
     CodeInspector inspector =
-        testForR8(backend)
+        testForR8(parameters.getBackend())
             .addProgramClasses(A.class, B.class, TestClass.class)
             .addKeepMainRule(TestClass.class)
+            .addOptionsModification(
+                options -> options.enableDynamicTypeOptimization = enableDynamicTypeOptimization)
             .enableInliningAnnotations()
-            .run(TestClass.class)
+            .setMinApi(parameters.getRuntime())
+            .run(parameters.getRuntime(), TestClass.class)
             .assertSuccessWithOutput(expected)
             .inspector();
 
@@ -165,10 +177,12 @@
         fooMethodSubject.iterateInstructions(InstructionSubject::isInstanceOf);
     assertEquals(0, Streams.stream(fooInstructionIterator).count());
 
-    // Without inlining we cannot prove any of the instance-of checks to be trivial.
+    // Without inlining we cannot prove any of the instance-of checks to be trivial, but the dynamic
+    // type optimization allows us to prove that some are safe.
     MethodSubject barMethodSubject = testClass.uniqueMethodWithName("bar");
     Iterator<InstructionSubject> barInstructionIterator =
         barMethodSubject.iterateInstructions(InstructionSubject::isInstanceOf);
-    assertEquals(6, Streams.stream(barInstructionIterator).count());
+    assertEquals(
+        enableDynamicTypeOptimization ? 4 : 6, Streams.stream(barInstructionIterator).count());
   }
 }