Postpone enum unboxing candidate removal

This allows to deterministically choose the number of
methods where peephole optimizations are not applied in
IR processing round 1, and therefore make the compilation
deterministic again.

Bug: 191157574
Change-Id: I99222b00c54d7734a437be5432e05f839ecc6864
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 f68c904..3f52f3d 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
@@ -894,6 +894,9 @@
     if (appView.options().protoShrinking().enableRemoveProtoEnumSwitchMap()) {
       appView.protoShrinker().protoEnumSwitchMapRemover.updateVisibleStaticFieldValues();
     }
+    if (enumUnboxer != null) {
+      enumUnboxer.updateEnumUnboxingCandidatesInfo();
+    }
     assert delayedOptimizationFeedback.noUpdatesLeft();
     onWaveDoneActions.forEach(com.android.tools.r8.utils.Action::execute);
     onWaveDoneActions = null;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
index edd774e..e9b1e25 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
@@ -127,6 +127,7 @@
   // Map the enum candidates with their dependencies, i.e., the methods to reprocess for the given
   // enum if the optimization eventually decides to unbox it.
   private final EnumUnboxingCandidateInfoCollection enumUnboxingCandidatesInfo;
+  private final Set<DexProgramClass> candidatesToRemoveInWave = Sets.newConcurrentHashSet();
   private final Map<DexType, EnumStaticFieldValues> staticFieldValuesMap =
       new ConcurrentHashMap<>();
   private final ProgramMethodSet methodsDependingOnLibraryModelisation =
@@ -165,6 +166,13 @@
     return ordinal + 1;
   }
 
+  public void updateEnumUnboxingCandidatesInfo() {
+    for (DexProgramClass candidate : candidatesToRemoveInWave) {
+      enumUnboxingCandidatesInfo.removeCandidate(candidate);
+    }
+    candidatesToRemoveInWave.clear();
+  }
+
   /**
    * Returns true if {@param enumClass} was marked as being unboxable.
    *
@@ -175,7 +183,7 @@
     assert enumClass.isEnum();
     if (!reportFailure(enumClass, reason)) {
       // The failure was not reported, meaning debug logging is disabled.
-      enumUnboxingCandidatesInfo.removeCandidate(enumClass);
+      candidatesToRemoveInWave.add(enumClass);
       return true;
     }
     return false;
@@ -461,7 +469,9 @@
       ExecutorService executorService,
       OptimizationFeedbackDelayed feedback)
       throws ExecutionException {
+    assert candidatesToRemoveInWave.isEmpty();
     EnumDataMap enumDataMap = finishAnalysis();
+    assert candidatesToRemoveInWave.isEmpty();
     // At this point the enum unboxing candidates are no longer candidates, they will all be
     // unboxed. We extract the now immutable enums to unbox information and clear the candidate
     // info.
@@ -540,6 +550,7 @@
 
   public EnumDataMap finishAnalysis() {
     analyzeInitializers();
+    updateEnumUnboxingCandidatesInfo();
     EnumDataMap enumDataMap = analyzeEnumInstances();
     if (debugLogEnabled) {
       // Remove all enums that have been reported as being unboxable.