Minor cleanup of profile rewriting event consumers

Change-Id: I0e5b7706cb99b476aed2413fdf4581beeecf0cd2
diff --git a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubberEventConsumer.java b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubberEventConsumer.java
index ac79346..7c42536 100644
--- a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubberEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubberEventConsumer.java
@@ -7,9 +7,7 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexLibraryClass;
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.profile.art.rewriting.ArtProfileCollectionAdditions;
 import com.android.tools.r8.profile.art.rewriting.ArtProfileRewritingApiReferenceStubberEventConsumer;
-import com.android.tools.r8.profile.art.rewriting.ConcreteArtProfileCollectionAdditions;
 
 public interface ApiReferenceStubberEventConsumer {
 
@@ -23,20 +21,7 @@
   boolean isEmpty();
 
   static ApiReferenceStubberEventConsumer create(AppView<?> appView) {
-    if (appView.options().getArtProfileOptions().isIncludingApiReferenceStubs()) {
-      ArtProfileCollectionAdditions artProfileCollectionAdditions =
-          ArtProfileCollectionAdditions.create(appView);
-      if (!artProfileCollectionAdditions.isNop()) {
-        return create(artProfileCollectionAdditions.asConcrete());
-      }
-    }
-    return empty();
-  }
-
-  static ApiReferenceStubberEventConsumer create(
-      ConcreteArtProfileCollectionAdditions artProfileCollectionAdditions) {
-    return ArtProfileRewritingApiReferenceStubberEventConsumer.attach(
-        artProfileCollectionAdditions, empty());
+    return ArtProfileRewritingApiReferenceStubberEventConsumer.attach(appView, empty());
   }
 
   static EmptyApiReferenceStubberEventConsumer empty() {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java b/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java
index 7a04167..54c3231 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java
@@ -50,7 +50,7 @@
       ExecutorService executorService) {
     this.artProfileCollectionAdditions = artProfileCollectionAdditions;
     this.converter = converter;
-    this.eventConsumer = MethodProcessorEventConsumer.create(artProfileCollectionAdditions);
+    this.eventConsumer = MethodProcessorEventConsumer.createForD8(artProfileCollectionAdditions);
     this.executorService = executorService;
     this.processorContext = converter.appView.createProcessorContext();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/MethodProcessorEventConsumer.java b/src/main/java/com/android/tools/r8/ir/conversion/MethodProcessorEventConsumer.java
index ff9c34c..16c6ce0 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/MethodProcessorEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/MethodProcessorEventConsumer.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.ir.conversion;
 
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.optimize.ServiceLoaderRewriterEventConsumer;
 import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizationsEventConsumer;
@@ -11,6 +13,7 @@
 import com.android.tools.r8.ir.optimize.enums.EnumUnboxerMethodProcessorEventConsumer;
 import com.android.tools.r8.profile.art.rewriting.ArtProfileCollectionAdditions;
 import com.android.tools.r8.profile.art.rewriting.ArtProfileRewritingMethodProcessorEventConsumer;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public abstract class MethodProcessorEventConsumer
     implements EnumUnboxerMethodProcessorEventConsumer,
@@ -18,12 +21,19 @@
         ServiceLoaderRewriterEventConsumer,
         UtilityMethodsForCodeOptimizationsEventConsumer {
 
-  public static MethodProcessorEventConsumer create(
+  public void finished(AppView<AppInfoWithLiveness> appView) {}
+
+  public static MethodProcessorEventConsumer createForD8(
       ArtProfileCollectionAdditions artProfileCollectionAdditions) {
     return ArtProfileRewritingMethodProcessorEventConsumer.attach(
         artProfileCollectionAdditions, empty());
   }
 
+  public static MethodProcessorEventConsumer createForR8(
+      AppView<? extends AppInfoWithClassHierarchy> appView) {
+    return ArtProfileRewritingMethodProcessorEventConsumer.attach(appView, empty());
+  }
+
   public static MethodProcessorEventConsumer empty() {
     return EmptyMethodProcessorEventConsumer.getInstance();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java
index aae02ab..3b7fcef 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java
@@ -16,7 +16,6 @@
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagator;
-import com.android.tools.r8.profile.art.rewriting.ArtProfileCollectionAdditions;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.CfgPrinter;
 import com.android.tools.r8.utils.Timing;
@@ -82,10 +81,8 @@
         new PostMethodProcessor.Builder(graphLensForPrimaryOptimizationPass);
     {
       timing.begin("Build primary method processor");
-      ArtProfileCollectionAdditions artProfileCollectionAdditions =
-          ArtProfileCollectionAdditions.create(appView);
       MethodProcessorEventConsumer eventConsumer =
-          MethodProcessorEventConsumer.create(artProfileCollectionAdditions);
+          MethodProcessorEventConsumer.createForR8(appView);
       PrimaryMethodProcessor primaryMethodProcessor =
           PrimaryMethodProcessor.create(
               appView.withLiveness(), eventConsumer, executorService, timing);
@@ -101,7 +98,7 @@
           timing,
           executorService);
       lastWaveDone(postMethodProcessorBuilder, executorService);
-      timing.time("Commit profile additions", () -> artProfileCollectionAdditions.commit(appView));
+      eventConsumer.finished(appView);
       assert appView.graphLens() == graphLensForPrimaryOptimizationPass;
       timing.end();
     }
@@ -155,17 +152,14 @@
 
     {
       timing.begin("IR conversion phase 2");
-      ArtProfileCollectionAdditions artProfileCollectionAdditions =
-          ArtProfileCollectionAdditions.create(appView);
+      MethodProcessorEventConsumer eventConsumer =
+          MethodProcessorEventConsumer.createForR8(appView);
       PostMethodProcessor postMethodProcessor =
           timing.time(
               "Build post method processor",
-              () -> {
-                MethodProcessorEventConsumer eventConsumer =
-                    MethodProcessorEventConsumer.create(artProfileCollectionAdditions);
-                return postMethodProcessorBuilder.build(
-                    appView, eventConsumer, executorService, timing);
-              });
+              () ->
+                  postMethodProcessorBuilder.build(
+                      appView, eventConsumer, executorService, timing));
       if (postMethodProcessor != null) {
         assert !options.debug;
         assert appView.graphLens() == graphLensForSecondaryOptimizationPass;
@@ -179,8 +173,7 @@
             timing);
         timing.end();
         timing.time("Update visible optimization info", feedback::updateVisibleOptimizationInfo);
-        timing.time(
-            "Commit profile additions", () -> artProfileCollectionAdditions.commit(appView));
+        eventConsumer.finished(appView);
         assert appView.graphLens() == graphLensForSecondaryOptimizationPass;
       }
       timing.end();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlineOptimizationEventConsumer.java b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlineOptimizationEventConsumer.java
index 4d8a9ed..86ac8ab 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlineOptimizationEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlineOptimizationEventConsumer.java
@@ -4,32 +4,20 @@
 
 package com.android.tools.r8.ir.optimize.outliner;
 
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.profile.art.rewriting.ArtProfileCollectionAdditions;
-import com.android.tools.r8.profile.art.rewriting.ConcreteArtProfileCollectionAdditions;
+import com.android.tools.r8.profile.art.rewriting.ArtProfileRewritingOutlineOptimizationEventConsumer;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.Collection;
 
 public interface OutlineOptimizationEventConsumer {
 
   void acceptOutlineMethod(ProgramMethod method, Collection<ProgramMethod> contexts);
 
-  static OutlineOptimizationEventConsumer create(
-      ArtProfileCollectionAdditions collectionAdditions) {
-    if (collectionAdditions.isNop()) {
-      return empty();
-    }
-    return create(collectionAdditions.asConcrete());
-  }
+  void finished(AppView<AppInfoWithLiveness> appView);
 
-  static OutlineOptimizationEventConsumer create(
-      ConcreteArtProfileCollectionAdditions collectionAdditions) {
-    return (method, contexts) -> {
-      for (ProgramMethod context : contexts) {
-        collectionAdditions.applyIfContextIsInProfile(
-            context,
-            additionsBuilder -> additionsBuilder.addRule(method).addRule(method.getHolder()));
-      }
-    };
+  static OutlineOptimizationEventConsumer create(AppView<AppInfoWithLiveness> appView) {
+    return ArtProfileRewritingOutlineOptimizationEventConsumer.attach(appView, empty());
   }
 
   static EmptyOutlineOptimizationEventConsumer empty() {
@@ -51,5 +39,10 @@
     public void acceptOutlineMethod(ProgramMethod method, Collection<ProgramMethod> contexts) {
       // Intentionally empty.
     }
+
+    @Override
+    public void finished(AppView<AppInfoWithLiveness> appView) {
+      // Intentionally empty.
+    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
index 7382a1e..b56f246 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
@@ -68,7 +68,6 @@
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackIgnore;
 import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.profile.art.rewriting.ArtProfileCollectionAdditions;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
@@ -1342,6 +1341,8 @@
     timing.begin("IR conversion phase 3");
     ProgramMethodSet methodsSelectedForOutlining = selectMethodsForOutlining();
     if (!methodsSelectedForOutlining.isEmpty()) {
+      OutlineOptimizationEventConsumer eventConsumer =
+          OutlineOptimizationEventConsumer.create(appView);
       forEachSelectedOutliningMethod(
           converter,
           methodsSelectedForOutlining,
@@ -1350,14 +1351,11 @@
             identifyOutlineSites(code);
           },
           executorService);
-      ArtProfileCollectionAdditions artProfileCollectionAdditions =
-          ArtProfileCollectionAdditions.create(appView);
-      List<ProgramMethod> outlineMethods =
-          buildOutlineMethods(
-              OutlineOptimizationEventConsumer.create(artProfileCollectionAdditions));
-      artProfileCollectionAdditions.commit(appView);
-      MethodProcessorEventConsumer eventConsumer = MethodProcessorEventConsumer.empty();
-      converter.optimizeSynthesizedMethods(outlineMethods, eventConsumer, executorService);
+      List<ProgramMethod> outlineMethods = buildOutlineMethods(eventConsumer);
+      MethodProcessorEventConsumer methodProcessorEventConsumer =
+          MethodProcessorEventConsumer.empty();
+      converter.optimizeSynthesizedMethods(
+          outlineMethods, methodProcessorEventConsumer, executorService);
       feedback.updateVisibleOptimizationInfo();
       forEachSelectedOutliningMethod(
           converter,
@@ -1374,6 +1372,7 @@
       feedback.updateVisibleOptimizationInfo();
       assert checkAllOutlineSitesFoundAgain();
       outlineMethods.forEach(m -> m.getDefinition().markNotProcessed());
+      eventConsumer.finished(appView);
     }
     timing.end();
   }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
index 16edb6a..1a2eaa6 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
@@ -36,7 +36,6 @@
 import com.android.tools.r8.ir.optimize.info.ConcreteCallSiteOptimizationInfo;
 import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagatorGraphLens.Builder;
 import com.android.tools.r8.optimize.argumentpropagation.utils.ParameterRemovalUtils;
-import com.android.tools.r8.profile.art.rewriting.ArtProfileCollectionAdditions;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.KeepFieldInfo;
 import com.android.tools.r8.shaking.KeepMethodInfo;
@@ -194,10 +193,8 @@
       Timing timing)
       throws ExecutionException {
     timing.begin("Optimize components");
-    ArtProfileCollectionAdditions artProfileCollectionAdditions =
-        ArtProfileCollectionAdditions.create(appView);
     ArgumentPropagatorSyntheticEventConsumer eventConsumer =
-        ArgumentPropagatorSyntheticEventConsumer.create(artProfileCollectionAdditions);
+        ArgumentPropagatorSyntheticEventConsumer.create(appView);
     ProcessorContext processorContext = appView.createProcessorContext();
     Collection<Builder> partialGraphLensBuilders =
         ThreadUtils.processItemsWithResults(
@@ -210,7 +207,7 @@
                             classes, DexMethodSignatureSet.empty()),
                         affectedClassConsumer),
             executorService);
-    artProfileCollectionAdditions.commit(appView);
+    eventConsumer.finished(appView);
     timing.end();
 
     // Merge all the partial, disjoint graph lens builders into a single graph lens.
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorSyntheticEventConsumer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorSyntheticEventConsumer.java
index aae0602..799cd92 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorSyntheticEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorSyntheticEventConsumer.java
@@ -4,28 +4,20 @@
 
 package com.android.tools.r8.optimize.argumentpropagation;
 
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.profile.art.rewriting.ArtProfileCollectionAdditions;
-import com.android.tools.r8.profile.art.rewriting.ConcreteArtProfileCollectionAdditions;
+import com.android.tools.r8.profile.art.rewriting.ArtProfileRewritingArgumentPropagatorSyntheticEventConsumer;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public interface ArgumentPropagatorSyntheticEventConsumer {
 
   void acceptInitializerArgumentClass(DexProgramClass clazz, ProgramMethod context);
 
-  static ArgumentPropagatorSyntheticEventConsumer create(
-      ArtProfileCollectionAdditions collectionAdditions) {
-    if (collectionAdditions.isNop()) {
-      return empty();
-    }
-    return create(collectionAdditions.asConcrete());
-  }
+  void finished(AppView<AppInfoWithLiveness> appView);
 
-  static ArgumentPropagatorSyntheticEventConsumer create(
-      ConcreteArtProfileCollectionAdditions collectionAdditions) {
-    return (clazz, context) ->
-        collectionAdditions.applyIfContextIsInProfile(
-            context, additionsBuilder -> additionsBuilder.addRule(clazz));
+  static ArgumentPropagatorSyntheticEventConsumer create(AppView<AppInfoWithLiveness> appView) {
+    return ArtProfileRewritingArgumentPropagatorSyntheticEventConsumer.attach(appView, empty());
   }
 
   static ArgumentPropagatorSyntheticEventConsumer empty() {
@@ -48,5 +40,10 @@
     public void acceptInitializerArgumentClass(DexProgramClass clazz, ProgramMethod context) {
       // Intentionally empty.
     }
+
+    @Override
+    public void finished(AppView<AppInfoWithLiveness> appView) {
+      // Intentionally empty.
+    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingApiReferenceStubberEventConsumer.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingApiReferenceStubberEventConsumer.java
index 683bb93..0b4dfde 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingApiReferenceStubberEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingApiReferenceStubberEventConsumer.java
@@ -24,11 +24,17 @@
     this.parent = parent;
   }
 
-  public static ArtProfileRewritingApiReferenceStubberEventConsumer attach(
-      ConcreteArtProfileCollectionAdditions collectionAdditions,
-      ApiReferenceStubberEventConsumer eventConsumer) {
-    return new ArtProfileRewritingApiReferenceStubberEventConsumer(
-        collectionAdditions, eventConsumer);
+  public static ApiReferenceStubberEventConsumer attach(
+      AppView<?> appView, ApiReferenceStubberEventConsumer eventConsumer) {
+    if (appView.options().getArtProfileOptions().isIncludingApiReferenceStubs()) {
+      ArtProfileCollectionAdditions artProfileCollectionAdditions =
+          ArtProfileCollectionAdditions.create(appView);
+      if (!artProfileCollectionAdditions.isNop()) {
+        return new ArtProfileRewritingApiReferenceStubberEventConsumer(
+            artProfileCollectionAdditions.asConcrete(), eventConsumer);
+      }
+    }
+    return eventConsumer;
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingArgumentPropagatorSyntheticEventConsumer.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingArgumentPropagatorSyntheticEventConsumer.java
new file mode 100644
index 0000000..1084d3a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingArgumentPropagatorSyntheticEventConsumer.java
@@ -0,0 +1,50 @@
+// 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.profile.art.rewriting;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagatorSyntheticEventConsumer;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+
+public class ArtProfileRewritingArgumentPropagatorSyntheticEventConsumer
+    implements ArgumentPropagatorSyntheticEventConsumer {
+
+  private final ConcreteArtProfileCollectionAdditions additionsCollection;
+  private final ArgumentPropagatorSyntheticEventConsumer parent;
+
+  private ArtProfileRewritingArgumentPropagatorSyntheticEventConsumer(
+      ConcreteArtProfileCollectionAdditions additionsCollection,
+      ArgumentPropagatorSyntheticEventConsumer parent) {
+    this.additionsCollection = additionsCollection;
+    this.parent = parent;
+  }
+
+  public static ArgumentPropagatorSyntheticEventConsumer attach(
+      AppView<AppInfoWithLiveness> appView,
+      ArgumentPropagatorSyntheticEventConsumer eventConsumer) {
+    ArtProfileCollectionAdditions additionsCollection =
+        ArtProfileCollectionAdditions.create(appView);
+    if (additionsCollection.isNop()) {
+      return eventConsumer;
+    }
+    return new ArtProfileRewritingArgumentPropagatorSyntheticEventConsumer(
+        additionsCollection.asConcrete(), eventConsumer);
+  }
+
+  @Override
+  public void acceptInitializerArgumentClass(DexProgramClass clazz, ProgramMethod context) {
+    additionsCollection.applyIfContextIsInProfile(
+        context, additionsBuilder -> additionsBuilder.addRule(clazz));
+    parent.acceptInitializerArgumentClass(clazz, context);
+  }
+
+  @Override
+  public void finished(AppView<AppInfoWithLiveness> appView) {
+    additionsCollection.commit(appView);
+    parent.finished(appView);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingMethodProcessorEventConsumer.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingMethodProcessorEventConsumer.java
index b359bf5..4835091 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingMethodProcessorEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingMethodProcessorEventConsumer.java
@@ -4,8 +4,10 @@
 
 package com.android.tools.r8.profile.art.rewriting;
 
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.conversion.MethodProcessorEventConsumer;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public class ArtProfileRewritingMethodProcessorEventConsumer extends MethodProcessorEventConsumer {
 
@@ -20,6 +22,17 @@
   }
 
   public static MethodProcessorEventConsumer attach(
+      AppView<?> appView, MethodProcessorEventConsumer eventConsumer) {
+    ArtProfileCollectionAdditions additionsCollection =
+        ArtProfileCollectionAdditions.create(appView);
+    if (additionsCollection.isNop()) {
+      return eventConsumer;
+    }
+    return new ArtProfileRewritingMethodProcessorEventConsumer(
+        additionsCollection.asConcrete(), eventConsumer);
+  }
+
+  public static MethodProcessorEventConsumer attach(
       ArtProfileCollectionAdditions artProfileCollectionAdditions,
       MethodProcessorEventConsumer eventConsumer) {
     if (artProfileCollectionAdditions.isNop()) {
@@ -115,4 +128,10 @@
         context, additionsBuilder -> additionsBuilder.addRule(method).addRule(method.getHolder()));
     parent.acceptUtilityThrowRuntimeExceptionWithMessageMethod(method, context);
   }
+
+  @Override
+  public void finished(AppView<AppInfoWithLiveness> appView) {
+    additionsCollection.commit(appView);
+    parent.finished(appView);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingOutlineOptimizationEventConsumer.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingOutlineOptimizationEventConsumer.java
new file mode 100644
index 0000000..2184a87
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingOutlineOptimizationEventConsumer.java
@@ -0,0 +1,52 @@
+// 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.profile.art.rewriting;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.optimize.outliner.OutlineOptimizationEventConsumer;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import java.util.Collection;
+
+public class ArtProfileRewritingOutlineOptimizationEventConsumer
+    implements OutlineOptimizationEventConsumer {
+
+  private final ConcreteArtProfileCollectionAdditions additionsCollection;
+  private final OutlineOptimizationEventConsumer parent;
+
+  private ArtProfileRewritingOutlineOptimizationEventConsumer(
+      ConcreteArtProfileCollectionAdditions additionsCollection,
+      OutlineOptimizationEventConsumer parent) {
+    this.additionsCollection = additionsCollection;
+    this.parent = parent;
+  }
+
+  public static OutlineOptimizationEventConsumer attach(
+      AppView<AppInfoWithLiveness> appView, OutlineOptimizationEventConsumer eventConsumer) {
+    ArtProfileCollectionAdditions additionsCollection =
+        ArtProfileCollectionAdditions.create(appView);
+    if (additionsCollection.isNop()) {
+      return eventConsumer;
+    }
+    return new ArtProfileRewritingOutlineOptimizationEventConsumer(
+        additionsCollection.asConcrete(), eventConsumer);
+  }
+
+  @Override
+  public void acceptOutlineMethod(ProgramMethod method, Collection<ProgramMethod> contexts) {
+    for (ProgramMethod context : contexts) {
+      additionsCollection.applyIfContextIsInProfile(
+          context,
+          additionsBuilder -> additionsBuilder.addRule(method).addRule(method.getHolder()));
+    }
+    parent.acceptOutlineMethod(method, contexts);
+  }
+
+  @Override
+  public void finished(AppView<AppInfoWithLiveness> appView) {
+    additionsCollection.commit(appView);
+    parent.finished(appView);
+  }
+}