Include method-to-reprocess set in determinism checks
Bug: 227138351
Change-Id: I4b467ae737caacb859d364073d255a660a0f5967
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 0292a0d..d6ca793 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
@@ -106,6 +106,9 @@
constantFields.forEach(this::markFieldAsDead);
readFields.keySet().forEach(this::markFieldAsDead);
writtenFields.keySet().forEach(this::markWriteOnlyFieldAsDead);
+
+ // Ensure determinism of method-to-reprocess set.
+ appView.testing().checkDeterminism(postMethodProcessorBuilder::dump);
}
private void markWriteOnlyFieldAsDead(DexEncodedField field) {
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 82b58a8..acadf11 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
@@ -821,6 +821,9 @@
inliner.onLastWaveDone(postMethodProcessorBuilder, executorService, timing);
}
openClosedInterfacesAnalysis.onPrimaryOptimizationPassComplete();
+
+ // Ensure determinism of method-to-reprocess set.
+ appView.testing().checkDeterminism(postMethodProcessorBuilder::dump);
}
public void addWaveDoneAction(com.android.tools.r8.utils.Action action) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java b/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
index ecee91f..780f5d4 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PostMethodProcessor.java
@@ -20,11 +20,13 @@
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.DeterminismChecker;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.Timing.TimingMerger;
import com.android.tools.r8.utils.collections.LongLivedProgramMethodSetBuilder;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
+import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
@@ -142,6 +144,10 @@
new PartialCallGraphBuilder(appView, methodsToReprocess).build(executorService, timing);
return new PostMethodProcessor(appView, callGraph);
}
+
+ public void dump(DeterminismChecker determinismChecker) throws IOException {
+ determinismChecker.accept(methodsToReprocessBuilder::dump);
+ }
}
private Deque<ProgramMethodSet> createWaves(CallGraph callGraph) {
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 d926360..f455175 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
@@ -706,6 +706,9 @@
enumUnboxingLens,
enumDataMap,
utilityClasses);
+
+ // Ensure determinism of method-to-reprocess set.
+ appView.testing().checkDeterminism(postMethodProcessorBuilder::dump);
}
private void updateOptimizationInfos(
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
index b7dd7ff..00be161 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
@@ -195,6 +195,9 @@
.fixupApplication(affectedClasses, executorService, timing);
timing.end();
+
+ // Ensure determinism of method-to-reprocess set.
+ appView.testing().checkDeterminism(postMethodProcessorBuilder::dump);
}
/**
diff --git a/src/main/java/com/android/tools/r8/utils/DeterminismChecker.java b/src/main/java/com/android/tools/r8/utils/DeterminismChecker.java
index 4871186..2f95428 100644
--- a/src/main/java/com/android/tools/r8/utils/DeterminismChecker.java
+++ b/src/main/java/com/android/tools/r8/utils/DeterminismChecker.java
@@ -10,12 +10,13 @@
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.Closeable;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
@@ -44,12 +45,14 @@
return new LineCallbackChecker(Files.newBufferedReader(log, StandardCharsets.UTF_8));
} else {
System.out.println("Writing determinism log: " + log);
+ // Note that Files.newBufferedWriter will cause issues in presence of malformed input
+ // and unmappable character errors, since Files.newBufferedWriter uses the
+ // java.nio.charset.CharsetDecoder default action, which is to report such errors,
+ // instead of dealing with them in java.nio.charset.CharsetDecoder#onMalformedInput.
BufferedWriter bufferedWriter =
- Files.newBufferedWriter(
- log,
- StandardCharsets.UTF_8,
- StandardOpenOption.CREATE,
- StandardOpenOption.TRUNCATE_EXISTING);
+ new BufferedWriter(
+ new OutputStreamWriter(
+ new FileOutputStream(log.toFile()), StandardCharsets.UTF_8));
return new LineCallbackWriter(bufferedWriter);
}
}
@@ -82,6 +85,13 @@
return method.getReference().toSourceString();
}
+ public <E extends Exception> void accept(ThrowingConsumer<LineCallback, E> consumer)
+ throws E, IOException {
+ try (LineCallback callback = callbackFactory.createCallback()) {
+ consumer.accept(callback);
+ }
+ }
+
public void check(AppView<?> appView) {
try (LineCallback callback = callbackFactory.createCallback()) {
List<DexProgramClass> classes = new ArrayList<>(appView.appInfo().classes());
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 77a670b..133f721 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1696,24 +1696,37 @@
private boolean hasReadCheckDeterminism = false;
private DeterminismChecker determinismChecker = null;
- public void setDeterminismChecker(DeterminismChecker checker) {
- determinismChecker = checker;
- }
-
- public void checkDeterminism(AppView<?> appView) {
+ private DeterminismChecker getDeterminismChecker() {
// Lazily read the env-var so that it can be set after options init.
if (determinismChecker == null && !hasReadCheckDeterminism) {
hasReadCheckDeterminism = true;
String dir = System.getProperty("com.android.tools.r8.checkdeterminism");
if (dir != null) {
- determinismChecker = DeterminismChecker.createWithFileBacking(Paths.get(dir));
+ setDeterminismChecker(DeterminismChecker.createWithFileBacking(Paths.get(dir)));
}
}
+ return determinismChecker;
+ }
+
+ public void setDeterminismChecker(DeterminismChecker checker) {
+ determinismChecker = checker;
+ }
+
+ public void checkDeterminism(AppView<?> appView) {
+ DeterminismChecker determinismChecker = getDeterminismChecker();
if (determinismChecker != null) {
determinismChecker.check(appView);
}
}
+ public <E extends Exception> void checkDeterminism(
+ ThrowingConsumer<DeterminismChecker, E> consumer) {
+ DeterminismChecker determinismChecker = getDeterminismChecker();
+ if (determinismChecker != null) {
+ consumer.acceptWithRuntimeException(determinismChecker);
+ }
+ }
+
public static void allowExperimentClassFileVersion(InternalOptions options) {
options.reportedExperimentClassFileVersion.set(true);
}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java b/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java
index ce4399b..735146a 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/LongLivedProgramMethodSetBuilder.java
@@ -13,7 +13,11 @@
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.DeterminismChecker.LineCallback;
import com.android.tools.r8.utils.SetUtils;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Set;
import java.util.function.IntFunction;
import java.util.function.Predicate;
@@ -184,4 +188,12 @@
!= null;
return true;
}
+
+ public void dump(LineCallback lineCallback) throws IOException {
+ List<DexMethod> sortedMethods = new ArrayList<>(methods);
+ sortedMethods.sort(DexMethod::compareTo);
+ for (DexMethod method : sortedMethods) {
+ lineCallback.onLine(method.toSourceString());
+ }
+ }
}