Improve logging in type propagation

Change-Id: I51d1cf307f05e9269919f8a89cd58f705b14e128
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithUpperBound.java b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithUpperBound.java
index 68777ec..2c9fc11 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithUpperBound.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithUpperBound.java
@@ -269,7 +269,19 @@
 
   @Override
   public String toString() {
-    return "DynamicTypeWithUpperBound(upperBound=" + getDynamicUpperBoundType() + ")";
+    if (isBottom()) {
+      return "BottomDynamicType";
+    }
+    if (isNotNullType()) {
+      return "NotNullDynamicType";
+    }
+    if (isNullType()) {
+      return "NullDynamicType";
+    }
+    if (isUnknown()) {
+      return "UnknownDynamicType";
+    }
+    return "DynamicTypeWithUpperBound(" + getDynamicUpperBoundType() + ")";
   }
 
   private static boolean verifyNotEffectivelyFinalClassType(
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java
index 816388f..b620d4c 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java
@@ -77,6 +77,6 @@
 
   @Override
   public String toString() {
-    return "ExactDynamicType(type=" + getExactClassType() + ")";
+    return "ExactDynamicType(" + getExactClassType() + ")";
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/StatefulObjectValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/StatefulObjectValue.java
index e735de5..8987509 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/StatefulObjectValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/StatefulObjectValue.java
@@ -68,7 +68,7 @@
 
   @Override
   public String toString() {
-    return "StatefulValue";
+    return "StatefulValue(" + state + ")";
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EmptyObjectState.java b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EmptyObjectState.java
index d16e2b0..110e009 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EmptyObjectState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EmptyObjectState.java
@@ -52,4 +52,9 @@
   public int hashCode() {
     return System.identityHashCode(this);
   }
+
+  @Override
+  public String toString() {
+    return "EmptyObjectState";
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/KnownLengthArrayState.java b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/KnownLengthArrayState.java
index a773fd2..ca07bf0 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/KnownLengthArrayState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/KnownLengthArrayState.java
@@ -60,4 +60,9 @@
   public int hashCode() {
     return System.identityHashCode(this);
   }
+
+  @Override
+  public String toString() {
+    return "KnownLengthArrayState(" + length + ")";
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/NonEmptyObjectState.java b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/NonEmptyObjectState.java
index 7acebdd..cc3f212 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/NonEmptyObjectState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/NonEmptyObjectState.java
@@ -10,7 +10,11 @@
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.ListUtils;
+import com.android.tools.r8.utils.StringUtils;
+import java.util.ArrayList;
 import java.util.IdentityHashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.function.BiConsumer;
 
@@ -78,4 +82,15 @@
   public int hashCode() {
     return state.hashCode();
   }
+
+  @Override
+  public String toString() {
+    List<DexField> sortedKeys = ListUtils.sort(state.keySet(), DexField::compareTo);
+    List<String> data = new ArrayList<>();
+    for (DexField key : sortedKeys) {
+      AbstractValue abstractValue = state.get(key);
+      data.add(key.toSourceString() + " -> " + abstractValue);
+    }
+    return "ObjectState(" + StringUtils.join(", ", data) + ")";
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/AbstractFunction.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/AbstractFunction.java
index 7b390d6..852bd2b 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/AbstractFunction.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/AbstractFunction.java
@@ -42,6 +42,10 @@
    */
   Iterable<BaseInFlow> getBaseInFlow();
 
+  default boolean hasSingleInFlow() {
+    return true;
+  }
+
   @Override
   default boolean isAbstractFunction() {
     return true;
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/FlowGraphStateProvider.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/FlowGraphStateProvider.java
index 764c7f4..fce1a27 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/FlowGraphStateProvider.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/FlowGraphStateProvider.java
@@ -17,10 +17,11 @@
     }
     // If the abstract function is a canonical function, or the abstract function has a single
     // declared input, we should never perform any state lookups.
-    if (abstractFunction.isIdentity()
-        || abstractFunction.isCastAbstractFunction()
-        || abstractFunction.isUnknownAbstractFunction()
-        || abstractFunction.isUpdateChangedFlagsAbstractFunction()) {
+    if (abstractFunction.hasSingleInFlow()) {
+      assert abstractFunction.isIdentity()
+          || abstractFunction.isCastAbstractFunction()
+          || abstractFunction.isUnknownAbstractFunction()
+          || abstractFunction.isUpdateChangedFlagsAbstractFunction();
       return new FlowGraphStateProvider() {
 
         @Override
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InFlow.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InFlow.java
index ab8aed4..3c071be 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InFlow.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InFlow.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.optimize.argumentpropagation.codescanner;
 
 import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.optimize.compose.UpdateChangedFlagsAbstractFunction;
 
 public interface InFlow {
@@ -56,6 +57,10 @@
     return false;
   }
 
+  default boolean isMethodParameter(DexMethod method, int parameterIndex) {
+    return false;
+  }
+
   default MethodParameter asMethodParameter() {
     return null;
   }
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 1993257..366dea4 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
@@ -63,6 +63,11 @@
   }
 
   @Override
+  public boolean hasSingleInFlow() {
+    return false;
+  }
+
+  @Override
   public boolean isInstanceFieldReadAbstractFunction() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodParameter.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodParameter.java
index 7ebb2d0..b8481e4 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodParameter.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodParameter.java
@@ -47,6 +47,11 @@
   }
 
   @Override
+  public boolean isMethodParameter(DexMethod method, int parameterIndex) {
+    return this.method.isIdenticalTo(method) && this.index == parameterIndex;
+  }
+
+  @Override
   public MethodParameter asMethodParameter() {
     return this;
   }
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 d65a397..04ec003 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
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramField;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.BaseInFlow;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.ValueState;
 
 public class FlowGraphFieldNode extends FlowGraphNode {
@@ -22,6 +23,11 @@
   }
 
   @Override
+  boolean equalsBaseInFlow(BaseInFlow inFlow) {
+    return inFlow.isFieldValue(field.getReference());
+  }
+
+  @Override
   DexType getStaticType() {
     return field.getType();
   }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphNode.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphNode.java
index ba8f33b..7e9e448 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphNode.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphNode.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.AbstractFunction;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.BaseInFlow;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteValueState;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.StateCloner;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.ValueState;
@@ -53,6 +54,8 @@
     }
   }
 
+  abstract boolean equalsBaseInFlow(BaseInFlow inFlow);
+
   boolean getDebug() {
     return debug;
   }
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 555e6c8..0bf105a 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.BaseInFlow;
 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;
@@ -34,6 +35,11 @@
   }
 
   @Override
+  boolean equalsBaseInFlow(BaseInFlow inFlow) {
+    return inFlow.isMethodParameter(method.getReference(), parameterIndex);
+  }
+
+  @Override
   DexType getStaticType() {
     return parameterType;
   }
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 67f7f65..2cdcf24 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
@@ -256,7 +256,8 @@
           state,
           transferFunction,
           transferState,
-          oldSuccessorStateForDebugging);
+          oldSuccessorStateForDebugging,
+          flowGraphStateProvider);
 
       // If this successor has become unknown, there is no point in continuing to propagate
       // flow to it from any of its predecessors. We therefore clear the predecessors to
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InFlowPropagatorDebugUtils.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InFlowPropagatorDebugUtils.java
index d7f38d8..e17e5b6 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InFlowPropagatorDebugUtils.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InFlowPropagatorDebugUtils.java
@@ -6,9 +6,13 @@
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.AbstractFunction;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.BaseInFlow;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteValueState;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.FlowGraphStateProvider;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.ValueState;
+import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.WorkList;
+import java.util.ArrayList;
 import java.util.List;
 
 public class InFlowPropagatorDebugUtils {
@@ -76,18 +80,37 @@
       ConcreteValueState nodeStateAfterNarrowing,
       AbstractFunction transferFunction,
       ValueState transferState,
-      ValueState oldSuccessorState) {
+      ValueState oldSuccessorState,
+      FlowGraphStateProvider flowGraphStateProvider) {
     if (successorNode.getDebug()) {
+      List<String> transferFunctionDependencies = new ArrayList<>();
+      if (!transferFunction.hasSingleInFlow()) {
+        transferFunctionDependencies.add("");
+        transferFunctionDependencies.add("TRANSFER FN INPUTS:");
+        for (BaseInFlow transferFunctionDependency : transferFunction.getBaseInFlow()) {
+          if (!node.equalsBaseInFlow(transferFunctionDependency)) {
+            ValueState transferFunctionDependencyState =
+                flowGraphStateProvider.getState(transferFunctionDependency, null);
+            transferFunctionDependencies.add("  DEP: " + transferFunctionDependency);
+            transferFunctionDependencies.add("  DEP STATE: " + transferFunctionDependencyState);
+          }
+        }
+      }
+      ValueState newSuccessorState = successorNode.getState();
       log(
           "PROPAGATE CONCRETE",
           "FROM: " + node,
           "TO: " + successorNode,
           "NODE STATE: " + node.getState(),
-          "NODE STATE (NARROWED): " + nodeStateAfterNarrowing,
-          "TRANSFER FN: " + transferFunction,
+          "NODE STATE (NARROWED): "
+              + (nodeStateAfterNarrowing.equals(node.getState())
+                  ? "<unchanged>"
+                  : nodeStateAfterNarrowing),
+          "TRANSFER FN: " + transferFunction + StringUtils.joinLines(transferFunctionDependencies),
           "TRANSFER STATE: " + transferState,
           "SUCCESSOR STATE: " + oldSuccessorState,
-          "SUCCESSOR STATE (NEW): " + successorNode.getState());
+          "SUCCESSOR STATE (NEW): "
+              + (newSuccessorState.equals(oldSuccessorState) ? "<unchanged>" : newSuccessorState));
     }
     return true;
   }