Defer clearing of in-flow to after flow graph construction

Change-Id: Ie34188a02588f9a425249fc2a36f1ff1c42fcd1f
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/CastAbstractFunction.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/CastAbstractFunction.java
index 2758d38..ee147a5 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/CastAbstractFunction.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/CastAbstractFunction.java
@@ -63,4 +63,9 @@
   public int hashCode() {
     return Objects.hash(inFlow, type);
   }
+
+  @Override
+  public String toString() {
+    return "Cast(" + inFlow + ", " + type.getTypeName() + ")";
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/FieldValue.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/FieldValue.java
index f7bd0ec..af8ec1a 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/FieldValue.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/FieldValue.java
@@ -51,4 +51,9 @@
   public int hashCode() {
     return field.hashCode();
   }
+
+  @Override
+  public String toString() {
+    return field.toSourceString();
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InstanceFieldReadAbstractFunction.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InstanceFieldReadAbstractFunction.java
index bd97c0b..1993257 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InstanceFieldReadAbstractFunction.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InstanceFieldReadAbstractFunction.java
@@ -71,4 +71,9 @@
   public InstanceFieldReadAbstractFunction asInstanceFieldReadAbstractFunction() {
     return this;
   }
+
+  @Override
+  public String toString() {
+    return "Read(" + receiver + ", " + field.toSourceString() + ")";
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphBuilder.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphBuilder.java
index 061c898..45ecb34 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphBuilder.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphBuilder.java
@@ -29,8 +29,8 @@
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.TraversalContinuation;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMaps;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
-import java.util.Collection;
 import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
@@ -57,10 +57,13 @@
     this.methodStates = methodStates;
   }
 
-  public FlowGraphBuilder addClasses(Collection<DexProgramClass> classes) {
-    for (DexProgramClass clazz : classes) {
-      add(clazz);
-    }
+  public FlowGraphBuilder addClasses() {
+    appView.appInfo().classes().forEach(this::add);
+    return this;
+  }
+
+  public FlowGraphBuilder clearInFlow() {
+    appView.appInfo().classes().forEach(this::clearInFlow);
     return this;
   }
 
@@ -97,15 +100,6 @@
         break;
       }
     }
-
-    ValueState concreteFieldStateOrBottom = concreteFieldState.clearInFlow();
-    if (concreteFieldStateOrBottom.isBottom()) {
-      fieldStates.remove(field);
-      if (!node.getState().isUnknown()) {
-        assert node.getState() == concreteFieldState;
-        node.setState(concreteFieldStateOrBottom);
-      }
-    }
   }
 
   private void addMethodParameters(ProgramMethod method) {
@@ -152,11 +146,6 @@
         break;
       }
     }
-
-    if (!node.getState().isUnknown()) {
-      assert node.getState() == concreteParameterState;
-      node.setState(concreteParameterState.clearInFlow());
-    }
   }
 
   // Returns BREAK if the current node has been set to unknown.
@@ -252,11 +241,60 @@
     return TraversalContinuation.doContinue();
   }
 
+  private void clearInFlow(DexProgramClass clazz) {
+    clazz.forEachProgramField(this::clearInFlow);
+    clazz.forEachProgramMethod(this::clearInFlow);
+  }
+
+  private void clearInFlow(ProgramField field) {
+    ConcreteValueState concreteFieldState = fieldStates.get(field).asConcrete();
+    if (concreteFieldState == null) {
+      return;
+    }
+    ValueState concreteFieldStateOrBottom = concreteFieldState.clearInFlow();
+    if (concreteFieldStateOrBottom.isBottom()) {
+      fieldStates.remove(field);
+      FlowGraphFieldNode node = getFieldNode(field);
+      if (node != null && !node.getState().isUnknown()) {
+        assert node.getState() == concreteFieldState;
+        node.setState(concreteFieldStateOrBottom);
+      }
+    }
+  }
+
+  private void clearInFlow(ProgramMethod method) {
+    ConcreteMonomorphicMethodState methodState = methodStates.get(method).asMonomorphic();
+    if (methodState != null) {
+      for (int i = 0; i < methodState.getParameterStates().size(); i++) {
+        ValueState parameterState = methodState.getParameterState(i);
+        ConcreteValueState concreteParameterState = parameterState.asConcrete();
+        if (concreteParameterState != null) {
+          ValueState concreteParameterStateOrBottom = concreteParameterState.clearInFlow();
+          FlowGraphParameterNode node = getParameterNode(method, i);
+          if (node != null && !node.getState().isUnknown()) {
+            assert node.getState() == concreteParameterState;
+            node.setState(concreteParameterStateOrBottom);
+          }
+        }
+      }
+    }
+  }
+
+  private FlowGraphFieldNode getFieldNode(ProgramField field) {
+    return fieldNodes.get(field.getReference());
+  }
+
   private FlowGraphFieldNode getOrCreateFieldNode(ProgramField field, ValueState fieldState) {
     return fieldNodes.computeIfAbsent(
         field.getReference(), ignoreKey(() -> new FlowGraphFieldNode(field, fieldState)));
   }
 
+  private FlowGraphParameterNode getParameterNode(ProgramMethod method, int parameterIndex) {
+    return parameterNodes
+        .getOrDefault(method.getReference(), Int2ReferenceMaps.emptyMap())
+        .get(parameterIndex);
+  }
+
   private FlowGraphParameterNode getOrCreateParameterNode(
       ProgramMethod method, int parameterIndex, MethodState methodState) {
     Int2ReferenceMap<FlowGraphParameterNode> parameterNodesForMethod =
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphFieldNode.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphFieldNode.java
index 4fed1f1..d65a397 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphFieldNode.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphFieldNode.java
@@ -45,4 +45,9 @@
   FlowGraphFieldNode asFieldNode() {
     return this;
   }
+
+  @Override
+  public String toString() {
+    return field.toSourceString();
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphParameterNode.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphParameterNode.java
index 12d516b..242faa1 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphParameterNode.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphParameterNode.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodParameter;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodState;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.ValueState;
 
@@ -67,4 +68,9 @@
   boolean isReceiverNode() {
     return !method.getAccessFlags().isStatic() && parameterIndex == 0;
   }
+
+  @Override
+  public String toString() {
+    return new MethodParameter(method, parameterIndex).toString();
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InFlowPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InFlowPropagator.java
index 0794838..1a26af0 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InFlowPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InFlowPropagator.java
@@ -92,7 +92,8 @@
     // must be included in the argument information for p'.
     FlowGraph flowGraph =
         FlowGraph.builder(appView, converter, fieldStates, methodStates)
-            .addClasses(appView.appInfo().classes())
+            .addClasses()
+            .clearInFlow()
             .build();
     List<Set<FlowGraphNode>> stronglyConnectedComponents =
         flowGraph.computeStronglyConnectedComponents();