Enable concurrent parsing in trace references

This makes the following improvements to trace references:

* Create an ExecutorService for reading the app concurrently

* Implement the new API for async parsing in the ProgramResourceProviders used by trace references

Bug: b/448130900
Change-Id: Ide3a22dbc841f5fb322b71d87367285eeede5345
diff --git a/src/main/java/com/android/tools/r8/tracereferences/TraceReferences.java b/src/main/java/com/android/tools/r8/tracereferences/TraceReferences.java
index 9d0ef51..ade3e8b 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/TraceReferences.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/TraceReferences.java
@@ -24,11 +24,13 @@
 import com.android.tools.r8.utils.ExceptionUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.timing.Timing;
 import com.google.common.collect.ImmutableList;
 import java.io.IOException;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.concurrent.ExecutorService;
 import java.util.function.Consumer;
 
 @KeepForApi
@@ -38,6 +40,11 @@
     runForTesting(command, command.getInternalOptions());
   }
 
+  public static void run(TraceReferencesCommand command, ExecutorService executorService)
+      throws CompilationFailedException {
+    runForTesting(command, command.getInternalOptions(), executorService);
+  }
+
   private static void forEachDescriptor(ProgramResourceProvider provider, Consumer<String> consumer)
       throws ResourceException, IOException {
     for (ProgramResource programResource : provider.getProgramResources()) {
@@ -63,11 +70,18 @@
 
   static void runForTesting(TraceReferencesCommand command, InternalOptions options)
       throws CompilationFailedException {
-    ExceptionUtils.withCompilationHandler(
-        command.getReporter(), () -> runInternal(command, options));
+    runForTesting(command, options, ThreadUtils.getExecutorService(options));
   }
 
-  static void runInternal(TraceReferencesCommand command, InternalOptions options)
+  static void runForTesting(
+      TraceReferencesCommand command, InternalOptions options, ExecutorService executorService)
+      throws CompilationFailedException {
+    ExceptionUtils.withCompilationHandler(
+        command.getReporter(), () -> runInternal(command, options, executorService));
+  }
+
+  static void runInternal(
+      TraceReferencesCommand command, InternalOptions options, ExecutorService executorService)
       throws IOException, ResourceException {
     AndroidApp.Builder builder = AndroidApp.builder();
     command.getLibrary().forEach(builder::addLibraryResourceProvider);
@@ -84,7 +98,7 @@
         AppView.createForTracer(
             AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(
                 new ApplicationReader(builder.build(), options, Timing.empty())
-                    .readDirectSingleThreaded(),
+                    .readDirect(executorService),
                 ClassToFeatureSplitMap.createEmptyClassToFeatureSplitMap(),
                 MainDexInfo.none(),
                 GlobalSyntheticsStrategy.forSingleOutputMode()));
diff --git a/src/main/java/com/android/tools/r8/tracereferences/TraceReferencesCommand.java b/src/main/java/com/android/tools/r8/tracereferences/TraceReferencesCommand.java
index 429b912..462e396 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/TraceReferencesCommand.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/TraceReferencesCommand.java
@@ -39,6 +39,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Consumer;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassVisitor;
 
@@ -214,15 +215,20 @@
       public ProgramResource getProgramResource(String descriptor) {
         return descriptor.equals(this.descriptor) ? programResource : null;
       }
+
+      @Override
+      public void getProgramResources(Consumer<ProgramResource> consumer) {
+        consumer.accept(programResource);
+      }
     }
 
-    private ClassFileResourceProvider singleClassFileClassFileResourceProvider(Path file)
+    private static ClassFileResourceProvider singleClassFileClassFileResourceProvider(Path file)
         throws IOException {
       return new SingleClassClassFileResourceProvider(
           new PathOrigin(file), Files.readAllBytes(file));
     }
 
-    private ProgramResourceProvider singleClassFileProgramResourceProvider(Path file)
+    private static ProgramResourceProvider singleClassFileProgramResourceProvider(Path file)
         throws IOException {
       byte[] bytes = Files.readAllBytes(file);
       String descriptor = extractClassDescriptor(bytes);
@@ -230,9 +236,33 @@
 
         @Override
         public Collection<ProgramResource> getProgramResources() {
-          return ImmutableList.of(
-              ProgramResource.fromBytes(
-                  new PathOrigin(file), Kind.CF, bytes, ImmutableSet.of(descriptor)));
+          return Collections.singletonList(createProgramResource());
+        }
+
+        @Override
+        public void getProgramResources(Consumer<ProgramResource> consumer) {
+          consumer.accept(createProgramResource());
+        }
+
+        private ProgramResource createProgramResource() {
+          return ProgramResource.fromBytes(
+              new PathOrigin(file), Kind.CF, bytes, ImmutableSet.of(descriptor));
+        }
+      };
+    }
+
+    private static ProgramResourceProvider singleDexFileProgramResourceProvider(Path file) {
+      ProgramResource programResource = ProgramResource.fromFile(Kind.DEX, file);
+      return new ProgramResourceProvider() {
+
+        @Override
+        public Collection<ProgramResource> getProgramResources() {
+          return Collections.singletonList(programResource);
+        }
+
+        @Override
+        public void getProgramResources(Consumer<ProgramResource> consumer) {
+          consumer.accept(programResource);
         }
       };
     }
@@ -277,15 +307,7 @@
           error(new ExceptionDiagnostic(e));
         }
       } else if (isDexFile(file)) {
-        traceSourceBuilder.add(
-            new ProgramResourceProvider() {
-              ProgramResource dexResource = ProgramResource.fromFile(Kind.DEX, file);
-
-              @Override
-              public Collection<ProgramResource> getProgramResources() {
-                return Collections.singletonList(dexResource);
-              }
-            });
+        traceSourceBuilder.add(singleDexFileProgramResourceProvider(file));
       } else {
         error(new StringDiagnostic("Unsupported source file type", new PathOrigin(file)));
       }