Revert "Allow class inlining of merged singleton classes"

This reverts commit 0365eeed2f0d5fb0cfc87103595d2436e4ba52d4.

Reason for revert: Failures

Change-Id: I5e9121ef24a9fe11824c0cd74fb974e88a556c0d
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 37b3796..eb016fe 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
@@ -224,6 +224,8 @@
           anyInlinedMethods = true;
         }
 
+        assert inliningIRProvider.verifyIRCacheIsEmpty();
+
         // Restore normality.
         code.removeAllDeadAndTrivialPhis(affectedValues);
         if (!affectedValues.isEmpty()) {
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 23d9242..4b15332 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
@@ -25,12 +25,11 @@
 import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
 import com.android.tools.r8.ir.analysis.type.Nullability;
 import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
-import com.android.tools.r8.ir.analysis.value.AbstractValue;
-import com.android.tools.r8.ir.analysis.value.ObjectState;
 import com.android.tools.r8.ir.code.AliasedValueConfiguration;
 import com.android.tools.r8.ir.code.AssumeAndCheckCastAliasedValueConfiguration;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.CheckCast;
+import com.android.tools.r8.ir.code.ConstNumber;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.If;
 import com.android.tools.r8.ir.code.InstanceGet;
@@ -60,6 +59,7 @@
 import com.android.tools.r8.kotlin.KotlinClassLevelInfo;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.OptionalBool;
+import com.android.tools.r8.utils.Pair;
 import com.android.tools.r8.utils.SetUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.Timing;
@@ -93,7 +93,6 @@
 
   private Value eligibleInstance;
   private DexProgramClass eligibleClass;
-  private ObjectState objectState;
 
   private final Map<InvokeMethodWithReceiver, InliningInfo> methodCallsOnInstance =
       new IdentityHashMap<>();
@@ -101,6 +100,8 @@
   private final ProgramMethodSet indirectMethodCallsOnInstance = ProgramMethodSet.create();
   private final Map<InvokeMethod, InliningInfo> extraMethodCalls
       = new IdentityHashMap<>();
+  private final List<Pair<InvokeMethod, Integer>> unusedArguments
+      = new ArrayList<>();
 
   private final Map<InvokeMethod, ProgramMethod> directInlinees = new IdentityHashMap<>();
   private final List<ProgramMethod> indirectInlinees = new ArrayList<>();
@@ -190,11 +191,6 @@
     if (eligibleClass == null) {
       return EligibilityStatus.NOT_ELIGIBLE;
     }
-    AbstractValue abstractValue = optimizationInfo.getAbstractValue();
-    objectState =
-        abstractValue.isSingleFieldValue()
-            ? abstractValue.asSingleFieldValue().getState()
-            : ObjectState.empty();
     return EligibilityStatus.ELIGIBLE;
   }
 
@@ -386,6 +382,7 @@
   // Process inlining, includes the following steps:
   //
   //  * remove linked assume instructions if any so that users of the eligible field are up-to-date.
+  //  * replace unused instance usages as arguments which are never used
   //  * inline extra methods if any, collect new direct method calls
   //  * inline direct methods if any
   //  * remove superclass initializer call and field reads
@@ -401,6 +398,7 @@
       throws IllegalClassInlinerStateException {
     // Verify that `eligibleInstance` is not aliased.
     assert eligibleInstance == eligibleInstance.getAliasedValue();
+    replaceUsagesAsUnusedArgument(code);
 
     boolean anyInlinedMethods = forceInlineExtraMethodInvocations(code, inliningIRProvider);
     if (anyInlinedMethods) {
@@ -414,6 +412,8 @@
       }
       assert extraMethodCalls.isEmpty()
           : "Remaining extra method calls: " + StringUtils.join(extraMethodCalls.entrySet(), ", ");
+      assert unusedArguments.isEmpty()
+          : "Remaining unused arg: " + StringUtils.join(unusedArguments, ", ");
     }
 
     anyInlinedMethods |= forceInlineDirectMethodInvocations(code, inliningIRProvider);
@@ -431,9 +431,26 @@
     methodCallsOnInstance.clear();
     indirectMethodCallsOnInstance.clear();
     extraMethodCalls.clear();
+    unusedArguments.clear();
     receivers.reset();
   }
 
+  private void replaceUsagesAsUnusedArgument(IRCode code) {
+    for (Pair<InvokeMethod, Integer> unusedArgument : unusedArguments) {
+      InvokeMethod invoke = unusedArgument.getFirst();
+      BasicBlock block = invoke.getBlock();
+
+      ConstNumber nullValue = code.createConstNull();
+      nullValue.setPosition(invoke.getPosition());
+      block.listIterator(code, invoke).add(nullValue);
+      assert nullValue.getBlock() == block;
+
+      int argIndex = unusedArgument.getSecond();
+      invoke.replaceValue(argIndex, nullValue.outValue());
+    }
+    unusedArguments.clear();
+  }
+
   private boolean forceInlineExtraMethodInvocations(
       IRCode code, InliningIRProvider inliningIRProvider) {
     if (extraMethodCalls.isEmpty()) {
@@ -720,7 +737,6 @@
         new TreeSet<>(Comparator.comparingInt(x -> x.outValue().getNumber()));
     for (Instruction user : eligibleInstance.uniqueUsers()) {
       if (user.isInstanceGet()) {
-        assert root.isNewInstance();
         if (user.outValue().hasAnyUsers()) {
           uniqueInstanceGetUsersWithDeterministicOrder.add(user.asInstanceGet());
         } else {
@@ -732,7 +748,6 @@
       if (user.isInstancePut()) {
         // Skip in this iteration since these instructions are needed to properly calculate what
         // value should field reads be replaced with.
-        assert root.isNewInstance();
         continue;
       }
 
@@ -1096,7 +1111,7 @@
 
     assert root.isStaticGet();
     return classInlinerMethodConstraint.isEligibleForStaticGetClassInlining(
-        appView, parameter, objectState);
+        singleTarget, parameter);
   }
 
   private boolean isExtraMethodCall(InvokeMethod invoke) {
@@ -1121,6 +1136,10 @@
   // Analyzes if a method invoke the eligible instance is passed to is eligible. In short,
   // it can be eligible if:
   //
+  //   -- eligible instance is passed as argument #N which is not used in the method,
+  //      such cases are collected in 'unusedArguments' parameter and later replaced
+  //      with 'null' value
+  //
   //   -- eligible instance is passed as argument #N which is only used in the method to
   //      call a method on this object (we call it indirect method call), and method is
   //      eligible according to the same rules defined for direct method call eligibility
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysFalseClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysFalseClassInlinerMethodConstraint.java
index ff68dfd..0c6d335e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysFalseClassInlinerMethodConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysFalseClassInlinerMethodConstraint.java
@@ -4,11 +4,8 @@
 
 package com.android.tools.r8.ir.optimize.classinliner.constraint;
 
-import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.analysis.value.ObjectState;
 import com.android.tools.r8.ir.optimize.classinliner.analysis.ParameterUsage;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public class AlwaysFalseClassInlinerMethodConstraint implements ClassInlinerMethodConstraint {
 
@@ -37,8 +34,7 @@
   }
 
   @Override
-  public boolean isEligibleForStaticGetClassInlining(
-      AppView<AppInfoWithLiveness> appView, int parameter, ObjectState objectState) {
+  public boolean isEligibleForStaticGetClassInlining(ProgramMethod method, int parameter) {
     return false;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java
index ce14bb4..c86f373 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java
@@ -4,11 +4,8 @@
 
 package com.android.tools.r8.ir.optimize.classinliner.constraint;
 
-import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.analysis.value.ObjectState;
 import com.android.tools.r8.ir.optimize.classinliner.analysis.ParameterUsage;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public interface ClassInlinerMethodConstraint {
 
@@ -18,8 +15,7 @@
 
   boolean isEligibleForNewInstanceClassInlining(ProgramMethod method, int parameter);
 
-  boolean isEligibleForStaticGetClassInlining(
-      AppView<AppInfoWithLiveness> appView, int parameter, ObjectState objectState);
+  boolean isEligibleForStaticGetClassInlining(ProgramMethod method, int parameter);
 
   static AlwaysFalseClassInlinerMethodConstraint alwaysFalse() {
     return AlwaysFalseClassInlinerMethodConstraint.getInstance();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ConditionalClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ConditionalClassInlinerMethodConstraint.java
index 8ad6b4a..5c384e8 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ConditionalClassInlinerMethodConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ConditionalClassInlinerMethodConstraint.java
@@ -4,18 +4,12 @@
 
 package com.android.tools.r8.ir.optimize.classinliner.constraint;
 
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.analysis.value.ObjectState;
 import com.android.tools.r8.ir.optimize.classinliner.analysis.AnalysisContext;
 import com.android.tools.r8.ir.optimize.classinliner.analysis.AnalysisState;
 import com.android.tools.r8.ir.optimize.classinliner.analysis.NonEmptyParameterUsage;
 import com.android.tools.r8.ir.optimize.classinliner.analysis.ParameterUsage;
 import com.android.tools.r8.ir.optimize.classinliner.analysis.ParameterUsagePerContext;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
 import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
 
@@ -57,8 +51,7 @@
   }
 
   @Override
-  public boolean isEligibleForStaticGetClassInlining(
-      AppView<AppInfoWithLiveness> appView, int parameter, ObjectState objectState) {
+  public boolean isEligibleForStaticGetClassInlining(ProgramMethod method, int parameter) {
     AnalysisContext defaultContext = AnalysisContext.getDefaultContext();
     ParameterUsage usage = usages.get(parameter).get(defaultContext);
     if (usage.isBottom()) {
@@ -79,13 +72,9 @@
       // We will not be able to remove the monitor instruction afterwards.
       return false;
     }
-    for (DexField fieldReadFromParameter : knownUsage.getFieldsReadFromParameter()) {
-      DexClass holder = appView.definitionFor(fieldReadFromParameter.getHolderType());
-      DexEncodedField definition = fieldReadFromParameter.lookupOnClass(holder);
-      if (definition == null
-          || !objectState.getAbstractFieldValue(definition).isSingleConstValue()) {
-        return false;
-      }
+    if (!knownUsage.getFieldsReadFromParameter().isEmpty()) {
+      // We don't know the value of the field.
+      return false;
     }
     return true;
   }