Use profile rewriting framework for startup profile

Bug: b/271822426
Change-Id: I76130d01b061bfd03efbc2b863272327d1ab5aac
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/rewriting/StartupProfileAdditions.java b/src/main/java/com/android/tools/r8/experimental/startup/rewriting/StartupProfileAdditions.java
index 1f12cb3..2522234 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/rewriting/StartupProfileAdditions.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/rewriting/StartupProfileAdditions.java
@@ -14,7 +14,6 @@
 import com.android.tools.r8.profile.art.rewriting.ProfileAdditions;
 import java.util.Comparator;
 
-// TODO(b/271822426): Use to include synthetics in startup profile.
 public class StartupProfileAdditions
     extends ProfileAdditions<
         StartupProfileAdditions,
@@ -26,7 +25,7 @@
         StartupProfile,
         StartupProfile.Builder> {
 
-  StartupProfileAdditions(StartupProfile profile) {
+  public StartupProfileAdditions(StartupProfile profile) {
     super(profile);
   }
 
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
index b3381c3..32dd38f 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -193,6 +193,7 @@
     // Amend art profile collection.
     profileCollectionAdditions
         .setArtProfileCollection(appView.getArtProfileCollection())
+        .setStartupProfile(appView.getStartupProfile())
         .commit(appView);
 
     // Record where the synthesized $r8$classId fields are read and written.
diff --git a/src/main/java/com/android/tools/r8/profile/art/ArtProfileCollection.java b/src/main/java/com/android/tools/r8/profile/art/ArtProfileCollection.java
index 0a256ba..a571922 100644
--- a/src/main/java/com/android/tools/r8/profile/art/ArtProfileCollection.java
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfileCollection.java
@@ -62,6 +62,8 @@
     return EmptyArtProfileCollection.getInstance();
   }
 
+  public abstract boolean isEmpty();
+
   public abstract boolean isNonEmpty();
 
   public abstract NonEmptyArtProfileCollection asNonEmpty();
diff --git a/src/main/java/com/android/tools/r8/profile/art/EmptyArtProfileCollection.java b/src/main/java/com/android/tools/r8/profile/art/EmptyArtProfileCollection.java
index b66f261..744ea4d 100644
--- a/src/main/java/com/android/tools/r8/profile/art/EmptyArtProfileCollection.java
+++ b/src/main/java/com/android/tools/r8/profile/art/EmptyArtProfileCollection.java
@@ -21,6 +21,11 @@
   }
 
   @Override
+  public boolean isEmpty() {
+    return true;
+  }
+
+  @Override
   public boolean isNonEmpty() {
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/profile/art/NonEmptyArtProfileCollection.java b/src/main/java/com/android/tools/r8/profile/art/NonEmptyArtProfileCollection.java
index 1d4756f..0cb809e 100644
--- a/src/main/java/com/android/tools/r8/profile/art/NonEmptyArtProfileCollection.java
+++ b/src/main/java/com/android/tools/r8/profile/art/NonEmptyArtProfileCollection.java
@@ -27,6 +27,11 @@
   }
 
   @Override
+  public boolean isEmpty() {
+    return false;
+  }
+
+  @Override
   public boolean isNonEmpty() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingCfPostProcessingDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingCfPostProcessingDesugaringEventConsumer.java
index d73b2ce..3012624 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingCfPostProcessingDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingCfPostProcessingDesugaringEventConsumer.java
@@ -80,7 +80,7 @@
   public void acceptDesugaredLibraryRetargeterForwardingMethod(
       ProgramMethod method, EmulatedDispatchMethodDescriptor descriptor) {
     if (options.isIncludingDesugaredLibraryRetargeterForwardingMethodsUnconditionally()) {
-      additionsCollection.apply(additions -> additions.addMethodRule(method, emptyConsumer()));
+      additionsCollection.accept(additions -> additions.addMethodRule(method, emptyConsumer()));
     }
     parent.acceptDesugaredLibraryRetargeterForwardingMethod(method, descriptor);
   }
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingNestBasedAccessDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingNestBasedAccessDesugaringEventConsumer.java
index 59346f70..0978cec 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingNestBasedAccessDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingNestBasedAccessDesugaringEventConsumer.java
@@ -46,7 +46,7 @@
           context.asProgramMethod(),
           additionsBuilder -> additionsBuilder.addRule(argumentClass).addRule(bridge));
     } else {
-      additionsCollection.apply(
+      additionsCollection.accept(
           additions ->
               additions.addClassRule(argumentClass).addMethodRule(bridge, emptyConsumer()));
     }
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ConcreteProfileCollectionAdditions.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ConcreteProfileCollectionAdditions.java
index 83cb551..90cbd6b 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ConcreteProfileCollectionAdditions.java
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ConcreteProfileCollectionAdditions.java
@@ -4,18 +4,20 @@
 
 package com.android.tools.r8.profile.art.rewriting;
 
+import com.android.tools.r8.experimental.startup.StartupProfile;
+import com.android.tools.r8.experimental.startup.rewriting.StartupProfileAdditions;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.profile.AbstractProfileMethodRule;
 import com.android.tools.r8.profile.art.ArtProfile;
 import com.android.tools.r8.profile.art.ArtProfileCollection;
-import com.android.tools.r8.profile.art.ArtProfileMethodRuleInfoImpl;
 import com.android.tools.r8.profile.art.NonEmptyArtProfileCollection;
 import com.android.tools.r8.profile.art.rewriting.ProfileAdditions.ProfileAdditionsBuilder;
+import com.android.tools.r8.utils.Box;
 import com.google.common.collect.Iterables;
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -26,19 +28,35 @@
 public class ConcreteProfileCollectionAdditions extends ProfileCollectionAdditions {
 
   private final List<ArtProfileAdditions> additionsCollection;
+  private final Box<StartupProfileAdditions> startupProfileAdditions;
 
   private boolean committed = false;
 
-  private ConcreteProfileCollectionAdditions(List<ArtProfileAdditions> additionsCollection) {
+  private ConcreteProfileCollectionAdditions(
+      List<ArtProfileAdditions> additionsCollection,
+      Box<StartupProfileAdditions> startupProfileAdditions) {
     this.additionsCollection = additionsCollection;
+    this.startupProfileAdditions = startupProfileAdditions;
   }
 
-  ConcreteProfileCollectionAdditions(NonEmptyArtProfileCollection artProfileCollection) {
+  ConcreteProfileCollectionAdditions(
+      ArtProfileCollection artProfileCollection, StartupProfile startupProfile) {
     additionsCollection = new ArrayList<>();
-    for (ArtProfile artProfile : artProfileCollection) {
-      additionsCollection.add(new ArtProfileAdditions(artProfile));
+    if (artProfileCollection.isNonEmpty()) {
+      for (ArtProfile artProfile : artProfileCollection.asNonEmpty()) {
+        additionsCollection.add(new ArtProfileAdditions(artProfile));
+      }
+      assert !additionsCollection.isEmpty();
     }
-    assert !additionsCollection.isEmpty();
+    startupProfileAdditions =
+        new Box<>(startupProfile.isEmpty() ? null : new StartupProfileAdditions(startupProfile));
+  }
+
+  void accept(Consumer<ProfileAdditions<?, ?, ?, ?, ?, ?, ?, ?>> additionsConsumer) {
+    for (ArtProfileAdditions additions : additionsCollection) {
+      additionsConsumer.accept(additions);
+    }
+    startupProfileAdditions.accept(additionsConsumer);
   }
 
   @Override
@@ -49,18 +67,11 @@
   public void addMethodIfContextIsInProfile(
       ProgramMethod method,
       DexClassAndMethod context,
-      Consumer<ArtProfileMethodRuleInfoImpl.Builder> methodRuleInfoBuilderConsumer) {
+      Consumer<AbstractProfileMethodRule.Builder<?, ?>> methodRuleBuilderConsumer) {
     if (context.isProgramMethod()) {
-      applyIfContextIsInProfile(
-          context.asProgramMethod(), additionsBuilder -> additionsBuilder.addRule(method));
+      addMethodIfContextIsInProfile(method, context.asProgramMethod());
     } else {
-      apply(
-          artProfileAdditions ->
-              artProfileAdditions.addMethodRule(
-                  method,
-                  methodRuleBuilder ->
-                      methodRuleBuilder.acceptMethodRuleInfoBuilder(
-                          methodRuleInfoBuilderConsumer)));
+      accept(additions -> additions.addMethodRule(method, methodRuleBuilderConsumer));
     }
   }
 
@@ -69,15 +80,9 @@
         context, additionsBuilder -> additionsBuilder.addRule(method).addRule(method.getHolder()));
   }
 
-  void apply(Consumer<ArtProfileAdditions> additionsConsumer) {
-    for (ArtProfileAdditions artProfileAdditions : additionsCollection) {
-      additionsConsumer.accept(artProfileAdditions);
-    }
-  }
-
   void applyIfContextIsInProfile(
       ProgramDefinition context,
-      Consumer<ArtProfileAdditions> additionsConsumer,
+      Consumer<ProfileAdditions<?, ?, ?, ?, ?, ?, ?, ?>> additionsConsumer,
       Consumer<ProfileAdditionsBuilder> additionsBuilderConsumer) {
     if (context.isProgramClass()) {
       applyIfContextIsInProfile(context.asProgramClass(), additionsConsumer);
@@ -88,14 +93,9 @@
   }
 
   void applyIfContextIsInProfile(
-      DexProgramClass context, Consumer<ArtProfileAdditions> additionsConsumer) {
-    applyIfContextIsInProfile(context.getType(), additionsConsumer);
-  }
-
-  void applyIfContextIsInProfile(DexType type, Consumer<ArtProfileAdditions> additionsConsumer) {
-    for (ArtProfileAdditions artProfileAdditions : additionsCollection) {
-      artProfileAdditions.applyIfContextIsInProfile(type, additionsConsumer);
-    }
+      DexProgramClass context,
+      Consumer<ProfileAdditions<?, ?, ?, ?, ?, ?, ?, ?>> additionsConsumer) {
+    accept(additions -> additions.applyIfContextIsInProfile(context.getType(), additionsConsumer));
   }
 
   public void applyIfContextIsInProfile(
@@ -106,9 +106,7 @@
   @Override
   public void applyIfContextIsInProfile(
       DexMethod context, Consumer<ProfileAdditionsBuilder> builderConsumer) {
-    for (ArtProfileAdditions artProfileAdditions : additionsCollection) {
-      artProfileAdditions.applyIfContextIsInProfile(context, builderConsumer);
-    }
+    accept(additions -> additions.applyIfContextIsInProfile(context, builderConsumer));
   }
 
   @Override
@@ -119,14 +117,17 @@
   @Override
   public void commit(AppView<?> appView) {
     assert !committed;
-    if (hasAdditions()) {
+    if (hasArtProfileAdditions()) {
       appView.setArtProfileCollection(createNewArtProfileCollection());
     }
+    if (hasStartupProfileAdditions()) {
+      appView.setStartupProfile(createNewStartupProfile());
+    }
     committed = true;
   }
 
   private ArtProfileCollection createNewArtProfileCollection() {
-    assert hasAdditions();
+    assert hasArtProfileAdditions();
     List<ArtProfile> newArtProfiles = new ArrayList<>(additionsCollection.size());
     for (ArtProfileAdditions additions : additionsCollection) {
       newArtProfiles.add(additions.createNewProfile());
@@ -134,8 +135,17 @@
     return new NonEmptyArtProfileCollection(newArtProfiles);
   }
 
-  private boolean hasAdditions() {
-    return Iterables.any(additionsCollection, ArtProfileAdditions::hasAdditions);
+  private StartupProfile createNewStartupProfile() {
+    assert hasStartupProfileAdditions();
+    return startupProfileAdditions.get().createNewProfile();
+  }
+
+  private boolean hasArtProfileAdditions() {
+    return Iterables.any(additionsCollection, ProfileAdditions::hasAdditions);
+  }
+
+  private boolean hasStartupProfileAdditions() {
+    return startupProfileAdditions.test(ProfileAdditions::hasAdditions);
   }
 
   @Override
@@ -146,21 +156,34 @@
     for (ArtProfileAdditions additions : additionsCollection) {
       rewrittenAdditionsCollection.add(additions.rewriteMethodReferences(methodFn));
     }
-    return new ConcreteProfileCollectionAdditions(rewrittenAdditionsCollection);
+    Box<StartupProfileAdditions> rewrittenStartupProfileAdditions =
+        startupProfileAdditions.rebuild(additions -> additions.rewriteMethodReferences(methodFn));
+    return new ConcreteProfileCollectionAdditions(
+        rewrittenAdditionsCollection, rewrittenStartupProfileAdditions);
   }
 
   @Override
   public ConcreteProfileCollectionAdditions setArtProfileCollection(
       ArtProfileCollection artProfileCollection) {
-    assert artProfileCollection.isNonEmpty();
-    Iterator<ArtProfile> artProfileIterator = artProfileCollection.asNonEmpty().iterator();
-    for (ArtProfileAdditions additions : additionsCollection) {
-      additions.setProfile(artProfileIterator.next());
+    if (artProfileCollection.isNonEmpty()) {
+      Iterator<ArtProfile> artProfileIterator = artProfileCollection.asNonEmpty().iterator();
+      for (ArtProfileAdditions additions : additionsCollection) {
+        additions.setProfile(artProfileIterator.next());
+      }
+    } else {
+      assert additionsCollection.isEmpty();
+      assert startupProfileAdditions.isSet();
     }
     return this;
   }
 
   @Override
+  public ProfileCollectionAdditions setStartupProfile(StartupProfile startupProfile) {
+    startupProfileAdditions.accept(additions -> additions.setProfile(startupProfile));
+    return this;
+  }
+
+  @Override
   public boolean verifyIsCommitted() {
     assert committed;
     return true;
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/NopProfileCollectionAdditions.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/NopProfileCollectionAdditions.java
index 7cad8bf..d27a083 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/NopProfileCollectionAdditions.java
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/NopProfileCollectionAdditions.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.profile.art.rewriting;
 
+import com.android.tools.r8.experimental.startup.StartupProfile;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -58,6 +59,12 @@
   }
 
   @Override
+  public NopProfileCollectionAdditions setStartupProfile(StartupProfile startupProfile) {
+    // Intentionally empty.
+    return this;
+  }
+
+  @Override
   public boolean verifyIsCommitted() {
     // Nothing to commit.
     return true;
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileAdditions.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileAdditions.java
index d4bd1bc..3df9866 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileAdditions.java
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileAdditions.java
@@ -90,13 +90,13 @@
     this.profile = profile;
   }
 
-  void applyIfContextIsInProfile(DexType context, Consumer<Additions> fn) {
+  public void applyIfContextIsInProfile(DexType context, Consumer<? super Additions> fn) {
     if (profile.containsClassRule(context) || classRuleAdditions.containsKey(context)) {
       fn.accept(self());
     }
   }
 
-  void applyIfContextIsInProfile(
+  public void applyIfContextIsInProfile(
       DexMethod context, Consumer<ProfileAdditionsBuilder> builderConsumer) {
     MethodRule contextMethodRule = profile.getMethodRule(context);
     if (contextMethodRule != null) {
@@ -163,12 +163,12 @@
   }
 
   public Additions addMethodRule(
-      DexClassAndMethod method, Consumer<MethodRuleBuilder> methodRuleBuilderConsumer) {
+      DexClassAndMethod method, Consumer<? super MethodRuleBuilder> methodRuleBuilderConsumer) {
     return addMethodRule(method.getReference(), methodRuleBuilderConsumer);
   }
 
   public Additions addMethodRule(
-      DexMethod method, Consumer<MethodRuleBuilder> methodRuleBuilderConsumer) {
+      DexMethod method, Consumer<? super MethodRuleBuilder> methodRuleBuilderConsumer) {
     // Create profile rule for method.
     MethodRuleBuilder methodRuleBuilder =
         methodRuleAdditions.computeIfAbsent(method, this::createMethodRuleBuilder);
@@ -187,7 +187,7 @@
     methodRuleRemovals.add(oldMethod);
   }
 
-  Profile createNewProfile() {
+  public Profile createNewProfile() {
     if (!hasAdditions()) {
       assert !hasRemovals();
       return profile;
@@ -229,7 +229,7 @@
     return profileBuilder.build();
   }
 
-  boolean hasAdditions() {
+  public boolean hasAdditions() {
     return !classRuleAdditions.isEmpty() || !methodRuleAdditions.isEmpty();
   }
 
@@ -237,7 +237,7 @@
     return !methodRuleRemovals.isEmpty();
   }
 
-  Additions rewriteMethodReferences(Function<DexMethod, DexMethod> methodFn) {
+  public Additions rewriteMethodReferences(Function<DexMethod, DexMethod> methodFn) {
     Additions rewrittenAdditions = create();
     assert methodRuleRemovals.isEmpty();
     rewrittenAdditions.classRuleAdditions.putAll(classRuleAdditions);
@@ -264,7 +264,7 @@
 
   public abstract Additions self();
 
-  void setProfile(Profile profile) {
+  public void setProfile(Profile profile) {
     this.profile = profile;
   }
 
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileCollectionAdditions.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileCollectionAdditions.java
index 31af956..93be945 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileCollectionAdditions.java
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileCollectionAdditions.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.profile.art.rewriting;
 
+import com.android.tools.r8.experimental.startup.StartupProfile;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -26,10 +27,11 @@
 
   public static ProfileCollectionAdditions create(AppView<?> appView) {
     ArtProfileCollection artProfileCollection = appView.getArtProfileCollection();
-    if (artProfileCollection.isNonEmpty()) {
-      return new ConcreteProfileCollectionAdditions(artProfileCollection.asNonEmpty());
+    StartupProfile startupProfile = appView.getStartupProfile();
+    if (artProfileCollection.isEmpty() && startupProfile.isEmpty()) {
+      return nop();
     }
-    return nop();
+    return new ConcreteProfileCollectionAdditions(artProfileCollection, startupProfile);
   }
 
   public static NopProfileCollectionAdditions nop() {
@@ -57,5 +59,7 @@
   public abstract ProfileCollectionAdditions setArtProfileCollection(
       ArtProfileCollection artProfileCollection);
 
+  public abstract ProfileCollectionAdditions setStartupProfile(StartupProfile startupProfile);
+
   public abstract boolean verifyIsCommitted();
 }
diff --git a/src/main/java/com/android/tools/r8/utils/Box.java b/src/main/java/com/android/tools/r8/utils/Box.java
index 1134718..00fde15 100644
--- a/src/main/java/com/android/tools/r8/utils/Box.java
+++ b/src/main/java/com/android/tools/r8/utils/Box.java
@@ -5,6 +5,8 @@
 package com.android.tools.r8.utils;
 
 import java.util.Comparator;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
 import java.util.function.Supplier;
 
 public class Box<T> extends BoxBase<T> {
@@ -16,6 +18,11 @@
   }
 
   @Override
+  public void accept(Consumer<? super T> consumer) {
+    super.accept(consumer);
+  }
+
+  @Override
   public void clear() {
     super.clear();
   }
@@ -35,6 +42,13 @@
     return super.getAndSet(newValue);
   }
 
+  public <E extends Exception> Box<T> rebuild(ThrowingFunction<T, T, E> fn) throws E {
+    if (isSet()) {
+      return new Box<>(fn.apply(get()));
+    }
+    return new Box<>();
+  }
+
   @Override
   public void set(T value) {
     super.set(value);
@@ -44,4 +58,9 @@
   public void setMin(T value, Comparator<T> comparator) {
     super.setMin(value, comparator);
   }
+
+  @Override
+  public boolean test(Predicate<T> predicate) {
+    return super.test(predicate);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/utils/BoxBase.java b/src/main/java/com/android/tools/r8/utils/BoxBase.java
index 93f70da..c2b4492 100644
--- a/src/main/java/com/android/tools/r8/utils/BoxBase.java
+++ b/src/main/java/com/android/tools/r8/utils/BoxBase.java
@@ -6,7 +6,9 @@
 
 import java.util.Comparator;
 import java.util.Objects;
+import java.util.function.Consumer;
 import java.util.function.Function;
+import java.util.function.Predicate;
 import java.util.function.Supplier;
 
 public abstract class BoxBase<T> {
@@ -19,6 +21,12 @@
     set(initialValue);
   }
 
+  void accept(Consumer<? super T> consumer) {
+    if (isSet()) {
+      consumer.accept(get());
+    }
+  }
+
   void clear() {
     set(null);
   }
@@ -56,6 +64,10 @@
     }
   }
 
+  boolean test(Predicate<T> predicate) {
+    return isSet() && predicate.test(get());
+  }
+
   public boolean isSet() {
     return value != null;
   }