Extend profile rewriting to var handle desugaring

Bug: b/265729283
Change-Id: I0cb55036c5236fc8f1b35646a02e1cb410442774
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 80eb732..c227e1c 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -73,7 +73,6 @@
 import com.android.tools.r8.optimize.proto.ProtoNormalizer;
 import com.android.tools.r8.origin.CommandLineOrigin;
 import com.android.tools.r8.profile.art.ArtProfileCompletenessChecker;
-import com.android.tools.r8.profile.art.rewriting.ArtProfileCollectionAdditions;
 import com.android.tools.r8.repackaging.Repackaging;
 import com.android.tools.r8.repackaging.RepackagingLens;
 import com.android.tools.r8.shaking.AbstractMethodRemover;
@@ -303,13 +302,11 @@
           appView.dexItemFactory());
 
       // Upfront desugaring generation: Generates new program classes to be added in the app.
-      ArtProfileCollectionAdditions artProfileCollectionAdditions =
-          ArtProfileCollectionAdditions.create(appView);
       CfClassSynthesizerDesugaringEventConsumer classSynthesizerEventConsumer =
-          CfClassSynthesizerDesugaringEventConsumer.create(artProfileCollectionAdditions);
+          CfClassSynthesizerDesugaringEventConsumer.createForR8(appView);
       CfClassSynthesizerDesugaringCollection.create(appView)
           .synthesizeClasses(executorService, classSynthesizerEventConsumer);
-      artProfileCollectionAdditions.commit(appView);
+      classSynthesizerEventConsumer.finished(appView);
       if (appView.getSyntheticItems().hasPendingSyntheticClasses()) {
         appView.setAppInfo(
             appView
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
index 7b3641f..7cbb122 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
@@ -117,7 +117,8 @@
     ArtProfileCollectionAdditions artProfileCollectionAdditions =
         methodProcessor.getArtProfileCollectionAdditions();
     CfClassSynthesizerDesugaringEventConsumer classSynthesizerEventConsumer =
-        CfClassSynthesizerDesugaringEventConsumer.create(artProfileCollectionAdditions);
+        CfClassSynthesizerDesugaringEventConsumer.createForD8(
+            appView, artProfileCollectionAdditions);
     converter.classSynthesisDesugaring(executorService, classSynthesizerEventConsumer);
     if (!classSynthesizerEventConsumer.getSynthesizedClasses().isEmpty()) {
       classes =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringEventConsumer.java
index f2cdd81..4e7a473 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfClassSynthesizerDesugaringEventConsumer.java
@@ -4,7 +4,10 @@
 
 package com.android.tools.r8.ir.desugar;
 
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterL8SynthesizerEventConsumer;
@@ -25,14 +28,24 @@
 
   protected CfClassSynthesizerDesugaringEventConsumer() {}
 
-  public static CfClassSynthesizerDesugaringEventConsumer create(
-      ArtProfileCollectionAdditions artProfileCollectionAdditions) {
+  public static CfClassSynthesizerDesugaringEventConsumer createForD8(
+      AppView<?> appView, ArtProfileCollectionAdditions artProfileCollectionAdditions) {
     CfClassSynthesizerDesugaringEventConsumer eventConsumer =
         new D8R8CfClassSynthesizerDesugaringEventConsumer();
     return ArtProfileRewritingCfClassSynthesizerDesugaringEventConsumer.attach(
-        artProfileCollectionAdditions, eventConsumer);
+        appView, eventConsumer, artProfileCollectionAdditions);
   }
 
+  public static CfClassSynthesizerDesugaringEventConsumer createForR8(
+      AppView<? extends AppInfoWithClassHierarchy> appView) {
+    CfClassSynthesizerDesugaringEventConsumer eventConsumer =
+        new D8R8CfClassSynthesizerDesugaringEventConsumer();
+    return ArtProfileRewritingCfClassSynthesizerDesugaringEventConsumer.attach(
+        appView, eventConsumer);
+  }
+
+  public void finished(AppView<? extends AppInfoWithClassHierarchy> appView) {}
+
   public abstract Set<DexProgramClass> getSynthesizedClasses();
 
   private static class D8R8CfClassSynthesizerDesugaringEventConsumer
@@ -77,6 +90,12 @@
     }
 
     @Override
+    public void acceptVarHandleDesugaringClassContext(
+        DexProgramClass clazz, ProgramDefinition context) {
+      // Intentionally empty.
+    }
+
+    @Override
     public Set<DexProgramClass> getSynthesizedClasses() {
       return synthesizedClasses;
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
index 595d1db..42fda4f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.graph.DexClasspathClass;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.conversion.ClassConverterResult;
@@ -219,6 +220,12 @@
     }
 
     @Override
+    public void acceptVarHandleDesugaringClassContext(
+        DexProgramClass clazz, ProgramDefinition context) {
+      // Intentionally empty.
+    }
+
+    @Override
     public void acceptLambdaClass(LambdaClass lambdaClass, ProgramMethod context) {
       synchronized (synthesizedLambdaClasses) {
         synthesizedLambdaClasses.add(lambdaClass);
@@ -488,6 +495,12 @@
     }
 
     @Override
+    public void acceptVarHandleDesugaringClassContext(
+        DexProgramClass clazz, ProgramDefinition context) {
+      // Intentionally empty.
+    }
+
+    @Override
     public void acceptCollectionConversion(ProgramMethod arrayConversion) {
       // Intentionally empty. The method will be hit by tracing if required.
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaring.java
index d8382b7..ceb6b75 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaring.java
@@ -22,6 +22,7 @@
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
@@ -174,19 +175,24 @@
   }
 
   private void ensureMethodHandlesLookupClass(
-      VarHandleDesugaringEventConsumer eventConsumer, Collection<ProgramDefinition> contexts) {
-    appView
-        .getSyntheticItems()
-        .ensureGlobalClass(
-            () -> new MissingGlobalSyntheticsConsumerDiagnostic("VarHandle desugaring"),
-            kinds -> kinds.METHOD_HANDLES_LOOKUP,
-            factory.lookupType,
-            contexts,
-            appView,
-            builder ->
-                VarHandleDesugaringMethods.generateDesugarMethodHandlesLookupClass(
-                    builder, appView.dexItemFactory()),
-            eventConsumer::acceptVarHandleDesugaringClass);
+      VarHandleDesugaringEventConsumer eventConsumer,
+      Collection<? extends ProgramDefinition> contexts) {
+    DexProgramClass clazz =
+        appView
+            .getSyntheticItems()
+            .ensureGlobalClass(
+                () -> new MissingGlobalSyntheticsConsumerDiagnostic("VarHandle desugaring"),
+                kinds -> kinds.METHOD_HANDLES_LOOKUP,
+                factory.lookupType,
+                contexts,
+                appView,
+                builder ->
+                    VarHandleDesugaringMethods.generateDesugarMethodHandlesLookupClass(
+                        builder, appView.dexItemFactory()),
+                eventConsumer::acceptVarHandleDesugaringClass);
+    for (ProgramDefinition context : contexts) {
+      eventConsumer.acceptVarHandleDesugaringClassContext(clazz, context);
+    }
   }
 
   private void ensureMethodHandlesLookupClass(
@@ -195,19 +201,24 @@
   }
 
   private void ensureVarHandleClass(
-      VarHandleDesugaringEventConsumer eventConsumer, Collection<ProgramDefinition> contexts) {
-    appView
-        .getSyntheticItems()
-        .ensureGlobalClass(
-            () -> new MissingGlobalSyntheticsConsumerDiagnostic("VarHandle desugaring"),
-            kinds -> kinds.VAR_HANDLE,
-            factory.varHandleType,
-            contexts,
-            appView,
-            builder ->
-                VarHandleDesugaringMethods.generateDesugarVarHandleClass(
-                    builder, appView.dexItemFactory()),
-            eventConsumer::acceptVarHandleDesugaringClass);
+      VarHandleDesugaringEventConsumer eventConsumer,
+      Collection<? extends ProgramDefinition> contexts) {
+    DexProgramClass clazz =
+        appView
+            .getSyntheticItems()
+            .ensureGlobalClass(
+                () -> new MissingGlobalSyntheticsConsumerDiagnostic("VarHandle desugaring"),
+                kinds -> kinds.VAR_HANDLE,
+                factory.varHandleType,
+                contexts,
+                appView,
+                builder ->
+                    VarHandleDesugaringMethods.generateDesugarVarHandleClass(
+                        builder, appView.dexItemFactory()),
+                eventConsumer::acceptVarHandleDesugaringClass);
+    for (ProgramDefinition context : contexts) {
+      eventConsumer.acceptVarHandleDesugaringClassContext(clazz, context);
+    }
   }
 
   private void ensureVarHandleClass(
@@ -598,9 +609,9 @@
       DexApplicationReadFlags flags,
       Predicate<DexApplicationReadFlags> hasReadReferenceFromProgramClass,
       Function<DexApplicationReadFlags, Set<DexType>> getWitnesses,
-      Consumer<List<ProgramDefinition>> consumeProgramWitnesses) {
+      Consumer<? super List<DexProgramClass>> consumeProgramWitnesses) {
     if (hasReadReferenceFromProgramClass.test(flags)) {
-      List<ProgramDefinition> classes = new ArrayList<>();
+      List<DexProgramClass> classes = new ArrayList<>();
       for (DexType witness : getWitnesses.apply(flags)) {
         DexClass dexClass = appView.contextIndependentDefinitionFor(witness);
         assert dexClass != null;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaringEventConsumer.java
index 8251809..d27e4d8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaringEventConsumer.java
@@ -4,8 +4,11 @@
 package com.android.tools.r8.ir.desugar.varhandle;
 
 import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramDefinition;
 
 public interface VarHandleDesugaringEventConsumer {
 
-  void acceptVarHandleDesugaringClass(DexProgramClass varHandleClass);
+  void acceptVarHandleDesugaringClass(DexProgramClass clazz);
+
+  void acceptVarHandleDesugaringClassContext(DexProgramClass clazz, ProgramDefinition context);
 }
diff --git a/src/main/java/com/android/tools/r8/profile/art/ArtProfileOptions.java b/src/main/java/com/android/tools/r8/profile/art/ArtProfileOptions.java
index eb21c54..623790d 100644
--- a/src/main/java/com/android/tools/r8/profile/art/ArtProfileOptions.java
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfileOptions.java
@@ -38,6 +38,13 @@
     return enableCompletenessCheckForTesting;
   }
 
+  public boolean isIncludingVarHandleClasses() {
+    // We only include var handle classes in the residual ART profiles for completeness testing,
+    // since the classes synthesized by var handle desugaring are fairly large and may not be that
+    // important for runtime performance.
+    return enableCompletenessCheckForTesting;
+  }
+
   public ArtProfileOptions setArtProfilesForRewriting(Collection<ArtProfileForRewriting> inputs) {
     this.artProfilesForRewriting = inputs;
     return this;
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingCfClassSynthesizerDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingCfClassSynthesizerDesugaringEventConsumer.java
index 3cc4631..fc09831 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingCfClassSynthesizerDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingCfClassSynthesizerDesugaringEventConsumer.java
@@ -4,32 +4,49 @@
 
 package com.android.tools.r8.profile.art.rewriting;
 
+import static com.android.tools.r8.profile.art.rewriting.ArtProfileRewritingVarHandleDesugaringEventConsumerUtils.handleVarHandleDesugaringClassContext;
+
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringEventConsumer;
+import com.android.tools.r8.profile.art.ArtProfileOptions;
 import java.util.Set;
 
 public class ArtProfileRewritingCfClassSynthesizerDesugaringEventConsumer
     extends CfClassSynthesizerDesugaringEventConsumer {
 
   private final ConcreteArtProfileCollectionAdditions additionsCollection;
+  private final ArtProfileOptions options;
   private final CfClassSynthesizerDesugaringEventConsumer parent;
 
   private ArtProfileRewritingCfClassSynthesizerDesugaringEventConsumer(
       ConcreteArtProfileCollectionAdditions additionsCollection,
+      ArtProfileOptions options,
       CfClassSynthesizerDesugaringEventConsumer parent) {
     this.additionsCollection = additionsCollection;
+    this.options = options;
     this.parent = parent;
   }
 
   public static CfClassSynthesizerDesugaringEventConsumer attach(
-      ArtProfileCollectionAdditions artProfileCollectionAdditions,
-      CfClassSynthesizerDesugaringEventConsumer eventConsumer) {
+      AppView<?> appView, CfClassSynthesizerDesugaringEventConsumer eventConsumer) {
+    return attach(appView, eventConsumer, ArtProfileCollectionAdditions.create(appView));
+  }
+
+  public static CfClassSynthesizerDesugaringEventConsumer attach(
+      AppView<?> appView,
+      CfClassSynthesizerDesugaringEventConsumer eventConsumer,
+      ArtProfileCollectionAdditions artProfileCollectionAdditions) {
     if (artProfileCollectionAdditions.isNop()) {
       return eventConsumer;
     }
     return new ArtProfileRewritingCfClassSynthesizerDesugaringEventConsumer(
-        artProfileCollectionAdditions.asConcrete(), eventConsumer);
+        artProfileCollectionAdditions.asConcrete(),
+        appView.options().getArtProfileOptions(),
+        eventConsumer);
   }
 
   @Override
@@ -79,8 +96,21 @@
   }
 
   @Override
-  public void acceptVarHandleDesugaringClass(DexProgramClass varHandleClass) {
-    parent.acceptVarHandleDesugaringClass(varHandleClass);
+  public void acceptVarHandleDesugaringClass(DexProgramClass clazz) {
+    parent.acceptVarHandleDesugaringClass(clazz);
+  }
+
+  @Override
+  public void acceptVarHandleDesugaringClassContext(
+      DexProgramClass clazz, ProgramDefinition context) {
+    handleVarHandleDesugaringClassContext(clazz, context, additionsCollection, options);
+    parent.acceptVarHandleDesugaringClassContext(clazz, context);
+  }
+
+  @Override
+  public void finished(AppView<? extends AppInfoWithClassHierarchy> appView) {
+    additionsCollection.commit(appView);
+    parent.finished(appView);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingCfInstructionDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingCfInstructionDesugaringEventConsumer.java
index 4a51eaf..ecfe904 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingCfInstructionDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingCfInstructionDesugaringEventConsumer.java
@@ -4,12 +4,14 @@
 
 package com.android.tools.r8.profile.art.rewriting;
 
+import static com.android.tools.r8.profile.art.rewriting.ArtProfileRewritingVarHandleDesugaringEventConsumerUtils.handleVarHandleDesugaringClassContext;
 import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexClasspathClass;
 import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
@@ -352,8 +354,16 @@
   }
 
   @Override
-  public void acceptVarHandleDesugaringClass(DexProgramClass varHandleClass) {
-    parent.acceptVarHandleDesugaringClass(varHandleClass);
+  public void acceptVarHandleDesugaringClass(DexProgramClass clazz) {
+    parent.acceptVarHandleDesugaringClass(clazz);
+  }
+
+  @Override
+  public void acceptVarHandleDesugaringClassContext(
+      DexProgramClass clazz, ProgramDefinition context) {
+    handleVarHandleDesugaringClassContext(
+        clazz, context, additionsCollection, appView.options().getArtProfileOptions());
+    parent.acceptVarHandleDesugaringClassContext(clazz, context);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingVarHandleDesugaringEventConsumerUtils.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingVarHandleDesugaringEventConsumerUtils.java
new file mode 100644
index 0000000..f53e9bc
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingVarHandleDesugaringEventConsumerUtils.java
@@ -0,0 +1,34 @@
+// 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 static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
+
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramDefinition;
+import com.android.tools.r8.profile.art.ArtProfileOptions;
+
+public class ArtProfileRewritingVarHandleDesugaringEventConsumerUtils {
+
+  static void handleVarHandleDesugaringClassContext(
+      DexProgramClass varHandleClass,
+      ProgramDefinition context,
+      ConcreteArtProfileCollectionAdditions additionsCollection,
+      ArtProfileOptions options) {
+    if (options.isIncludingVarHandleClasses()) {
+      additionsCollection.applyIfContextIsInProfile(
+          context,
+          additions -> {
+            additions.addClassRule(varHandleClass);
+            varHandleClass.forEachProgramMethod(
+                method -> additions.addMethodRule(method, emptyConsumer()));
+          },
+          additionsBuilder -> {
+            additionsBuilder.addRule(varHandleClass);
+            varHandleClass.forEachProgramMethod(additionsBuilder::addRule);
+          });
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ConcreteArtProfileCollectionAdditions.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ConcreteArtProfileCollectionAdditions.java
index fde8889..da03c64 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ConcreteArtProfileCollectionAdditions.java
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ConcreteArtProfileCollectionAdditions.java
@@ -9,6 +9,7 @@
 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.art.ArtProfile;
 import com.android.tools.r8.profile.art.ArtProfileCollection;
@@ -69,6 +70,18 @@
   }
 
   void applyIfContextIsInProfile(
+      ProgramDefinition context,
+      Consumer<ArtProfileAdditions> additionsConsumer,
+      Consumer<ArtProfileAdditionsBuilder> additionsBuilderConsumer) {
+    if (context.isProgramClass()) {
+      applyIfContextIsInProfile(context.asProgramClass(), additionsConsumer);
+    } else {
+      assert context.isProgramMethod();
+      applyIfContextIsInProfile(context.asProgramMethod(), additionsBuilderConsumer);
+    }
+  }
+
+  void applyIfContextIsInProfile(
       DexProgramClass context, Consumer<ArtProfileAdditions> additionsConsumer) {
     applyIfContextIsInProfile(context.getType(), additionsConsumer);
   }