Add inspection of D8 and R8 input and output for R8 partial compilation
Bug: b/309743298
Change-Id: I6eb8b64d990c429892f0529c57d059a242cefa3b
diff --git a/src/main/java/com/android/tools/r8/R8Partial.java b/src/main/java/com/android/tools/r8/R8Partial.java
index e9cb9b8..ff1d8a6 100644
--- a/src/main/java/com/android/tools/r8/R8Partial.java
+++ b/src/main/java/com/android/tools/r8/R8Partial.java
@@ -21,9 +21,12 @@
import com.android.tools.r8.tracereferences.TraceReferencesKeepRules;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.AndroidAppConsumers;
import com.android.tools.r8.utils.DumpInputFlags;
+import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.ZipUtils;
import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
@@ -34,15 +37,38 @@
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
+import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
class R8Partial {
private final InternalOptions options;
+ private final Consumer<AndroidApp> r8InputApp;
+ private final Consumer<AndroidApp> d8InputApp;
+ private final Consumer<AndroidApp> r8OutputApp;
+ private final Consumer<AndroidApp> d8OutputApp;
R8Partial(InternalOptions options) {
this.options = options;
+ this.r8InputApp = options.r8PartialCompilationOptions.r8InputApp;
+ this.d8InputApp = options.r8PartialCompilationOptions.d8InputApp;
+ this.r8OutputApp = options.r8PartialCompilationOptions.r8OutputApp;
+ this.d8OutputApp = options.r8PartialCompilationOptions.d8OutputApp;
+ }
+
+ static void runForTesting(AndroidApp app, InternalOptions options)
+ throws CompilationFailedException {
+ ExecutorService executor = ThreadUtils.getExecutorService(options);
+ ExceptionUtils.withR8CompilationHandler(
+ options.reporter,
+ () -> {
+ try {
+ new R8Partial(options).runInternal(app, executor);
+ } finally {
+ executor.shutdown();
+ }
+ });
}
void runInternal(AndroidApp app, ExecutorService executor) throws IOException, ResourceException {
@@ -151,13 +177,23 @@
d8Builder.addDesugaredLibraryConfiguration(
Files.readString(dump.getDesugaredLibraryFile(), UTF_8));
}
+ AndroidAppConsumers d8OutputAppSink = null;
+ if (d8OutputApp != null) {
+ d8OutputAppSink = new AndroidAppConsumers(d8Builder);
+ }
d8Builder.validate();
D8Command d8command = d8Builder.makeCommand();
AndroidApp d8App = d8command.getInputApp();
+ if (d8InputApp != null) {
+ d8InputApp.accept(d8App);
+ }
InternalOptions d8Options = d8command.getInternalOptions();
assert d8Options.getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N)
: "Default interface methods not yet supported";
D8.runInternal(d8App, d8Options, executor);
+ if (d8OutputApp != null) {
+ d8OutputApp.accept(d8OutputAppSink.build());
+ }
// Run trace references to produce keep rules for the D8 compiled part.
// TODO(b/309743298): Do not emit keep rules into a file.
@@ -192,12 +228,23 @@
r8Builder.addDesugaredLibraryConfiguration(
Files.readString(dump.getDesugaredLibraryFile(), UTF_8));
}
+ AndroidAppConsumers r8OutputAppSink = null;
+ if (r8Builder != null) {
+ r8OutputAppSink = new AndroidAppConsumers(r8Builder);
+ }
+ r8Builder.validate();
R8Command r8Command = r8Builder.makeCommand();
AndroidApp r8App = r8Command.getInputApp();
+ if (r8InputApp != null) {
+ r8InputApp.accept(r8App);
+ }
InternalOptions r8Options = r8Command.getInternalOptions();
r8Options.mapConsumer = originalMapConsumer;
r8Options.quiet = true; // Don't write the R8 version.
R8.runInternal(r8App, r8Options, executor);
+ if (r8OutputApp != null) {
+ r8OutputApp.accept(r8OutputAppSink.build());
+ }
// Emit resources and merged DEX to the output consumer.
// TODO(b/309743298): Consider passing the DataResourceConsumer to the R8 invocation above.
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 7d9439b..7b907e9 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -2286,6 +2286,10 @@
public boolean enabled;
public Path tempDir = null;
public Predicate<String> isR8 = null;
+ public Consumer<AndroidApp> r8InputApp;
+ public Consumer<AndroidApp> d8InputApp;
+ public Consumer<AndroidApp> r8OutputApp;
+ public Consumer<AndroidApp> d8OutputApp;
R8PartialCompilationOptions(String partialR8) {
this.enabled = partialR8 != null;
diff --git a/src/test/java/com/android/tools/r8/partial/PartialCompilationBasicTest.java b/src/test/java/com/android/tools/r8/partial/PartialCompilationBasicTest.java
index 662aa21..4783aaa 100644
--- a/src/test/java/com/android/tools/r8/partial/PartialCompilationBasicTest.java
+++ b/src/test/java/com/android/tools/r8/partial/PartialCompilationBasicTest.java
@@ -41,6 +41,34 @@
.addKeepMainRule(Main.class)
.setR8PartialConfiguration(builder -> builder.includeAll().excludeClasses(A.class).build())
.compile()
+ .inspectR8Input(
+ inspector -> {
+ // TODO(b/309743298): These are all present as inspection currently also look at
+ // classpath.
+ assertThat(inspector.clazz(A.class), isPresent());
+ assertThat(inspector.clazz(B.class), isPresent());
+ assertThat(inspector.clazz(Main.class), isPresent());
+ })
+ .inspectD8Input(
+ // TODO(b/309743298): These are all present as inspection currently also look at
+ // classpath.
+ inspector -> {
+ assertThat(inspector.clazz(A.class), isPresent());
+ assertThat(inspector.clazz(B.class), isPresent());
+ assertThat(inspector.clazz(Main.class), isPresent());
+ })
+ .inspectR8Output(
+ inspector -> {
+ assertThat(inspector.clazz(A.class), isAbsent());
+ assertThat(inspector.clazz(B.class), isAbsent());
+ assertThat(inspector.clazz(Main.class), isPresent());
+ })
+ .inspectD8Output(
+ inspector -> {
+ assertThat(inspector.clazz(A.class), isPresent());
+ assertThat(inspector.clazz(B.class), isAbsent());
+ assertThat(inspector.clazz(Main.class), isAbsent());
+ })
.inspect(
inspector -> {
assertThat(inspector.clazz(A.class), isPresent());
@@ -58,6 +86,34 @@
.addKeepMainRule(Main.class)
.setR8PartialConfiguration(builder -> builder.includeAll().excludeClasses(B.class).build())
.compile()
+ .inspectR8Input(
+ inspector -> {
+ // TODO(b/309743298): These are all present as inspection currently also look at
+ // classpath.
+ assertThat(inspector.clazz(A.class), isPresent());
+ assertThat(inspector.clazz(B.class), isPresent());
+ assertThat(inspector.clazz(Main.class), isPresent());
+ })
+ .inspectD8Input(
+ inspector -> {
+ // TODO(b/309743298): These are all present as inspection currently also look at
+ // classpath.
+ assertThat(inspector.clazz(A.class), isPresent());
+ assertThat(inspector.clazz(B.class), isPresent());
+ assertThat(inspector.clazz(Main.class), isPresent());
+ })
+ .inspectR8Output(
+ inspector -> {
+ assertThat(inspector.clazz(A.class), isAbsent());
+ assertThat(inspector.clazz(B.class), isAbsent());
+ assertThat(inspector.clazz(Main.class), isPresent());
+ })
+ .inspectD8Output(
+ inspector -> {
+ assertThat(inspector.clazz(A.class), isAbsent());
+ assertThat(inspector.clazz(B.class), isPresent());
+ assertThat(inspector.clazz(Main.class), isAbsent());
+ })
.inspect(
inspector -> {
assertThat(inspector.clazz(A.class), isAbsent());
diff --git a/src/test/testbase/java/com/android/tools/r8/R8PartialTestBuilder.java b/src/test/testbase/java/com/android/tools/r8/R8PartialTestBuilder.java
index 319b633..9ea93eb 100644
--- a/src/test/testbase/java/com/android/tools/r8/R8PartialTestBuilder.java
+++ b/src/test/testbase/java/com/android/tools/r8/R8PartialTestBuilder.java
@@ -165,12 +165,20 @@
Box<List<ProguardConfigurationRule>> syntheticProguardRulesConsumer,
StringBuilder proguardMapBuilder)
throws CompilationFailedException {
+ Box<AndroidApp> r8InputApp = new Box<>();
+ Box<AndroidApp> d8InputApp = new Box<>();
+ Box<AndroidApp> r8OutputApp = new Box<>();
+ Box<AndroidApp> d8OutputApp = new Box<>();
Consumer<InternalOptions> configureR8PartialCompilation =
options -> {
options.r8PartialCompilationOptions.enabled = true;
options.r8PartialCompilationOptions.isR8 = r8PartialConfiguration;
+ options.r8PartialCompilationOptions.r8InputApp = r8InputApp::set;
+ options.r8PartialCompilationOptions.d8InputApp = d8InputApp::set;
+ options.r8PartialCompilationOptions.r8OutputApp = r8OutputApp::set;
+ options.r8PartialCompilationOptions.d8OutputApp = d8OutputApp::set;
};
- ToolHelper.runAndBenchmarkR8WithoutResult(
+ ToolHelper.runAndBenchmarkR8PartialWithoutResult(
builder, configureR8PartialCompilation.andThen(optionsConsumer), benchmarkResults);
return new R8PartialTestCompileResult(
getState(),
@@ -186,6 +194,10 @@
residualArtProfiles,
resourceShrinkerOutput,
resourceShrinkerOutputForFeatures,
- buildMetadata != null ? buildMetadata.get() : null);
+ buildMetadata != null ? buildMetadata.get() : null,
+ r8InputApp.get(),
+ d8InputApp.get(),
+ r8OutputApp.get(),
+ d8OutputApp.get());
}
}
diff --git a/src/test/testbase/java/com/android/tools/r8/R8PartialTestCompileResult.java b/src/test/testbase/java/com/android/tools/r8/R8PartialTestCompileResult.java
index 18f75fb..8bdc393 100644
--- a/src/test/testbase/java/com/android/tools/r8/R8PartialTestCompileResult.java
+++ b/src/test/testbase/java/com/android/tools/r8/R8PartialTestCompileResult.java
@@ -8,13 +8,23 @@
import com.android.tools.r8.shaking.CollectingGraphConsumer;
import com.android.tools.r8.shaking.ProguardConfigurationRule;
import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.ThrowingConsumer;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.io.IOException;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
+import java.util.function.Consumer;
public class R8PartialTestCompileResult
extends R8TestCompileResultBase<R8PartialTestCompileResult> {
+ private final AndroidApp r8InputApp;
+ private final AndroidApp d8InputApp;
+ private final AndroidApp r8OutputApp;
+ private final AndroidApp d8OutputApp;
+
R8PartialTestCompileResult(
TestState state,
OutputMode outputMode,
@@ -29,7 +39,11 @@
List<ExternalArtProfile> residualArtProfiles,
Path resourceShrinkerOutput,
HashMap<String, Path> resourceShrinkerOutputForFeatures,
- R8BuildMetadata buildMetadata) {
+ R8BuildMetadata buildMetadata,
+ AndroidApp r8InputApp,
+ AndroidApp d8InputApp,
+ AndroidApp r8OutputApp,
+ AndroidApp d8OutputApp) {
super(
state,
outputMode,
@@ -45,10 +59,74 @@
resourceShrinkerOutput,
resourceShrinkerOutputForFeatures,
buildMetadata);
+ this.r8InputApp = r8InputApp;
+ this.d8InputApp = d8InputApp;
+ this.r8OutputApp = r8OutputApp;
+ this.d8OutputApp = d8OutputApp;
}
@Override
public R8PartialTestCompileResult self() {
return this;
}
+
+ public CodeInspector inspectorR8Input() throws IOException {
+ return new CodeInspector(r8InputApp);
+ }
+
+ public CodeInspector inspectorR8Input(Consumer<InternalOptions> debugOptionsConsumer)
+ throws IOException {
+ return new CodeInspector(r8InputApp, debugOptionsConsumer);
+ }
+
+ public <E extends Throwable> R8PartialTestCompileResult inspectR8Input(
+ ThrowingConsumer<CodeInspector, E> consumer) throws IOException, E {
+ consumer.accept(inspectorR8Input());
+ return self();
+ }
+
+ public CodeInspector inspectorD8Input() throws IOException {
+ return new CodeInspector(d8InputApp);
+ }
+
+ public CodeInspector inspectorD8Input(Consumer<InternalOptions> debugOptionsConsumer)
+ throws IOException {
+ return new CodeInspector(d8InputApp, debugOptionsConsumer);
+ }
+
+ public <E extends Throwable> R8PartialTestCompileResult inspectD8Input(
+ ThrowingConsumer<CodeInspector, E> consumer) throws IOException, E {
+ consumer.accept(inspectorR8Input());
+ return self();
+ }
+
+ public CodeInspector inspectorR8Output() throws IOException {
+ return new CodeInspector(r8OutputApp);
+ }
+
+ public CodeInspector inspectorR8Output(Consumer<InternalOptions> debugOptionsConsumer)
+ throws IOException {
+ return new CodeInspector(r8OutputApp, debugOptionsConsumer);
+ }
+
+ public <E extends Throwable> R8PartialTestCompileResult inspectR8Output(
+ ThrowingConsumer<CodeInspector, E> consumer) throws IOException, E {
+ consumer.accept(inspectorR8Output());
+ return self();
+ }
+
+ public CodeInspector inspectorD8Output() throws IOException {
+ return new CodeInspector(d8OutputApp);
+ }
+
+ public CodeInspector inspectorD8Output(Consumer<InternalOptions> debugOptionsConsumer)
+ throws IOException {
+ return new CodeInspector(d8OutputApp, debugOptionsConsumer);
+ }
+
+ public <E extends Throwable> R8PartialTestCompileResult inspectD8Output(
+ ThrowingConsumer<CodeInspector, E> consumer) throws IOException, E {
+ consumer.accept(inspectorD8Output());
+ return self();
+ }
}
diff --git a/src/test/testbase/java/com/android/tools/r8/ToolHelper.java b/src/test/testbase/java/com/android/tools/r8/ToolHelper.java
index 1a8a049..0608acb 100644
--- a/src/test/testbase/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/testbase/java/com/android/tools/r8/ToolHelper.java
@@ -1807,6 +1807,28 @@
}
}
+ public static void runAndBenchmarkR8PartialWithoutResult(
+ R8Command.Builder commandBuilder,
+ Consumer<InternalOptions> optionsConsumer,
+ BenchmarkResults benchmarkResults)
+ throws CompilationFailedException {
+ long start = 0;
+ if (benchmarkResults != null) {
+ start = System.nanoTime();
+ }
+ R8Command command = commandBuilder.build();
+ InternalOptions internalOptions = command.getInternalOptions();
+ optionsConsumer.accept(internalOptions);
+ try {
+ R8Partial.runForTesting(command.getInputApp(), internalOptions);
+ } finally {
+ if (benchmarkResults != null) {
+ long end = System.nanoTime();
+ benchmarkResults.addRuntimeResult(end - start);
+ }
+ }
+ }
+
public static AndroidApp runR8WithFullResult(
R8Command command, Consumer<InternalOptions> optionsConsumer)
throws CompilationFailedException {