Revert "[KeepAnno] Maintain field preconditions using witnesses"

This reverts commit 450169d1fb91d0729c1d1e8aa1f491329e107afc.

Reason for revert: broke the build

Change-Id: I009e8a4618372ba6f965dfb1ce98c0ab94db7560
diff --git a/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
index 75ee123..a3da4f7 100644
--- a/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
+++ b/src/main/java/com/android/tools/r8/graph/AssemblyWriter.java
@@ -138,16 +138,13 @@
       writeAnnotations(null, field.annotations(), ps);
       ps.print(field.accessFlags + " ");
       ps.print(retracer.toSourceString(field.getReference()));
+      if (!retracer.isEmpty()) {
+        ps.println("# Residual: '" + field.getReference().toSourceString() + "'");
+      }
       if (field.isStatic() && field.hasExplicitStaticValue()) {
         ps.print(" = " + field.getStaticValue());
       }
       ps.println();
-      if (!retracer.isEmpty()) {
-        ps.println("# Residual: '" + field.getReference().toSourceString() + "'");
-      }
-      if (field.hasNonIdentityOriginalFieldWitness()) {
-        ps.println("# Original: '" + field.getOriginalFieldWitness() + "'");
-      }
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
index 5f72db6..2093937 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -18,7 +18,6 @@
 import com.android.tools.r8.kotlin.KotlinFieldLevelInfo;
 import com.android.tools.r8.kotlin.KotlinMetadataUtils;
 import com.android.tools.r8.utils.ConsumerUtils;
-import com.android.tools.r8.utils.ObjectUtils;
 import com.android.tools.r8.utils.structural.StructuralItem;
 import com.android.tools.r8.utils.structural.StructuralMapping;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
@@ -32,7 +31,6 @@
 
   public final FieldAccessFlags accessFlags;
   private DexValue staticValue;
-  private OriginalFieldWitness originalFieldWitness = null;
   private final boolean deprecated;
   /** Generic signature information if the attribute is present in the input */
   private FieldTypeSignature genericSignature;
@@ -360,28 +358,6 @@
     return true;
   }
 
-  void recordOriginalFieldWitness(
-      ProgramField field, AppView<? extends AppInfoWithClassHierarchy> appView) {
-    assert ObjectUtils.identical(this, field.getDefinition());
-    originalFieldWitness = OriginalFieldWitness.forProgramField(field);
-    optimizationInfo =
-        optimizationInfo
-            .toMutableOptimizationInfo()
-            .addOriginalFieldWitness(originalFieldWitness, field, appView);
-  }
-
-  public OriginalFieldWitness getOriginalFieldWitness() {
-    return originalFieldWitness;
-  }
-
-  public boolean hasOriginalFieldWitness() {
-    return originalFieldWitness != null;
-  }
-
-  public boolean hasNonIdentityOriginalFieldWitness() {
-    return hasOriginalFieldWitness() && !originalFieldWitness.isEqualToDexField(getReference());
-  }
-
   public static class Builder {
 
     private DexField field;
@@ -390,7 +366,6 @@
     private FieldTypeSignature genericSignature = FieldTypeSignature.noSignature();
     private KotlinFieldLevelInfo kotlinInfo = KotlinMetadataUtils.getNoKotlinInfo();
     private DexValue staticValue = null;
-    private OriginalFieldWitness originalFieldWitness = null;
     private ComputedApiLevel apiLevel = ComputedApiLevel.notSet();
     private FieldOptimizationInfo optimizationInfo = DefaultFieldOptimizationInfo.getInstance();
     private boolean deprecated;
@@ -413,7 +388,6 @@
       kotlinInfo = from.getKotlinInfo();
       annotations = from.annotations();
       staticValue = from.staticValue;
-      originalFieldWitness = from.originalFieldWitness;
       apiLevel = from.getApiLevel();
       optimizationInfo =
           from.optimizationInfo.isMutableOptimizationInfo()
@@ -513,7 +487,6 @@
               d8R8Synthesized);
       dexEncodedField.setKotlinMemberInfo(kotlinInfo);
       dexEncodedField.optimizationInfo = optimizationInfo;
-      dexEncodedField.originalFieldWitness = originalFieldWitness;
       buildConsumer.accept(dexEncodedField);
       return dexEncodedField;
     }
diff --git a/src/main/java/com/android/tools/r8/graph/OriginalFieldWitness.java b/src/main/java/com/android/tools/r8/graph/OriginalFieldWitness.java
deleted file mode 100644
index a66cc33..0000000
--- a/src/main/java/com/android/tools/r8/graph/OriginalFieldWitness.java
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (c) 2024, 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.graph;
-
-import com.android.tools.r8.lightir.LirConstant;
-import com.android.tools.r8.utils.structural.CompareToVisitor;
-import com.android.tools.r8.utils.structural.Equatable;
-import com.android.tools.r8.utils.structural.HashingVisitor;
-import com.android.tools.r8.utils.structural.StructuralItem;
-import com.android.tools.r8.utils.structural.StructuralMapping;
-import com.android.tools.r8.utils.structural.StructuralSpecification;
-import java.util.Objects;
-import java.util.function.Consumer;
-
-public class OriginalFieldWitness implements LirConstant, StructuralItem<OriginalFieldWitness> {
-  private final OriginalFieldWitness parent;
-  private final DexField originalField;
-
-  private static void specify(StructuralSpecification<OriginalFieldWitness, ?> spec) {
-    spec.withItem(d -> d.originalField).withNullableItem(d -> d.parent);
-  }
-
-  private OriginalFieldWitness(OriginalFieldWitness parent, DexField originalField) {
-    this.parent = parent;
-    this.originalField = originalField;
-  }
-
-  @Override
-  public OriginalFieldWitness self() {
-    return this;
-  }
-
-  @Override
-  public StructuralMapping<OriginalFieldWitness> getStructuralMapping() {
-    return OriginalFieldWitness::specify;
-  }
-
-  public static OriginalFieldWitness forProgramField(ProgramField field) {
-    return new OriginalFieldWitness(null, field.getReference());
-  }
-
-  public boolean isEqualToDexField(DexField field) {
-    return parent == null && originalField.isIdenticalTo(field);
-  }
-
-  public void forEachReference(Consumer<? super DexField> fn) {
-    fn.accept(originalField);
-    if (parent != null) {
-      parent.forEachReference(fn);
-    }
-  }
-
-  @Override
-  public String toString() {
-    if (parent == null) {
-      return originalField.toString();
-    }
-    return originalField + ":" + parent.toString();
-  }
-
-  @Override
-  public boolean equals(Object obj) {
-    return Equatable.equalsImpl(this, obj);
-  }
-
-  @Override
-  public int hashCode() {
-    return Objects.hash(originalField, parent);
-  }
-
-  @Override
-  public LirConstantOrder getLirConstantOrder() {
-    return LirConstantOrder.ORIGINAL_FIELD_WITNESS;
-  }
-
-  @Override
-  public int internalLirConstantAcceptCompareTo(LirConstant other, CompareToVisitor visitor) {
-    return visitor.visit(this, (OriginalFieldWitness) other, OriginalFieldWitness::specify);
-  }
-
-  @Override
-  public void internalLirConstantAcceptHashing(HashingVisitor visitor) {
-    visitor.visit(this, OriginalFieldWitness::specify);
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramField.java b/src/main/java/com/android/tools/r8/graph/ProgramField.java
index 7ed8b59..60d3b0e 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramField.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramField.java
@@ -99,8 +99,4 @@
   public KotlinFieldLevelInfo getKotlinInfo() {
     return getDefinition().getKotlinInfo();
   }
-
-  public void recordOriginalFieldWitness(AppView<? extends AppInfoWithClassHierarchy> appView) {
-    getDefinition().recordOriginalFieldWitness(this, appView);
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/UseRegistry.java b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
index 5d92dc1..6238dd5 100644
--- a/src/main/java/com/android/tools/r8/graph/UseRegistry.java
+++ b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
@@ -65,8 +65,6 @@
     assert position.hasCallerPosition();
   }
 
-  public void registerOriginalFieldWitness(OriginalFieldWitness witness) {}
-
   public void registerRecordFieldValues(DexField[] fields) {
     registerTypeReference(appView.dexItemFactory().objectArrayType);
   }
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 cc8cfb9..fdb9d4b 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
@@ -237,10 +237,6 @@
     return null;
   }
 
-  public boolean hasWitness() {
-    return false;
-  }
-
   public boolean isUnknown() {
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueJoiner.java b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueJoiner.java
index 1814214..047e4ef 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueJoiner.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueJoiner.java
@@ -38,11 +38,6 @@
         || abstractValue.equals(otherAbstractValue)) {
       return abstractValue;
     }
-    if (abstractValue.hasWitness() || otherAbstractValue.hasWitness()) {
-      // TODO(b/334822108): Implement support for actually joining values with witness.
-      assert !(abstractValue.hasWitness() && otherAbstractValue.hasWitness());
-      return unknown();
-    }
     if (type.isReferenceType()) {
       return joinReference(abstractValue, otherAbstractValue);
     } else {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueWithWitness.java b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueWithWitness.java
deleted file mode 100644
index b11af88..0000000
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueWithWitness.java
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2024, 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.DexType;
-import com.android.tools.r8.graph.lens.GraphLens;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-
-public class AbstractValueWithWitness extends AbstractValue {
-
-  private static final AbstractValueWithWitness INSTANCE = new AbstractValueWithWitness();
-
-  private AbstractValueWithWitness() {}
-
-  public static AbstractValueWithWitness getInstance() {
-    return INSTANCE;
-  }
-
-  @Override
-  public boolean hasWitness() {
-    return true;
-  }
-
-  @Override
-  public boolean isNonTrivial() {
-    return true;
-  }
-
-  @Override
-  public AbstractValue rewrittenWithLens(
-      AppView<AppInfoWithLiveness> appView, DexType newType, GraphLens lens, GraphLens codeLens) {
-    return this;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    return this == o;
-  }
-
-  @Override
-  public int hashCode() {
-    return System.identityHashCode(this);
-  }
-
-  @Override
-  public String toString() {
-    return "AbstractValueWithWitness";
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRMetadata.java b/src/main/java/com/android/tools/r8/ir/code/IRMetadata.java
index c0888c0..e111001 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRMetadata.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRMetadata.java
@@ -111,10 +111,6 @@
     return get(Opcodes.RESOURCE_CONST_NUMBER);
   }
 
-  public boolean mayHaveOriginalFieldWitness() {
-    return get(Opcodes.ORIGINAL_FIELD_WITNESS);
-  }
-
   public boolean mayHaveConstString() {
     return get(Opcodes.CONST_STRING);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
index 6b9743a..e81b4d0 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -880,14 +880,6 @@
     return null;
   }
 
-  public boolean isOriginalFieldWitness() {
-    return false;
-  }
-
-  public OriginalFieldWitnessInstruction asOriginalFieldWitness() {
-    return null;
-  }
-
   public boolean isConstInstruction() {
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Opcodes.java b/src/main/java/com/android/tools/r8/ir/code/Opcodes.java
index 5ee18f3..58889ac 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Opcodes.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Opcodes.java
@@ -78,5 +78,4 @@
   int UNINITIALIZED_THIS_LOCAL_READ = 69;
   int RECORD_FIELD_VALUES = 70;
   int RESOURCE_CONST_NUMBER = 71;
-  int ORIGINAL_FIELD_WITNESS = 72;
 }
diff --git a/src/main/java/com/android/tools/r8/ir/code/OriginalFieldWitnessInstruction.java b/src/main/java/com/android/tools/r8/ir/code/OriginalFieldWitnessInstruction.java
deleted file mode 100644
index 7fbab29..0000000
--- a/src/main/java/com/android/tools/r8/ir/code/OriginalFieldWitnessInstruction.java
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (c) 2024, 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.code;
-
-import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.OriginalFieldWitness;
-import com.android.tools.r8.ir.conversion.CfBuilder;
-import com.android.tools.r8.ir.conversion.DexBuilder;
-import com.android.tools.r8.lightir.LirBuilder;
-
-public class OriginalFieldWitnessInstruction extends Move {
-
-  private final OriginalFieldWitness witness;
-
-  public OriginalFieldWitnessInstruction(
-      OriginalFieldWitness witness, Value outValue, Value inValue) {
-    super(outValue, inValue);
-    this.witness = witness;
-  }
-
-  public OriginalFieldWitness getWitness() {
-    return witness;
-  }
-
-  @Override
-  public int opcode() {
-    return Opcodes.ORIGINAL_FIELD_WITNESS;
-  }
-
-  @Override
-  public boolean isOriginalFieldWitness() {
-    return true;
-  }
-
-  @Override
-  public OriginalFieldWitnessInstruction asOriginalFieldWitness() {
-    return this;
-  }
-
-  @Override
-  public <T> T accept(InstructionVisitor<T> visitor) {
-    return visitor.visit(this);
-  }
-
-  @Override
-  public void buildLir(LirBuilder<Value, ?> builder) {
-    builder.addOriginalFieldWitness(getWitness(), src());
-  }
-
-  @Override
-  public boolean identicalNonValueNonPositionParts(Instruction other) {
-    if (this == other) {
-      return true;
-    }
-    if (!other.isOriginalFieldWitness()) {
-      return false;
-    }
-    OriginalFieldWitnessInstruction o = other.asOriginalFieldWitness();
-    return witness.isEqualTo(o.witness);
-  }
-
-  @Override
-  public void buildCf(CfBuilder builder) {
-    throw new Unreachable("We never write out witness instructions");
-  }
-
-  @Override
-  public void buildDex(DexBuilder builder) {
-    throw new Unreachable("We never write out witness instructions");
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java
index 1f92cc0..8810391 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java
@@ -19,7 +19,6 @@
 import com.android.tools.r8.ir.conversion.passes.DexItemBasedConstStringRemover;
 import com.android.tools.r8.ir.conversion.passes.FilledNewArrayRewriter;
 import com.android.tools.r8.ir.conversion.passes.InitClassRemover;
-import com.android.tools.r8.ir.conversion.passes.OriginalFieldWitnessRemover;
 import com.android.tools.r8.ir.conversion.passes.StringSwitchConverter;
 import com.android.tools.r8.ir.conversion.passes.StringSwitchRemover;
 import com.android.tools.r8.ir.optimize.ConstantCanonicalizer;
@@ -148,7 +147,6 @@
         new CodeRewriterPassCollection(
             new AdaptClassStringsRewriter(appView),
             new ConstResourceNumberRemover(appView),
-            new OriginalFieldWitnessRemover(appView),
             // Must run before DexItemBasedConstStringRemover.
             new StringSwitchRemover(appView),
             new DexItemBasedConstStringRemover(appView),
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/passes/OriginalFieldWitnessRemover.java b/src/main/java/com/android/tools/r8/ir/conversion/passes/OriginalFieldWitnessRemover.java
deleted file mode 100644
index aebea12..0000000
--- a/src/main/java/com/android/tools/r8/ir/conversion/passes/OriginalFieldWitnessRemover.java
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2024, 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.conversion.passes;
-
-import com.android.tools.r8.graph.AppInfo;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.ir.code.IRCode;
-import com.android.tools.r8.ir.code.Instruction;
-import com.android.tools.r8.ir.code.InstructionListIterator;
-import com.android.tools.r8.ir.code.OriginalFieldWitnessInstruction;
-import com.android.tools.r8.ir.conversion.MethodProcessor;
-import com.android.tools.r8.ir.conversion.passes.result.CodeRewriterResult;
-
-public class OriginalFieldWitnessRemover extends CodeRewriterPass<AppInfo> {
-
-  public OriginalFieldWitnessRemover(AppView<?> appView) {
-    super(appView);
-  }
-
-  @Override
-  protected String getRewriterId() {
-    return "OriginalFieldWitnessRemover";
-  }
-
-  @Override
-  protected boolean shouldRewriteCode(IRCode code, MethodProcessor methodProcessor) {
-    return code.metadata().mayHaveOriginalFieldWitness();
-  }
-
-  @Override
-  protected CodeRewriterResult rewriteCode(IRCode code) {
-    boolean hasChanged = false;
-    InstructionListIterator iterator = code.instructionListIterator();
-    while (iterator.hasNext()) {
-      Instruction current = iterator.next();
-      if (current.isOriginalFieldWitness()) {
-        OriginalFieldWitnessInstruction instruction = current.asOriginalFieldWitness();
-        instruction.outValue().replaceUsers(instruction.src());
-        iterator.removeOrReplaceByDebugLocalRead();
-        hasChanged = true;
-      }
-    }
-    return CodeRewriterResult.hasChanged(hasChanged);
-  }
-}
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 75c8231..46d4883 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
@@ -35,7 +35,6 @@
 import com.android.tools.r8.ir.code.AliasedValueConfiguration;
 import com.android.tools.r8.ir.code.AssumeAndCheckCastAliasedValueConfiguration;
 import com.android.tools.r8.ir.code.BasicBlock;
-import com.android.tools.r8.ir.code.BasicBlockInstructionListIterator;
 import com.android.tools.r8.ir.code.BasicBlockIterator;
 import com.android.tools.r8.ir.code.CheckCast;
 import com.android.tools.r8.ir.code.IRCode;
@@ -50,7 +49,6 @@
 import com.android.tools.r8.ir.code.InvokeDirect;
 import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.ir.code.InvokeMethodWithReceiver;
-import com.android.tools.r8.ir.code.OriginalFieldWitnessInstruction;
 import com.android.tools.r8.ir.code.Phi;
 import com.android.tools.r8.ir.code.StaticGet;
 import com.android.tools.r8.ir.code.Value;
@@ -767,20 +765,11 @@
       AffectedValues affectedValues,
       Map<DexField, FieldValueHelper> fieldHelpers) {
     Value value = fieldRead.outValue();
-    Instruction replacement = null;
     if (value != null) {
       FieldValueHelper helper =
           fieldHelpers.computeIfAbsent(
               fieldRead.getField(), field -> new FieldValueHelper(field, code, root, appView));
       Value newValue = helper.getValueForFieldRead(fieldRead.getBlock(), fieldRead);
-      DexEncodedField definition = eligibleClass.lookupInstanceField(fieldRead.getField());
-      if (definition.getOriginalFieldWitness() != null) {
-        Value dest = code.createValue(newValue.getType(), newValue.getLocalInfo());
-        replacement =
-            new OriginalFieldWitnessInstruction(
-                definition.getOriginalFieldWitness(), dest, newValue);
-        newValue = dest;
-      }
       value.replaceUsers(newValue);
       for (FieldValueHelper fieldValueHelper : fieldHelpers.values()) {
         fieldValueHelper.replaceValue(value, newValue);
@@ -792,12 +781,7 @@
       affectedValues.add(newValue);
       affectedValues.addAll(newValue.affectedValues());
     }
-    if (replacement != null) {
-      BasicBlockInstructionListIterator it = fieldRead.getBlock().listIterator(code, fieldRead);
-      it.replaceCurrentInstruction(replacement, affectedValues);
-    } else {
-      removeInstruction(fieldRead);
-    }
+    removeInstruction(fieldRead);
   }
 
   private void removeFieldReadsFromStaticGet(IRCode code, AffectedValues affectedValues) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
index 821a5ab..6c7a777 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableFieldOptimizationInfo.java
@@ -6,17 +6,12 @@
 
 import static java.util.Collections.emptySet;
 
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.OriginalFieldWitness;
-import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.type.DynamicType;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
-import com.android.tools.r8.ir.analysis.value.AbstractValueJoiner.AbstractValueFieldJoiner;
-import com.android.tools.r8.ir.analysis.value.AbstractValueWithWitness;
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.Set;
@@ -71,18 +66,6 @@
     return setAbstractValue(abstractValue);
   }
 
-  public MutableFieldOptimizationInfo addOriginalFieldWitness(
-      OriginalFieldWitness unused,
-      ProgramField field,
-      AppView<? extends AppInfoWithClassHierarchy> appView) {
-    AbstractValueWithWitness witnessValue = AbstractValueWithWitness.getInstance();
-    if (abstractValue.isUnknown()) {
-      return setAbstractValue(witnessValue);
-    }
-    return setAbstractValue(
-        new AbstractValueFieldJoiner(appView).join(abstractValue, witnessValue, field));
-  }
-
   private MutableFieldOptimizationInfo setAbstractValue(AbstractValue abstractValue) {
     assert getAbstractValue().isUnknown()
         || abstractValue.isNonTrivial()
diff --git a/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java b/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
index 27f4575..42c94e5 100644
--- a/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
+++ b/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
@@ -14,7 +14,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.graph.OriginalFieldWitness;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.proto.ArgumentInfo;
 import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
@@ -81,7 +80,6 @@
 import com.android.tools.r8.ir.code.NumberGenerator;
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.code.Or;
-import com.android.tools.r8.ir.code.OriginalFieldWitnessInstruction;
 import com.android.tools.r8.ir.code.Phi;
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.code.RecordFieldValues;
@@ -1039,12 +1037,5 @@
       Value dest = getOutValueForNextInstruction(typeElement);
       addInstruction(new RecordFieldValues(fields, dest, getValues(values)));
     }
-
-    @Override
-    public void onOriginalFieldWitness(OriginalFieldWitness witness, EV value) {
-      // The instruction is a move and its type must be computed as that of its source value.
-      Value dest = getOutValueForNextInstruction(TypeElement.getBottom());
-      addInstruction(new OriginalFieldWitnessInstruction(witness, dest, getValue(value)));
-    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/lightir/LirBuilder.java b/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
index ba37ad1..a35a20f 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
@@ -18,7 +18,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.graph.OriginalFieldWitness;
 import com.android.tools.r8.graph.bytecodemetadata.BytecodeInstructionMetadata;
 import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
@@ -1115,11 +1114,4 @@
     return addInstructionTemplate(
         LirOpcodes.RECORDFIELDVALUES, Collections.singletonList(payload), values);
   }
-
-  public LirBuilder<V, EV> addOriginalFieldWitness(OriginalFieldWitness witness, V value) {
-    return addInstructionTemplate(
-        LirOpcodes.ORIGINALFIELDWITNESS,
-        Collections.singletonList(witness),
-        Collections.singletonList(value));
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/lightir/LirConstant.java b/src/main/java/com/android/tools/r8/lightir/LirConstant.java
index c889c00..41a7115 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirConstant.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirConstant.java
@@ -25,8 +25,7 @@
     STRING_SWITCH,
     FILL_ARRAY,
     NAME_COMPUTATION,
-    RECORD_FIELD_VALUES,
-    ORIGINAL_FIELD_WITNESS
+    RECORD_FIELD_VALUES
   }
 
   class LirConstantStructuralAcceptor implements StructuralAcceptor<LirConstant> {
diff --git a/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java b/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java
index d1881c3..702dbba 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java
@@ -213,7 +213,6 @@
   int CONSTCLASS_IGNORE_COMPAT = 226;
   int STRINGSWITCH = 227;
   int RESOURCENUMBER = 228;
-  int ORIGINALFIELDWITNESS = 229;
 
   static String toString(int opcode) {
     switch (opcode) {
diff --git a/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java b/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
index 953890c..4fe7d83 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
@@ -14,7 +14,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.graph.OriginalFieldWitness;
 import com.android.tools.r8.ir.code.IfType;
 import com.android.tools.r8.ir.code.MemberType;
 import com.android.tools.r8.ir.code.NumericType;
@@ -527,10 +526,6 @@
     onInstruction();
   }
 
-  public void onOriginalFieldWitness(OriginalFieldWitness witness, EV value) {
-    onInstruction();
-  }
-
   private LirConstant getConstantItem(int index) {
     return code.getConstantItem(index);
   }
@@ -1293,14 +1288,6 @@
           onConstResourceNumber(value);
           return;
         }
-      case LirOpcodes.ORIGINALFIELDWITNESS:
-        {
-          OriginalFieldWitness witness =
-              (OriginalFieldWitness) getConstantItem(view.getNextConstantOperand());
-          EV value = getNextValueOperand(view);
-          onOriginalFieldWitness(witness, value);
-          return;
-        }
       default:
         throw new Unimplemented("No dispatch for opcode " + LirOpcodes.toString(opcode));
     }
diff --git a/src/main/java/com/android/tools/r8/lightir/LirPrinter.java b/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
index e01877a..c27b1ed 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
@@ -12,7 +12,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.graph.OriginalFieldWitness;
 import com.android.tools.r8.ir.code.CatchHandlers.CatchHandler;
 import com.android.tools.r8.ir.code.IfType;
 import com.android.tools.r8.ir.code.MemberType;
@@ -444,10 +443,4 @@
   public void onRecordFieldValues(DexField[] fields, List<EV> values) {
     appendValueArguments(values);
   }
-
-  @Override
-  public void onOriginalFieldWitness(OriginalFieldWitness witness, EV value) {
-    appendOutValue().append(witness);
-    appendValueArguments(value);
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/lightir/LirUseRegistryCallback.java b/src/main/java/com/android/tools/r8/lightir/LirUseRegistryCallback.java
index 7b8eeac..d97b0a9 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirUseRegistryCallback.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirUseRegistryCallback.java
@@ -13,7 +13,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.graph.OriginalFieldWitness;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.graph.UseRegistry.MethodHandleUse;
 import com.android.tools.r8.graph.bytecodemetadata.BytecodeInstructionMetadata;
@@ -236,9 +235,4 @@
   public void onRecordFieldValues(DexField[] fields, List<EV> values) {
     registry.registerRecordFieldValues(fields);
   }
-
-  @Override
-  public void onOriginalFieldWitness(OriginalFieldWitness witness, EV value) {
-    registry.registerOriginalFieldWitness(witness);
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphFieldNode.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphFieldNode.java
index 4fed1f1..c25ed35 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphFieldNode.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphFieldNode.java
@@ -3,9 +3,21 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.optimize.argumentpropagation.propagation;
 
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramField;
+import com.android.tools.r8.ir.analysis.type.DynamicType;
+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.AbstractValueFactory;
+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.NonEmptyValueState;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.ValueState;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.Action;
 
 public class FlowGraphFieldNode extends FlowGraphNode {
 
@@ -26,6 +38,42 @@
     return field.getType();
   }
 
+  void addDefaultValue(AppView<AppInfoWithLiveness> appView, Action onChangedAction) {
+    AbstractValueFactory abstractValueFactory = appView.abstractValueFactory();
+    AbstractValue defaultValue;
+    if (field.getAccessFlags().isStatic() && field.getDefinition().hasExplicitStaticValue()) {
+      defaultValue = field.getDefinition().getStaticValue().toAbstractValue(abstractValueFactory);
+    } else if (field.getType().isPrimitiveType()) {
+      defaultValue = abstractValueFactory.createZeroValue();
+    } else {
+      defaultValue = abstractValueFactory.createUncheckedNullValue();
+    }
+    NonEmptyValueState fieldStateToAdd;
+    if (field.getType().isArrayType()) {
+      Nullability defaultNullability = Nullability.definitelyNull();
+      fieldStateToAdd = ConcreteArrayTypeValueState.create(defaultNullability);
+    } else if (field.getType().isClassType()) {
+      assert defaultValue.isNull() || defaultValue.isSingleStringValue();
+      DynamicType dynamicType =
+          defaultValue.isNull()
+              ? DynamicType.definitelyNull()
+              : DynamicType.createExact(
+                  TypeElement.stringClassType(appView, Nullability.definitelyNotNull()));
+      fieldStateToAdd = ConcreteClassTypeValueState.create(defaultValue, dynamicType);
+    } else {
+      assert field.getType().isPrimitiveType();
+      fieldStateToAdd = ConcretePrimitiveTypeValueState.create(defaultValue);
+    }
+    if (fieldStateToAdd.isConcrete()) {
+      addState(appView, fieldStateToAdd.asConcrete(), onChangedAction);
+    } else {
+      // We should always be able to map static field values to an unknown abstract value.
+      assert false;
+      setStateToUnknown();
+      onChangedAction.execute();
+    }
+  }
+
   @Override
   ValueState getState() {
     return fieldState;
diff --git a/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java b/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
index 667479b..9e6fbf6 100644
--- a/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
@@ -19,7 +19,6 @@
 import com.android.tools.r8.graph.DexMethodHandle;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.OriginalFieldWitness;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.ir.code.Position;
@@ -106,12 +105,6 @@
   }
 
   @Override
-  public void registerOriginalFieldWitness(OriginalFieldWitness witness) {
-    super.registerOriginalFieldWitness(witness);
-    enqueuer.traceOriginalFieldWitness(witness);
-  }
-
-  @Override
   public void registerInitClass(DexType clazz) {
     super.registerInitClass(clazz);
     enqueuer.traceInitClass(clazz, getContext());
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 0b345b0..629d003 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -80,7 +80,6 @@
 import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
 import com.android.tools.r8.graph.NestMemberClassAttribute;
 import com.android.tools.r8.graph.ObjectAllocationInfoCollectionImpl;
-import com.android.tools.r8.graph.OriginalFieldWitness;
 import com.android.tools.r8.graph.PermittedSubclassAttribute;
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramDerivedContext;
@@ -1690,15 +1689,7 @@
     }
   }
 
-  void traceOriginalFieldWitness(OriginalFieldWitness witness) {
-    markEffectivelyLiveOriginalReference(witness);
-  }
-
-  private void markEffectivelyLiveOriginalReference(OriginalFieldWitness witness) {
-    witness.forEachReference(this::markEffectivelyLiveOriginalReference);
-  }
-
-  private void markEffectivelyLiveOriginalReference(DexReference reference) {
+  void markEffectivelyLiveOriginalReference(DexReference reference) {
     // TODO(b/325014359): It might be reasonable to reduce this map size by tracking which items
     //  actually are used in preconditions.
     if (effectivelyLiveOriginalReferences.add(reference) && reference.isDexMember()) {
@@ -3288,11 +3279,7 @@
     if (!options.testing.isKeepAnnotationsEnabled()) {
       return;
     }
-    if (field.getDefinition().hasOriginalFieldWitness()) {
-      markEffectivelyLiveOriginalReference(field.getDefinition().getOriginalFieldWitness());
-    } else {
-      markEffectivelyLiveOriginalReference(field.getReference());
-    }
+    markEffectivelyLiveOriginalReference(field.getReference());
   }
 
   private void markFieldAsLive(ProgramField field, ProgramMethod context) {
@@ -3864,7 +3851,7 @@
     if (mode.isInitialTreeShaking()) {
       applicableRules =
           KeepAnnotationMatcher.computeInitialRules(
-              appView, keepDeclarations, options.getThreadingModule(), executorService);
+              appInfo, keepDeclarations, options.getThreadingModule(), executorService);
       // Amend library methods with covariant return types.
       timing.begin("Model library");
       modelLibraryMethodsWithCovariantReturnTypes(appView);
diff --git a/src/main/java/com/android/tools/r8/shaking/rules/ApplicableRulesEvaluator.java b/src/main/java/com/android/tools/r8/shaking/rules/ApplicableRulesEvaluator.java
index ab1abbb..ea65365 100644
--- a/src/main/java/com/android/tools/r8/shaking/rules/ApplicableRulesEvaluator.java
+++ b/src/main/java/com/android/tools/r8/shaking/rules/ApplicableRulesEvaluator.java
@@ -4,9 +4,6 @@
 
 package com.android.tools.r8.shaking.rules;
 
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.shaking.Enqueuer;
 import com.android.tools.r8.shaking.MinimumKeepInfoCollection;
 import java.util.ArrayList;
@@ -68,22 +65,11 @@
       rules.add(rule);
     }
 
-    public ApplicableRulesEvaluator build(AppView<? extends AppInfoWithClassHierarchy> appView) {
+    public ApplicableRulesEvaluator build() {
       if (rootConsequences.isEmpty() && rules.isEmpty()) {
         return ApplicableRulesEvaluator.empty();
       }
-      return new ApplicableRulesEvaluatorImpl<>(
-          rootConsequences,
-          new ArrayList<>(rules),
-          (rule, enqueuer) -> {
-            // When evaluating the initial rules, if a satisfied rule has a field precondition,
-            // mark it to maintain its original field witness.
-            for (ProgramDefinition precondition : rule.getSatisfiedPreconditions()) {
-              if (precondition.isProgramField()) {
-                precondition.asProgramField().recordOriginalFieldWitness(appView);
-              }
-            }
-          });
+      return new ApplicableRulesEvaluatorImpl<>(rootConsequences, new ArrayList<>(rules));
     }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/shaking/rules/ApplicableRulesEvaluatorImpl.java b/src/main/java/com/android/tools/r8/shaking/rules/ApplicableRulesEvaluatorImpl.java
index d8b3d66..5e65713 100644
--- a/src/main/java/com/android/tools/r8/shaking/rules/ApplicableRulesEvaluatorImpl.java
+++ b/src/main/java/com/android/tools/r8/shaking/rules/ApplicableRulesEvaluatorImpl.java
@@ -11,10 +11,8 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
-import java.util.function.BiConsumer;
 
-public class ApplicableRulesEvaluatorImpl<T, R extends PendingConditionalRuleBase<T>>
-    extends ApplicableRulesEvaluator {
+public class ApplicableRulesEvaluatorImpl<T> extends ApplicableRulesEvaluator {
 
   private final MinimumKeepInfoCollection rootConsequences;
 
@@ -22,25 +20,16 @@
   private static final int reallocMinThreshold = 1;
   private static final int reallocRatioThreshold = 10;
   private int prunedCount = 0;
-  private List<R> pendingConditionalRules;
+  private List<PendingConditionalRuleBase<T>> pendingConditionalRules;
 
   private final List<MaterializedConditionalRule> materializedRules = new ArrayList<>();
 
-  private BiConsumer<R, Enqueuer> onSatisfiedRuleCallback;
-
-  ApplicableRulesEvaluatorImpl(
-      MinimumKeepInfoCollection rootConsequences, List<R> conditionalRules) {
-    this(rootConsequences, conditionalRules, (unusedRule, unusedEnqueuer) -> {});
-  }
-
   ApplicableRulesEvaluatorImpl(
       MinimumKeepInfoCollection rootConsequences,
-      List<R> conditionalRules,
-      BiConsumer<R, Enqueuer> onSatisfiedRuleCallback) {
+      List<PendingConditionalRuleBase<T>> conditionalRules) {
     assert !rootConsequences.isEmpty() || !conditionalRules.isEmpty();
     this.rootConsequences = rootConsequences;
     this.pendingConditionalRules = conditionalRules;
-    this.onSatisfiedRuleCallback = onSatisfiedRuleCallback;
   }
 
   @Override
@@ -59,13 +48,12 @@
     // TODO(b/323816623): If we tracked newly live, we could speed up finding rules.
     // TODO(b/323816623): Parallelize this.
     for (int i = 0; i < pendingConditionalRules.size(); i++) {
-      R rule = pendingConditionalRules.get(i);
+      PendingConditionalRuleBase<T> rule = pendingConditionalRules.get(i);
       if (rule != null && rule.isSatisfiedAfterUpdate(enqueuer)) {
         ++prunedCount;
         pendingConditionalRules.set(i, null);
         enqueuer.includeMinimumKeepInfo(rule.getConsequences());
         materializedRules.add(rule.asMaterialized());
-        onSatisfiedRuleCallback.accept(rule, enqueuer);
       }
     }
 
@@ -80,8 +68,8 @@
         Math.max(reallocMinThreshold, pendingConditionalRules.size() / reallocRatioThreshold);
     if (prunedCount >= threshold) {
       int newSize = pendingConditionalRules.size() - prunedCount;
-      List<R> newPending = new ArrayList<>(newSize);
-      for (R rule : pendingConditionalRules) {
+      List<PendingConditionalRuleBase<T>> newPending = new ArrayList<>(newSize);
+      for (PendingConditionalRuleBase<T> rule : pendingConditionalRules) {
         if (rule != null) {
           assert rule.isOutstanding();
           newPending.add(rule);
diff --git a/src/main/java/com/android/tools/r8/shaking/rules/KeepAnnotationMatcher.java b/src/main/java/com/android/tools/r8/shaking/rules/KeepAnnotationMatcher.java
index 6a74308..82c28fb 100644
--- a/src/main/java/com/android/tools/r8/shaking/rules/KeepAnnotationMatcher.java
+++ b/src/main/java/com/android/tools/r8/shaking/rules/KeepAnnotationMatcher.java
@@ -6,7 +6,6 @@
 
 import com.android.tools.r8.errors.Unimplemented;
 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.DexType;
 import com.android.tools.r8.graph.ProgramDefinition;
@@ -57,20 +56,20 @@
 public class KeepAnnotationMatcher {
 
   public static ApplicableRulesEvaluator computeInitialRules(
-      AppView<? extends AppInfoWithClassHierarchy> appView,
+      AppInfoWithClassHierarchy appInfo,
       List<KeepDeclaration> keepDeclarations,
       ThreadingModule threadingModule,
       ExecutorService executorService)
       throws ExecutionException {
     KeepAnnotationMatcherPredicates predicates =
-        new KeepAnnotationMatcherPredicates(appView.dexItemFactory());
+        new KeepAnnotationMatcherPredicates(appInfo.dexItemFactory());
     ApplicableRulesEvaluator.Builder builder = ApplicableRulesEvaluator.initialRulesBuilder();
     ThreadUtils.processItems(
         keepDeclarations,
-        declaration -> processDeclaration(declaration, appView.appInfo(), predicates, builder),
+        declaration -> processDeclaration(declaration, appInfo, predicates, builder),
         threadingModule,
         executorService);
-    return builder.build(appView);
+    return builder.build();
   }
 
   private static void processDeclaration(
@@ -108,6 +107,19 @@
               minimumKeepInfoCollection.getOrCreateMinimumKeepInfoFor(item.getReference());
           updateWithConstraints(item, joiner, result.constraints.get(i), result.edge);
         });
+    // TODO(b/323816623): Encode originals instead of soft-pinning class/field preconditions.
+    for (ProgramDefinition precondition : result.preconditions) {
+      if (precondition.isClass() || precondition.isField()) {
+        minimumKeepInfoCollection
+            .getOrCreateMinimumKeepInfoFor(precondition.getReference())
+            .disallowOptimization();
+        if (precondition.isField()) {
+          minimumKeepInfoCollection
+              .getOrCreateMinimumKeepInfoFor(precondition.getContextType())
+              .disallowOptimization();
+        }
+      }
+    }
     return minimumKeepInfoCollection;
   }
 
diff --git a/src/main/java/com/android/tools/r8/shaking/rules/PendingConditionalRule.java b/src/main/java/com/android/tools/r8/shaking/rules/PendingConditionalRule.java
index 952fd50..22d06ed 100644
--- a/src/main/java/com/android/tools/r8/shaking/rules/PendingConditionalRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/rules/PendingConditionalRule.java
@@ -16,8 +16,8 @@
   }
 
   @Override
-  List<DexReference> getReferences(List<DexReference> items) {
-    return items;
+  DexReference getReference(DexReference item) {
+    return item;
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/shaking/rules/PendingConditionalRuleBase.java b/src/main/java/com/android/tools/r8/shaking/rules/PendingConditionalRuleBase.java
index 8ca2654..5716e74 100644
--- a/src/main/java/com/android/tools/r8/shaking/rules/PendingConditionalRuleBase.java
+++ b/src/main/java/com/android/tools/r8/shaking/rules/PendingConditionalRuleBase.java
@@ -8,14 +8,12 @@
 import com.android.tools.r8.shaking.Enqueuer;
 import com.android.tools.r8.shaking.MinimumKeepInfoCollection;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
 
 public abstract class PendingConditionalRuleBase<T> {
 
-  private List<T> outstandingPreconditions;
-  private final List<T> satisfiedPreconditions;
+  private final List<T> outstandingPreconditions;
+  private final List<DexReference> satisfiedPreconditions;
   private final MinimumKeepInfoCollection consequences;
 
   PendingConditionalRuleBase(List<T> preconditions, MinimumKeepInfoCollection consequences) {
@@ -24,11 +22,7 @@
     this.consequences = consequences;
   }
 
-  public List<T> getSatisfiedPreconditions() {
-    return satisfiedPreconditions;
-  }
-
-  abstract List<DexReference> getReferences(List<T> items);
+  abstract DexReference getReference(T item);
 
   abstract boolean isSatisfied(T item, Enqueuer enqueuer);
 
@@ -38,7 +32,7 @@
 
   MaterializedConditionalRule asMaterialized() {
     assert !isOutstanding();
-    return new MaterializedConditionalRule(getReferences(satisfiedPreconditions), consequences);
+    return new MaterializedConditionalRule(satisfiedPreconditions, consequences);
   }
 
   final boolean isOutstanding() {
@@ -51,7 +45,7 @@
     for (T precondition : outstandingPreconditions) {
       if (isSatisfied(precondition, enqueuer)) {
         ++newlySatisfied;
-        satisfiedPreconditions.add(precondition);
+        satisfiedPreconditions.add(getReference(precondition));
       }
     }
     // Not satisfied and nothing changed.
@@ -60,26 +54,13 @@
     }
     // The rule is satisfied in full.
     if (newlySatisfied == outstandingPreconditions.size()) {
-      outstandingPreconditions = Collections.emptyList();
+      outstandingPreconditions.clear();
       return true;
     }
     // Partially satisfied.
     // This is expected to be the uncommon case so the update to outstanding is delayed to here.
-    int newOutstandingSize = outstandingPreconditions.size() - newlySatisfied;
-    assert newOutstandingSize > 0;
-    List<DexReference> satisfied = getReferences(satisfiedPreconditions);
-    List<DexReference> outstanding = getReferences(outstandingPreconditions);
-    List<T> newOutstanding = new ArrayList<>();
-    Iterator<T> it = outstandingPreconditions.iterator();
-    for (DexReference reference : outstanding) {
-      T precondition = it.next();
-      if (!satisfied.contains(reference)) {
-        newOutstanding.add(precondition);
-      }
-    }
-    assert !it.hasNext();
-    assert newOutstanding.size() == newOutstandingSize;
-    outstandingPreconditions = newOutstanding;
+    outstandingPreconditions.removeIf(
+        outstanding -> satisfiedPreconditions.contains(getReference(outstanding)));
     assert isOutstanding();
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/shaking/rules/PendingInitialConditionalRule.java b/src/main/java/com/android/tools/r8/shaking/rules/PendingInitialConditionalRule.java
index 8e916c9..8983f20 100644
--- a/src/main/java/com/android/tools/r8/shaking/rules/PendingInitialConditionalRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/rules/PendingInitialConditionalRule.java
@@ -8,7 +8,6 @@
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.shaking.Enqueuer;
 import com.android.tools.r8.shaking.MinimumKeepInfoCollection;
-import com.android.tools.r8.utils.ListUtils;
 import java.util.List;
 
 public class PendingInitialConditionalRule extends PendingConditionalRuleBase<ProgramDefinition> {
@@ -20,8 +19,8 @@
   }
 
   @Override
-  List<DexReference> getReferences(List<ProgramDefinition> items) {
-    return ListUtils.map(items, ProgramDefinition::getReference);
+  DexReference getReference(ProgramDefinition item) {
+    return item.getReference();
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionFieldAnnotationTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionFieldAnnotationTest.java
index c68a01d..15f96ab 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionFieldAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepUsesReflectionFieldAnnotationTest.java
@@ -49,15 +49,8 @@
   }
 
   private void checkOutput(CodeInspector inspector) {
-    if (parameters.isNativeR8()) {
-      // A and its field are completely eliminated despite being a precondition.
-      assertThat(inspector.clazz(A.class), isAbsent());
-    } else {
-      // A and its field are soft-pinned in the rules-based extraction.
-      assertThat(inspector.clazz(A.class), isPresent());
-      assertThat(
-          inspector.clazz(A.class).uniqueFieldWithOriginalName("classNameForB"), isPresent());
-    }
+    assertThat(inspector.clazz(A.class), isPresent());
+    assertThat(inspector.clazz(A.class).uniqueFieldWithOriginalName("classNameForB"), isPresent());
     assertThat(inspector.clazz(B.class), isPresent());
     assertThat(inspector.clazz(B.class).init(), isPresent());
     assertThat(inspector.clazz(B.class).init("int"), isAbsent());