Use ensureSyntheticClass pattern

Bug: 197081367
Change-Id: Ia5f3d32bdc4cb868818c9e506bc3eeaa41dcf73c
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordRewriter.java
index 5333665..3f5eccc 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordRewriter.java
@@ -103,21 +103,21 @@
     if (instruction.isInvoke()) {
       CfInvoke cfInvoke = instruction.asInvoke();
       if (refersToRecord(cfInvoke.getMethod())) {
-        requiresRecordClass(eventConsumer);
+        ensureRecordClass(eventConsumer);
       }
       return;
     }
     if (instruction.isFieldInstruction()) {
       CfFieldInstruction fieldInstruction = instruction.asFieldInstruction();
       if (refersToRecord(fieldInstruction.getField())) {
-        requiresRecordClass(eventConsumer);
+        ensureRecordClass(eventConsumer);
       }
       return;
     }
     if (instruction.isTypeInstruction()) {
       CfTypeInstruction typeInstruction = instruction.asTypeInstruction();
       if (refersToRecord(typeInstruction.getType())) {
-        requiresRecordClass(eventConsumer);
+        ensureRecordClass(eventConsumer);
       }
       return;
     }
@@ -321,10 +321,38 @@
     return false;
   }
 
-  private void requiresRecordClass(RecordDesugaringEventConsumer eventConsumer) {
-    DexProgramClass recordClass = synthesizeR8Record();
-    if (recordClass != null) {
-      eventConsumer.acceptRecordClass(recordClass);
+  private void ensureRecordClass(RecordDesugaringEventConsumer eventConsumer) {
+    DexItemFactory factory = appView.dexItemFactory();
+    checkRecordTagNotPresent(factory);
+    appView
+        .getSyntheticItems()
+        .ensureFixedClassFromType(
+            SyntheticNaming.SyntheticKind.RECORD_TAG,
+            factory.recordType,
+            appView,
+            builder -> {
+              DexEncodedMethod init = synthesizeRecordInitMethod();
+              DexEncodedMethod abstractGetFieldsAsObjectsMethod =
+                  synthesizeAbstractGetFieldsAsObjectsMethod();
+              builder
+                  .setAbstract()
+                  .setVirtualMethods(ImmutableList.of(abstractGetFieldsAsObjectsMethod))
+                  .setDirectMethods(ImmutableList.of(init));
+            },
+            eventConsumer::acceptRecordClass);
+  }
+
+  private void checkRecordTagNotPresent(DexItemFactory factory) {
+    DexClass r8RecordClass =
+        appView.appInfo().definitionForWithoutExistenceAssert(factory.recordTagType);
+    if (r8RecordClass != null && r8RecordClass.isProgramClass()) {
+      appView
+          .options()
+          .reporter
+          .error(
+              "D8/R8 is compiling a mix of desugared and non desugared input using"
+                  + " java.lang.Record, but the application reader did not import correctly "
+                  + factory.recordTagType);
     }
   }
 
@@ -337,7 +365,7 @@
   public void desugar(DexProgramClass clazz, CfClassDesugaringEventConsumer eventConsumer) {
     if (clazz.isRecord()) {
       assert clazz.superType == factory.recordType;
-      requiresRecordClass(eventConsumer);
+      ensureRecordClass(eventConsumer);
       clazz.accessFlags.unsetRecord();
     }
   }
@@ -471,50 +499,6 @@
     return factory.objectMembers.toString;
   }
 
-  private DexProgramClass synthesizeR8Record() {
-    DexItemFactory factory = appView.dexItemFactory();
-    DexClass r8RecordClass =
-        appView.appInfo().definitionForWithoutExistenceAssert(factory.recordTagType);
-    if (r8RecordClass != null && r8RecordClass.isProgramClass()) {
-      appView
-          .options()
-          .reporter
-          .error(
-              "D8/R8 is compiling a mix of desugared and non desugared input using"
-                  + " java.lang.Record, but the application reader did not import correctly "
-                  + factory.recordTagType.toString());
-    }
-    DexClass recordClass =
-        appView.appInfo().definitionForWithoutExistenceAssert(factory.recordType);
-    if (recordClass != null && recordClass.isProgramClass()) {
-      return null;
-    }
-    return synchronizedSynthesizeR8Record();
-  }
-
-  private synchronized DexProgramClass synchronizedSynthesizeR8Record() {
-    DexItemFactory factory = appView.dexItemFactory();
-    DexClass recordClass =
-        appView.appInfo().definitionForWithoutExistenceAssert(factory.recordType);
-    if (recordClass != null && recordClass.isProgramClass()) {
-      return null;
-    }
-    DexEncodedMethod init = synthesizeRecordInitMethod();
-    DexEncodedMethod abstractGetFieldsAsObjectsMethod =
-        synthesizeAbstractGetFieldsAsObjectsMethod();
-    return appView
-        .getSyntheticItems()
-        .createFixedClassFromType(
-            SyntheticNaming.SyntheticKind.RECORD_TAG,
-            factory.recordType,
-            factory,
-            builder ->
-                builder
-                    .setAbstract()
-                    .setVirtualMethods(ImmutableList.of(abstractGetFieldsAsObjectsMethod))
-                    .setDirectMethods(ImmutableList.of(init)));
-  }
-
   private DexEncodedMethod synthesizeAbstractGetFieldsAsObjectsMethod() {
     MethodAccessFlags methodAccessFlags =
         MethodAccessFlags.fromSharedAccessFlags(
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
index b5f7c2a..4baf66c 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -474,7 +474,36 @@
     return legacyItem;
   }
 
-  private DexProgramClass internalCreateClass(
+  private DexProgramClass internalEnsureDexProgramClass(
+      SyntheticKind kind,
+      Consumer<SyntheticProgramClassBuilder> classConsumer,
+      Consumer<DexProgramClass> onCreationConsumer,
+      SynthesizingContext outerContext,
+      DexType type,
+      AppView<?> appView) {
+    // Fast path is that the synthetic is already present. If so it must be a program class.
+    DexClass dexClass = appView.appInfo().definitionFor(type);
+    if (dexClass != null) {
+      assert dexClass.isProgramClass();
+      return dexClass.asProgramClass();
+    }
+    // Slow path creates the class using the context to make it thread safe.
+    synchronized (type) {
+      // Recheck if it is present now the lock is held.
+      dexClass = appView.appInfo().definitionFor(type);
+      if (dexClass != null) {
+        assert dexClass.isProgramClass();
+        return dexClass.asProgramClass();
+      }
+      DexProgramClass clazz =
+          internalCreateProgramClass(
+              kind, classConsumer, outerContext, type, appView.dexItemFactory());
+      onCreationConsumer.accept(clazz);
+      return clazz;
+    }
+  }
+
+  private DexProgramClass internalCreateProgramClass(
       SyntheticKind kind,
       Consumer<SyntheticProgramClassBuilder> fn,
       SynthesizingContext outerContext,
@@ -499,7 +528,7 @@
     DexType type =
         SyntheticNaming.createInternalType(
             kind, outerContext, context.getSyntheticSuffix(), appView.dexItemFactory());
-    return internalCreateClass(kind, fn, outerContext, type, appView.dexItemFactory());
+    return internalCreateProgramClass(kind, fn, outerContext, type, appView.dexItemFactory());
   }
 
   // TODO(b/172194101): Make this take a unique context.
@@ -510,7 +539,7 @@
       Consumer<SyntheticProgramClassBuilder> fn) {
     SynthesizingContext outerContext = internalGetOuterContext(context, appView);
     DexType type = SyntheticNaming.createFixedType(kind, outerContext, appView.dexItemFactory());
-    return internalCreateClass(kind, fn, outerContext, type, appView.dexItemFactory());
+    return internalCreateProgramClass(kind, fn, outerContext, type, appView.dexItemFactory());
   }
 
   public DexProgramClass getExistingFixedClass(
@@ -547,36 +576,7 @@
     assert kind.isFixedSuffixSynthetic;
     SynthesizingContext outerContext = internalGetOuterContext(context, appView);
     DexType type = SyntheticNaming.createFixedType(kind, outerContext, appView.dexItemFactory());
-    // Fast path is that the synthetic is already present. If so it must be a program class.
-    DexClass clazz = appView.definitionFor(type);
-    if (clazz != null) {
-      assert isSyntheticClass(type);
-      assert clazz.isProgramClass();
-      return clazz.asProgramClass();
-    }
-    // Slow path creates the class using the context to make it thread safe.
-    synchronized (context) {
-      // Recheck if it is present now the lock is held.
-      clazz = appView.definitionFor(type);
-      if (clazz != null) {
-        assert isSyntheticClass(type);
-        assert clazz.isProgramClass();
-        return clazz.asProgramClass();
-      }
-      assert !isSyntheticClass(type);
-      DexProgramClass dexProgramClass =
-          internalCreateClass(
-              kind,
-              syntheticProgramClassBuilder -> {
-                syntheticProgramClassBuilder.setUseSortedMethodBacking(true);
-                fn.accept(syntheticProgramClassBuilder);
-              },
-              outerContext,
-              type,
-              appView.dexItemFactory());
-      onCreationConsumer.accept(dexProgramClass);
-      return dexProgramClass;
-    }
+    return internalEnsureDexProgramClass(kind, fn, onCreationConsumer, outerContext, type, appView);
   }
 
   public ProgramMethod ensureFixedClassMethod(
@@ -710,16 +710,17 @@
     }
   }
 
-  public DexProgramClass createFixedClassFromType(
+  public DexProgramClass ensureFixedClassFromType(
       SyntheticKind kind,
       DexType contextType,
-      DexItemFactory factory,
-      Consumer<SyntheticProgramClassBuilder> fn) {
+      AppView<?> appView,
+      Consumer<SyntheticProgramClassBuilder> fn,
+      Consumer<DexProgramClass> onCreationConsumer) {
     // Obtain the outer synthesizing context in the case the context itself is synthetic.
     // This is to ensure a flat input-type -> synthetic-item mapping.
     SynthesizingContext outerContext = SynthesizingContext.fromType(contextType);
-    DexType type = SyntheticNaming.createFixedType(kind, outerContext, factory);
-    return internalCreateClass(kind, fn, outerContext, type, factory);
+    DexType type = SyntheticNaming.createFixedType(kind, outerContext, appView.dexItemFactory());
+    return internalEnsureDexProgramClass(kind, fn, onCreationConsumer, outerContext, type, appView);
   }
 
   /** Create a single synthetic method item. */