[GlobalSynthetics] Add var-handle desugared class to output

Bug: b/280016114
Change-Id: I4ba3402aad7014f17ec79814782b8a2c518d99a3
diff --git a/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java b/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
index 827931b..b0d984f 100644
--- a/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
+++ b/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
@@ -14,6 +14,7 @@
 import com.android.tools.r8.androidapi.ComputedApiLevel.KnownApiLevel;
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.dex.ApplicationWriter;
+import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ClassAccessFlags;
@@ -30,16 +31,20 @@
 import com.android.tools.r8.graph.GenericSignature.ClassSignature;
 import com.android.tools.r8.graph.MethodCollection.MethodCollectionFactory;
 import com.android.tools.r8.graph.NestHostClassAttribute;
+import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.ThrowExceptionCode;
 import com.android.tools.r8.ir.conversion.IRConverter;
 import com.android.tools.r8.ir.desugar.TypeRewriter;
 import com.android.tools.r8.ir.desugar.records.RecordDesugaring;
-import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.ir.desugar.varhandle.VarHandleDesugaring;
+import com.android.tools.r8.ir.desugar.varhandle.VarHandleDesugaringEventConsumer;
 import com.android.tools.r8.naming.RecordRewritingNamingLens;
+import com.android.tools.r8.naming.VarHandleDesugaringRewritingNamingLens;
 import com.android.tools.r8.origin.CommandLineOrigin;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.MainDexInfo;
+import com.android.tools.r8.synthesis.SyntheticFinalization;
 import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy;
 import com.android.tools.r8.synthesis.SyntheticNaming;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
@@ -116,13 +121,15 @@
               AppView<AppInfo> appView = readApp(app, options, executorService, timing);
               timing.end();
 
-              timing.time(
-                  "Create global synthetics",
-                  () -> createGlobalSynthetics(appView, executorService));
+              timing.begin("Create global synthetics");
+              createGlobalSynthetics(appView, timing, executorService);
+              timing.end();
 
               ApplicationWriter.create(appView, options.getMarker()).write(executorService, app);
             } catch (ExecutionException e) {
               throw unwrapExecutionException(e);
+            } catch (IOException e) {
+              throw new CompilationError(e.getMessage(), e);
             } finally {
               options.signalFinishedToConsumers();
               // Dump timings.
@@ -156,7 +163,8 @@
   }
 
   private static void createGlobalSynthetics(
-      AppView<AppInfo> appView, ExecutorService executorService) throws ExecutionException {
+      AppView<AppInfo> appView, Timing timing, ExecutorService executorService)
+      throws ExecutionException, IOException {
     assert ensureAllGlobalSyntheticsModeled(appView.getSyntheticItems().getNaming());
     Set<DexProgramClass> synthesizingContext =
         ImmutableSet.of(createSynthesizingContext(appView.dexItemFactory()));
@@ -166,14 +174,20 @@
         appView,
         synthesizingContext,
         recordTagClass -> recordTagClass.programMethods().forEach(methodsToProcess::add));
-    NamingLens namingLens = RecordRewritingNamingLens.createRecordRewritingNamingLens(appView);
+    VarHandleDesugaring.ensureVarHandleClass(
+        appView,
+        new VarHandleDesugaringEventConsumer() {
+          @Override
+          public void acceptVarHandleDesugaringClass(DexProgramClass clazz) {
+            clazz.programMethods().forEach(methodsToProcess::add);
+          }
 
-    // TODO(b/280016114): Create Var Handle
-    // TODO(b/280016114): Create MethodHandlesLookup
+          @Override
+          public void acceptVarHandleDesugaringClassContext(
+              DexProgramClass clazz, ProgramDefinition context) {}
+        },
+        synthesizingContext);
 
-    createAllApiStubs(appView, synthesizingContext, executorService);
-
-    appView.setNamingLens(namingLens);
     IRConverter converter = new IRConverter(appView);
     converter.processSimpleSynthesizeMethods(methodsToProcess, executorService);
 
@@ -183,6 +197,24 @@
             new AppInfo(
                 appView.appInfo().getSyntheticItems().commit(appView.app()),
                 appView.appInfo().getMainDexInfo()));
+
+    timing.time(
+        "Finalize synthetics",
+        () -> SyntheticFinalization.finalize(appView, timing, executorService));
+
+    appView.setNamingLens(RecordRewritingNamingLens.createRecordRewritingNamingLens(appView));
+    appView.setNamingLens(
+        VarHandleDesugaringRewritingNamingLens.createVarHandleDesugaringRewritingNamingLens(
+            appView));
+
+    createAllApiStubs(appView, synthesizingContext, executorService);
+
+    appView
+        .withoutClassHierarchy()
+        .setAppInfo(
+            new AppInfo(
+                appView.appInfo().getSyntheticItems().commit(appView.app()),
+                appView.appInfo().getMainDexInfo()));
   }
 
   private static DexProgramClass createSynthesizingContext(DexItemFactory factory) {
diff --git a/src/main/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommand.java b/src/main/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommand.java
index bc5e1c0..54cf918 100644
--- a/src/main/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommand.java
+++ b/src/main/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommand.java
@@ -15,6 +15,7 @@
 import com.android.tools.r8.utils.ExceptionDiagnostic;
 import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.InternalOptions.DesugarState;
 import com.android.tools.r8.utils.Reporter;
 import com.android.tools.r8.utils.StringDiagnostic;
 import java.nio.file.Path;
@@ -137,6 +138,8 @@
     assert !internal.passthroughDexCode;
 
     internal.tool = Tool.GlobalSyntheticsGenerator;
+    internal.desugarState = DesugarState.ON;
+    internal.enableVarHandleDesugaring = true;
 
     return internal;
   }
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 063286c..a77261e 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
@@ -210,17 +210,20 @@
     ensureMethodHandlesLookupClass(eventConsumer, ImmutableList.of(context));
   }
 
-  private void ensureVarHandleClass(
+  @SuppressWarnings("InconsistentOverloads")
+  public static void ensureVarHandleClass(
+      AppView<?> appView,
       VarHandleDesugaringEventConsumer eventConsumer,
       Collection<? extends ProgramDefinition> contexts) {
-    assert contexts.stream().allMatch(context -> context.getContextType() != factory.varHandleType);
+    assert contexts.stream()
+        .allMatch(context -> context.getContextType() != appView.dexItemFactory().varHandleType);
     DexProgramClass clazz =
         appView
             .getSyntheticItems()
             .ensureGlobalClass(
                 () -> new MissingGlobalSyntheticsConsumerDiagnostic("VarHandle desugaring"),
                 kinds -> kinds.VAR_HANDLE,
-                factory.varHandleType,
+                appView.dexItemFactory().varHandleType,
                 contexts,
                 appView,
                 builder ->
@@ -235,7 +238,7 @@
   private void ensureVarHandleClass(
       VarHandleDesugaringEventConsumer eventConsumer, ProgramDefinition context) {
     if (context.getContextType() != factory.varHandleType) {
-      ensureVarHandleClass(eventConsumer, ImmutableList.of(context));
+      ensureVarHandleClass(appView, eventConsumer, ImmutableList.of(context));
     }
   }
 
@@ -595,7 +598,7 @@
         flags,
         DexApplicationReadFlags::hasReadVarHandleReferenceFromProgramClass,
         DexApplicationReadFlags::getVarHandleWitnesses,
-        classes -> ensureVarHandleClass(eventConsumer, classes));
+        classes -> ensureVarHandleClass(appView, eventConsumer, classes));
   }
 
   private void synthesizeClassIfReferenced(
diff --git a/src/test/java/com/android/tools/r8/globalsynthetics/GlobalSyntheticsEnsureClassesOutputTest.java b/src/test/java/com/android/tools/r8/globalsynthetics/GlobalSyntheticsEnsureClassesOutputTest.java
index 13e2f29..47a78fe 100644
--- a/src/test/java/com/android/tools/r8/globalsynthetics/GlobalSyntheticsEnsureClassesOutputTest.java
+++ b/src/test/java/com/android/tools/r8/globalsynthetics/GlobalSyntheticsEnsureClassesOutputTest.java
@@ -13,6 +13,8 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
@@ -48,7 +50,7 @@
             .setProgramConsumer(new DexIndexedConsumer.ArchiveConsumer(output))
             .build());
     CodeInspector inspector = new CodeInspector(output);
-    assertEquals(1024, inspector.allClasses().size());
+    assertEquals(1025, inspector.allClasses().size());
   }
 
   @Test
@@ -64,6 +66,7 @@
     // The output contains a RecordTag type that is mapped back to the original java.lang.Record by
     // our codeinspector.
     expectedInOutput.add("Ljava/lang/Record;");
+    expectedInOutput.add("Ljava/lang/invoke/VarHandle;");
     assertEquals(
         expectedInOutput,
         new CodeInspector(output)
@@ -84,7 +87,21 @@
             .build(),
         options ->
             options.testing.globalSyntheticCreatedCallback =
-                programClass -> generatedGlobalSynthetics.add(programClass.getTypeName()));
+                programClass -> {
+                  if (programClass
+                      .getClassReference()
+                      .getDescriptor()
+                      .equals(DexItemFactory.varHandleDescriptorString)) {
+                    // We emit a desugared var handle. Rewrite it here to allow checking for final
+                    // type names.
+                    generatedGlobalSynthetics.add(
+                        Reference.classFromDescriptor(
+                                DexItemFactory.desugarVarHandleDescriptorString)
+                            .getTypeName());
+                  } else {
+                    generatedGlobalSynthetics.add(programClass.getTypeName());
+                  }
+                });
     Set<String> readGlobalSynthetics =
         new CodeInspector(output)
             .allClasses().stream().map(FoundClassSubject::getFinalName).collect(Collectors.toSet());