Refactor R8 partial phases into separate methods

Change-Id: I6019728a61a0f046535e959acfc8d60bb78823dc
diff --git a/src/main/java/com/android/tools/r8/R8Partial.java b/src/main/java/com/android/tools/r8/R8Partial.java
index ebca5fa..985b03a 100644
--- a/src/main/java/com/android/tools/r8/R8Partial.java
+++ b/src/main/java/com/android/tools/r8/R8Partial.java
@@ -4,19 +4,22 @@
 package com.android.tools.r8;
 
 import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
-import static java.nio.charset.StandardCharsets.UTF_8;
 
 import com.android.tools.r8.DexIndexedConsumer.ArchiveConsumer;
 import com.android.tools.r8.DexIndexedConsumer.ForwardingConsumer;
 import com.android.tools.r8.StringConsumer.FileConsumer;
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.dump.CompilerDump;
-import com.android.tools.r8.dump.DumpOptions;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.naming.MapConsumer;
+import com.android.tools.r8.partial.R8PartialD8DexResult;
+import com.android.tools.r8.partial.R8PartialDataResourceConsumer;
+import com.android.tools.r8.partial.R8PartialInput;
+import com.android.tools.r8.partial.R8PartialInputToDumpFlags;
+import com.android.tools.r8.partial.R8PartialR8Result;
+import com.android.tools.r8.partial.R8PartialTraceReferencesResult;
 import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy;
 import com.android.tools.r8.tracereferences.TraceReferencesBridge;
 import com.android.tools.r8.tracereferences.TraceReferencesCommand;
@@ -24,7 +27,6 @@
 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.InternalOptions;
 import com.android.tools.r8.utils.ThreadUtils;
@@ -33,11 +35,8 @@
 import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
 import com.google.common.io.ByteStreams;
 import java.io.IOException;
-import java.nio.file.Files;
 import java.nio.file.Path;
-import java.util.ArrayList;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
 import java.util.function.Consumer;
@@ -75,46 +74,32 @@
 
   void runInternal(AndroidApp app, ExecutorService executor) throws IOException, ResourceException {
     Timing timing = Timing.create("R8 partial " + Version.LABEL, options);
-
-    ProgramConsumer originalProgramConsumer = options.programConsumer;
-    DataResourceConsumer originalDataResourceConsumer = options.dataResourceConsumer;
-    MapConsumer originalMapConsumer = options.mapConsumer;
-    if (!(originalProgramConsumer instanceof DexIndexedConsumer)) {
+    if (!(options.programConsumer instanceof DexIndexedConsumer)) {
       throw options.reporter.fatalError(
           "Partial shrinking does not support generating class files");
     }
 
-    Path tmp = options.partialCompilationConfiguration.getTempDir();
-    Path dumpFile = options.partialCompilationConfiguration.getDumpFile();
+    R8PartialInput input = runProcessInputStep(app, timing);
+    R8PartialD8DexResult d8DexResult = runD8DexStep(input, executor);
+    R8PartialTraceReferencesResult traceReferencesResult = runTraceReferencesStep(input);
+    R8PartialR8Result r8Result = runR8PartialStep(input, traceReferencesResult, executor);
+    runD8MergeStep(input, d8DexResult, r8Result, executor);
 
+    // Feed the data resource output by R8 to the output consumer. Keeping this at the end after the
+    // merge keeps the order of calls to the output consumer closer to full R8.
+    r8Result.supplyConsumers(options);
+    timing.end();
+  }
+
+  private R8PartialInput runProcessInputStep(AndroidApp androidApp, Timing timing)
+      throws IOException {
     // Create a dump of the compiler input.
     // TODO(b/309743298): Do not use compiler dump to handle splitting the compilation. This should
-    // be all in memory.
-    ApplicationReader applicationReader = new ApplicationReader(app, options, timing);
-    applicationReader.dump(
-        new DumpInputFlags() {
-
-          @Override
-          public Path getDumpPath() {
-            return dumpFile;
-          }
-
-          @Override
-          public boolean shouldDump(DumpOptions options) {
-            return true;
-          }
-
-          @Override
-          public boolean shouldFailCompilation() {
-            return false;
-          }
-
-          @Override
-          public boolean shouldLogDumpInfoMessage() {
-            return false;
-          }
-        });
-    CompilerDump dump = CompilerDump.fromArchive(dumpFile, tmp);
+    //  be all in memory.
+    ApplicationReader applicationReader = new ApplicationReader(androidApp, options, timing);
+    Path dumpFile = resolveTmp("dump.zip");
+    applicationReader.dump(new R8PartialInputToDumpFlags(dumpFile));
+    CompilerDump dump = CompilerDump.fromArchive(dumpFile);
     if (dump.getBuildProperties().hasMainDexKeepRules()
         || dump.getBuildProperties().hasArtProfileProviders()
         || dump.getBuildProperties().hasStartupProfileProviders()) {
@@ -122,41 +107,35 @@
           "Partial shrinking does not support legacy multi-dex, baseline or startup profiles");
     }
 
-    DexApplication dapp = applicationReader.read().toDirect();
+    DexApplication app = applicationReader.read().toDirect();
     AppInfoWithClassHierarchy appInfo =
         AppInfoWithClassHierarchy.createForDesugaring(
-            AppInfo.createInitialAppInfo(dapp, GlobalSyntheticsStrategy.forNonSynthesizing()));
+            AppInfo.createInitialAppInfo(app, GlobalSyntheticsStrategy.forNonSynthesizing()));
 
     Set<DexProgramClass> d8classes = new HashSet<>();
-    appInfo
-        .classes()
-        .forEach(
-            clazz -> {
-              if (!d8classes.contains(clazz)
-                  && !options.partialCompilationConfiguration.test(
-                      clazz.getType().getDescriptor())) {
-                d8classes.add(clazz);
-                // TODO(b/309743298): Improve this to only visit each class once and stop at
-                //  library boundary.
-                appInfo.forEachSuperType(
-                    clazz,
-                    (superType, subclass, ignored) -> {
-                      DexProgramClass superClass =
-                          asProgramClassOrNull(appInfo.definitionFor(superType));
-                      if (superClass != null) {
-                        d8classes.add(superClass);
-                      }
-                    });
+    for (DexProgramClass clazz : appInfo.classes()) {
+      if (!d8classes.contains(clazz) && !options.partialCompilationConfiguration.test(clazz)) {
+        d8classes.add(clazz);
+        // TODO(b/309743298): Improve this to only visit each class once and stop at
+        //  library boundary.
+        appInfo.forEachSuperType(
+            clazz,
+            (superType, subclass, ignored) -> {
+              DexProgramClass superClass = asProgramClassOrNull(appInfo.definitionFor(superType));
+              if (superClass != null) {
+                d8classes.add(superClass);
               }
             });
+      }
+    }
 
     // Filter the program input into the D8 and R8 parts.
     Set<String> d8ZipEntries =
         d8classes.stream()
             .map(clazz -> ZipUtils.zipEntryNameForClass(clazz.getClassReference()))
             .collect(Collectors.toSet());
-    ZipBuilder d8ProgramBuilder = ZipBuilder.builder(tmp.resolve("d8-program.jar"));
-    ZipBuilder r8ProgramBuilder = ZipBuilder.builder(tmp.resolve("r8-program.jar"));
+    ZipBuilder d8ProgramBuilder = ZipBuilder.builder(resolveTmp("d8-program.jar"));
+    ZipBuilder r8ProgramBuilder = ZipBuilder.builder(resolveTmp("r8-program.jar"));
     ZipUtils.iter(
         dump.getProgramArchive(),
         (entry, input) -> {
@@ -168,33 +147,28 @@
         });
     Path d8Program = d8ProgramBuilder.build();
     Path r8Program = r8ProgramBuilder.build();
+    return new R8PartialInput(d8Program, r8Program, dump);
+  }
 
+  private R8PartialD8DexResult runD8DexStep(R8PartialInput input, ExecutorService executor)
+      throws IOException {
     // Compile D8 input with D8.
-    Path d8Output = tmp.resolve("d8-output.zip");
+    Path d8Output = resolveTmp("d8-output.zip");
     D8Command.Builder d8Builder =
         D8Command.builder(options.reporter)
-            .setMinApiLevel(dump.getBuildProperties().getMinApi())
-            .addLibraryFiles(dump.getLibraryArchive())
-            .addClasspathFiles(dump.getClasspathArchive())
-            .addClasspathFiles(r8Program)
-            .addProgramFiles(d8Program)
-            .setMode(dump.getBuildProperties().getCompilationMode())
             .setOutput(d8Output, OutputMode.DexIndexed);
-    if (dump.hasDesugaredLibrary()) {
-      d8Builder.addDesugaredLibraryConfiguration(
-          Files.readString(dump.getDesugaredLibraryFile(), UTF_8));
-    }
+    input.configure(d8Builder);
     AndroidAppConsumers d8OutputAppSink = null;
     if (d8OutputAppConsumer != null) {
       d8OutputAppSink = new AndroidAppConsumers(d8Builder);
     }
     d8Builder.validate();
-    D8Command d8command = d8Builder.makeCommand();
-    AndroidApp d8App = d8command.getInputApp();
+    D8Command d8Command = d8Builder.makeCommand();
+    AndroidApp d8App = d8Command.getInputApp();
     if (d8InputAppConsumer != null) {
       d8InputAppConsumer.accept(d8App);
     }
-    InternalOptions d8Options = d8command.getInternalOptions();
+    InternalOptions d8Options = d8Command.getInternalOptions();
     options.partialCompilationConfiguration.d8DexOptionsConsumer.accept(d8Options);
     assert d8Options.getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N)
         : "Default interface methods not yet supported";
@@ -202,78 +176,48 @@
     if (d8OutputAppConsumer != null) {
       d8OutputAppConsumer.accept(d8OutputAppSink.build());
     }
+    return new R8PartialD8DexResult(d8Output);
+  }
 
+  private R8PartialTraceReferencesResult runTraceReferencesStep(R8PartialInput input)
+      throws IOException, ResourceException {
     // Run trace references to produce keep rules for the D8 compiled part.
     // TODO(b/309743298): Do not emit keep rules into a file.
-    Path traceReferencesRules = tmp.resolve("tr.rules");
+    Path traceReferencesRules = resolveTmp("tr.rules");
     TraceReferencesKeepRules keepRulesConsumer =
         TraceReferencesKeepRules.builder()
             .setOutputConsumer(new FileConsumer(traceReferencesRules))
             .build();
     TraceReferencesCommand.Builder trBuilder =
-        TraceReferencesCommand.builder()
-            .setConsumer(keepRulesConsumer)
-            .addLibraryFiles(dump.getLibraryArchive())
-            .addTargetFiles(r8Program)
-            .addSourceFiles(d8Program);
+        TraceReferencesCommand.builder().setConsumer(keepRulesConsumer);
+    input.configure(trBuilder);
     TraceReferencesCommand tr = TraceReferencesBridge.makeCommand(trBuilder);
     TraceReferencesBridge.runInternal(tr);
+    return new R8PartialTraceReferencesResult(traceReferencesRules);
+  }
 
-    class R8DataResources implements DataResourceConsumer {
-      final List<DataResource> dataResources = new ArrayList<>();
-
-      @Override
-      public void accept(DataDirectoryResource directory, DiagnosticsHandler diagnosticsHandler) {
-        dataResources.add(directory);
-      }
-
-      @Override
-      public void accept(DataEntryResource file, DiagnosticsHandler diagnosticsHandler) {
-        dataResources.add(file);
-      }
-
-      @Override
-      public void finished(DiagnosticsHandler handler) {}
-
-      public void feed(DataResourceConsumer consumer, DiagnosticsHandler handler) {
-        dataResources.forEach(
-            dataResource -> {
-              if (dataResource instanceof DataDirectoryResource) {
-                consumer.accept((DataDirectoryResource) dataResource, handler);
-              } else {
-                assert dataResource instanceof DataEntryResource;
-                consumer.accept((DataEntryResource) dataResource, handler);
-              }
-            });
-      }
-    }
-
+  private R8PartialR8Result runR8PartialStep(
+      R8PartialInput input,
+      R8PartialTraceReferencesResult traceReferencesResult,
+      ExecutorService executor)
+      throws IOException {
     // Compile R8 input with R8 using the keep rules from trace references.
-    Path r8Output = tmp.resolve("r8-output.zip");
-    R8DataResources r8DataResources = new R8DataResources();
+    Path r8Output = resolveTmp("r8-output.zip");
+    R8PartialDataResourceConsumer r8DataResourcesConsumer = new R8PartialDataResourceConsumer();
     R8Command.Builder r8Builder =
         R8Command.builder(options.reporter)
-            .setMinApiLevel(dump.getBuildProperties().getMinApi())
-            .addLibraryFiles(dump.getLibraryArchive())
-            .addClasspathFiles(dump.getClasspathArchive())
-            .addClasspathFiles(d8Program)
-            .addProgramFiles(r8Program)
-            .addProguardConfigurationFiles(dump.getProguardConfigFile(), traceReferencesRules)
+            .addProguardConfigurationFiles(traceReferencesResult.getOutputPath())
             .enableLegacyFullModeForKeepRules(true)
-            .setMode(dump.getBuildProperties().getCompilationMode())
             .setProgramConsumer(
                 new ForwardingConsumer(new ArchiveConsumer(r8Output)) {
                   @Override
                   public DataResourceConsumer getDataResourceConsumer() {
-                    return r8DataResources;
+                    return r8DataResourcesConsumer;
                   }
                 });
-    if (dump.hasDesugaredLibrary()) {
-      r8Builder.addDesugaredLibraryConfiguration(
-          Files.readString(dump.getDesugaredLibraryFile(), UTF_8));
-    }
+    input.configure(r8Builder);
     AndroidAppConsumers r8OutputAppSink = null;
-    if (r8Builder != null) {
+    if (r8OutputAppConsumer != null) {
       r8OutputAppSink = new AndroidAppConsumers(r8Builder);
     }
     r8Builder.validate();
@@ -284,34 +228,36 @@
     }
     InternalOptions r8Options = r8Command.getInternalOptions();
     options.partialCompilationConfiguration.r8OptionsConsumer.accept(r8Options);
-    r8Options.mapConsumer = originalMapConsumer;
+    r8Options.mapConsumer = options.mapConsumer;
     r8Options.quiet = true; // Don't write the R8 version.
     R8.runInternal(r8App, r8Options, executor);
     if (r8OutputAppConsumer != null) {
       r8OutputAppConsumer.accept(r8OutputAppSink.build());
     }
+    return new R8PartialR8Result(r8DataResourcesConsumer.getDataResources(), r8Output);
+  }
 
+  private void runD8MergeStep(
+      R8PartialInput input,
+      R8PartialD8DexResult d8DexResult,
+      R8PartialR8Result r8Result,
+      ExecutorService executor)
+      throws IOException {
     // TODO(b/309743298): Handle jumbo string rewriting with PCs in mapping file.
     D8Command.Builder mergerBuilder =
         D8Command.builder(options.reporter)
-            .setMinApiLevel(dump.getBuildProperties().getMinApi())
-            .addLibraryFiles(dump.getLibraryArchive())
-            .addClasspathFiles(dump.getClasspathArchive())
-            .addProgramFiles(d8Output, r8Output)
-            .setMode(dump.getBuildProperties().getCompilationMode())
-            .setProgramConsumer(originalProgramConsumer);
+            .addProgramFiles(d8DexResult.getOutputPath(), r8Result.getOutputPath())
+            .setProgramConsumer(options.programConsumer);
+    input.configureMerge(mergerBuilder);
     mergerBuilder.validate();
     D8Command mergeCommand = mergerBuilder.makeCommand();
     AndroidApp mergeApp = mergeCommand.getInputApp();
     InternalOptions mergeOptions = mergeCommand.getInternalOptions();
     options.partialCompilationConfiguration.d8MergeOptionsConsumer.accept(mergeOptions);
     D8.runInternal(mergeApp, mergeOptions, executor);
-    // Feed the data resource output by R8 to the output consumer. Keeping this at the end after the
-    // merge keeps the order of calls to the output consumer closer to full R8.
-    if (originalDataResourceConsumer != null) {
-      r8DataResources.feed(originalDataResourceConsumer, options.reporter);
-      originalDataResourceConsumer.finished(options.reporter);
-    }
-    timing.end();
+  }
+
+  private Path resolveTmp(String string) throws IOException {
+    return options.partialCompilationConfiguration.getTempDir().resolve(string);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/dump/CompilerDump.java b/src/main/java/com/android/tools/r8/dump/CompilerDump.java
index f572d3d..5e9b815 100644
--- a/src/main/java/com/android/tools/r8/dump/CompilerDump.java
+++ b/src/main/java/com/android/tools/r8/dump/CompilerDump.java
@@ -16,6 +16,10 @@
 
   private final Path directory;
 
+  public static CompilerDump fromArchive(Path dumpArchive) throws IOException {
+    return fromArchive(dumpArchive, dumpArchive.getParent());
+  }
+
   public static CompilerDump fromArchive(Path dumpArchive, Path dumpExtractionDirectory)
       throws IOException {
     ZipUtils.unzip(dumpArchive, dumpExtractionDirectory);
diff --git a/src/main/java/com/android/tools/r8/partial/R8PartialD8DexResult.java b/src/main/java/com/android/tools/r8/partial/R8PartialD8DexResult.java
new file mode 100644
index 0000000..fc71c3e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/partial/R8PartialD8DexResult.java
@@ -0,0 +1,19 @@
+// Copyright (c) 2025, 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.partial;
+
+import java.nio.file.Path;
+
+public class R8PartialD8DexResult {
+
+  private final Path outputPath;
+
+  public R8PartialD8DexResult(Path outputPath) {
+    this.outputPath = outputPath;
+  }
+
+  public Path getOutputPath() {
+    return outputPath;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/partial/R8PartialDataResourceConsumer.java b/src/main/java/com/android/tools/r8/partial/R8PartialDataResourceConsumer.java
new file mode 100644
index 0000000..2d1481a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/partial/R8PartialDataResourceConsumer.java
@@ -0,0 +1,38 @@
+// Copyright (c) 2025, 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.partial;
+
+import com.android.tools.r8.DataDirectoryResource;
+import com.android.tools.r8.DataEntryResource;
+import com.android.tools.r8.DataResource;
+import com.android.tools.r8.DataResourceConsumer;
+import com.android.tools.r8.DiagnosticsHandler;
+import java.util.ArrayList;
+import java.util.List;
+
+public class R8PartialDataResourceConsumer implements DataResourceConsumer {
+
+  private final List<DataResource> dataResources = new ArrayList<>();
+  boolean finished;
+
+  public List<DataResource> getDataResources() {
+    assert finished;
+    return dataResources;
+  }
+
+  @Override
+  public void accept(DataDirectoryResource directory, DiagnosticsHandler diagnosticsHandler) {
+    dataResources.add(directory);
+  }
+
+  @Override
+  public void accept(DataEntryResource file, DiagnosticsHandler diagnosticsHandler) {
+    dataResources.add(file);
+  }
+
+  @Override
+  public void finished(DiagnosticsHandler handler) {
+    finished = true;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/partial/R8PartialInput.java b/src/main/java/com/android/tools/r8/partial/R8PartialInput.java
new file mode 100644
index 0000000..3f07cd0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/partial/R8PartialInput.java
@@ -0,0 +1,70 @@
+// Copyright (c) 2025, 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.partial;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.android.tools.r8.BaseCompilerCommand;
+import com.android.tools.r8.D8Command;
+import com.android.tools.r8.R8Command;
+import com.android.tools.r8.dump.CompilerDump;
+import com.android.tools.r8.tracereferences.TraceReferencesCommand;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+public class R8PartialInput {
+
+  private final Path d8Program;
+  private final Path r8Program;
+  private final CompilerDump dump;
+
+  public R8PartialInput(Path d8Program, Path r8Program, CompilerDump dump) {
+    this.d8Program = d8Program;
+    this.r8Program = r8Program;
+    this.dump = dump;
+  }
+
+  public void configure(D8Command.Builder commandBuilder) throws IOException {
+    configureBase(commandBuilder);
+    configureDesugaredLibrary(commandBuilder);
+    commandBuilder.addProgramFiles(d8Program).addClasspathFiles(r8Program);
+  }
+
+  public void configureMerge(D8Command.Builder commandBuilder) throws IOException {
+    configureBase(commandBuilder);
+  }
+
+  public void configure(R8Command.Builder commandBuilder) throws IOException {
+    configureBase(commandBuilder);
+    configureDesugaredLibrary(commandBuilder);
+    commandBuilder
+        .addProgramFiles(r8Program)
+        .addClasspathFiles(d8Program)
+        .addProguardConfigurationFiles(dump.getProguardConfigFile());
+  }
+
+  public void configure(TraceReferencesCommand.Builder commandBuilder) throws IOException {
+    commandBuilder
+        .addLibraryFiles(dump.getLibraryArchive())
+        .addSourceFiles(d8Program)
+        .addTargetFiles(r8Program);
+  }
+
+  private void configureBase(BaseCompilerCommand.Builder<?, ?> commandBuilder) throws IOException {
+    commandBuilder
+        .addClasspathFiles(dump.getClasspathArchive())
+        .addLibraryFiles(dump.getLibraryArchive())
+        .setMinApiLevel(dump.getBuildProperties().getMinApi())
+        .setMode(dump.getBuildProperties().getCompilationMode());
+  }
+
+  private void configureDesugaredLibrary(BaseCompilerCommand.Builder<?, ?> commandBuilder)
+      throws IOException {
+    if (dump.hasDesugaredLibrary()) {
+      commandBuilder.addDesugaredLibraryConfiguration(
+          Files.readString(dump.getDesugaredLibraryFile(), UTF_8));
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/partial/R8PartialInputToDumpFlags.java b/src/main/java/com/android/tools/r8/partial/R8PartialInputToDumpFlags.java
new file mode 100644
index 0000000..ddfef8f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/partial/R8PartialInputToDumpFlags.java
@@ -0,0 +1,37 @@
+// Copyright (c) 2025, 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.partial;
+
+import com.android.tools.r8.dump.DumpOptions;
+import com.android.tools.r8.utils.DumpInputFlags;
+import java.nio.file.Path;
+
+public class R8PartialInputToDumpFlags extends DumpInputFlags {
+
+  private final Path dumpFile;
+
+  public R8PartialInputToDumpFlags(Path dumpFile) {
+    this.dumpFile = dumpFile;
+  }
+
+  @Override
+  public Path getDumpPath() {
+    return dumpFile;
+  }
+
+  @Override
+  public boolean shouldDump(DumpOptions options) {
+    return true;
+  }
+
+  @Override
+  public boolean shouldFailCompilation() {
+    return false;
+  }
+
+  @Override
+  public boolean shouldLogDumpInfoMessage() {
+    return false;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/partial/R8PartialR8Result.java b/src/main/java/com/android/tools/r8/partial/R8PartialR8Result.java
new file mode 100644
index 0000000..bd5fee2
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/partial/R8PartialR8Result.java
@@ -0,0 +1,43 @@
+// Copyright (c) 2025, 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.partial;
+
+import com.android.tools.r8.DataDirectoryResource;
+import com.android.tools.r8.DataEntryResource;
+import com.android.tools.r8.DataResource;
+import com.android.tools.r8.DataResourceConsumer;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Reporter;
+import java.nio.file.Path;
+import java.util.List;
+
+public class R8PartialR8Result {
+
+  private final List<DataResource> outputDataResources;
+  private final Path outputPath;
+
+  public R8PartialR8Result(List<DataResource> outputDataResources, Path outputPath) {
+    this.outputDataResources = outputDataResources;
+    this.outputPath = outputPath;
+  }
+
+  public Path getOutputPath() {
+    return outputPath;
+  }
+
+  public void supplyConsumers(InternalOptions options) {
+    supplyDataResourceConsumer(options.dataResourceConsumer, options.reporter);
+  }
+
+  private void supplyDataResourceConsumer(DataResourceConsumer consumer, Reporter reporter) {
+    for (DataResource dataResource : outputDataResources) {
+      if (dataResource instanceof DataDirectoryResource) {
+        consumer.accept((DataDirectoryResource) dataResource, reporter);
+      } else {
+        assert dataResource instanceof DataEntryResource;
+        consumer.accept((DataEntryResource) dataResource, reporter);
+      }
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/partial/R8PartialTraceReferencesResult.java b/src/main/java/com/android/tools/r8/partial/R8PartialTraceReferencesResult.java
new file mode 100644
index 0000000..fb7c900
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/partial/R8PartialTraceReferencesResult.java
@@ -0,0 +1,19 @@
+// Copyright (c) 2025, 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.partial;
+
+import java.nio.file.Path;
+
+public class R8PartialTraceReferencesResult {
+
+  private final Path outputPath;
+
+  public R8PartialTraceReferencesResult(Path outputPath) {
+    this.outputPath = outputPath;
+  }
+
+  public Path getOutputPath() {
+    return outputPath;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/R8PartialCompilationConfiguration.java b/src/main/java/com/android/tools/r8/utils/R8PartialCompilationConfiguration.java
index 2586b2d..4adb654 100644
--- a/src/main/java/com/android/tools/r8/utils/R8PartialCompilationConfiguration.java
+++ b/src/main/java/com/android/tools/r8/utils/R8PartialCompilationConfiguration.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.utils;
 
+import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexString;
 import com.google.common.base.Predicates;
 import com.google.common.base.Splitter;
@@ -16,7 +17,7 @@
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 
-public class R8PartialCompilationConfiguration implements Predicate<DexString> {
+public class R8PartialCompilationConfiguration {
 
   private final boolean enabled;
   private Path tempDir = null;
@@ -46,8 +47,8 @@
     this.excludePredicates = excludePredicates;
   }
 
-  @Override
-  public boolean test(DexString name) {
+  public boolean test(DexProgramClass clazz) {
+    DexString name = clazz.getType().getDescriptor();
     for (Predicate<DexString> isR8ClassPredicate : includePredicates) {
       if (isR8ClassPredicate.test(name)) {
         for (Predicate<DexString> isD8ClassPredicate : excludePredicates) {
@@ -100,10 +101,6 @@
     this.tempDir = tempDir;
   }
 
-  public Path getDumpFile() throws IOException {
-    return getTempDir().resolve("dump.zip");
-  }
-
   public static class Builder {
     private final List<Predicate<DexString>> includePredicates = new ArrayList<>();
     private final List<Predicate<DexString>> excludePredicates = new ArrayList<>();