Revert "Move Array length to ObjectState"

This reverts commit 277219e668ecca2092570a3795bcd76ff4d90e4b.

Reason for revert: Breaks FieldInitializedByConstantArgumentSubtypeTest

Change-Id: Iba1c7635c100fa10acad0b9c36fe19ed5d31c8f9
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
index 0303ba7..30060d9 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
@@ -11,6 +11,7 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexValue;
 import com.android.tools.r8.graph.DexValue.DexValueNull;
@@ -24,7 +25,6 @@
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
 import com.android.tools.r8.ir.analysis.value.objectstate.EnumValuesObjectState;
 import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
-import com.android.tools.r8.ir.analysis.value.objectstate.ObjectStateAnalysis;
 import com.android.tools.r8.ir.code.ArrayPut;
 import com.android.tools.r8.ir.code.FieldInstruction;
 import com.android.tools.r8.ir.code.IRCode;
@@ -35,6 +35,8 @@
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.optimize.ClassInitializerDefaultsOptimization.ClassInitializerDefaultsResult;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
+import com.android.tools.r8.ir.optimize.info.field.InstanceFieldArgumentInitializationInfo;
+import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.Timing;
 import java.util.IdentityHashMap;
@@ -238,7 +240,7 @@
       // This implicitely answers null if the value could not get computed.
       if (valuesValue.isSingleFieldValue()) {
         SingleFieldValue fieldValue = valuesValue.asSingleFieldValue();
-        if (fieldValue.getObjectState().isEnumValuesObjectState()) {
+        if (fieldValue.getState().isEnumValuesObjectState()) {
           return fieldValue;
         }
       }
@@ -437,12 +439,62 @@
   }
 
   private ObjectState computeObjectState(Value value) {
-    // TODO(b/204159267): Move this logic into Instruction#getAbstractValue in NewInstance.
-    return ObjectStateAnalysis.computeObjectState(value, appView, context);
+    assert !value.hasAliasedValue();
+    if (!value.isDefinedByInstructionSatisfying(Instruction::isNewInstance)) {
+      return ObjectState.empty();
+    }
+
+    NewInstance newInstance = value.definition.asNewInstance();
+    InvokeDirect uniqueConstructorInvoke =
+        newInstance.getUniqueConstructorInvoke(appView.dexItemFactory());
+    if (uniqueConstructorInvoke == null) {
+      return ObjectState.empty();
+    }
+
+    DexClassAndMethod singleTarget = uniqueConstructorInvoke.lookupSingleTarget(appView, context);
+    if (singleTarget == null) {
+      return ObjectState.empty();
+    }
+
+    InstanceFieldInitializationInfoCollection initializationInfos =
+        singleTarget
+            .getDefinition()
+            .getOptimizationInfo()
+            .getInstanceInitializerInfo(uniqueConstructorInvoke)
+            .fieldInitializationInfos();
+    if (initializationInfos.isEmpty()) {
+      return ObjectState.empty();
+    }
+
+    ObjectState.Builder builder = ObjectState.builder();
+    initializationInfos.forEach(
+        appView,
+        (field, initializationInfo) -> {
+          // If the instance field is not written only in the instance initializer, then we can't
+          // conclude that this field will have a constant value.
+          //
+          // We have special handling for library fields that satisfy the property that they are
+          // only written in their corresponding instance initializers. This is needed since we
+          // don't analyze these instance initializers in the Enqueuer, as they are in the library.
+          if (!appView.appInfo().isInstanceFieldWrittenOnlyInInstanceInitializers(field)
+              && !appView.dexItemFactory().enumMembers.isNameOrOrdinalField(field.getReference())) {
+            return;
+          }
+          if (initializationInfo.isArgumentInitializationInfo()) {
+            InstanceFieldArgumentInitializationInfo argumentInitializationInfo =
+                initializationInfo.asArgumentInitializationInfo();
+            Value argument =
+                uniqueConstructorInvoke.getArgument(argumentInitializationInfo.getArgumentIndex());
+            builder.recordFieldHasValue(field, argument.getAbstractValue(appView, context));
+          } else if (initializationInfo.isSingleValue()) {
+            builder.recordFieldHasValue(field, initializationInfo.asSingleValue());
+          }
+        });
+    return builder.build();
   }
 
   private boolean isEnumValuesArray(Value value) {
     SingleFieldValue singleFieldValue = computeSingleEnumFieldValueForValuesArray(value);
-    return singleFieldValue != null && singleFieldValue.getObjectState().isEnumValuesObjectState();
+    return singleFieldValue != null && singleFieldValue.getState().isEnumValuesObjectState();
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java
index e57052f..0b9a6cd 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java
@@ -59,18 +59,17 @@
           DexEncodedField staticField, AbstractValue value, DexItemFactory factory) {
         if (factory.enumMembers.isValuesFieldCandidate(staticField, staticField.getHolderType())) {
           if (value.isSingleFieldValue()
-              && value.asSingleFieldValue().getObjectState().isEnumValuesObjectState()) {
+              && value.asSingleFieldValue().getState().isEnumValuesObjectState()) {
             assert valuesCandidateAbstractValue == null
                 || valuesCandidateAbstractValue.equals(value);
             valuesCandidateAbstractValue = value;
             enumObjectStateBuilder.put(
-                staticField.getReference(), value.asSingleFieldValue().getObjectState());
+                staticField.getReference(), value.asSingleFieldValue().getState());
           }
         } else if (factory.enumMembers.isEnumField(staticField, staticField.getHolderType())) {
-          if (value.isSingleFieldValue()
-              && !value.asSingleFieldValue().getObjectState().isEmpty()) {
+          if (value.isSingleFieldValue() && !value.asSingleFieldValue().getState().isEmpty()) {
             enumObjectStateBuilder.put(
-                staticField.getReference(), value.asSingleFieldValue().getObjectState());
+                staticField.getReference(), value.asSingleFieldValue().getState());
           }
         }
       }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
index 854ea6d..d69ca26 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
@@ -7,7 +7,6 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public abstract class AbstractValue {
@@ -58,32 +57,14 @@
     return null;
   }
 
-  public boolean hasObjectState() {
+  public boolean isKnownLengthArrayValue() {
     return false;
   }
 
-  public ObjectState getObjectState() {
-    throw new UnsupportedOperationException(
-        "Abstract value " + this + " does not have any object state.");
-  }
-
-  public boolean isStatefulObjectValue() {
-    return false;
-  }
-
-  public StatefulObjectValue asStatefulObjectValue() {
+  public KnownLengthArrayValue asKnownLengthArrayValue() {
     return null;
   }
 
-  public boolean hasKnownArrayLength() {
-    return false;
-  }
-
-  public int getKnownArrayLength() {
-    throw new UnsupportedOperationException(
-        "Abstract value " + this + " does not have a known array length.");
-  }
-
   public boolean isSingleConstValue() {
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueFactory.java b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueFactory.java
index bc1a554..e1cdb6c 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueFactory.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueFactory.java
@@ -8,7 +8,6 @@
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.analysis.value.objectstate.KnownLengthArrayState;
 import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
 import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
 import java.util.concurrent.ConcurrentHashMap;
@@ -20,15 +19,15 @@
   private ConcurrentHashMap<Long, SingleNumberValue> singleNumberValues = new ConcurrentHashMap<>();
   private ConcurrentHashMap<DexString, SingleStringValue> singleStringValues =
       new ConcurrentHashMap<>();
-  private ConcurrentHashMap<Integer, KnownLengthArrayState> knownArrayLengthStates =
+  private ConcurrentHashMap<Integer, KnownLengthArrayValue> knownArrayLengthValues =
       new ConcurrentHashMap<>();
 
   public SingleConstClassValue createSingleConstClassValue(DexType type) {
     return singleConstClassValues.computeIfAbsent(type, SingleConstClassValue::new);
   }
 
-  public KnownLengthArrayState createKnownLengthArrayState(int length) {
-    return knownArrayLengthStates.computeIfAbsent(length, KnownLengthArrayState::new);
+  public AbstractValue createKnownLengthArrayValue(int length) {
+    return knownArrayLengthValues.computeIfAbsent(length, KnownLengthArrayValue::new);
   }
 
   public SingleFieldValue createSingleFieldValue(DexField field, ObjectState state) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/KnownLengthArrayValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/KnownLengthArrayValue.java
new file mode 100644
index 0000000..9721031
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/KnownLengthArrayValue.java
@@ -0,0 +1,57 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.ir.analysis.value;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+
+/** A KnownLengthArrayValue implicitly implies the value is non null. */
+public class KnownLengthArrayValue extends AbstractValue {
+
+  private final int length;
+
+  public KnownLengthArrayValue(int length) {
+    this.length = length;
+  }
+
+  public int getLength() {
+    return length;
+  }
+
+  @Override
+  public boolean isKnownLengthArrayValue() {
+    return true;
+  }
+
+  @Override
+  public KnownLengthArrayValue asKnownLengthArrayValue() {
+    return this;
+  }
+
+  @Override
+  public boolean isNonTrivial() {
+    return true;
+  }
+
+  @Override
+  public AbstractValue rewrittenWithLens(AppView<AppInfoWithLiveness> appView, GraphLens lens) {
+    return this;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    return this == o;
+  }
+
+  @Override
+  public int hashCode() {
+    return System.identityHashCode(this);
+  }
+
+  @Override
+  public String toString() {
+    return "KnownLengthArrayValue(len=" + length + ")";
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
index b499b81..71a6dbf 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
@@ -48,11 +48,7 @@
     return field.lookupOnClass(holder);
   }
 
-  @Override
-  public abstract ObjectState getObjectState();
-
-  @Override
-  public abstract boolean hasObjectState();
+  public abstract ObjectState getState();
 
   public boolean mayHaveFinalizeMethodDirectlyOrIndirectly(AppView<AppInfoWithLiveness> appView) {
     DexType fieldType = field.type;
@@ -144,6 +140,6 @@
       }
     }
     return factory.createSingleFieldValue(
-        lens.lookupField(field), getObjectState().rewrittenWithLens(appView, lens));
+        lens.lookupField(field), getState().rewrittenWithLens(appView, lens));
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStatefulFieldValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStatefulFieldValue.java
index 4191a9c..d14f5a9 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStatefulFieldValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStatefulFieldValue.java
@@ -20,22 +20,7 @@
   }
 
   @Override
-  public boolean hasKnownArrayLength() {
-    return getObjectState().hasKnownArrayLength();
-  }
-
-  @Override
-  public int getKnownArrayLength() {
-    return getObjectState().getKnownArrayLength();
-  }
-
-  @Override
-  public boolean hasObjectState() {
-    return true;
-  }
-
-  @Override
-  public ObjectState getObjectState() {
+  public ObjectState getState() {
     return state;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStatelessFieldValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStatelessFieldValue.java
index 3845594..809b365 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStatelessFieldValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStatelessFieldValue.java
@@ -15,16 +15,11 @@
   }
 
   @Override
-  public ObjectState getObjectState() {
+  public ObjectState getState() {
     return ObjectState.empty();
   }
 
   @Override
-  public boolean hasObjectState() {
-    return false;
-  }
-
-  @Override
   public String toString() {
     return "SingleStatelessFieldValue(" + field.toSourceString() + ")";
   }
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
deleted file mode 100644
index 39174da..0000000
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/StatefulObjectValue.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.ir.analysis.value;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-
-/** A KnownLengthArrayValue implicitly implies the value is non null. */
-public class StatefulObjectValue extends AbstractValue {
-
-  private final ObjectState state;
-
-  StatefulObjectValue(ObjectState state) {
-    assert !state.isEmpty();
-    this.state = state;
-  }
-
-  public static AbstractValue create(ObjectState objectState) {
-    return objectState.isEmpty()
-        ? UnknownValue.getInstance()
-        : new StatefulObjectValue(objectState);
-  }
-
-  @Override
-  public boolean isNonTrivial() {
-    return true;
-  }
-
-  @Override
-  public boolean isStatefulObjectValue() {
-    return true;
-  }
-
-  @Override
-  public StatefulObjectValue asStatefulObjectValue() {
-    return this;
-  }
-
-  @Override
-  public boolean hasKnownArrayLength() {
-    return getObjectState().hasKnownArrayLength();
-  }
-
-  @Override
-  public int getKnownArrayLength() {
-    return getObjectState().getKnownArrayLength();
-  }
-
-  @Override
-  public AbstractValue rewrittenWithLens(AppView<AppInfoWithLiveness> appView, GraphLens lens) {
-    return create(getObjectState().rewrittenWithLens(appView, lens));
-  }
-
-  @Override
-  public boolean hasObjectState() {
-    return true;
-  }
-
-  @Override
-  public ObjectState getObjectState() {
-    return state;
-  }
-
-  @Override
-  public String toString() {
-    return "StatefulValue";
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (getClass() != o.getClass()) {
-      return false;
-    }
-    StatefulObjectValue statefulObjectValue = (StatefulObjectValue) o;
-    return state.equals(statefulObjectValue.state);
-  }
-
-  @Override
-  public int hashCode() {
-    return state.hashCode();
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EnumValuesObjectState.java b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EnumValuesObjectState.java
index 817b166..397e79f 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EnumValuesObjectState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/EnumValuesObjectState.java
@@ -45,16 +45,6 @@
   }
 
   @Override
-  public boolean hasKnownArrayLength() {
-    return true;
-  }
-
-  @Override
-  public int getKnownArrayLength() {
-    return state.length;
-  }
-
-  @Override
   public boolean isEnumValuesObjectState() {
     return true;
   }
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
deleted file mode 100644
index a379776..0000000
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/KnownLengthArrayState.java
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.ir.analysis.value.objectstate;
-
-import com.android.tools.r8.graph.AppView;
-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.ir.analysis.value.AbstractValue;
-import com.android.tools.r8.ir.analysis.value.UnknownValue;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import java.util.function.BiConsumer;
-
-public class KnownLengthArrayState extends ObjectState {
-
-  private final int length;
-
-  public KnownLengthArrayState(int length) {
-    this.length = length;
-  }
-
-  @Override
-  public void forEachAbstractFieldValue(BiConsumer<DexField, AbstractValue> consumer) {
-    // Intentionally empty.
-  }
-
-  @Override
-  public AbstractValue getAbstractFieldValue(DexEncodedField field) {
-    return UnknownValue.getInstance();
-  }
-
-  @Override
-  public boolean isEmpty() {
-    return false;
-  }
-
-  @Override
-  public boolean hasKnownArrayLength() {
-    return true;
-  }
-
-  @Override
-  public int getKnownArrayLength() {
-    return length;
-  }
-
-  @Override
-  public ObjectState rewrittenWithLens(AppView<AppInfoWithLiveness> appView, GraphLens lens) {
-    return this;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    return this == o;
-  }
-
-  @Override
-  public int hashCode() {
-    return System.identityHashCode(this);
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectState.java b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectState.java
index b81fb32..f709c59 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectState.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.ir.analysis.value.objectstate;
 
-import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
@@ -59,15 +58,6 @@
   @Override
   public abstract int hashCode();
 
-  public boolean hasKnownArrayLength() {
-    return false;
-  }
-
-  public int getKnownArrayLength() {
-    // Override this method if hasKnownArrayLength answers true.
-    throw new Unreachable();
-  }
-
   public boolean isEnumValuesObjectState() {
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectStateAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectStateAnalysis.java
deleted file mode 100644
index 414b74f..0000000
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/objectstate/ObjectStateAnalysis.java
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.ir.analysis.value.objectstate;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClassAndMethod;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.analysis.value.AbstractValue;
-import com.android.tools.r8.ir.code.Instruction;
-import com.android.tools.r8.ir.code.InvokeDirect;
-import com.android.tools.r8.ir.code.NewInstance;
-import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.optimize.info.field.InstanceFieldArgumentInitializationInfo;
-import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-
-public class ObjectStateAnalysis {
-
-  public static ObjectState computeObjectState(
-      Value value, AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
-    assert !value.hasAliasedValue();
-    if (value.isDefinedByInstructionSatisfying(
-        i -> i.isNewArrayEmpty() || i.isNewArrayFilledData())) {
-      return computeNewArrayObjectState(value, appView, context);
-    }
-    if (value.isDefinedByInstructionSatisfying(Instruction::isNewInstance)) {
-      return computeNewInstanceObjectState(value, appView, context);
-    }
-    return ObjectState.empty();
-  }
-
-  private static ObjectState computeNewArrayObjectState(
-      Value value, AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
-    AbstractValue abstractValue = value.definition.getAbstractValue(appView, context);
-    if (abstractValue.isStatefulObjectValue()) {
-      // TODO(b/204272377): Avoid wrapping and unwrapping the object state.
-      return abstractValue.asStatefulObjectValue().getObjectState();
-    }
-    return ObjectState.empty();
-  }
-
-  private static ObjectState computeNewInstanceObjectState(
-      Value value, AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
-    NewInstance newInstance = value.definition.asNewInstance();
-    InvokeDirect uniqueConstructorInvoke =
-        newInstance.getUniqueConstructorInvoke(appView.dexItemFactory());
-    if (uniqueConstructorInvoke == null) {
-      return ObjectState.empty();
-    }
-
-    DexClassAndMethod singleTarget = uniqueConstructorInvoke.lookupSingleTarget(appView, context);
-    if (singleTarget == null) {
-      return ObjectState.empty();
-    }
-
-    InstanceFieldInitializationInfoCollection initializationInfos =
-        singleTarget
-            .getDefinition()
-            .getOptimizationInfo()
-            .getInstanceInitializerInfo(uniqueConstructorInvoke)
-            .fieldInitializationInfos();
-    if (initializationInfos.isEmpty()) {
-      return ObjectState.empty();
-    }
-
-    ObjectState.Builder builder = ObjectState.builder();
-    initializationInfos.forEach(
-        appView,
-        (field, initializationInfo) -> {
-          // If the instance field is not written only in the instance initializer, then we can't
-          // conclude that this field will have a constant value.
-          //
-          // We have special handling for library fields that satisfy the property that they are
-          // only written in their corresponding instance initializers. This is needed since we
-          // don't analyze these instance initializers in the Enqueuer, as they are in the library.
-          if (!appView.appInfo().isInstanceFieldWrittenOnlyInInstanceInitializers(field)
-              && !appView.dexItemFactory().enumMembers.isNameOrOrdinalField(field.getReference())) {
-            return;
-          }
-          if (initializationInfo.isArgumentInitializationInfo()) {
-            InstanceFieldArgumentInitializationInfo argumentInitializationInfo =
-                initializationInfo.asArgumentInitializationInfo();
-            Value argument =
-                uniqueConstructorInvoke.getArgument(argumentInitializationInfo.getArgumentIndex());
-            builder.recordFieldHasValue(field, argument.getAbstractValue(appView, context));
-          } else if (initializationInfo.isSingleValue()) {
-            builder.recordFieldHasValue(field, initializationInfo.asSingleValue());
-          }
-        });
-    return builder.build();
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java b/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
index e1bb5bf..9aff428 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayGet.java
@@ -276,10 +276,10 @@
       return true;
     }
     AbstractValue abstractValue = array().getAliasedValue().getAbstractValue(appView, context);
-    if (!abstractValue.hasKnownArrayLength()) {
+    if (!abstractValue.isKnownLengthArrayValue()) {
       return true;
     }
-    int newArraySize = abstractValue.getKnownArrayLength();
+    int newArraySize = abstractValue.asKnownLengthArrayValue().getLength();
     int index = index().getConstInstruction().asConstNumber().getIntValue();
     return newArraySize <= 0 || index < 0 || newArraySize <= index;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
index 3be3d3d..3ddbcbd 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
@@ -14,7 +14,6 @@
 import com.android.tools.r8.ir.analysis.type.Nullability;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
-import com.android.tools.r8.ir.analysis.value.StatefulObjectValue;
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
@@ -91,10 +90,9 @@
       AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
     if (!instructionMayHaveSideEffects(appView, context) && size().getType().isInt()) {
       assert !instructionInstanceCanThrow();
-      return StatefulObjectValue.create(
-          appView
-              .abstractValueFactory()
-              .createKnownLengthArrayState(size().definition.asConstNumber().getIntValue()));
+      return appView
+          .abstractValueFactory()
+          .createKnownLengthArrayValue(size().definition.asConstNumber().getIntValue());
     }
     return UnknownValue.getInstance();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
index fb04f03..ce235d4 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
@@ -11,7 +11,6 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
-import com.android.tools.r8.ir.analysis.value.StatefulObjectValue;
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
@@ -128,8 +127,7 @@
       AppView<AppInfoWithLiveness> appView, ProgramMethod context) {
     if (!instructionMayHaveSideEffects(appView, context) && size <= Integer.MAX_VALUE) {
       assert !instructionInstanceCanThrow();
-      return StatefulObjectValue.create(
-          appView.abstractValueFactory().createKnownLengthArrayState((int) size));
+      return appView.abstractValueFactory().createKnownLengthArrayValue((int) size);
     }
     return UnknownValue.getInstance();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index dae6f04..bcd27e6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -3451,7 +3451,7 @@
       }
 
       AbstractValue abstractValue = array.getAbstractValue(appView, code.context());
-      if (!abstractValue.hasKnownArrayLength() && !array.isNeverNull()) {
+      if (!abstractValue.isKnownLengthArrayValue() && !array.isNeverNull()) {
         continue;
       }
       Instruction arrayDefinition = array.getDefinition();
@@ -3468,13 +3468,15 @@
           continue;
         }
         iterator.replaceCurrentInstructionWithConstInt(code, (int) size);
-      } else if (abstractValue.hasKnownArrayLength()) {
-        iterator.replaceCurrentInstructionWithConstInt(code, abstractValue.getKnownArrayLength());
+      } else if (abstractValue.isKnownLengthArrayValue()) {
+        iterator.replaceCurrentInstructionWithConstInt(
+            code, abstractValue.asKnownLengthArrayValue().getLength());
       } else {
         continue;
       }
 
       phiUsers.forEach(Phi::removeTrivialPhi);
+      // TODO(139489070): static-get of constant array
     }
     assert code.isConsistentSSA();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index 206c455..9e8d052 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -401,8 +401,12 @@
       if (abstractValue.isUnknown() && !definition.isStatic()) {
         AbstractValue abstractReceiverValue =
             current.asInstanceGet().object().getAbstractValue(appView, code.context());
-        if (abstractReceiverValue.hasObjectState()) {
-          abstractValue = abstractReceiverValue.getObjectState().getAbstractFieldValue(definition);
+        if (abstractReceiverValue.isSingleFieldValue()) {
+          abstractValue =
+              abstractReceiverValue
+                  .asSingleFieldValue()
+                  .getState()
+                  .getAbstractFieldValue(definition);
         }
       }
     } else if (definition.isStatic()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
index 290f25b..e42266b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
@@ -421,7 +421,7 @@
       SingleFieldValue singleFieldValue =
           field.getDefinition().getOptimizationInfo().getAbstractValue().asSingleFieldValue();
       if (singleFieldValue != null) {
-        applyObjectState(staticGet.outValue(), singleFieldValue.getObjectState());
+        applyObjectState(staticGet.outValue(), singleFieldValue.getState());
       }
     }
   }
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..487d677 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
@@ -191,7 +191,7 @@
     AbstractValue abstractValue = optimizationInfo.getAbstractValue();
     objectState =
         abstractValue.isSingleFieldValue()
-            ? abstractValue.asSingleFieldValue().getObjectState()
+            ? abstractValue.asSingleFieldValue().getState()
             : ObjectState.empty();
     return EligibilityStatus.ELIGIBLE;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
index ff79200..f51dc69 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueOptimizer.java
@@ -356,7 +356,7 @@
     if (encodedField == null) {
       return null;
     }
-    return abstractValue.asSingleFieldValue().getObjectState().getAbstractFieldValue(encodedField);
+    return abstractValue.asSingleFieldValue().getState().getAbstractFieldValue(encodedField);
   }
 
   private static final class EnumSwitchInfo {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index b5ced8c..15819c7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -65,9 +65,6 @@
 import com.android.tools.r8.ir.analysis.type.Nullability;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
-import com.android.tools.r8.ir.analysis.value.StatefulObjectValue;
-import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
-import com.android.tools.r8.ir.analysis.value.objectstate.ObjectStateAnalysis;
 import com.android.tools.r8.ir.code.AliasedValueConfiguration;
 import com.android.tools.r8.ir.code.Argument;
 import com.android.tools.r8.ir.code.AssumeAndCheckCastAliasedValueConfiguration;
@@ -212,13 +209,6 @@
             checkCastAndInstanceOfMethodSpecialization.addCandidateForOptimization(
                 context, abstractReturnValue, methodProcessor);
           }
-        } else if (returnValue.getType().isReferenceType()) {
-          // TODO(b/204159267): Move this logic into Instruction#getAbstractValue in NewInstance.
-          ObjectState objectState =
-              ObjectStateAnalysis.computeObjectState(aliasedValue, appView, context);
-          // TODO(b/204272377): Avoid wrapping and unwrapping the object state.
-          feedback.methodReturnsAbstractValue(
-              method, appView, StatefulObjectValue.create(objectState));
         }
       }
     }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/StatePropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/StatePropagationTest.java
deleted file mode 100644
index f4b90ed..0000000
--- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/StatePropagationTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.ir.optimize.membervaluepropagation;
-
-import static org.junit.Assert.assertEquals;
-
-import com.android.tools.r8.NeverClassInline;
-import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ir.optimize.membervaluepropagation.StatePropagationTest.TestClass.Data;
-import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class StatePropagationTest extends TestBase {
-
-  private final TestParameters parameters;
-
-  @Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimesAndApiLevels().build();
-  }
-
-  public StatePropagationTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
-
-  @Test
-  public void test() throws Exception {
-    testForR8(parameters.getBackend())
-        .addInnerClasses(StatePropagationTest.class)
-        .addKeepMainRule(TestClass.class)
-        .setMinApi(parameters.getApiLevel())
-        .enableInliningAnnotations()
-        .enableNeverClassInliningAnnotations()
-        .compile()
-        .inspect(this::inspect)
-        .run(parameters.getRuntime(), TestClass.class)
-        .assertSuccessWithOutputLines("1", "1.0", "2", "2.0");
-  }
-
-  private void inspect(CodeInspector inspector) {
-    ClassSubject data = inspector.clazz(Data.class);
-    assertEquals(0, data.allInstanceFields().size());
-  }
-
-  static class TestClass {
-
-    @NeverClassInline
-    static class Data {
-      final int i;
-      final float j;
-
-      private Data(int i, float j) {
-        this.i = i;
-        this.j = j;
-      }
-    }
-
-    @NeverInline
-    public static Data getData1() {
-      return new Data(1, 1.0f);
-    }
-
-    @NeverInline
-    public static Data getData2() {
-      return new Data(2, 2.0f);
-    }
-
-    public static void main(String[] args) {
-      Data data1 = getData1();
-      Data data2 = getData2();
-      System.out.println(data1.i);
-      System.out.println(data1.j);
-      System.out.println(data2.i);
-      System.out.println(data2.j);
-    }
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/rewrite/arrays/ArrayLengthRewriteTest.java b/src/test/java/com/android/tools/r8/rewrite/arrays/ArrayLengthRewriteTest.java
index c38c66f..5a7be26 100644
--- a/src/test/java/com/android/tools/r8/rewrite/arrays/ArrayLengthRewriteTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/arrays/ArrayLengthRewriteTest.java
@@ -68,7 +68,7 @@
         .addProgramClasses(Main.class)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines(expectedOutput)
-        .inspect(i -> inspect(i, true));
+        .inspect(this::inspect);
   }
 
   @Test public void r8() throws Exception {
@@ -80,10 +80,10 @@
         .enableInliningAnnotations()
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines(expectedOutput)
-        .inspect(i -> inspect(i, false));
+        .inspect(this::inspect);
   }
 
-  private void inspect(CodeInspector inspector, boolean d8) {
+  private void inspect(CodeInspector inspector) {
     ClassSubject mainClass = inspector.clazz(Main.class);
     assertTrue(mainClass.isPresent());
 
@@ -104,10 +104,10 @@
 
     // TODO(139489070): these should be rewritten and result in 0 array-length bytecodes
     MethodSubject staticConstants = mainClass.uniqueMethodWithName("staticConstants");
-    assertArrayLengthCallCount(staticConstants, (d8 || debugMode) ? 3 : 0);
+    assertArrayLengthCallCount(staticConstants, 3);
 
     MethodSubject staticNonConstants = mainClass.uniqueMethodWithName("staticNonConstants");
-    assertArrayLengthCallCount(staticNonConstants, (d8 || debugMode) ? 2 : 0);
+    assertArrayLengthCallCount(staticNonConstants, 2);
   }
 
   private static void assertArrayLengthCallCount(MethodSubject subject, int expected) {
@@ -200,7 +200,7 @@
     }
 
     private static String[] mutable = { "one" };
-    private static final String[] runtimeInit = {"two"};
+    private static final String[] runtimeInit = { System.lineSeparator() };
 
     @NeverInline
     private static void staticNonConstants() {