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. */