Remove old field optimizations

Bug: b/330674939
Change-Id: Icf2bd4807f0e1f17d2a7da64cd7b1ac4934acd2b
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAccessAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAccessAnalysis.java
index b9f074c..d87ade4 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAccessAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAccessAnalysis.java
@@ -4,19 +4,14 @@
 
 package com.android.tools.r8.ir.analysis.fieldaccess;
 
-import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
-
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
 import com.android.tools.r8.ir.code.FieldInstruction;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
-import com.android.tools.r8.ir.code.NewInstance;
 import com.android.tools.r8.ir.conversion.MethodProcessor;
-import com.android.tools.r8.ir.optimize.ClassInitializerDefaultsOptimization.ClassInitializerDefaultsResult;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.InternalOptions;
@@ -25,7 +20,6 @@
 public class FieldAccessAnalysis {
 
   private final AppView<? extends AppInfoWithClassHierarchy> appView;
-  private final FieldAssignmentTracker fieldAssignmentTracker;
   private final FieldBitAccessAnalysis fieldBitAccessAnalysis;
   private final FieldReadForInvokeReceiverAnalysis fieldReadForInvokeReceiverAnalysis;
   private final FieldReadForWriteAnalysis fieldReadForWriteAnalysis;
@@ -35,8 +29,6 @@
     this.appView = appView;
     this.fieldBitAccessAnalysis =
         options.enableFieldBitAccessAnalysis ? new FieldBitAccessAnalysis() : null;
-    this.fieldAssignmentTracker =
-        options.enableFieldAssignmentTracker ? new FieldAssignmentTracker(appView) : null;
     this.fieldReadForInvokeReceiverAnalysis = new FieldReadForInvokeReceiverAnalysis(appView);
     this.fieldReadForWriteAnalysis = new FieldReadForWriteAnalysis(appView);
   }
@@ -44,28 +36,15 @@
   @VisibleForTesting
   public FieldAccessAnalysis(
       AppView<? extends AppInfoWithClassHierarchy> appView,
-      FieldAssignmentTracker fieldAssignmentTracker,
       FieldBitAccessAnalysis fieldBitAccessAnalysis,
       FieldReadForInvokeReceiverAnalysis fieldReadForInvokeReceiverAnalysis,
       FieldReadForWriteAnalysis fieldReadForWriteAnalysis) {
     this.appView = appView;
-    this.fieldAssignmentTracker = fieldAssignmentTracker;
     this.fieldBitAccessAnalysis = fieldBitAccessAnalysis;
     this.fieldReadForInvokeReceiverAnalysis = fieldReadForInvokeReceiverAnalysis;
     this.fieldReadForWriteAnalysis = fieldReadForWriteAnalysis;
   }
 
-  public FieldAssignmentTracker fieldAssignmentTracker() {
-    return fieldAssignmentTracker;
-  }
-
-  public void acceptClassInitializerDefaultsResult(
-      ClassInitializerDefaultsResult classInitializerDefaultsResult) {
-    if (fieldAssignmentTracker != null) {
-      fieldAssignmentTracker.acceptClassInitializerDefaultsResult(classInitializerDefaultsResult);
-    }
-  }
-
   public void recordFieldAccesses(
       IRCode code,
       BytecodeMetadataProvider.Builder bytecodeMetadataProviderBuilder,
@@ -85,9 +64,6 @@
         ProgramField field =
             appView.appInfo().resolveField(fieldInstruction.getField()).getProgramField();
         if (field != null) {
-          if (fieldAssignmentTracker != null) {
-            fieldAssignmentTracker.recordFieldAccess(fieldInstruction, field);
-          }
           if (fieldBitAccessAnalysis != null) {
             fieldBitAccessAnalysis.recordFieldAccess(
                 fieldInstruction, field.getDefinition(), feedback);
@@ -101,14 +77,6 @@
                 fieldInstruction, field, bytecodeMetadataProviderBuilder);
           }
         }
-      } else if (instruction.isNewInstance()) {
-        NewInstance newInstance = instruction.asNewInstance();
-        DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(newInstance.clazz));
-        if (clazz != null) {
-          if (fieldAssignmentTracker != null) {
-            fieldAssignmentTracker.recordAllocationSite(newInstance, clazz, code.context());
-          }
-        }
       }
     }
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
deleted file mode 100644
index af58cdc..0000000
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
+++ /dev/null
@@ -1,531 +0,0 @@
-// Copyright (c) 2020, 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.fieldaccess;
-
-import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClassAndMethod;
-import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.FieldAccessInfo;
-import com.android.tools.r8.graph.FieldAccessInfoCollection;
-import com.android.tools.r8.graph.ObjectAllocationInfoCollection;
-import com.android.tools.r8.graph.ProgramField;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
-import com.android.tools.r8.ir.analysis.type.DynamicType;
-import com.android.tools.r8.ir.analysis.type.DynamicTypeWithUpperBound;
-import com.android.tools.r8.ir.analysis.type.Nullability;
-import com.android.tools.r8.ir.analysis.value.AbstractValue;
-import com.android.tools.r8.ir.analysis.value.AbstractValueFactory;
-import com.android.tools.r8.ir.analysis.value.BottomValue;
-import com.android.tools.r8.ir.analysis.value.SingleValue;
-import com.android.tools.r8.ir.analysis.value.UnknownValue;
-import com.android.tools.r8.ir.code.FieldInstruction;
-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.ClassInitializerDefaultsOptimization.ClassInitializerDefaultsResult;
-import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
-import com.android.tools.r8.ir.optimize.info.field.InstanceFieldArgumentInitializationInfo;
-import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfo;
-import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
-import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteArrayTypeValueState;
-import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteClassTypeValueState;
-import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcretePrimitiveTypeValueState;
-import com.android.tools.r8.optimize.argumentpropagation.codescanner.ValueState;
-import com.android.tools.r8.optimize.argumentpropagation.utils.WideningUtils;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.TraversalContinuation;
-import com.android.tools.r8.utils.collections.ProgramFieldMap;
-import com.android.tools.r8.utils.collections.ProgramMethodSet;
-import it.unimi.dsi.fastutil.objects.Reference2IntMap;
-import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
-import java.util.ArrayList;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Consumer;
-
-// TODO(b/330674939): Remove legacy field optimizations.
-public class FieldAssignmentTracker {
-
-  private final AbstractValueFactory abstractValueFactory;
-  private final AppView<AppInfoWithLiveness> appView;
-  private final DexItemFactory dexItemFactory;
-
-  // A field access graph with edges from methods to the fields that they access. Edges are removed
-  // from the graph as we process methods, such that we can conclude that all field writes have been
-  // processed when a field no longer has any incoming edges.
-  private final FieldAccessGraph fieldAccessGraph;
-
-  // An object allocation graph with edges from methods to the classes they instantiate. Edges are
-  // removed from the graph as we process methods, such that we can conclude that all allocation
-  // sites have been seen when a class no longer has any incoming edges.
-  private final ObjectAllocationGraph objectAllocationGraph;
-
-  // Information about the fields in the program. If a field is not a key in the map then no writes
-  // has been seen to the field.
-  private final Map<DexEncodedField, ValueState> fieldStates = new ConcurrentHashMap<>();
-
-  private final Map<DexProgramClass, ProgramFieldMap<AbstractValue>>
-      abstractFinalInstanceFieldValues = new ConcurrentHashMap<>();
-
-  private final Set<DexProgramClass> classesWithPrunedInstanceInitializers =
-      ConcurrentHashMap.newKeySet();
-
-  FieldAssignmentTracker(AppView<AppInfoWithLiveness> appView) {
-    this.abstractValueFactory = appView.abstractValueFactory();
-    this.appView = appView;
-    this.dexItemFactory = appView.dexItemFactory();
-    this.fieldAccessGraph = new FieldAccessGraph();
-    this.objectAllocationGraph = new ObjectAllocationGraph();
-  }
-
-  public void initialize() {
-    fieldAccessGraph.initialize(appView);
-    objectAllocationGraph.initialize(appView);
-    initializeAbstractInstanceFieldValues();
-  }
-
-  /**
-   * For each class with known allocation sites, adds a mapping from clazz -> instance field ->
-   * bottom.
-   *
-   * <p>If an entry (clazz, instance field) is missing in {@link #abstractFinalInstanceFieldValues},
-   * it is interpreted as if we known nothing about the value of the field.
-   */
-  private void initializeAbstractInstanceFieldValues() {
-    FieldAccessInfoCollection<?> fieldAccessInfos =
-        appView.appInfo().getFieldAccessInfoCollection();
-    ObjectAllocationInfoCollection objectAllocationInfos =
-        appView.appInfo().getObjectAllocationInfoCollection();
-    objectAllocationInfos.forEachClassWithKnownAllocationSites(
-        (clazz, allocationSites) -> {
-          if (appView.appInfo().isInstantiatedIndirectly(clazz)) {
-            // TODO(b/147652121): Handle classes that are instantiated indirectly.
-            return;
-          }
-          List<DexEncodedField> instanceFields = clazz.instanceFields();
-          if (instanceFields.isEmpty()) {
-            // No instance fields to track.
-            return;
-          }
-          ProgramFieldMap<AbstractValue> abstractFinalInstanceFieldValuesForClass =
-              ProgramFieldMap.create();
-          clazz.forEachProgramInstanceField(
-              field -> {
-                if (field.isFinalOrEffectivelyFinal(appView)) {
-                  FieldAccessInfo fieldAccessInfo = fieldAccessInfos.get(field.getReference());
-                  if (fieldAccessInfo != null && !fieldAccessInfo.hasReflectiveAccess()) {
-                    abstractFinalInstanceFieldValuesForClass.put(field, BottomValue.getInstance());
-                  }
-                }
-              });
-          if (!abstractFinalInstanceFieldValuesForClass.isEmpty()) {
-            abstractFinalInstanceFieldValues.put(clazz, abstractFinalInstanceFieldValuesForClass);
-          }
-        });
-    for (DexProgramClass clazz : appView.appInfo().classes()) {
-      clazz.forEachProgramField(
-          field -> {
-            FieldAccessInfo accessInfo = fieldAccessInfos.get(field.getReference());
-            if (!appView.getKeepInfo(field).isValuePropagationAllowed(appView, field)
-                || (accessInfo != null && accessInfo.isWrittenFromMethodHandle())) {
-              fieldStates.put(field.getDefinition(), ValueState.unknown());
-            }
-          });
-    }
-  }
-
-  @SuppressWarnings("ReferenceEquality")
-  void acceptClassInitializerDefaultsResult(
-      ClassInitializerDefaultsResult classInitializerDefaultsResult) {
-    classInitializerDefaultsResult.forEachOptimizedField(
-        (field, value) -> {
-          DexType fieldType = field.getType();
-          if (value.isDefault(field.getType())) {
-            return;
-          }
-          assert fieldType.isClassType() || fieldType.isPrimitiveType();
-          fieldStates.compute(
-              field,
-              (f, fieldState) -> {
-                if (fieldState == null) {
-                  AbstractValue abstractValue = value.toAbstractValue(abstractValueFactory);
-                  if (fieldType.isClassType()) {
-                    assert abstractValue.isSingleStringValue()
-                        || abstractValue.isSingleDexItemBasedStringValue();
-                    if (fieldType == dexItemFactory.stringType) {
-                      return ConcreteClassTypeValueState.create(
-                          abstractValue, DynamicType.definitelyNotNull());
-                    } else {
-                      ClassTypeElement nonNullableStringType =
-                          dexItemFactory
-                              .stringType
-                              .toTypeElement(appView, definitelyNotNull())
-                              .asClassType();
-                      return ConcreteClassTypeValueState.create(
-                          abstractValue, DynamicType.createExact(nonNullableStringType));
-                    }
-                  } else {
-                    assert fieldType.isPrimitiveType();
-                    return ConcretePrimitiveTypeValueState.create(abstractValue);
-                  }
-                }
-                // If the field is already assigned outside the class initializer then just give up.
-                return ValueState.unknown();
-              });
-        });
-  }
-
-  void recordFieldAccess(FieldInstruction instruction, ProgramField field) {
-    if (instruction.isFieldPut()) {
-      recordFieldPut(field, instruction.value());
-    }
-  }
-
-  private void recordFieldPut(ProgramField field, Value value) {
-    // For now only attempt to prove that fields are definitely null. In order to prove a single
-    // value for fields that are not definitely null, we need to prove that the given field is never
-    // read before it is written.
-    AbstractValue abstractValue =
-        value.isZero()
-            ? abstractValueFactory.createDefaultValue(field.getType())
-            : AbstractValue.unknown();
-    Nullability nullability = value.getType().nullability();
-    fieldStates.compute(
-        field.getDefinition(),
-        (f, fieldState) -> {
-          if (fieldState == null || fieldState.isBottom()) {
-            DexType fieldType = field.getType();
-            if (fieldType.isArrayType()) {
-              return ConcreteArrayTypeValueState.create(nullability);
-            }
-            if (fieldType.isPrimitiveType()) {
-              return ConcretePrimitiveTypeValueState.create(abstractValue);
-            }
-            assert fieldType.isClassType();
-            DynamicType dynamicType =
-                WideningUtils.widenDynamicNonReceiverType(
-                    appView,
-                    value.getDynamicType(appView).withNullability(Nullability.maybeNull()),
-                    field.getType());
-            return ConcreteClassTypeValueState.create(abstractValue, dynamicType);
-          }
-
-          if (fieldState.isUnknown()) {
-            return fieldState;
-          }
-
-          assert fieldState.isConcrete();
-
-          if (fieldState.isArrayState()) {
-            ConcreteArrayTypeValueState arrayFieldState = fieldState.asArrayState();
-            return arrayFieldState.mutableJoin(appView, field, nullability);
-          }
-
-          if (fieldState.isPrimitiveState()) {
-            ConcretePrimitiveTypeValueState primitiveFieldState = fieldState.asPrimitiveState();
-            return primitiveFieldState.mutableJoin(appView, field, abstractValue);
-          }
-
-          assert fieldState.isClassState();
-
-          ConcreteClassTypeValueState classFieldState = fieldState.asClassState();
-          DexType inStaticType = null;
-          return classFieldState.mutableJoin(
-              appView, abstractValue, value.getDynamicType(appView), inStaticType, field);
-        });
-  }
-
-  void recordAllocationSite(NewInstance instruction, DexProgramClass clazz, ProgramMethod context) {
-    ProgramFieldMap<AbstractValue> abstractInstanceFieldValuesForClass =
-        abstractFinalInstanceFieldValues.get(clazz);
-    if (abstractInstanceFieldValuesForClass == null) {
-      // We are not tracking the value of any of clazz' instance fields.
-      return;
-    }
-
-    InvokeDirect invoke = instruction.getUniqueConstructorInvoke(dexItemFactory);
-    if (invoke == null) {
-      // We just lost track.
-      abstractFinalInstanceFieldValues.remove(clazz);
-      return;
-    }
-
-    DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, context);
-    if (singleTarget == null) {
-      // We just lost track.
-      abstractFinalInstanceFieldValues.remove(clazz);
-      return;
-    }
-
-    InstanceFieldInitializationInfoCollection initializationInfoCollection =
-        singleTarget
-            .getDefinition()
-            .getOptimizationInfo()
-            .getInstanceInitializerInfo(invoke)
-            .fieldInitializationInfos();
-
-    // Synchronize on the lattice element (abstractInstanceFieldValuesForClass) in case we process
-    // another allocation site of `clazz` concurrently.
-    synchronized (abstractInstanceFieldValuesForClass) {
-      abstractInstanceFieldValuesForClass.removeIf(
-          (field, abstractValue, entry) -> {
-            InstanceFieldInitializationInfo initializationInfo =
-                initializationInfoCollection.get(field);
-            if (initializationInfo.isArgumentInitializationInfo()) {
-              InstanceFieldArgumentInitializationInfo argumentInitializationInfo =
-                  initializationInfo.asArgumentInitializationInfo();
-              Value argument =
-                  invoke.arguments().get(argumentInitializationInfo.getArgumentIndex());
-              AbstractValue argumentAbstractValue = argument.getAbstractValue(appView, context);
-              abstractValue =
-                  appView
-                      .getAbstractValueFieldJoiner()
-                      .join(abstractValue, argumentAbstractValue, field);
-            } else if (initializationInfo.isSingleValue()) {
-              SingleValue singleValueInitializationInfo = initializationInfo.asSingleValue();
-              abstractValue =
-                  appView
-                      .getAbstractValueFieldJoiner()
-                      .join(abstractValue, singleValueInitializationInfo, field);
-            } else if (initializationInfo.isTypeInitializationInfo()) {
-              // TODO(b/149732532): Not handled, for now.
-              abstractValue = UnknownValue.getInstance();
-            } else {
-              assert initializationInfo.isUnknown();
-              abstractValue = UnknownValue.getInstance();
-            }
-
-            assert !abstractValue.isBottom();
-            entry.setValue(abstractValue);
-            return abstractValue.isUnknown();
-          });
-    }
-  }
-
-  private void recordAllFieldPutsProcessed(
-      ProgramField field, OptimizationFeedbackDelayed feedback) {
-    ValueState fieldState =
-        fieldStates.getOrDefault(field.getDefinition(), ValueState.bottom(field));
-    AbstractValue abstractValue =
-        fieldState.isBottom()
-            ? appView.abstractValueFactory().createDefaultValue(field.getType())
-            : fieldState.getAbstractValue(appView);
-    if (abstractValue.isNonTrivial()) {
-      feedback.recordFieldHasAbstractValue(field, appView, abstractValue);
-    }
-
-    if (fieldState.isClassState() && field.getOptimizationInfo().getDynamicType().isUnknown()) {
-      ConcreteClassTypeValueState classFieldState = fieldState.asClassState();
-      DynamicType dynamicType = classFieldState.getDynamicType();
-      if (!dynamicType.isUnknown()) {
-        assert WideningUtils.widenDynamicNonReceiverType(appView, dynamicType, field.getType())
-            .equals(dynamicType);
-        if (dynamicType.isNotNullType()) {
-          feedback.markFieldHasDynamicType(field, dynamicType);
-        } else {
-          DynamicTypeWithUpperBound staticType = field.getType().toDynamicType(appView);
-          if (dynamicType.asDynamicTypeWithUpperBound().strictlyLessThan(staticType, appView)) {
-            feedback.markFieldHasDynamicType(field, dynamicType);
-          }
-        }
-      }
-    }
-
-    if (!field.getAccessFlags().isStatic()) {
-      recordAllInstanceFieldPutsProcessed(field, feedback);
-    }
-  }
-
-  private void recordAllInstanceFieldPutsProcessed(
-      ProgramField field, OptimizationFeedbackDelayed feedback) {
-    if (!appView.appInfo().isInstanceFieldWrittenOnlyInInstanceInitializers(field)) {
-      return;
-    }
-    DexProgramClass clazz = field.getHolder();
-    if (classesWithPrunedInstanceInitializers.contains(clazz)) {
-      // The current method is analyzing the instance-puts to the field in the instance initializers
-      // of the holder class. Due to single caller inlining of instance initializers some of the
-      // methods needed for the analysis may have been pruned from the app, in which case the
-      // analysis result will not be conservative.
-      return;
-    }
-    AbstractValue abstractValue = BottomValue.getInstance();
-    for (DexEncodedMethod method : clazz.directMethods(DexEncodedMethod::isInstanceInitializer)) {
-      InstanceFieldInitializationInfo fieldInitializationInfo =
-          method
-              .getOptimizationInfo()
-              .getContextInsensitiveInstanceInitializerInfo()
-              .fieldInitializationInfos()
-              .get(field);
-      if (fieldInitializationInfo.isSingleValue()) {
-        abstractValue =
-            appView
-                .getAbstractValueFieldJoiner()
-                .join(abstractValue, fieldInitializationInfo.asSingleValue(), field);
-        if (abstractValue.isUnknown()) {
-          break;
-        }
-      } else if (fieldInitializationInfo.isTypeInitializationInfo()) {
-        // TODO(b/149732532): Not handled, for now.
-        abstractValue = UnknownValue.getInstance();
-        break;
-      } else {
-        assert fieldInitializationInfo.isArgumentInitializationInfo()
-            || fieldInitializationInfo.isUnknown();
-        abstractValue = UnknownValue.getInstance();
-        break;
-      }
-    }
-
-    assert !abstractValue.isBottom();
-
-    if (!abstractValue.isUnknown()) {
-      feedback.recordFieldHasAbstractValue(field, appView, abstractValue);
-    }
-  }
-
-  private void recordAllAllocationsSitesProcessed(
-      DexProgramClass clazz, OptimizationFeedbackDelayed feedback) {
-    ProgramFieldMap<AbstractValue> abstractInstanceFieldValuesForClass =
-        abstractFinalInstanceFieldValues.get(clazz);
-    if (abstractInstanceFieldValuesForClass == null) {
-      return;
-    }
-
-    clazz.traverseProgramInstanceFields(
-        field -> {
-          AbstractValue abstractValue =
-              abstractInstanceFieldValuesForClass.getOrDefault(field, UnknownValue.getInstance());
-          if (abstractValue.isBottom()) {
-            feedback.modifyAppInfoWithLiveness(modifier -> modifier.removeInstantiatedType(clazz));
-            return TraversalContinuation.doBreak();
-          }
-          if (abstractValue.isNonTrivial()) {
-            feedback.recordFieldHasAbstractValue(field, appView, abstractValue);
-          }
-          return TraversalContinuation.doContinue();
-        });
-  }
-
-  public void onMethodPruned(ProgramMethod method) {
-    onMethodCodePruned(method);
-  }
-
-  public void onMethodCodePruned(ProgramMethod method) {
-    if (method.getDefinition().isInstanceInitializer()) {
-      classesWithPrunedInstanceInitializers.add(method.getHolder());
-    }
-  }
-
-  public void waveDone(ProgramMethodSet wave, OptimizationFeedbackDelayed feedback) {
-    // This relies on the instance initializer info in the method optimization feedback. It is
-    // therefore important that the optimization info has been flushed in advance.
-    assert feedback.noUpdatesLeft();
-    for (ProgramMethod method : wave) {
-      fieldAccessGraph.markProcessed(method, field -> recordAllFieldPutsProcessed(field, feedback));
-      objectAllocationGraph.markProcessed(
-          method, clazz -> recordAllAllocationsSitesProcessed(clazz, feedback));
-    }
-    feedback.refineAppInfoWithLiveness(appView.appInfo().withLiveness());
-    feedback.updateVisibleOptimizationInfo();
-  }
-
-  static class FieldAccessGraph {
-
-    // The fields written by each method.
-    private final Map<DexEncodedMethod, List<ProgramField>> fieldWrites = new IdentityHashMap<>();
-
-    // The number of writes that have not yet been processed per field.
-    private final Reference2IntMap<DexEncodedField> pendingFieldWrites =
-        new Reference2IntOpenHashMap<>();
-
-    FieldAccessGraph() {}
-
-    public void initialize(AppView<AppInfoWithLiveness> appView) {
-      FieldAccessInfoCollection<?> fieldAccessInfoCollection =
-          appView.appInfo().getFieldAccessInfoCollection();
-      fieldAccessInfoCollection.forEach(
-          info -> {
-            ProgramField field =
-                appView.appInfo().resolveField(info.getField()).getSingleProgramField();
-            if (field == null) {
-              return;
-            }
-            if (!info.hasReflectiveAccess() && !info.isWrittenFromMethodHandle()) {
-              info.forEachWriteContext(
-                  context ->
-                      fieldWrites
-                          .computeIfAbsent(context.getDefinition(), ignore -> new ArrayList<>())
-                          .add(field));
-              pendingFieldWrites.put(field.getDefinition(), info.getNumberOfWriteContexts());
-            }
-          });
-    }
-
-    void markProcessed(ProgramMethod method, Consumer<ProgramField> allWritesSeenConsumer) {
-      List<ProgramField> fieldWritesInMethod = fieldWrites.get(method.getDefinition());
-      if (fieldWritesInMethod != null) {
-        for (ProgramField field : fieldWritesInMethod) {
-          int numberOfPendingFieldWrites = pendingFieldWrites.removeInt(field.getDefinition()) - 1;
-          if (numberOfPendingFieldWrites > 0) {
-            pendingFieldWrites.put(field.getDefinition(), numberOfPendingFieldWrites);
-          } else {
-            allWritesSeenConsumer.accept(field);
-          }
-        }
-      }
-    }
-  }
-
-  static class ObjectAllocationGraph {
-
-    // The classes instantiated by each method.
-    private final Map<DexEncodedMethod, List<DexProgramClass>> objectAllocations =
-        new IdentityHashMap<>();
-
-    // The number of allocation sites that have not yet been processed per class.
-    private final Reference2IntMap<DexProgramClass> pendingObjectAllocations =
-        new Reference2IntOpenHashMap<>();
-
-    ObjectAllocationGraph() {}
-
-    public void initialize(AppView<AppInfoWithLiveness> appView) {
-      ObjectAllocationInfoCollection objectAllocationInfos =
-          appView.appInfo().getObjectAllocationInfoCollection();
-      objectAllocationInfos.forEachClassWithKnownAllocationSites(
-          (clazz, contexts) -> {
-            for (DexEncodedMethod context : contexts) {
-              objectAllocations.computeIfAbsent(context, ignore -> new ArrayList<>()).add(clazz);
-            }
-            pendingObjectAllocations.put(clazz, contexts.size());
-          });
-    }
-
-    void markProcessed(
-        ProgramMethod method, Consumer<DexProgramClass> allAllocationsSitesSeenConsumer) {
-      List<DexProgramClass> allocationSitesInMethod = objectAllocations.get(method.getDefinition());
-      if (allocationSitesInMethod != null) {
-        for (DexProgramClass type : allocationSitesInMethod) {
-          int numberOfPendingAllocationSites = pendingObjectAllocations.removeInt(type) - 1;
-          if (numberOfPendingAllocationSites > 0) {
-            pendingObjectAllocations.put(type, numberOfPendingAllocationSites);
-          } else {
-            allAllocationsSitesSeenConsumer.accept(type);
-          }
-        }
-      }
-    }
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
index 23bebb5..b18d828 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
@@ -135,7 +135,7 @@
 
   private void computeFieldsWithNonTrivialValue() {
     for (DexProgramClass clazz : appView.appInfo().classes()) {
-      for (DexEncodedField field : clazz.instanceFields()) {
+      for (DexEncodedField field : clazz.fields()) {
         FieldClassification fieldClassification = classifyField(field, appView);
         switch (fieldClassification) {
           case CONSTANT:
@@ -143,7 +143,7 @@
             constantFields.add(field);
             break;
           case NON_CONSTANT:
-            // Only reprocess writes, to allow branch pruning.
+            // Reprocess reads to allow branch pruning and value propagation.
             nonConstantFields.add(field);
             break;
           default:
@@ -151,17 +151,6 @@
             break;
         }
       }
-      if (appView.canUseInitClass() || !clazz.classInitializationMayHaveSideEffects(appView)) {
-        for (DexEncodedField field : clazz.staticFields()) {
-          FieldClassification fieldClassification = classifyField(field, appView);
-          if (fieldClassification == FieldClassification.CONSTANT) {
-            constantFields.add(field);
-          } else {
-            assert fieldClassification == FieldClassification.NON_CONSTANT
-                || fieldClassification == FieldClassification.UNKNOWN;
-          }
-        }
-      }
     }
     assert verifyNoConstantFieldsOnSynthesizedClasses(appView);
   }
@@ -203,7 +192,6 @@
         });
   }
 
-  @SuppressWarnings("ReferenceEquality")
   private static FieldClassification classifyField(
       DexEncodedField field, AppView<AppInfoWithLiveness> appView) {
     FieldAccessInfo fieldAccessInfo =
@@ -226,10 +214,13 @@
       if (singleValue.isSingleFieldValue()) {
         SingleFieldValue singleFieldValue = singleValue.asSingleFieldValue();
         DexField singleField = singleFieldValue.getField();
-        if (singleField != field.getReference()
+        if (singleField.isNotIdenticalTo(field.getReference())
             && !singleFieldValue.mayHaveFinalizeMethodDirectlyOrIndirectly(appView)) {
           return FieldClassification.CONSTANT;
         }
+        if (singleFieldValue.hasObjectState()) {
+          return FieldClassification.NON_CONSTANT;
+        }
       }
       return FieldClassification.UNKNOWN;
     }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicType.java b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicType.java
index 971a56e..5f0acbe 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicType.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicType.java
@@ -206,6 +206,11 @@
   @Override
   public abstract int hashCode();
 
+  public DynamicType uncanonicalizeNotNullType(
+      AppView<AppInfoWithLiveness> appView, DexType staticType) {
+    return this;
+  }
+
   private static boolean verifyNotEffectivelyFinalClassType(
       AppView<AppInfoWithLiveness> appView, TypeElement type) {
     if (type.isClassType()) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/NotNullDynamicType.java b/src/main/java/com/android/tools/r8/ir/analysis/type/NotNullDynamicType.java
index 7645341..d5f7fe1 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/NotNullDynamicType.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/NotNullDynamicType.java
@@ -75,4 +75,10 @@
   public String toString() {
     return "NotNullDynamicType";
   }
+
+  @Override
+  public DynamicType uncanonicalizeNotNullType(
+      AppView<AppInfoWithLiveness> appView, DexType staticType) {
+    return DynamicType.create(appView, staticType.toNonNullTypeElement(appView));
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index d5da488..36d72fc 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -596,6 +596,16 @@
       previous = printMethod(code, "IR after identifier-name strings (SSA)", previous);
     }
 
+    timing.begin("Run proto shrinking tasks");
+    appView.withGeneratedExtensionRegistryShrinker(shrinker -> shrinker.rewriteCode(method, code));
+
+    previous = printMethod(code, "IR after generated extension registry shrinking (SSA)", previous);
+
+    appView.withGeneratedMessageLiteShrinker(shrinker -> shrinker.run(code));
+    timing.end();
+
+    previous = printMethod(code, "IR after generated message lite shrinking (SSA)", previous);
+
     if (memberValuePropagation != null) {
       timing.begin("Propagate member values");
       memberValuePropagation.run(code);
@@ -632,16 +642,6 @@
 
     previous = printMethod(code, "IR after inserting assume instructions (SSA)", previous);
 
-    timing.begin("Run proto shrinking tasks");
-    appView.withGeneratedExtensionRegistryShrinker(shrinker -> shrinker.rewriteCode(method, code));
-
-    previous = printMethod(code, "IR after generated extension registry shrinking (SSA)", previous);
-
-    appView.withGeneratedMessageLiteShrinker(shrinker -> shrinker.run(code));
-    timing.end();
-
-    previous = printMethod(code, "IR after generated message lite shrinking (SSA)", previous);
-
     if (!isDebugMode && options.inlinerOptions().enableInlining && inliner != null) {
       timing.begin("Inlining");
       inliner.performInlining(code.context(), code, feedback, methodProcessor, timing);
@@ -899,9 +899,6 @@
       timing.begin("Analyze field accesses");
       fieldAccessAnalysis.recordFieldAccesses(
           code, bytecodeMetadataProviderBuilder, feedback, methodProcessor);
-      if (classInitializerDefaultsResult != null) {
-        fieldAccessAnalysis.acceptClassInitializerDefaultsResult(classInitializerDefaultsResult);
-      }
       timing.end();
     }
 
@@ -1092,7 +1089,6 @@
     assert method.getHolder().lookupMethod(method.getReference()) == null;
     appView.withArgumentPropagator(argumentPropagator -> argumentPropagator.onMethodPruned(method));
     enumUnboxer.onMethodPruned(method);
-    fieldAccessAnalysis.fieldAssignmentTracker().onMethodPruned(method);
     numberUnboxer.onMethodPruned(method);
     outliner.onMethodPruned(method);
     if (inliner != null) {
@@ -1110,7 +1106,6 @@
     appView.withArgumentPropagator(
         argumentPropagator -> argumentPropagator.onMethodCodePruned(method));
     enumUnboxer.onMethodCodePruned(method);
-    fieldAccessAnalysis.fieldAssignmentTracker().onMethodCodePruned(method);
     numberUnboxer.onMethodCodePruned(method);
     outliner.onMethodCodePruned(method);
     if (inliner != null) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java
index 035690f..9215753 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java
@@ -73,10 +73,6 @@
     numberUnboxer.prepareForPrimaryOptimizationPass(timing, executorService);
     outliner.prepareForPrimaryOptimizationPass(graphLensForPrimaryOptimizationPass);
 
-    if (fieldAccessAnalysis != null && fieldAccessAnalysis.fieldAssignmentTracker() != null) {
-      fieldAccessAnalysis.fieldAssignmentTracker().initialize();
-    }
-
     // Process the application identifying outlining candidates.
     OptimizationFeedbackDelayed feedback = delayedOptimizationFeedback;
     PostMethodProcessor.Builder postMethodProcessorBuilder =
@@ -255,9 +251,6 @@
   public void waveDone(ProgramMethodSet wave, ExecutorService executorService) {
     delayedOptimizationFeedback.refineAppInfoWithLiveness(appView.appInfo().withLiveness());
     delayedOptimizationFeedback.updateVisibleOptimizationInfo();
-    if (fieldAccessAnalysis.fieldAssignmentTracker() != null) {
-      fieldAccessAnalysis.fieldAssignmentTracker().waveDone(wave, delayedOptimizationFeedback);
-    }
     appView.withArgumentPropagator(ArgumentPropagator::publishDelayedReprocessingCriteria);
     if (appView.options().protoShrinking().enableRemoveProtoEnumSwitchMap()) {
       appView.protoShrinker().protoEnumSwitchMapRemover.updateVisibleStaticFieldValues();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
index 23ae714..23517ba 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.ir.optimize;
 
 import static com.android.tools.r8.graph.ProgramField.asProgramFieldOrNull;
+import static com.android.tools.r8.ir.optimize.info.OptimizationFeedback.getSimpleFeedback;
 import static com.android.tools.r8.utils.MapUtils.ignoreKey;
 import static com.android.tools.r8.utils.PredicateUtils.not;
 
@@ -686,6 +687,9 @@
       if (replacement != null) {
         if (isRedundantFieldLoadEliminationAllowed(field)) {
           replacement.eliminateRedundantRead(it, instanceGet);
+          if (field.isProgramField()) {
+            getSimpleFeedback().markFieldAsPropagated(field.getDefinition());
+          }
         }
         return;
       }
@@ -774,6 +778,9 @@
       FieldValue replacement = activeState.getStaticFieldValue(field.getReference());
       if (replacement != null) {
         replacement.eliminateRedundantRead(instructionIterator, staticGet);
+        if (field.isProgramField()) {
+          getSimpleFeedback().markFieldAsPropagated(field.getDefinition());
+        }
         return;
       }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
index 65487d8..7661efc 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
@@ -967,14 +967,14 @@
                 unboxedValues.put(field.getReference(), ordinalToUnboxedInt(ordinal));
                 ordinalToObjectState.put(ordinal, enumState);
                 if (isEnumWithSubtypes) {
-                  DynamicType dynamicType = field.getOptimizationInfo().getDynamicType();
-                  // If the dynamic type is a NotNull dynamic type, then de-canonicalize the dynamic
+                  // If the dynamic type is a NotNull dynamic type, then uncanonicalize the dynamic
                   // type. If the static type is an effectively final class then this yields an
                   // exact dynamic type.
-                  if (dynamicType.isNotNullType()) {
-                    dynamicType =
-                        DynamicType.create(appView, field.getType().toNonNullTypeElement(appView));
-                  }
+                  DynamicType dynamicType =
+                      field
+                          .getOptimizationInfo()
+                          .getDynamicType()
+                          .uncanonicalizeNotNullType(appView, field.getType());
                   if (dynamicType.isExactClassType()) {
                     valueTypes.put(ordinal, dynamicType.getExactClassType().getClassType());
                   } else {
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 9f3a782..0284378 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
@@ -151,7 +151,11 @@
 
         // Since the value is a single field value, the type should be exact.
         assert abstractValue.isSingleFieldValue();
-        ClassTypeElement enumFieldType = optimizationInfo.getDynamicType().getExactClassType();
+        ClassTypeElement enumFieldType =
+            optimizationInfo
+                .getDynamicType()
+                .uncanonicalizeNotNullType(appView.withLiveness(), field.getType())
+                .getExactClassType();
         if (enumFieldType == null) {
           assert false : "Expected to have an exact dynamic type for enum instance";
           continue;
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 163e2e1..60f2cbd 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -404,7 +404,6 @@
   // Optimization-related flags. These should conform to -dontoptimize and disableAllOptimizations.
   public boolean enableFieldBitAccessAnalysis =
       System.getProperty("com.android.tools.r8.fieldBitAccessAnalysis") != null;
-  public boolean enableFieldAssignmentTracker = true;
   public boolean enableFieldValueAnalysis = true;
   public boolean enableUnusedInterfaceRemoval = true;
   public boolean enableDevirtualization = true;
diff --git a/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java b/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
index 64e4c42..270116a 100644
--- a/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
+++ b/src/test/java/com/android/tools/r8/internal/proto/Proto2ShrinkingTest.java
@@ -80,7 +80,6 @@
             .addProgramFiles(PROGRAM_FILES)
             .addKeepMainRule("proto2.TestClass")
             .addKeepRuleFiles(PROTOBUF_LITE_PROGUARD_RULES)
-            .addKeepRules(allGeneratedMessageLiteSubtypesAreInstantiatedRule())
             // TODO(b/173340579): This rule should not be needed to allow shrinking of
             //  PartiallyUsed$Enum.
             .addNoHorizontalClassMergingRule(PARTIALLY_USED + "$Enum$1")
@@ -407,7 +406,6 @@
         .addKeepMainRule("proto2.TestClass")
         .addKeepRuleFiles(PROTOBUF_LITE_PROGUARD_RULES)
         .addKeepRules(findLiteExtensionByNumberInDuplicateCalledRule())
-        .addKeepRules(allGeneratedMessageLiteSubtypesAreInstantiatedRule())
         // TODO(b/173340579): This rule should not be needed to allow shrinking of
         //  PartiallyUsed$Enum.
         .addNoHorizontalClassMergingRule(PARTIALLY_USED + "$Enum$1")
diff --git a/src/test/java/com/android/tools/r8/internal/proto/ProtoShrinkingTestBase.java b/src/test/java/com/android/tools/r8/internal/proto/ProtoShrinkingTestBase.java
index 9bd5a74..f0db90b 100644
--- a/src/test/java/com/android/tools/r8/internal/proto/ProtoShrinkingTestBase.java
+++ b/src/test/java/com/android/tools/r8/internal/proto/ProtoShrinkingTestBase.java
@@ -75,14 +75,6 @@
     }
   }
 
-  static String allGeneratedMessageLiteSubtypesAreInstantiatedRule() {
-    return StringUtils.lines(
-        "-if class * extends com.google.protobuf.GeneratedMessageLite",
-        "-keep,allowobfuscation class <1> {",
-        "  <init>(...);",
-        "}");
-  }
-
   static String findLiteExtensionByNumberInDuplicateCalledRule() {
     return StringUtils.lines(
         "-keep class com.google.protobuf.proto2_registryGeneratedExtensionRegistryLiteDuplicate {",
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java b/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java
index ea825ed..1c8a244 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldBitAccessInfoTest.java
@@ -87,7 +87,7 @@
     OptimizationFeedbackMock feedback = new OptimizationFeedbackMock();
     FieldBitAccessAnalysis fieldBitAccessAnalysis = new FieldBitAccessAnalysis();
     FieldAccessAnalysis fieldAccessAnalysis =
-        new FieldAccessAnalysis(appView, null, fieldBitAccessAnalysis, null, null);
+        new FieldAccessAnalysis(appView, fieldBitAccessAnalysis, null, null);
 
     DexProgramClass clazz = appView.appInfo().classes().iterator().next();
     assertEquals(TestClass.class.getTypeName(), clazz.type.toSourceString());
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/FieldWriteBeforeFieldReadTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/FieldWriteBeforeFieldReadTest.java
index a603d83..16060c2 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/FieldWriteBeforeFieldReadTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/FieldWriteBeforeFieldReadTest.java
@@ -4,14 +4,13 @@
 
 package com.android.tools.r8.ir.optimize.membervaluepropagation;
 
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.NeverClassInline;
 import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverReprocessMethod;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -24,49 +23,47 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class FieldWriteBeforeFieldReadTest extends TestBase {
 
-  private final TestParameters parameters;
+  @Parameter(0)
+  public TestParameters parameters;
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
-  public FieldWriteBeforeFieldReadTest(TestParameters parameters) {
-    this.parameters = parameters;
-  }
-
   @Test
   public void test() throws Exception {
     testForR8(parameters.getBackend())
         .addInnerClasses(FieldWriteBeforeFieldReadTest.class)
         .addKeepMainRule(TestClass.class)
         .addOptionsModification(
-            options -> {
-              options.testing.waveModifier =
-                  (waves) -> {
-                    Function<String, Predicate<ProgramMethodSet>> wavePredicate =
-                        methodName ->
-                            wave ->
-                                wave.stream()
-                                    .anyMatch(
-                                        method -> method.toSourceString().contains(methodName));
-                    int readFieldsWaveIndex =
-                        IterableUtils.firstIndexMatching(waves, wavePredicate.apply("readFields"));
-                    assertTrue(readFieldsWaveIndex >= 0);
-                    int writeFieldsWaveIndex =
-                        IterableUtils.firstIndexMatching(waves, wavePredicate.apply("writeFields"));
-                    assertTrue(writeFieldsWaveIndex >= 0);
-                    assertTrue(writeFieldsWaveIndex < readFieldsWaveIndex);
-                  };
-            })
+            options ->
+                options.testing.waveModifier =
+                    (waves) -> {
+                      Function<String, Predicate<ProgramMethodSet>> wavePredicate =
+                          methodName ->
+                              wave ->
+                                  wave.stream()
+                                      .anyMatch(
+                                          method -> method.toSourceString().contains(methodName));
+                      int readFieldsWaveIndex =
+                          IterableUtils.firstIndexMatching(
+                              waves, wavePredicate.apply("readFields"));
+                      assertTrue(readFieldsWaveIndex >= 0);
+                      int writeFieldsWaveIndex =
+                          IterableUtils.firstIndexMatching(
+                              waves, wavePredicate.apply("writeFields"));
+                      assertTrue(writeFieldsWaveIndex >= 0);
+                      assertTrue(writeFieldsWaveIndex < readFieldsWaveIndex);
+                    })
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
-        .enableNeverReprocessMethodAnnotations()
         .setMinApi(parameters)
         .compile()
         .inspect(this::inspect)
@@ -78,7 +75,7 @@
     ClassSubject testClassSubject = inspector.clazz(TestClass.class);
     assertThat(testClassSubject, isPresent());
     assertThat(testClassSubject.uniqueMethodWithOriginalName("live"), isPresent());
-    assertThat(testClassSubject.uniqueMethodWithOriginalName("dead"), not(isPresent()));
+    assertThat(testClassSubject.uniqueMethodWithOriginalName("dead"), isAbsent());
   }
 
   static class TestClass {
@@ -100,8 +97,10 @@
 
     static void increaseDistanceToNearestLeaf() {}
 
+    // By processing writeFields() before readFields() and publishing the fact that alwaysFalse is
+    // the constant false after processing writeFields(), it would be possible to optimize
+    // readFields() in just a single optimization pass.
     @NeverInline
-    @NeverReprocessMethod
     static void readFields(A obj) {
       if (alwaysFalse || obj.alwaysFalse) {
         dead();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/InstanceFieldValuePropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/InstanceFieldValuePropagationTest.java
index 9fdff7c..2f716b7 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/InstanceFieldValuePropagationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/InstanceFieldValuePropagationTest.java
@@ -6,6 +6,8 @@
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.NeverClassInline;
@@ -74,10 +76,12 @@
     MethodSubject testMaybeNullMethodSubject =
         testClassSubject.uniqueMethodWithOriginalName("testMaybeNull");
     assertThat(testMaybeNullMethodSubject, isPresent());
-    assertTrue(
+    // TODO(b/330674939): Should not have any instance-gets.
+    assertEquals(
+        parameters.canInitNewInstanceUsingSuperclassConstructor(),
         testMaybeNullMethodSubject
             .streamInstructions()
-            .noneMatch(InstructionSubject::isInstanceGet));
+            .anyMatch(InstructionSubject::isInstanceGet));
     // TODO(b/125282093): Should be able to remove the new-instance instruction since the instance
     //  ends up being unused.
     assertTrue(
@@ -87,7 +91,10 @@
 
     ClassSubject aClassSubject = inspector.clazz(A.class);
     assertThat(aClassSubject, isPresent());
-    assertTrue(aClassSubject.allInstanceFields().isEmpty());
+    // TODO(b/330674939): Should never have any instance fields.
+    assertNotEquals(
+        parameters.canInitNewInstanceUsingSuperclassConstructor(),
+        aClassSubject.allInstanceFields().isEmpty());
   }
 
   static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/FieldStateArgumentPropagationTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/FieldStateArgumentPropagationTest.java
index 6272631..b79e37a 100644
--- a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/FieldStateArgumentPropagationTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/FieldStateArgumentPropagationTest.java
@@ -37,7 +37,6 @@
         .addKeepMainRule(Main.class)
         .addOptionsModification(
             options -> {
-              options.enableFieldAssignmentTracker = false;
               options.enableFieldValueAnalysis = false;
             })
         .enableInliningAnnotations()