Introduce a StartupProfileProvider interface

This changes the provided startup profile to be typed as a StartupProfileProvider.

This is consistent with other input providers, e.g., MapIdProvider, SourceFileProvider.

Change-Id: I37dfb011753a60e2b91efa6d16a717273cd2cc8d
diff --git a/src/main/java/com/android/tools/r8/StartupProfileProvider.java b/src/main/java/com/android/tools/r8/StartupProfileProvider.java
new file mode 100644
index 0000000..fc5e4b1
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/StartupProfileProvider.java
@@ -0,0 +1,13 @@
+// Copyright (c) 2022, 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;
+
+/** Interface for providing a startup profile to the compiler. */
+@FunctionalInterface
+public interface StartupProfileProvider {
+
+  /** Return the startup profile. */
+  String get();
+}
diff --git a/src/main/java/com/android/tools/r8/StringResource.java b/src/main/java/com/android/tools/r8/StringResource.java
index a28f936..515f2ab 100644
--- a/src/main/java/com/android/tools/r8/StringResource.java
+++ b/src/main/java/com/android/tools/r8/StringResource.java
@@ -33,7 +33,7 @@
    *
    * @param file Path of file with UTF-8 encoded text.
    */
-  static StringResource fromFile(Path file) {
+  static FileResource fromFile(Path file) {
     return fromFile(file, StandardCharsets.UTF_8);
   }
 
@@ -45,7 +45,7 @@
    * @param file Path of file.
    * @param charset Charset coding of file.
    */
-  static StringResource fromFile(Path file, Charset charset) {
+  static FileResource fromFile(Path file, Charset charset) {
     return new FileResource(file, charset);
   }
 
@@ -74,7 +74,7 @@
     }
 
     @Override
-    public String getString() throws ResourceException {
+    public String getString() {
       return content;
     }
   }
@@ -105,5 +105,13 @@
         throw new ResourceException(origin, e);
       }
     }
+
+    public String getStringWithRuntimeException() {
+      try {
+        return getString();
+      } catch (ResourceException e) {
+        throw new RuntimeException(e);
+      }
+    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/dex/VirtualFile.java b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
index e9330aa..fafe700 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -1396,7 +1396,7 @@
         return;
       }
 
-      assert options.getStartupOptions().hasStartupProfile();
+      assert options.getStartupOptions().hasStartupProfileProvider();
 
       // In practice, all startup classes should fit in a single dex file, so optimistically try to
       // commit the startup classes using a single transaction.
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupOptions.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupOptions.java
index 1d37b90..7d1b4dc 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/StartupOptions.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupOptions.java
@@ -6,6 +6,7 @@
 
 import static com.android.tools.r8.utils.SystemPropertyUtils.parseSystemPropertyForDevelopmentOrDefault;
 
+import com.android.tools.r8.StartupProfileProvider;
 import com.android.tools.r8.StringResource;
 import com.android.tools.r8.utils.SystemPropertyUtils;
 import java.nio.file.Paths;
@@ -48,10 +49,11 @@
   private boolean enableStartupLayoutOptimizations =
       parseSystemPropertyForDevelopmentOrDefault("com.android.tools.r8.startup.layout", true);
 
-  private StringResource startupProfile =
+  private StartupProfileProvider startupProfileProvider =
       SystemPropertyUtils.applySystemProperty(
           "com.android.tools.r8.startup.profile",
-          propertyValue -> StringResource.fromFile(Paths.get(propertyValue)),
+          propertyValue ->
+              StringResource.fromFile(Paths.get(propertyValue))::getStringWithRuntimeException,
           () -> null);
 
   public boolean isMinimalStartupDexEnabled() {
@@ -91,16 +93,16 @@
     return this;
   }
 
-  public boolean hasStartupProfile() {
-    return startupProfile != null;
+  public boolean hasStartupProfileProvider() {
+    return startupProfileProvider != null;
   }
 
-  public StringResource getStartupProfile() {
-    return startupProfile;
+  public StartupProfileProvider getStartupProfileProvider() {
+    return startupProfileProvider;
   }
 
-  public StartupOptions setStartupProfile(StringResource startupProfile) {
-    this.startupProfile = startupProfile;
+  public StartupOptions setStartupProfileProvider(StartupProfileProvider startupProfileProvider) {
+    this.startupProfileProvider = startupProfileProvider;
     return this;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java
index 821b86c..20cd31b 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java
@@ -4,8 +4,7 @@
 
 package com.android.tools.r8.experimental.startup;
 
-import com.android.tools.r8.ResourceException;
-import com.android.tools.r8.StringResource;
+import com.android.tools.r8.StartupProfileProvider;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.utils.InternalOptions;
@@ -44,16 +43,12 @@
    * </pre>
    */
   public static StartupProfile parseStartupProfile(InternalOptions options) {
-    if (!options.getStartupOptions().hasStartupProfile()) {
+    if (!options.getStartupOptions().hasStartupProfileProvider()) {
       return null;
     }
-    try {
-      StringResource resource = options.getStartupOptions().getStartupProfile();
-      List<String> startupDescriptors = StringUtils.splitLines(resource.getString());
-      return createStartupConfigurationFromLines(options, startupDescriptors);
-    } catch (ResourceException e) {
-      throw new RuntimeException(e);
-    }
+    StartupProfileProvider resource = options.getStartupOptions().getStartupProfileProvider();
+    List<String> startupDescriptors = StringUtils.splitLines(resource.get());
+    return createStartupConfigurationFromLines(options, startupDescriptors);
   }
 
   public static StartupProfile createStartupConfigurationFromLines(
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingWithStartupClassesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingWithStartupClassesTest.java
index dee7541..417a097 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingWithStartupClassesTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingWithStartupClassesTest.java
@@ -5,13 +5,12 @@
 package com.android.tools.r8.classmerging.horizontal;
 
 import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.StringResource;
+import com.android.tools.r8.StartupProfileProvider;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.experimental.startup.StartupClass;
 import com.android.tools.r8.experimental.startup.StartupProfile;
 import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.google.common.collect.ImmutableList;
 import java.util.Collections;
@@ -64,9 +63,8 @@
                                                       toDexType(startupClass, dexItemFactory))
                                                   .build())))
                       .build();
-              StringResource startupProfileResource =
-                  StringResource.fromString(startupProfile.serializeToString(), Origin.unknown());
-              options.getStartupOptions().setStartupProfile(startupProfileResource);
+              StartupProfileProvider startupProfileProvider = startupProfile::serializeToString;
+              options.getStartupOptions().setStartupProfileProvider(startupProfileProvider);
             })
         .addHorizontallyMergedClassesInspector(
             inspector ->
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeV1719Test.java b/src/test/java/com/android/tools/r8/internal/YouTubeV1719Test.java
index 18921a8..e293b6e 100644
--- a/src/test/java/com/android/tools/r8/internal/YouTubeV1719Test.java
+++ b/src/test/java/com/android/tools/r8/internal/YouTubeV1719Test.java
@@ -21,6 +21,7 @@
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.ResourceException;
+import com.android.tools.r8.StartupProfileProvider;
 import com.android.tools.r8.StringConsumer.FileConsumer;
 import com.android.tools.r8.StringResource;
 import com.android.tools.r8.TestCompileResult;
@@ -57,7 +58,7 @@
 
   // By setting this to an actual startup list, YouTube will be build with layout optimizations
   // enabled.
-  private final StringResource startupProfile = null;
+  private final StartupProfileProvider startupProfileProvider = null;
   private final boolean enableMinimalStartupDex = true;
   private final boolean enableStartupBoundaryOptimizations = false;
 
@@ -131,8 +132,8 @@
    * Running this test will dump an R8 build of YouTube in the {@link #dumpDirectory}, where the
    * desugared library keep rules are generated using trace references.
    *
-   * <p>If {@link #startupProfile} is set to a concrete startup list, YouTube will be build with
-   * layout optimizations enabled.
+   * <p>If {@link #startupProfileProvider} is set to a concrete startup list, YouTube will be build
+   * with layout optimizations enabled.
    */
   @Test
   public void testR8() throws Exception {
@@ -145,10 +146,10 @@
             testBuilder ->
                 testBuilder.addOptionsModification(
                     options -> {
-                      if (startupProfile != null) {
+                      if (startupProfileProvider != null) {
                         options
                             .getStartupOptions()
-                            .setStartupProfile(startupProfile)
+                            .setStartupProfileProvider(startupProfileProvider)
                             .setEnableMinimalStartupDex(enableMinimalStartupDex)
                             .setEnableStartupBoundaryOptimizations(
                                 enableStartupBoundaryOptimizations);
diff --git a/src/test/java/com/android/tools/r8/internal/startup/ChromeStartupTest.java b/src/test/java/com/android/tools/r8/internal/startup/ChromeStartupTest.java
index e75c5ba..89b37d0 100644
--- a/src/test/java/com/android/tools/r8/internal/startup/ChromeStartupTest.java
+++ b/src/test/java/com/android/tools/r8/internal/startup/ChromeStartupTest.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.ArchiveProgramResourceProvider;
 import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.StartupProfileProvider;
 import com.android.tools.r8.StringResource;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
@@ -234,7 +235,9 @@
       boolean enableStartupBoundaryOptimizations,
       Path outDirectory)
       throws Exception {
-    StringResource startupProfile = StringResource.fromFile(chromeDirectory.resolve("startup.txt"));
+    StartupProfileProvider startupProfileProvider =
+        StringResource.fromFile(chromeDirectory.resolve("startup.txt"))
+            ::getStringWithRuntimeException;
     buildR8(
         testBuilder ->
             testBuilder.addOptionsModification(
@@ -243,7 +246,7 @@
                         .getStartupOptions()
                         .setEnableMinimalStartupDex(enableMinimalStartupDex)
                         .setEnableStartupBoundaryOptimizations(enableStartupBoundaryOptimizations)
-                        .setStartupProfile(startupProfile)),
+                        .setStartupProfileProvider(startupProfileProvider)),
         outDirectory);
   }
 
diff --git a/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java b/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java
index 37b75c2..ec7e59f 100644
--- a/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java
+++ b/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java
@@ -10,7 +10,7 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.D8TestBuilder;
 import com.android.tools.r8.D8TestRunResult;
-import com.android.tools.r8.StringResource;
+import com.android.tools.r8.StartupProfileProvider;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestCompilerBuilder;
 import com.android.tools.r8.TestParameters;
@@ -22,7 +22,6 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.references.TypeReference;
@@ -158,9 +157,8 @@
                                   builder.addStartupItem(
                                       convertStartupItemToDex(startupItem, dexItemFactory))))
                   .build();
-          StringResource startupProfileResource =
-              StringResource.fromString(startupProfile.serializeToString(), Origin.unknown());
-          options.getStartupOptions().setStartupProfile(startupProfileResource);
+          StartupProfileProvider startupProfileProvider = startupProfile::serializeToString;
+          options.getStartupOptions().setStartupProfileProvider(startupProfileProvider);
         });
   }