Dump: deduplicate

- Generate 1 dump for L8 compilation
- Do not generate a dump while asserting in R8

Bug: 171195238
Change-Id: Ic71df8ed21b20e8c0ae13b00760c24934f1be333
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 84bc9b3..3372bc9 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -73,6 +73,7 @@
     private String synthesizedClassPrefix = "";
     private boolean enableMainDexListCheck = true;
     private boolean minimalMainDex = false;
+    private boolean skipDump = false;
 
     private Builder() {
       this(new DefaultD8DiagnosticsHandler());
@@ -163,6 +164,15 @@
       return self();
     }
 
+    /**
+     * Allow to skip to dump into file and dump into directory instruction, this is primarily used
+     * for chained compilation in L8 so there are no duplicated dumps.
+     */
+    Builder skipDump() {
+      skipDump = true;
+      return self();
+    }
+
     @Override
     Builder self() {
       return this;
@@ -255,6 +265,7 @@
           getAssertionsConfiguration(),
           getOutputInspections(),
           synthesizedClassPrefix,
+          skipDump,
           enableMainDexListCheck,
           minimalMainDex,
           getThreadCount(),
@@ -269,6 +280,7 @@
   private final StringConsumer desugaredLibraryKeepRuleConsumer;
   private final DesugaredLibraryConfiguration libraryConfiguration;
   private final String synthesizedClassPrefix;
+  private final boolean skipDump;
   private final boolean enableMainDexListCheck;
   private final boolean minimalMainDex;
   private final DexItemFactory factory;
@@ -331,6 +343,7 @@
       List<AssertionsConfiguration> assertionsConfiguration,
       List<Consumer<Inspector>> outputInspections,
       String synthesizedClassPrefix,
+      boolean skipDump,
       boolean enableMainDexListCheck,
       boolean minimalMainDex,
       int threadCount,
@@ -354,6 +367,7 @@
     this.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
     this.libraryConfiguration = libraryConfiguration;
     this.synthesizedClassPrefix = synthesizedClassPrefix;
+    this.skipDump = skipDump;
     this.enableMainDexListCheck = enableMainDexListCheck;
     this.minimalMainDex = minimalMainDex;
     this.factory = factory;
@@ -366,6 +380,7 @@
     desugaredLibraryKeepRuleConsumer = null;
     libraryConfiguration = null;
     synthesizedClassPrefix = null;
+    skipDump = false;
     enableMainDexListCheck = true;
     minimalMainDex = false;
     factory = null;
@@ -430,6 +445,11 @@
       internal.threadCount = getThreadCount();
     }
 
+    if (skipDump) {
+      internal.dumpInputToDirectory = null;
+      internal.dumpInputToFile = null;
+    }
+
     return internal;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 1141688..8e4bb2a 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -317,6 +317,7 @@
             libraryConfiguration.getExtraKeepRules(), Origin.unknown());
         r8Builder.addProguardConfigurationFiles(proguardConfigFiles);
         r8Builder.setDisableDesugaring(true);
+        r8Builder.skipDump();
         r8Command = r8Builder.makeCommand();
       } else if (!(getProgramConsumer() instanceof ClassFileConsumer)) {
         l8CfConsumer = new InMemoryJarContent();
@@ -335,6 +336,7 @@
           d8Builder.addLibraryResourceProvider(libraryResourceProvider);
         }
         d8Builder.setDisableDesugaring(true);
+        d8Builder.skipDump();
         d8Command = d8Builder.makeCommand();
       } else {
         assert getProgramConsumer() instanceof ClassFileConsumer;
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index ebc0bc6..408e3a0 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -907,7 +907,7 @@
               .verifyMappingToOriginalProgram(
                   appView,
                   new ApplicationReader(inputApp.withoutMainDexList(), options, timing)
-                      .read(executorService));
+                      .readWithoutDumping(executorService));
 
       // Report synthetic rules (only for testing).
       // TODO(b/120959039): Move this to being reported through the graph consumer.
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index bbe9387..4a68964 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -107,6 +107,7 @@
     private BiFunction<String, Long, Boolean> dexClassChecksumFilter = (name, checksum) -> true;
     private final List<FeatureSplit> featureSplits = new ArrayList<>();
     private String synthesizedClassPrefix = "";
+    private boolean skipDump = false;
 
     private boolean allowPartiallyImplementedProguardOptions = false;
     private boolean allowTestProguardOptions =
@@ -270,6 +271,15 @@
     }
 
     /**
+     * Allow to skip to dump into file and dump into directory instruction, this is primarily used
+     * for chained compilation in L8 so there are no duplicated dumps.
+     */
+    Builder skipDump() {
+      skipDump = true;
+      return self();
+    }
+
+    /**
      * Set a consumer for receiving the proguard usage information.
      *
      * <p>Note that any subsequent calls to this method will replace the previous setting.
@@ -584,6 +594,7 @@
               getAssertionsConfiguration(),
               getOutputInspections(),
               synthesizedClassPrefix,
+              skipDump,
               getThreadCount());
 
       return command;
@@ -667,6 +678,7 @@
   private final DesugaredLibraryConfiguration libraryConfiguration;
   private final FeatureSplitConfiguration featureSplitConfiguration;
   private final String synthesizedClassPrefix;
+  private final boolean skipDump;
 
   /** Get a new {@link R8Command.Builder}. */
   public static Builder builder() {
@@ -745,6 +757,7 @@
       List<AssertionsConfiguration> assertionsConfiguration,
       List<Consumer<Inspector>> outputInspections,
       String synthesizedClassPrefix,
+      boolean skipDump,
       int threadCount) {
     super(
         inputApp,
@@ -779,6 +792,7 @@
     this.libraryConfiguration = libraryConfiguration;
     this.featureSplitConfiguration = featureSplitConfiguration;
     this.synthesizedClassPrefix = synthesizedClassPrefix;
+    this.skipDump = skipDump;
   }
 
   private R8Command(boolean printHelp, boolean printVersion) {
@@ -800,6 +814,7 @@
     libraryConfiguration = null;
     featureSplitConfiguration = null;
     synthesizedClassPrefix = null;
+    skipDump = false;
   }
 
   /** Get the enable-tree-shaking state. */
@@ -955,6 +970,11 @@
       internal.threadCount = getThreadCount();
     }
 
+    if (skipDump) {
+      internal.dumpInputToDirectory = null;
+      internal.dumpInputToFile = null;
+    }
+
     return internal;
   }
 
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
index 6b0d055..2f3c56e 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -100,6 +100,15 @@
         ProgramClassCollection.defaultConflictResolver(options.reporter));
   }
 
+  public final LazyLoadedDexApplication readWithoutDumping(ExecutorService executorService)
+      throws IOException {
+    return read(
+        inputApp.getProguardMapInputData(),
+        executorService,
+        ProgramClassCollection.defaultConflictResolver(options.reporter),
+        false);
+  }
+
   public final LazyLoadedDexApplication read(
       StringResource proguardMap,
       ExecutorService executorService)
@@ -115,31 +124,18 @@
       ExecutorService executorService,
       ProgramClassConflictResolver resolver)
       throws IOException {
+    return read(proguardMap, executorService, resolver, true);
+  }
+
+  public final LazyLoadedDexApplication read(
+      StringResource proguardMap,
+      ExecutorService executorService,
+      ProgramClassConflictResolver resolver,
+      boolean shouldDump)
+      throws IOException {
     assert verifyMainDexOptionsCompatible(inputApp, options);
-    Path dumpOutput = null;
-    boolean cleanDump = false;
-    if (options.dumpInputToFile != null) {
-      dumpOutput = Paths.get(options.dumpInputToFile);
-    } else if (options.dumpInputToDirectory != null) {
-      dumpOutput =
-          Paths.get(options.dumpInputToDirectory).resolve("dump" + System.nanoTime() + ".zip");
-    } else if (options.testing.dumpAll) {
-      cleanDump = true;
-      dumpOutput = Paths.get("/tmp").resolve("dump" + System.nanoTime() + ".zip");
-    }
-    if (dumpOutput != null) {
-      timing.begin("ApplicationReader.dump");
-      dumpInputToFile(inputApp, dumpOutput, options);
-      if (cleanDump) {
-        Files.delete(dumpOutput);
-      }
-      timing.end();
-      Diagnostic message = new StringDiagnostic("Dumped compilation inputs to: " + dumpOutput);
-      if (options.dumpInputToFile != null) {
-        throw options.reporter.fatalError(message);
-      } else if (!cleanDump) {
-        options.reporter.info(message);
-      }
+    if (shouldDump) {
+      dumpApplication();
     }
     timing.begin("DexApplication.read");
     final LazyLoadedDexApplication.Builder builder =
@@ -174,6 +170,34 @@
     return builder.build();
   }
 
+  private void dumpApplication() throws IOException {
+    Path dumpOutput = null;
+    boolean cleanDump = false;
+    if (options.dumpInputToFile != null) {
+      dumpOutput = Paths.get(options.dumpInputToFile);
+    } else if (options.dumpInputToDirectory != null) {
+      dumpOutput =
+          Paths.get(options.dumpInputToDirectory).resolve("dump" + System.nanoTime() + ".zip");
+    } else if (options.testing.dumpAll) {
+      cleanDump = true;
+      dumpOutput = Paths.get("/tmp").resolve("dump" + System.nanoTime() + ".zip");
+    }
+    if (dumpOutput != null) {
+      timing.begin("ApplicationReader.dump");
+      dumpInputToFile(inputApp, dumpOutput, options);
+      if (cleanDump) {
+        Files.delete(dumpOutput);
+      }
+      timing.end();
+      Diagnostic message = new StringDiagnostic("Dumped compilation inputs to: " + dumpOutput);
+      if (options.dumpInputToFile != null) {
+        throw options.reporter.fatalError(message);
+      } else if (!cleanDump) {
+        options.reporter.info(message);
+      }
+    }
+  }
+
   public MainDexClasses readMainDexClasses(DexApplication app) {
     MainDexClasses.Builder builder = MainDexClasses.builder();
     if (inputApp.hasMainDexList()) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDumpInputsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDumpInputsTest.java
index faba098..ea80848 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDumpInputsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDumpInputsTest.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.desugar.desugaredlibrary;
 
 import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.TestParameters;
@@ -101,6 +102,7 @@
   private void verifyDumpDir(Path dumpDir) throws IOException {
     assertTrue(Files.isDirectory(dumpDir));
     List<Path> paths = Files.walk(dumpDir, 1).collect(Collectors.toList());
+    assertEquals(3, paths.size());
     boolean hasVerified = false;
     for (Path path : paths) {
       if (!path.equals(dumpDir)) {