Only analyze BasicBlock instructions once in FieldValueAnalysis

Change-Id: Ife528e77988cc2f5d90c7ce2b94f6d3127ea1c8c
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java
index e9060a4..0f02442 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java
@@ -239,20 +239,24 @@
 
       if (!blockOrPredecessorMaybeReadAnyField) {
         // Finally, we update the read set with the fields that are read by the instructions in the
-        // current block.
-        for (Instruction instruction : block.getInstructions()) {
-          AbstractFieldSet instructionReadSet = instruction.readSet(appView, context);
-          if (instructionReadSet.isBottom()) {
-            continue;
+        // current block. This can be skipped if the block has already been processed.
+        if (seenBefore) {
+          assert verifyFieldSetContainsAllFieldReadsInBlock(knownReadSet, block, context);
+        } else {
+          for (Instruction instruction : block.getInstructions()) {
+            AbstractFieldSet instructionReadSet = instruction.readSet(appView, context);
+            if (instructionReadSet.isBottom()) {
+              continue;
+            }
+            if (instructionReadSet.isTop()) {
+              blockOrPredecessorMaybeReadAnyField = true;
+              break;
+            }
+            if (!knownReadSet.isConcreteFieldSet()) {
+              knownReadSet = new ConcreteMutableFieldSet();
+            }
+            knownReadSet.asConcreteFieldSet().addAll(instructionReadSet.asConcreteFieldSet());
           }
-          if (instructionReadSet.isTop()) {
-            blockOrPredecessorMaybeReadAnyField = true;
-            break;
-          }
-          if (!knownReadSet.isConcreteFieldSet()) {
-            knownReadSet = new ConcreteMutableFieldSet();
-          }
-          knownReadSet.asConcreteFieldSet().addAll(instructionReadSet.asConcreteFieldSet());
         }
       }
 
@@ -279,6 +283,21 @@
     return result;
   }
 
+  private boolean verifyFieldSetContainsAllFieldReadsInBlock(
+      KnownFieldSet readSet, BasicBlock block, DexType context) {
+    for (Instruction instruction : block.getInstructions()) {
+      AbstractFieldSet instructionReadSet = instruction.readSet(appView, context);
+      assert !instructionReadSet.isTop();
+      if (instructionReadSet.isBottom()) {
+        continue;
+      }
+      for (DexEncodedField field : instructionReadSet.asConcreteFieldSet().getFields()) {
+        assert readSet.contains(field);
+      }
+    }
+    return true;
+  }
+
   private void updateFieldOptimizationInfo(DexEncodedField field, Value value) {
     // Abstract value.
     Value root = value.getAliasedValue();
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/KnownFieldSet.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/KnownFieldSet.java
index b96918e..263101b 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/KnownFieldSet.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/KnownFieldSet.java
@@ -4,8 +4,12 @@
 
 package com.android.tools.r8.ir.analysis.fieldvalueanalysis;
 
+import com.android.tools.r8.graph.DexEncodedField;
+
 public interface KnownFieldSet {
 
+  boolean contains(DexEncodedField field);
+
   default boolean isConcreteFieldSet() {
     return false;
   }