Remove class inliner bail-out from singleton field read

Change-Id: Ic7cdff89cf6dc028fe93568af0123ac88736295b
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/ObjectState.java b/src/main/java/com/android/tools/r8/ir/analysis/value/ObjectState.java
index f0af9b4..4db63a6 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/ObjectState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/ObjectState.java
@@ -8,10 +8,12 @@
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.IdentityHashMap;
 import java.util.Map;
 import java.util.function.BiConsumer;
+import java.util.function.Predicate;
 
 public abstract class ObjectState {
 
@@ -25,6 +27,22 @@
 
   public abstract void forEachAbstractFieldValue(BiConsumer<DexField, AbstractValue> consumer);
 
+  public final boolean hasMaterializableFieldValueThatMatches(
+      AppView<AppInfoWithLiveness> appView,
+      DexEncodedField field,
+      ProgramMethod context,
+      Predicate<SingleValue> predicate) {
+    AbstractValue abstractValue = getAbstractFieldValue(field);
+    if (!abstractValue.isSingleValue()) {
+      return false;
+    }
+    SingleValue singleValue = abstractValue.asSingleValue();
+    if (!singleValue.isMaterializableInContext(appView, context)) {
+      return false;
+    }
+    return predicate.test(singleValue);
+  }
+
   public abstract AbstractValue getAbstractFieldValue(DexEncodedField field);
 
   public abstract boolean 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 91a2d83..7b97eb6 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
@@ -256,10 +256,6 @@
         }
 
         if (user.isInstanceGet()) {
-          if (root.isStaticGet()) {
-            // We don't have a replacement for this field read.
-            return user; // Not eligible.
-          }
           DexEncodedField field =
               appView
                   .appInfo()
@@ -268,6 +264,11 @@
           if (field == null || field.isStatic()) {
             return user; // Not eligible.
           }
+          if (root.isStaticGet()
+              && !objectState.hasMaterializableFieldValueThatMatches(
+                  appView, field, method, AbstractValue::isSingleConstValue)) {
+            return user; // Not eligible.
+          }
           continue;
         }
 
@@ -324,23 +325,20 @@
           }
 
           // Eligible constructor call (for new instance roots only).
-          if (user.isInvokeDirect()) {
+          if (user.isInvokeConstructor(dexItemFactory)) {
             InvokeDirect invoke = user.asInvokeDirect();
-            if (dexItemFactory.isConstructor(invoke.getInvokedMethod())) {
-              boolean isCorrespondingConstructorCall =
-                  root.isNewInstance()
-                      && !invoke.inValues().isEmpty()
-                      && root.outValue() == invoke.getReceiver();
-              if (isCorrespondingConstructorCall) {
-                InliningInfo inliningInfo = isEligibleConstructorCall(invoke, singleProgramTarget);
-                if (inliningInfo != null) {
-                  methodCallsOnInstance.put(invoke, inliningInfo);
-                  continue;
-                }
+            boolean isCorrespondingConstructorCall =
+                root.isNewInstance()
+                    && !invoke.inValues().isEmpty()
+                    && root.outValue() == invoke.getReceiver();
+            if (isCorrespondingConstructorCall) {
+              InliningInfo inliningInfo = isEligibleConstructorCall(invoke, singleProgramTarget);
+              if (inliningInfo != null) {
+                methodCallsOnInstance.put(invoke, inliningInfo);
+                continue;
               }
-              assert !isExtraMethodCall(invoke);
-              return user; // Not eligible.
             }
+            return user; // Not eligible.
           }
 
           // Eligible virtual method call on the instance as a receiver.
@@ -483,7 +481,7 @@
             }
 
             DexProgramClass holder =
-                asProgramClassOrNull(appView.definitionForHolder(invokedMethod));
+                asProgramClassOrNull(appView.definitionForHolder(invokedMethod, method));
             if (holder == null) {
               throw new IllegalClassInlinerStateException();
             }
@@ -932,7 +930,8 @@
       if (parent == null) {
         return null;
       }
-      DexProgramClass parentClass = asProgramClassOrNull(appView.definitionForHolder(parent));
+      DexProgramClass parentClass =
+          asProgramClassOrNull(appView.definitionForHolder(parent, method));
       if (parentClass == null) {
         return null;
       }