Remove assume instructions after optimizing field get

Change-Id: Ia983932284883a1beb52ddf2e049b479d8af1e1c
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/AssumeRemover.java b/src/main/java/com/android/tools/r8/ir/optimize/AssumeRemover.java
index 85ac5b8..f8abfc5 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/AssumeRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/AssumeRemover.java
@@ -33,14 +33,19 @@
   private final AppView<?> appView;
   private final IRCode code;
 
-  private final Set<Value> affectedValues = Sets.newIdentityHashSet();
+  private final Set<Value> affectedValues;
   private final Set<Assume> assumeInstructionsToRemove = Sets.newIdentityHashSet();
 
   private boolean mayHaveIntroducedTrivialPhi = false;
 
   public AssumeRemover(AppView<?> appView, IRCode code) {
+    this(appView, code, Sets.newIdentityHashSet());
+  }
+
+  public AssumeRemover(AppView<?> appView, IRCode code, Set<Value> affectedValues) {
     this.appView = appView;
     this.code = code;
+    this.affectedValues = affectedValues;
   }
 
   public Set<Value> getAffectedValues() {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index 510331b..b4a067e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -1108,8 +1108,7 @@
       }
     }
     assert inlineeStack.isEmpty();
-    assumeRemover.removeMarkedInstructions(blocksToRemove);
-    assumeRemover.finish();
+    assumeRemover.removeMarkedInstructions(blocksToRemove).finish();
     classInitializationAnalysis.finish();
     code.removeBlocks(blocksToRemove);
     code.removeAllDeadAndTrivialPhis();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
index afb7003..b3f74c5 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
@@ -16,7 +16,6 @@
 import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
-import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
 import com.android.tools.r8.ir.analysis.value.SingleFieldValue;
 import com.android.tools.r8.ir.analysis.value.SingleValue;
 import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
@@ -189,6 +188,7 @@
       }
     }
 
+    AssumeRemover assumeRemover = new AssumeRemover(appView, code, affectedValues);
     for (BasicBlock head : code.topologicallySortedBlocks()) {
       if (head.hasUniquePredecessor() && head.getUniquePredecessor().hasUniqueNormalSuccessor()) {
         // Already visited.
@@ -211,14 +211,16 @@
             }
 
             if (instruction.isInstanceGet()) {
-              handleInstanceGet(it, instruction.asInstanceGet(), field);
+              handleInstanceGet(it, instruction.asInstanceGet(), field, assumeRemover);
             } else if (instruction.isInstancePut()) {
               handleInstancePut(instruction.asInstancePut(), field);
             } else if (instruction.isStaticGet()) {
-              handleStaticGet(it, instruction.asStaticGet(), field);
+              handleStaticGet(it, instruction.asStaticGet(), field, assumeRemover);
             } else if (instruction.isStaticPut()) {
               handleStaticPut(instruction.asStaticPut(), field);
             }
+          } else if (instruction.isAssume()) {
+            assumeRemover.removeIfMarked(instruction.asAssume(), it);
           } else if (instruction.isInitClass()) {
             handleInitClass(it, instruction.asInitClass());
           } else if (instruction.isMonitor()) {
@@ -288,9 +290,7 @@
       activeStates.recordActiveStateOnBlockExit(end, activeState);
     }
     processInstructionsToRemove();
-    if (!affectedValues.isEmpty()) {
-      new TypeAnalysis(appView).narrowing(affectedValues);
-    }
+    assumeRemover.removeMarkedInstructions().finish();
     assert code.isConsistentSSA();
   }
 
@@ -398,7 +398,10 @@
   }
 
   private void handleInstanceGet(
-      InstructionListIterator it, InstanceGet instanceGet, DexClassAndField field) {
+      InstructionListIterator it,
+      InstanceGet instanceGet,
+      DexClassAndField field,
+      AssumeRemover assumeRemover) {
     if (instanceGet.outValue().hasLocalInfo()) {
       clearMostRecentInstanceFieldWrite(instanceGet, field);
       return;
@@ -408,6 +411,7 @@
     FieldAndObject fieldAndObject = new FieldAndObject(field.getReference(), object);
     FieldValue replacement = activeState.getInstanceFieldValue(fieldAndObject);
     if (replacement != null) {
+      assumeRemover.markAssumeDynamicTypeUsersForRemoval(instanceGet.outValue());
       replacement.eliminateRedundantRead(it, instanceGet);
       return;
     }
@@ -464,7 +468,10 @@
   }
 
   private void handleStaticGet(
-      InstructionListIterator instructionIterator, StaticGet staticGet, DexClassAndField field) {
+      InstructionListIterator instructionIterator,
+      StaticGet staticGet,
+      DexClassAndField field,
+      AssumeRemover assumeRemover) {
     if (staticGet.outValue().hasLocalInfo()) {
       killNonFinalActiveFields(staticGet);
       clearMostRecentStaticFieldWrite(staticGet, field);
@@ -473,6 +480,7 @@
 
     FieldValue replacement = activeState.getStaticFieldValue(field.getReference());
     if (replacement != null) {
+      assumeRemover.markAssumeDynamicTypeUsersForRemoval(staticGet.outValue());
       replacement.eliminateRedundantRead(instructionIterator, staticGet);
       return;
     }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
index c3c2307..ef3795d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
@@ -14,12 +14,12 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionOrPhi;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.conversion.MethodProcessor;
+import com.android.tools.r8.ir.optimize.AssumeRemover;
 import com.android.tools.r8.ir.optimize.CodeRewriter;
 import com.android.tools.r8.ir.optimize.Inliner;
 import com.android.tools.r8.ir.optimize.InliningOracle;
@@ -209,8 +209,10 @@
 
         // Inline the class instance.
         Set<Value> affectedValues = Sets.newIdentityHashSet();
+        AssumeRemover assumeRemover = new AssumeRemover(appView, code, affectedValues);
         try {
-          anyInlinedMethods |= processor.processInlining(code, affectedValues, inliningIRProvider);
+          anyInlinedMethods |=
+              processor.processInlining(code, affectedValues, assumeRemover, inliningIRProvider);
         } catch (IllegalClassInlinerStateException e) {
           // We introduced a user that we cannot handle in the class inliner as a result of force
           // inlining. Abort gracefully from class inlining without removing the instance.
@@ -225,9 +227,7 @@
 
         // Restore normality.
         code.removeAllDeadAndTrivialPhis(affectedValues);
-        if (!affectedValues.isEmpty()) {
-          new TypeAnalysis(appView).narrowing(affectedValues);
-        }
+        assumeRemover.removeMarkedInstructions().finish();
         assert code.isConsistentSSA();
         rootsIterator.remove();
         repeat = true;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index 82322c7..375a8c3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -48,6 +48,7 @@
 import com.android.tools.r8.ir.code.StaticGet;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.conversion.MethodProcessor;
+import com.android.tools.r8.ir.optimize.AssumeRemover;
 import com.android.tools.r8.ir.optimize.Inliner;
 import com.android.tools.r8.ir.optimize.Inliner.InliningInfo;
 import com.android.tools.r8.ir.optimize.Inliner.Reason;
@@ -376,6 +377,7 @@
   boolean processInlining(
       IRCode code,
       Set<Value> affectedValues,
+      AssumeRemover assumeRemover,
       InliningIRProvider inliningIRProvider)
       throws IllegalClassInlinerStateException {
     // Verify that `eligibleInstance` is not aliased.
@@ -386,7 +388,7 @@
 
     rebindIndirectEligibleInstanceUsersFromPhis();
     removeMiscUsages(code, affectedValues);
-    removeFieldReads(code);
+    removeFieldReads(code, assumeRemover);
     removeFieldWrites();
     removeInstruction(root);
     return anyInlinedMethods;
@@ -666,24 +668,26 @@
   }
 
   // Replace field reads with appropriate values, insert phis when needed.
-  private void removeFieldReads(IRCode code) {
+  private void removeFieldReads(IRCode code, AssumeRemover assumeRemover) {
     Set<Value> affectedValues = Sets.newIdentityHashSet();
     if (root.isNewInstance()) {
-      removeFieldReadsFromNewInstance(code, affectedValues);
+      removeFieldReadsFromNewInstance(code, affectedValues, assumeRemover);
     } else {
       assert root.isStaticGet();
-      removeFieldReadsFromStaticGet(code, affectedValues);
+      removeFieldReadsFromStaticGet(code, affectedValues, assumeRemover);
     }
     if (!affectedValues.isEmpty()) {
       new TypeAnalysis(appView).narrowing(affectedValues);
     }
   }
 
-  private void removeFieldReadsFromNewInstance(IRCode code, Set<Value> affectedValues) {
+  private void removeFieldReadsFromNewInstance(
+      IRCode code, Set<Value> affectedValues, AssumeRemover assumeRemover) {
     TreeSet<InstanceGet> uniqueInstanceGetUsersWithDeterministicOrder =
         new TreeSet<>(Comparator.comparingInt(x -> x.outValue().getNumber()));
     for (Instruction user : eligibleInstance.uniqueUsers()) {
       if (user.isInstanceGet()) {
+        assumeRemover.markAssumeDynamicTypeUsersForRemoval(user.outValue());
         if (user.hasUsedOutValue()) {
           uniqueInstanceGetUsersWithDeterministicOrder.add(user.asInstanceGet());
         } else {
@@ -738,7 +742,8 @@
     removeInstruction(fieldRead);
   }
 
-  private void removeFieldReadsFromStaticGet(IRCode code, Set<Value> affectedValues) {
+  private void removeFieldReadsFromStaticGet(
+      IRCode code, Set<Value> affectedValues, AssumeRemover assumeRemover) {
     Set<BasicBlock> seen = Sets.newIdentityHashSet();
     Set<Instruction> users = eligibleInstance.uniqueUsers();
     for (Instruction user : users) {
@@ -759,6 +764,7 @@
         }
 
         if (instruction.isInstanceGet()) {
+          assumeRemover.markAssumeDynamicTypeUsersForRemoval(instruction.outValue());
           if (instruction.hasUsedOutValue()) {
             replaceFieldReadFromStaticGet(
                 code, instructionIterator, user.asInstanceGet(), affectedValues);