Fix non-determinism in adding synthetics to profile
Bug: b/298344609
Change-Id: I6c9736fc683cf591dcf3f49021f66bb75ba5a92a
diff --git a/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java b/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
index be74e08..395a877 100644
--- a/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
+++ b/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
@@ -175,7 +175,9 @@
RecordDesugaring.ensureRecordClassHelper(
appView,
synthesizingContext,
- recordTagClass -> recordTagClass.programMethods().forEach(methodsToProcess::add));
+ recordTagClass -> recordTagClass.programMethods().forEach(methodsToProcess::add),
+ null,
+ null);
VarHandleDesugaringEventConsumer varHandleEventConsumer =
new VarHandleDesugaringEventConsumer() {
diff --git a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
index 9aa3575..d4f9278 100644
--- a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
+++ b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
@@ -204,40 +204,41 @@
if (contexts == null) {
throw new Unreachable("Attempt to create a global synthetic with no contexts");
}
- DexProgramClass mockClass =
- appView
- .appInfo()
- .getSyntheticItems()
- .ensureGlobalClass(
- () -> new MissingGlobalSyntheticsConsumerDiagnostic("API stubbing"),
- kinds -> kinds.API_MODEL_STUB,
- libraryClass.getType(),
- contexts,
- appView,
- classBuilder -> {
- classBuilder
- .setSuperType(libraryClass.getSuperType())
- .setInterfaces(Arrays.asList(libraryClass.getInterfaces().values))
- // Add throwing static initializer
- .addMethod(
- methodBuilder ->
- methodBuilder
- .setName(factory.classConstructorMethodName)
- .setProto(factory.createProto(factory.voidType))
- .setAccessFlags(MethodAccessFlags.createForClassInitializer())
- .setCode(method -> throwExceptionCode));
- if (libraryClass.isInterface()) {
- classBuilder.setInterface();
- }
- if (!libraryClass.isFinal()) {
- classBuilder.unsetFinal();
- }
- },
- clazz -> eventConsumer.acceptMockedLibraryClass(clazz, libraryClass));
- if (!eventConsumer.isEmpty()) {
- for (DexProgramClass context : contexts) {
- eventConsumer.acceptMockedLibraryClassContext(mockClass, libraryClass, context);
- }
- }
+ appView
+ .appInfo()
+ .getSyntheticItems()
+ .ensureGlobalClass(
+ () -> new MissingGlobalSyntheticsConsumerDiagnostic("API stubbing"),
+ kinds -> kinds.API_MODEL_STUB,
+ libraryClass.getType(),
+ contexts,
+ appView,
+ classBuilder -> {
+ classBuilder
+ .setSuperType(libraryClass.getSuperType())
+ .setInterfaces(Arrays.asList(libraryClass.getInterfaces().values))
+ // Add throwing static initializer
+ .addMethod(
+ methodBuilder ->
+ methodBuilder
+ .setName(factory.classConstructorMethodName)
+ .setProto(factory.createProto(factory.voidType))
+ .setAccessFlags(MethodAccessFlags.createForClassInitializer())
+ .setCode(method -> throwExceptionCode));
+ if (libraryClass.isInterface()) {
+ classBuilder.setInterface();
+ }
+ if (!libraryClass.isFinal()) {
+ classBuilder.unsetFinal();
+ }
+ },
+ clazz -> eventConsumer.acceptMockedLibraryClass(clazz, libraryClass),
+ clazz -> {
+ if (!eventConsumer.isEmpty()) {
+ for (DexProgramClass context : contexts) {
+ eventConsumer.acceptMockedLibraryClassContext(clazz, libraryClass, context);
+ }
+ }
+ });
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java b/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java
index 208c8ad..a7bbaae 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java
@@ -20,6 +20,11 @@
}
@Override
+ default DexProgramClass asClass() {
+ return null;
+ }
+
+ @Override
default ProgramField asField() {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java
index 5cd5230..c8a0668 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaring.java
@@ -416,17 +416,13 @@
private void ensureRecordClass(
RecordInstructionDesugaringEventConsumer eventConsumer, ProgramMethod context) {
- DexProgramClass recordTagClass =
- internalEnsureRecordClass(eventConsumer, ImmutableList.of(context));
- eventConsumer.acceptRecordClassContext(recordTagClass, context);
+ internalEnsureRecordClass(eventConsumer, null, eventConsumer, ImmutableList.of(context));
}
private void ensureRecordClass(
RecordClassSynthesizerDesugaringEventConsumer eventConsumer,
Collection<DexProgramClass> recordClasses) {
- DexProgramClass recordTagClass = internalEnsureRecordClass(eventConsumer, recordClasses);
- recordClasses.forEach(
- recordClass -> eventConsumer.acceptRecordClassContext(recordTagClass, recordClass));
+ internalEnsureRecordClass(eventConsumer, eventConsumer, null, recordClasses);
}
/**
@@ -439,16 +435,25 @@
*/
private DexProgramClass internalEnsureRecordClass(
RecordDesugaringEventConsumer eventConsumer,
+ RecordClassSynthesizerDesugaringEventConsumer recordClassSynthesizerDesugaringEventConsumer,
+ RecordInstructionDesugaringEventConsumer recordInstructionDesugaringEventConsumer,
Collection<? extends ProgramDefinition> contexts) {
DexItemFactory factory = appView.dexItemFactory();
checkRecordTagNotPresent(factory);
- return ensureRecordClassHelper(appView, contexts, eventConsumer);
+ return ensureRecordClassHelper(
+ appView,
+ contexts,
+ eventConsumer,
+ recordClassSynthesizerDesugaringEventConsumer,
+ recordInstructionDesugaringEventConsumer);
}
public static DexProgramClass ensureRecordClassHelper(
AppView<?> appView,
Collection<? extends ProgramDefinition> contexts,
- RecordDesugaringEventConsumer eventConsumer) {
+ RecordDesugaringEventConsumer eventConsumer,
+ RecordClassSynthesizerDesugaringEventConsumer recordClassSynthesizerDesugaringEventConsumer,
+ RecordInstructionDesugaringEventConsumer recordInstructionDesugaringEventConsumer) {
return appView
.getSyntheticItems()
.ensureGlobalClass(
@@ -461,7 +466,21 @@
DexEncodedMethod init = synthesizeRecordInitMethod(appView);
builder.setAbstract().setDirectMethods(ImmutableList.of(init));
},
- eventConsumer::acceptRecordClass);
+ eventConsumer::acceptRecordClass,
+ clazz -> {
+ if (recordClassSynthesizerDesugaringEventConsumer != null) {
+ for (ProgramDefinition context : contexts) {
+ recordClassSynthesizerDesugaringEventConsumer.acceptRecordClassContext(
+ clazz, context.asClass());
+ }
+ }
+ if (recordInstructionDesugaringEventConsumer != null) {
+ for (ProgramDefinition context : contexts) {
+ recordInstructionDesugaringEventConsumer.acceptRecordClassContext(
+ clazz, context.asMethod());
+ }
+ }
+ });
}
private void checkRecordTagNotPresent(DexItemFactory factory) {
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 1e5bf89..a5f2b75 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
@@ -221,22 +221,23 @@
Collection<? extends ProgramDefinition> contexts) {
assert contexts.stream()
.allMatch(context -> context.getContextType() != appView.dexItemFactory().varHandleType);
- DexProgramClass clazz =
- appView
- .getSyntheticItems()
- .ensureGlobalClass(
- () -> new MissingGlobalSyntheticsConsumerDiagnostic("VarHandle desugaring"),
- kinds -> kinds.VAR_HANDLE,
- appView.dexItemFactory().varHandleType,
- contexts,
- appView,
- builder ->
- VarHandleDesugaringMethods.generateDesugarVarHandleClass(
- builder, appView.dexItemFactory()),
- eventConsumer::acceptVarHandleDesugaringClass);
- for (ProgramDefinition context : contexts) {
- eventConsumer.acceptVarHandleDesugaringClassContext(clazz, context);
- }
+ appView
+ .getSyntheticItems()
+ .ensureGlobalClass(
+ () -> new MissingGlobalSyntheticsConsumerDiagnostic("VarHandle desugaring"),
+ kinds -> kinds.VAR_HANDLE,
+ appView.dexItemFactory().varHandleType,
+ contexts,
+ appView,
+ builder ->
+ VarHandleDesugaringMethods.generateDesugarVarHandleClass(
+ builder, appView.dexItemFactory()),
+ eventConsumer::acceptVarHandleDesugaringClass,
+ clazz -> {
+ for (ProgramDefinition context : contexts) {
+ eventConsumer.acceptVarHandleDesugaringClassContext(clazz, context);
+ }
+ });
}
private void ensureVarHandleClass(
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 e7dc070..5446ed9 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -666,6 +666,7 @@
private DexProgramClass internalEnsureFixedProgramClass(
SyntheticKind kind,
Consumer<SyntheticProgramClassBuilder> classConsumer,
+ Consumer<DexProgramClass> onReferencingContextConsumer,
Consumer<DexProgramClass> onCreationConsumer,
SynthesizingContext outerContext,
AppView<?> appView) {
@@ -675,6 +676,7 @@
// Fast path is that the synthetic is already present. If so it must be a program class.
DexProgramClass clazz = internalLookupProgramClass(type, kind, appView);
if (clazz != null) {
+ onReferencingContextConsumer.accept(clazz);
return clazz;
}
// Slow path creates the class using the context to make it thread safe.
@@ -696,6 +698,7 @@
type,
contextToType,
appView);
+ onReferencingContextConsumer.accept(clazz);
onCreationConsumer.accept(clazz);
return clazz;
}
@@ -805,8 +808,10 @@
Consumer<DexProgramClass> onCreationConsumer) {
SyntheticKind kind = kindSelector.select(naming);
assert kind.isFixedSuffixSynthetic();
+ Consumer<DexProgramClass> onReferencingContextConsumer = ConsumerUtils.emptyConsumer();
SynthesizingContext outerContext = internalGetOuterContext(context, appView);
- return internalEnsureFixedProgramClass(kind, fn, onCreationConsumer, outerContext, appView);
+ return internalEnsureFixedProgramClass(
+ kind, fn, onCreationConsumer, onReferencingContextConsumer, outerContext, appView);
}
public ProgramMethod ensureFixedClassMethod(
@@ -1008,6 +1013,26 @@
AppView<?> appView,
Consumer<SyntheticProgramClassBuilder> fn,
Consumer<DexProgramClass> onCreationConsumer) {
+ return ensureGlobalClass(
+ diagnosticSupplier,
+ kindSelector,
+ globalType,
+ contexts,
+ appView,
+ fn,
+ onCreationConsumer,
+ ConsumerUtils.emptyConsumer());
+ }
+
+ public DexProgramClass ensureGlobalClass(
+ Supplier<MissingGlobalSyntheticsConsumerDiagnostic> diagnosticSupplier,
+ SyntheticKindSelector kindSelector,
+ DexType globalType,
+ Collection<? extends ProgramDefinition> contexts,
+ AppView<?> appView,
+ Consumer<SyntheticProgramClassBuilder> fn,
+ Consumer<DexProgramClass> onCreationConsumer,
+ Consumer<DexProgramClass> onReferencingContextConsumer) {
SyntheticKind kind = kindSelector.select(naming);
assert kind.isGlobal();
assert !contexts.isEmpty();
@@ -1017,7 +1042,8 @@
// A global type is its own context.
SynthesizingContext outerContext = SynthesizingContext.fromType(globalType);
DexProgramClass globalSynthetic =
- internalEnsureFixedProgramClass(kind, fn, onCreationConsumer, outerContext, appView);
+ internalEnsureFixedProgramClass(
+ kind, fn, onReferencingContextConsumer, onCreationConsumer, outerContext, appView);
Consumer<DexProgramClass> globalSyntheticCreatedCallback =
appView.options().testing.globalSyntheticCreatedCallback;
if (globalSyntheticCreatedCallback != null) {