Reland "Account for art profiles in compiledump.py"

This reverts commit f065e0c1c145fb76ff94198eb719d73e90821436.

Change-Id: If8cd6a56ceff69524df8b216d0341cb55d5649e1
diff --git a/src/main/java/com/android/tools/r8/utils/CompileDumpBase.java b/src/main/java/com/android/tools/r8/utils/CompileDumpBase.java
new file mode 100644
index 0000000..2a928b0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/CompileDumpBase.java
@@ -0,0 +1,171 @@
+// Copyright (c) 2023, 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.utils;
+
+import com.android.tools.r8.CompatProguardCommandBuilder;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+public class CompileDumpBase {
+
+  static void setEnableExperimentalMissingLibraryApiModeling(
+      Object builder, boolean enableMissingLibraryApiModeling) {
+    getReflectiveBuilderMethod(
+            builder, "setEnableExperimentalMissingLibraryApiModeling", boolean.class)
+        .accept(new Object[] {enableMissingLibraryApiModeling});
+  }
+
+  static void setAndroidPlatformBuild(Object builder, boolean androidPlatformBuild) {
+    getReflectiveBuilderMethod(builder, "setAndroidPlatformBuild", boolean.class)
+        .accept(new Object[] {androidPlatformBuild});
+  }
+
+  static void addArtProfilesForRewriting(Object builder, Map<Path, Path> artProfileFiles) {
+    try {
+      Class<?> artProfileProviderClass =
+          Class.forName("com.android.tools.r8.profile.art.ArtProfileProvider");
+      Class<?> artProfileConsumerClass =
+          Class.forName("com.android.tools.r8.profile.art.ArtProfileConsumer");
+      artProfileFiles.forEach(
+          (artProfile, residualArtProfile) ->
+              getReflectiveBuilderMethod(
+                      builder,
+                      "addArtProfileForRewriting",
+                      artProfileProviderClass,
+                      artProfileConsumerClass)
+                  .accept(
+                      new Object[] {
+                        createArtProfileProvider(artProfile),
+                        createResidualArtProfileConsumer(residualArtProfile)
+                      }));
+    } catch (ClassNotFoundException e) {
+      // Ignore.
+    }
+  }
+
+  static void addStartupProfileProviders(Object builder, List<Path> startupProfileFiles) {
+    getReflectiveBuilderMethod(builder, "addStartupProfileProviders", Collection.class)
+        .accept(new Object[] {createStartupProfileProviders(startupProfileFiles)});
+  }
+
+  static Object createArtProfileProvider(Path artProfile) {
+    Object[] artProfileProvider = new Object[1];
+    boolean found =
+        callReflectiveUtilsMethod(
+            "createArtProfileProviderFromDumpFile",
+            new Class<?>[] {Path.class},
+            fn -> artProfileProvider[0] = fn.apply(new Object[] {artProfile}));
+    if (!found) {
+      System.out.println(
+          "Unable to add art profiles as input. "
+              + "Method createArtProfileProviderFromDumpFile() was not found.");
+      return null;
+    }
+    System.out.println(artProfileProvider[0]);
+    return artProfileProvider[0];
+  }
+
+  static Object createResidualArtProfileConsumer(Path residualArtProfile) {
+    Object[] residualArtProfileConsumer = new Object[1];
+    boolean found =
+        callReflectiveUtilsMethod(
+            "createResidualArtProfileConsumerFromDumpFile",
+            new Class<?>[] {Path.class},
+            fn -> residualArtProfileConsumer[0] = fn.apply(new Object[] {residualArtProfile}));
+    if (!found) {
+      System.out.println(
+          "Unable to add art profiles as input. "
+              + "Method createResidualArtProfileConsumerFromDumpFile() was not found.");
+      return null;
+    }
+    System.out.println(residualArtProfileConsumer[0]);
+    return residualArtProfileConsumer[0];
+  }
+
+  static Collection<Object> createStartupProfileProviders(List<Path> startupProfileFiles) {
+    List<Object> startupProfileProviders = new ArrayList<>();
+    for (Path startupProfileFile : startupProfileFiles) {
+      boolean found =
+          callReflectiveUtilsMethod(
+              "createStartupProfileProviderFromDumpFile",
+              new Class<?>[] {Path.class},
+              fn -> startupProfileProviders.add(fn.apply(new Object[] {startupProfileFile})));
+      if (!found) {
+        System.out.println(
+            "Unable to add startup profiles as input. "
+                + "Method createStartupProfileProviderFromDumpFile() was not found.");
+        break;
+      }
+    }
+    return startupProfileProviders;
+  }
+
+  static Consumer<Object[]> getReflectiveBuilderMethod(
+      Object builder, String setter, Class<?>... parameters) {
+    try {
+      Method declaredMethod = CompatProguardCommandBuilder.class.getMethod(setter, parameters);
+      return args -> {
+        try {
+          declaredMethod.invoke(builder, args);
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      };
+    } catch (NoSuchMethodException e) {
+      System.out.println(setter + " is not available on the compiledump version.");
+      // The option is not available so we just return an empty consumer
+      return args -> {};
+    }
+  }
+
+  static boolean callReflectiveUtilsMethod(
+      String methodName, Class<?>[] parameters, Consumer<Function<Object[], Object>> fnConsumer) {
+    Class<?> utilsClass;
+    try {
+      utilsClass = Class.forName("com.android.tools.r8.utils.CompileDumpUtils");
+    } catch (ClassNotFoundException e) {
+      return false;
+    }
+
+    Method declaredMethod;
+    try {
+      declaredMethod = utilsClass.getDeclaredMethod(methodName, parameters);
+    } catch (NoSuchMethodException e) {
+      return false;
+    }
+
+    fnConsumer.accept(
+        args -> {
+          try {
+            return declaredMethod.invoke(null, args);
+          } catch (Exception e) {
+            throw new RuntimeException(e);
+          }
+        });
+    return true;
+  }
+
+  // We cannot use StringResource since this class is added to the class path and has access only
+  // to the public APIs.
+  static String readAllBytesJava7(Path filePath) {
+    String content = "";
+
+    try {
+      content = new String(Files.readAllBytes(filePath));
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+
+    return content;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/CompileDumpCompatR8.java b/src/main/java/com/android/tools/r8/utils/CompileDumpCompatR8.java
index 57cdc5f..c4612a7 100644
--- a/src/main/java/com/android/tools/r8/utils/CompileDumpCompatR8.java
+++ b/src/main/java/com/android/tools/r8/utils/CompileDumpCompatR8.java
@@ -12,21 +12,15 @@
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.R8Command.Builder;
 import com.android.tools.r8.StringConsumer;
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-import java.util.function.Consumer;
-import java.util.function.Function;
 
 /**
  * Wrapper to make it easy to call R8 in compat mode when compiling a dump file.
@@ -38,7 +32,7 @@
  * valid on past version of the R8 API. Thus there is little else to do than reimplement the parts
  * we want to support for reading dumps.
  */
-public class CompileDumpCompatR8 {
+public class CompileDumpCompatR8 extends CompileDumpBase {
 
   private static final List<String> VALID_OPTIONS =
       Arrays.asList(
@@ -66,7 +60,7 @@
           "--startup-profile");
 
   private static final List<String> VALID_OPTIONS_WITH_TWO_OPERANDS =
-      Arrays.asList("--feature-jar");
+      Arrays.asList("--art-profile", "--feature-jar");
 
   private static boolean FileUtils_isArchive(Path path) {
     String name = path.getFileName().toString().toLowerCase();
@@ -90,6 +84,7 @@
     List<Path> classpath = new ArrayList<>();
     List<Path> config = new ArrayList<>();
     List<Path> mainDexRulesFiles = new ArrayList<>();
+    Map<Path, Path> artProfileFiles = new LinkedHashMap<>();
     List<Path> startupProfileFiles = new ArrayList<>();
     int minApi = 1;
     int threads = -1;
@@ -193,6 +188,11 @@
         String firstOperand = args[++i];
         String secondOperand = args[++i];
         switch (option) {
+          case "--art-profile":
+            {
+              artProfileFiles.put(Paths.get(firstOperand), Paths.get(secondOperand));
+              break;
+            }
           case "--feature-jar":
             {
               Path featureIn = Paths.get(firstOperand);
@@ -220,13 +220,10 @@
             .addMainDexRulesFiles(mainDexRulesFiles)
             .setOutput(outputPath, outputMode)
             .setMode(compilationMode);
-    getReflectiveBuilderMethod(
-            commandBuilder, "setEnableExperimentalMissingLibraryApiModeling", boolean.class)
-        .accept(new Object[] {enableMissingLibraryApiModeling});
-    getReflectiveBuilderMethod(commandBuilder, "setAndroidPlatformBuild", boolean.class)
-        .accept(new Object[] {androidPlatformBuild});
-    getReflectiveBuilderMethod(commandBuilder, "addStartupProfileProviders", Collection.class)
-        .accept(new Object[] {createStartupProfileProviders(startupProfileFiles)});
+    addArtProfilesForRewriting(commandBuilder, artProfileFiles);
+    addStartupProfileProviders(commandBuilder, startupProfileFiles);
+    setAndroidPlatformBuild(commandBuilder, androidPlatformBuild);
+    setEnableExperimentalMissingLibraryApiModeling(commandBuilder, enableMissingLibraryApiModeling);
     if (desugaredLibJson != null) {
       commandBuilder.addDesugaredLibraryConfiguration(readAllBytesJava7(desugaredLibJson));
     }
@@ -259,81 +256,4 @@
       R8.run(command);
     }
   }
-
-  private static Collection<Object> createStartupProfileProviders(List<Path> startupProfileFiles) {
-    List<Object> startupProfileProviders = new ArrayList<>();
-    for (Path startupProfileFile : startupProfileFiles) {
-      boolean found =
-          callReflectiveUtilsMethod(
-              "createStartupProfileProviderFromDumpFile",
-              new Class<?>[] {Path.class},
-              fn -> startupProfileProviders.add(fn.apply(new Object[] {startupProfileFile})));
-      if (!found) {
-        System.out.println(
-            "Unable to add startup profiles as input. "
-                + "Method createStartupProfileProviderFromDumpFile() was not found.");
-        break;
-      }
-    }
-    return startupProfileProviders;
-  }
-
-  private static Consumer<Object[]> getReflectiveBuilderMethod(
-      Builder builder, String setter, Class<?>... parameters) {
-    try {
-      Method declaredMethod = CompatProguardCommandBuilder.class.getMethod(setter, parameters);
-      return args -> {
-        try {
-          declaredMethod.invoke(builder, args);
-        } catch (Exception e) {
-          throw new RuntimeException(e);
-        }
-      };
-    } catch (NoSuchMethodException e) {
-      System.out.println(setter + " is not available on the compiledump version.");
-      // The option is not available so we just return an empty consumer
-      return args -> {};
-    }
-  }
-
-  private static boolean callReflectiveUtilsMethod(
-      String methodName, Class<?>[] parameters, Consumer<Function<Object[], Object>> fnConsumer) {
-    Class<?> utilsClass;
-    try {
-      utilsClass = Class.forName("com.android.tools.r8.utils.CompileDumpUtils");
-    } catch (ClassNotFoundException e) {
-      return false;
-    }
-
-    Method declaredMethod;
-    try {
-      declaredMethod = utilsClass.getMethod(methodName, parameters);
-    } catch (NoSuchMethodException e) {
-      return false;
-    }
-
-    fnConsumer.accept(
-        args -> {
-          try {
-            return declaredMethod.invoke(null, args);
-          } catch (Exception e) {
-            throw new RuntimeException(e);
-          }
-        });
-    return true;
-  }
-
-  // We cannot use StringResource since this class is added to the class path and has access only
-  // to the public APIs.
-  private static String readAllBytesJava7(Path filePath) {
-    String content = "";
-
-    try {
-      content = new String(Files.readAllBytes(filePath));
-    } catch (IOException e) {
-      e.printStackTrace();
-    }
-
-    return content;
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/utils/CompileDumpD8.java b/src/main/java/com/android/tools/r8/utils/CompileDumpD8.java
index 613701c..b63f5d8 100644
--- a/src/main/java/com/android/tools/r8/utils/CompileDumpD8.java
+++ b/src/main/java/com/android/tools/r8/utils/CompileDumpD8.java
@@ -8,19 +8,15 @@
 import com.android.tools.r8.D8;
 import com.android.tools.r8.D8Command;
 import com.android.tools.r8.OutputMode;
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-import java.util.function.Consumer;
-import java.util.function.Function;
 
 /**
  * Wrapper to make it easy to call D8 mode when compiling a dump file.
@@ -32,7 +28,7 @@
  * valid on past version of the D8 API. Thus there is little else to do than reimplement the parts
  * we want to support for reading dumps.
  */
-public class CompileDumpD8 {
+public class CompileDumpD8 extends CompileDumpBase {
 
   private static final List<String> VALID_OPTIONS =
       Arrays.asList(
@@ -55,6 +51,9 @@
           "--threads",
           "--startup-profile");
 
+  private static final List<String> VALID_OPTIONS_WITH_TWO_OPERANDS =
+      Arrays.asList("--art-profile");
+
   public static void main(String[] args) throws CompilationFailedException {
     OutputMode outputMode = OutputMode.DexIndexed;
     Path outputPath = null;
@@ -64,6 +63,7 @@
     List<Path> library = new ArrayList<>();
     List<Path> classpath = new ArrayList<>();
     List<Path> mainDexRulesFiles = new ArrayList<>();
+    Map<Path, Path> artProfileFiles = new LinkedHashMap<>();
     List<Path> startupProfileFiles = new ArrayList<>();
     int minApi = 1;
     int threads = -1;
@@ -143,6 +143,18 @@
           default:
             throw new IllegalArgumentException("Unimplemented option: " + option);
         }
+      } else if (VALID_OPTIONS_WITH_TWO_OPERANDS.contains(option)) {
+        String firstOperand = args[++i];
+        String secondOperand = args[++i];
+        switch (option) {
+          case "--art-profile":
+            {
+              artProfileFiles.put(Paths.get(firstOperand), Paths.get(secondOperand));
+              break;
+            }
+          default:
+            throw new IllegalArgumentException("Unimplemented option: " + option);
+        }
       } else {
         program.add(Paths.get(option));
       }
@@ -155,13 +167,10 @@
             .addMainDexRulesFiles(mainDexRulesFiles)
             .setOutput(outputPath, outputMode)
             .setMode(compilationMode);
-    getReflectiveBuilderMethod(
-            commandBuilder, "setEnableExperimentalMissingLibraryApiModeling", boolean.class)
-        .accept(new Object[] {enableMissingLibraryApiModeling});
-    getReflectiveBuilderMethod(commandBuilder, "setAndroidPlatformBuild", boolean.class)
-        .accept(new Object[] {androidPlatformBuild});
-    getReflectiveBuilderMethod(commandBuilder, "addStartupProfileProviders", Collection.class)
-        .accept(new Object[] {createStartupProfileProviders(startupProfileFiles)});
+    addArtProfilesForRewriting(commandBuilder, artProfileFiles);
+    addStartupProfileProviders(commandBuilder, startupProfileFiles);
+    setAndroidPlatformBuild(commandBuilder, androidPlatformBuild);
+    setEnableExperimentalMissingLibraryApiModeling(commandBuilder, enableMissingLibraryApiModeling);
     if (desugaredLibJson != null) {
       commandBuilder.addDesugaredLibraryConfiguration(readAllBytesJava7(desugaredLibJson));
     }
@@ -178,81 +187,4 @@
       D8.run(command);
     }
   }
-
-  private static Collection<Object> createStartupProfileProviders(List<Path> startupProfileFiles) {
-    List<Object> startupProfileProviders = new ArrayList<>();
-    for (Path startupProfileFile : startupProfileFiles) {
-      boolean found =
-          callReflectiveUtilsMethod(
-              "createStartupProfileProviderFromDumpFile",
-              new Class<?>[] {Path.class},
-              fn -> startupProfileProviders.add(fn.apply(new Object[] {startupProfileFile})));
-      if (!found) {
-        System.out.println(
-            "Unable to add startup profiles as input. "
-                + "Method createStartupProfileProviderFromDumpFile() was not found.");
-        break;
-      }
-    }
-    return startupProfileProviders;
-  }
-
-  private static Consumer<Object[]> getReflectiveBuilderMethod(
-      D8Command.Builder builder, String setter, Class<?>... parameters) {
-    try {
-      Method declaredMethod = D8Command.Builder.class.getMethod(setter, parameters);
-      return args -> {
-        try {
-          declaredMethod.invoke(builder, args);
-        } catch (Exception e) {
-          throw new RuntimeException(e);
-        }
-      };
-    } catch (NoSuchMethodException e) {
-      e.printStackTrace();
-      // The option is not available so we just return an empty consumer
-      return args -> {};
-    }
-  }
-
-  private static boolean callReflectiveUtilsMethod(
-      String methodName, Class<?>[] parameters, Consumer<Function<Object[], Object>> fnConsumer) {
-    Class<?> utilsClass;
-    try {
-      utilsClass = Class.forName("com.android.tools.r8.utils.CompileDumpUtils");
-    } catch (ClassNotFoundException e) {
-      return false;
-    }
-
-    Method declaredMethod;
-    try {
-      declaredMethod = utilsClass.getMethod(methodName, parameters);
-    } catch (NoSuchMethodException e) {
-      return false;
-    }
-
-    fnConsumer.accept(
-        args -> {
-          try {
-            return declaredMethod.invoke(null, args);
-          } catch (Exception e) {
-            throw new RuntimeException(e);
-          }
-        });
-    return true;
-  }
-
-  // We cannot use StringResource since this class is added to the class path and has access only
-  // to the public APIs.
-  private static String readAllBytesJava7(Path filePath) {
-    String content = "";
-
-    try {
-      content = new String(Files.readAllBytes(filePath));
-    } catch (IOException e) {
-      e.printStackTrace();
-    }
-
-    return content;
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/utils/CompileDumpUtils.java b/src/main/java/com/android/tools/r8/utils/CompileDumpUtils.java
index 14acc11..f0275f5 100644
--- a/src/main/java/com/android/tools/r8/utils/CompileDumpUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/CompileDumpUtils.java
@@ -7,6 +7,10 @@
 import com.android.tools.r8.KeepMethodForCompileDump;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.origin.PathOrigin;
+import com.android.tools.r8.profile.art.ArtProfileConsumer;
+import com.android.tools.r8.profile.art.ArtProfileConsumerUtils;
+import com.android.tools.r8.profile.art.ArtProfileProvider;
+import com.android.tools.r8.profile.art.ArtProfileProviderUtils;
 import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.startup.StartupProfileBuilder;
@@ -20,6 +24,16 @@
 class CompileDumpUtils {
 
   @KeepMethodForCompileDump
+  static ArtProfileProvider createArtProfileProviderFromDumpFile(Path artProfile) {
+    return ArtProfileProviderUtils.createFromHumanReadableArtProfile(artProfile);
+  }
+
+  @KeepMethodForCompileDump
+  static ArtProfileConsumer createResidualArtProfileConsumerFromDumpFile(Path residualArtProfile) {
+    return ArtProfileConsumerUtils.create(residualArtProfile);
+  }
+
+  @KeepMethodForCompileDump
   static StartupProfileProvider createStartupProfileProviderFromDumpFile(Path path) {
     return new StartupProfileProvider() {
 
diff --git a/tools/compiledump.py b/tools/compiledump.py
index 843c0b1..9c495a1 100755
--- a/tools/compiledump.py
+++ b/tools/compiledump.py
@@ -199,6 +199,16 @@
   def main_dex_rules_resource(self):
     return self.if_exists('main-dex-rules.txt')
 
+  def art_profile_resources(self):
+    art_profile_resources = []
+    while True:
+      current_art_profile_index = len(art_profile_resources) + 1
+      art_profile_resource = self.if_exists(
+          'art-profile-%s.txt' % current_art_profile_index)
+      if art_profile_resource is None:
+        return art_profile_resources
+      art_profile_resources.append(art_profile_resource)
+
   def startup_profile_resources(self):
     startup_profile_resources = []
     while True:
@@ -316,6 +326,9 @@
     return build_properties.get('min-api')
   return None
 
+def determine_residual_art_profile_output(art_profile, temp):
+  return os.path.join(temp, os.path.basename(art_profile)[:-4] + ".out.txt")
+
 def determine_desugared_lib_pg_conf_output(temp):
   return os.path.join(temp, 'desugared-library-keep-rules.config')
 
@@ -412,7 +425,7 @@
   return False
 
 def prepare_r8_wrapper(dist, temp, jdkhome):
-  compile_with_javac(
+  compile_wrapper_with_javac(
     dist,
     temp,
     jdkhome,
@@ -421,7 +434,7 @@
       'src/main/java/com/android/tools/r8/utils/CompileDumpCompatR8.java'))
 
 def prepare_d8_wrapper(dist, temp, jdkhome):
-  compile_with_javac(
+  compile_wrapper_with_javac(
     dist,
     temp,
     jdkhome,
@@ -429,10 +442,14 @@
       utils.REPO_ROOT,
       'src/main/java/com/android/tools/r8/utils/CompileDumpD8.java'))
 
-def compile_with_javac(dist, temp, jdkhome, path):
+def compile_wrapper_with_javac(dist, temp, jdkhome, path):
+  base_path = os.path.join(
+      utils.REPO_ROOT,
+      'src/main/java/com/android/tools/r8/utils/CompileDumpBase.java')
   cmd = [
     jdk.GetJavacExecutable(jdkhome),
     path,
+    base_path,
     '-d', temp,
     '-cp', dist,
   ]
@@ -545,6 +562,11 @@
       cmd.extend(['--main-dex-list', dump.main_dex_list_resource()])
     if dump.main_dex_rules_resource():
       cmd.extend(['--main-dex-rules', dump.main_dex_rules_resource()])
+    for art_profile_resource in dump.art_profile_resources():
+      residual_art_profile_output = \
+          determine_residual_art_profile_output(art_profile_resource, temp)
+      cmd.extend([
+          '--art-profile', art_profile_resource, residual_art_profile_output])
     for startup_profile_resource in dump.startup_profile_resources():
       cmd.extend(['--startup-profile', startup_profile_resource])
     if min_api: