Extend profile rewriting to record desugaring
Bug: b/265729283
Change-Id: I2b53f06b9689884fc6a3e34435f9b4796416f009
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index d9e374d..7fac411 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -71,6 +71,7 @@
import com.android.tools.r8.optimize.interfaces.analysis.CfOpenClosedInterfacesAnalysis;
import com.android.tools.r8.optimize.proto.ProtoNormalizer;
import com.android.tools.r8.origin.CommandLineOrigin;
+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;
@@ -302,10 +303,13 @@
appView.dexItemFactory());
// Upfront desugaring generation: Generates new program classes to be added in the app.
+ ArtProfileCollectionAdditions artProfileCollectionAdditions =
+ ArtProfileCollectionAdditions.create(appView);
CfClassSynthesizerDesugaringEventConsumer classSynthesizerEventConsumer =
- new CfClassSynthesizerDesugaringEventConsumer();
+ CfClassSynthesizerDesugaringEventConsumer.create(artProfileCollectionAdditions);
CfClassSynthesizerDesugaringCollection.create(appView)
.synthesizeClasses(executorService, classSynthesizerEventConsumer);
+ artProfileCollectionAdditions.commit(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 5dc2584..b108b8d 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,9 +117,8 @@
ClassConverterResult.Builder resultBuilder, ExecutorService executorService)
throws ExecutionException {
Collection<DexProgramClass> classes = appView.appInfo().classes();
-
CfClassSynthesizerDesugaringEventConsumer classSynthesizerEventConsumer =
- new CfClassSynthesizerDesugaringEventConsumer();
+ CfClassSynthesizerDesugaringEventConsumer.create(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 dfaa50d..f2cdd81 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
@@ -9,56 +9,81 @@
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer;
import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterL8SynthesizerEventConsumer;
import com.android.tools.r8.ir.desugar.itf.EmulatedInterfaceSynthesizerEventConsumer.L8ProgramEmulatedInterfaceSynthesizerEventConsumer;
-import com.android.tools.r8.ir.desugar.records.RecordDesugaringEventConsumer;
+import com.android.tools.r8.ir.desugar.records.RecordDesugaringEventConsumer.RecordClassSynthesizerDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.varhandle.VarHandleDesugaringEventConsumer;
+import com.android.tools.r8.profile.art.rewriting.ArtProfileCollectionAdditions;
+import com.android.tools.r8.profile.art.rewriting.ArtProfileRewritingCfClassSynthesizerDesugaringEventConsumer;
import com.google.common.collect.Sets;
import java.util.Set;
-public class CfClassSynthesizerDesugaringEventConsumer
+public abstract class CfClassSynthesizerDesugaringEventConsumer
implements L8ProgramEmulatedInterfaceSynthesizerEventConsumer,
DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer,
DesugaredLibraryRetargeterL8SynthesizerEventConsumer,
- RecordDesugaringEventConsumer,
+ RecordClassSynthesizerDesugaringEventConsumer,
VarHandleDesugaringEventConsumer {
- private Set<DexProgramClass> synthesizedClasses = Sets.newConcurrentHashSet();
+ protected CfClassSynthesizerDesugaringEventConsumer() {}
- @Override
- public void acceptProgramEmulatedInterface(DexProgramClass clazz) {
- synthesizedClasses.add(clazz);
+ public static CfClassSynthesizerDesugaringEventConsumer create(
+ ArtProfileCollectionAdditions artProfileCollectionAdditions) {
+ CfClassSynthesizerDesugaringEventConsumer eventConsumer =
+ new D8R8CfClassSynthesizerDesugaringEventConsumer();
+ return ArtProfileRewritingCfClassSynthesizerDesugaringEventConsumer.attach(
+ artProfileCollectionAdditions, eventConsumer);
}
- @Override
- public void acceptWrapperProgramClass(DexProgramClass clazz) {
- synthesizedClasses.add(clazz);
- }
+ public abstract Set<DexProgramClass> getSynthesizedClasses();
- @Override
- public void acceptEnumConversionProgramClass(DexProgramClass clazz) {
- synthesizedClasses.add(clazz);
- }
+ private static class D8R8CfClassSynthesizerDesugaringEventConsumer
+ extends CfClassSynthesizerDesugaringEventConsumer {
- @Override
- public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) {
- synthesizedClasses.add(clazz);
- }
+ private final Set<DexProgramClass> synthesizedClasses = Sets.newConcurrentHashSet();
- @Override
- public void acceptRecordClass(DexProgramClass clazz) {
- synthesizedClasses.add(clazz);
- }
+ @Override
+ public void acceptProgramEmulatedInterface(DexProgramClass clazz) {
+ synthesizedClasses.add(clazz);
+ }
- @Override
- public void acceptVarHandleDesugaringClass(DexProgramClass clazz) {
- synthesizedClasses.add(clazz);
- }
+ @Override
+ public void acceptWrapperProgramClass(DexProgramClass clazz) {
+ synthesizedClasses.add(clazz);
+ }
- public Set<DexProgramClass> getSynthesizedClasses() {
- return synthesizedClasses;
- }
+ @Override
+ public void acceptEnumConversionProgramClass(DexProgramClass clazz) {
+ synthesizedClasses.add(clazz);
+ }
- @Override
- public void acceptCollectionConversion(ProgramMethod arrayConversion) {
- synthesizedClasses.add(arrayConversion.getHolder());
+ @Override
+ public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) {
+ synthesizedClasses.add(clazz);
+ }
+
+ @Override
+ public void acceptRecordClass(DexProgramClass recordTagClass) {
+ synthesizedClasses.add(recordTagClass);
+ }
+
+ @Override
+ public void acceptRecordClassContext(
+ DexProgramClass recordTagClass, DexProgramClass recordClass) {
+ // Intentionally empty.
+ }
+
+ @Override
+ public void acceptVarHandleDesugaringClass(DexProgramClass clazz) {
+ synthesizedClasses.add(clazz);
+ }
+
+ @Override
+ public Set<DexProgramClass> getSynthesizedClasses() {
+ return synthesizedClasses;
+ }
+
+ @Override
+ public void acceptCollectionConversion(ProgramMethod arrayConversion) {
+ synthesizedClasses.add(arrayConversion.getHolder());
+ }
}
}
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 d852270..45a508e 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
@@ -173,7 +173,23 @@
}
@Override
- public void acceptRecordMethod(ProgramMethod method) {
+ public void acceptRecordEqualsHelperMethod(ProgramMethod method, ProgramMethod context) {
+ // Intentionally empty. Added to the program using ProgramAdditions.
+ }
+
+ @Override
+ public void acceptRecordGetFieldsAsObjectsHelperMethod(
+ ProgramMethod method, ProgramMethod context) {
+ // Intentionally empty. Added to the program using ProgramAdditions.
+ }
+
+ @Override
+ public void acceptRecordHashCodeHelperMethod(ProgramMethod method, ProgramMethod context) {
+ methodProcessor.scheduleDesugaredMethodForProcessing(method);
+ }
+
+ @Override
+ public void acceptRecordToStringHelperMethod(ProgramMethod method, ProgramMethod context) {
methodProcessor.scheduleDesugaredMethodForProcessing(method);
}
@@ -191,6 +207,11 @@
}
@Override
+ public void acceptRecordClassContext(DexProgramClass recordTagClass, ProgramMethod context) {
+ // Intentionally empty.
+ }
+
+ @Override
public void acceptVarHandleDesugaringClass(DexProgramClass clazz) {
clazz
.programMethods()
@@ -423,6 +444,11 @@
}
@Override
+ public void acceptRecordClassContext(DexProgramClass recordTagClass, ProgramMethod context) {
+ // Intentionally empty.
+ }
+
+ @Override
public void acceptVarHandleDesugaringClass(DexProgramClass clazz) {
// Intentionally empty. The class will be hit by tracing if required.
}
@@ -433,7 +459,23 @@
}
@Override
- public void acceptRecordMethod(ProgramMethod method) {
+ public void acceptRecordEqualsHelperMethod(ProgramMethod method, ProgramMethod context) {
+ // Intentionally empty. The method will be hit by tracing if required.
+ }
+
+ @Override
+ public void acceptRecordGetFieldsAsObjectsHelperMethod(
+ ProgramMethod method, ProgramMethod context) {
+ // Intentionally empty. The method will be hit by tracing if required.
+ }
+
+ @Override
+ public void acceptRecordHashCodeHelperMethod(ProgramMethod method, ProgramMethod context) {
+ // Intentionally empty. The method will be hit by tracing if required.
+ }
+
+ @Override
+ public void acceptRecordToStringHelperMethod(ProgramMethod method, ProgramMethod context) {
// Intentionally empty. The method will be hit by tracing if required.
}
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 afae01d..2140c13 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
@@ -48,6 +48,7 @@
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
import com.android.tools.r8.ir.desugar.LocalStackAllocator;
import com.android.tools.r8.ir.desugar.ProgramAdditions;
+import com.android.tools.r8.ir.desugar.records.RecordDesugaringEventConsumer.RecordClassSynthesizerDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.records.RecordDesugaringEventConsumer.RecordInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.records.RecordRewriterHelper.RecordInvokeDynamic;
import com.android.tools.r8.ir.synthetic.CallObjectInitCfCodeProvider;
@@ -59,7 +60,6 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.function.BiFunction;
import org.objectweb.asm.Opcodes;
@@ -103,22 +103,26 @@
CfCode cfCode = method.getDefinition().getCode().asCfCode();
for (CfInstruction instruction : cfCode.getInstructions()) {
if (instruction.isInvokeDynamic() && needsDesugaring(instruction, method)) {
- prepareInvokeDynamicOnRecord(instruction.asInvokeDynamic(), programAdditions, method);
+ prepareInvokeDynamicOnRecord(
+ instruction.asInvokeDynamic(), programAdditions, method, eventConsumer);
}
}
}
private void prepareInvokeDynamicOnRecord(
- CfInvokeDynamic invokeDynamic, ProgramAdditions programAdditions, ProgramMethod context) {
+ CfInvokeDynamic invokeDynamic,
+ ProgramAdditions programAdditions,
+ ProgramMethod context,
+ RecordInstructionDesugaringEventConsumer eventConsumer) {
RecordInvokeDynamic recordInvokeDynamic =
parseInvokeDynamicOnRecord(invokeDynamic, appView, context);
if (recordInvokeDynamic.getMethodName() == factory.toStringMethodName
|| recordInvokeDynamic.getMethodName() == factory.hashCodeMethodName) {
- ensureGetFieldsAsObjects(recordInvokeDynamic, programAdditions);
+ ensureGetFieldsAsObjects(recordInvokeDynamic, programAdditions, context, eventConsumer);
return;
}
if (recordInvokeDynamic.getMethodName() == factory.equalsMethodName) {
- ensureEqualsRecord(recordInvokeDynamic, programAdditions);
+ ensureEqualsRecord(recordInvokeDynamic, programAdditions, context, eventConsumer);
return;
}
throw new Unreachable("Invoke dynamic needs record desugaring but could not be desugared.");
@@ -207,11 +211,19 @@
parseInvokeDynamicOnRecord(invokeDynamic, appView, context);
if (recordInvokeDynamic.getMethodName() == factory.toStringMethodName) {
return desugarInvokeRecordToString(
- recordInvokeDynamic, localStackAllocator, eventConsumer, methodProcessingContext);
+ recordInvokeDynamic,
+ localStackAllocator,
+ eventConsumer,
+ context,
+ methodProcessingContext);
}
if (recordInvokeDynamic.getMethodName() == factory.hashCodeMethodName) {
return desugarInvokeRecordHashCode(
- recordInvokeDynamic, localStackAllocator, eventConsumer, methodProcessingContext);
+ recordInvokeDynamic,
+ localStackAllocator,
+ eventConsumer,
+ context,
+ methodProcessingContext);
}
if (recordInvokeDynamic.getMethodName() == factory.equalsMethodName) {
return desugarInvokeRecordEquals(recordInvokeDynamic);
@@ -251,24 +263,37 @@
}
private DexMethod ensureEqualsRecord(
- RecordInvokeDynamic recordInvokeDynamic, ProgramAdditions programAdditions) {
- DexMethod getFieldsAsObjects = ensureGetFieldsAsObjects(recordInvokeDynamic, programAdditions);
+ RecordInvokeDynamic recordInvokeDynamic,
+ ProgramAdditions programAdditions,
+ ProgramMethod context,
+ RecordInstructionDesugaringEventConsumer eventConsumer) {
+ DexMethod getFieldsAsObjects =
+ ensureGetFieldsAsObjects(recordInvokeDynamic, programAdditions, context, eventConsumer);
DexProgramClass clazz = recordInvokeDynamic.getRecordClass();
DexMethod method = equalsRecordMethod(clazz.type);
assert clazz.lookupProgramMethod(method) == null;
- programAdditions.ensureMethod(
- method, () -> synthesizeEqualsRecordMethod(clazz, getFieldsAsObjects, method));
+ ProgramMethod equalsHelperMethod =
+ programAdditions.ensureMethod(
+ method, () -> synthesizeEqualsRecordMethod(clazz, getFieldsAsObjects, method));
+ eventConsumer.acceptRecordEqualsHelperMethod(equalsHelperMethod, context);
return method;
}
private DexMethod ensureGetFieldsAsObjects(
- RecordInvokeDynamic recordInvokeDynamic, ProgramAdditions programAdditions) {
+ RecordInvokeDynamic recordInvokeDynamic,
+ ProgramAdditions programAdditions,
+ ProgramMethod context,
+ RecordInstructionDesugaringEventConsumer eventConsumer) {
DexProgramClass clazz = recordInvokeDynamic.getRecordClass();
DexMethod method = getFieldsAsObjectsMethod(clazz.type);
assert clazz.lookupProgramMethod(method) == null;
- programAdditions.ensureMethod(
- method,
- () -> synthesizeGetFieldsAsObjectsMethod(clazz, recordInvokeDynamic.getFields(), method));
+ ProgramMethod getFieldsAsObjectsHelperMethod =
+ programAdditions.ensureMethod(
+ method,
+ () ->
+ synthesizeGetFieldsAsObjectsMethod(clazz, recordInvokeDynamic.getFields(), method));
+ eventConsumer.acceptRecordGetFieldsAsObjectsHelperMethod(
+ getFieldsAsObjectsHelperMethod, context);
return method;
}
@@ -306,6 +331,7 @@
RecordInvokeDynamic recordInvokeDynamic,
LocalStackAllocator localStackAllocator,
RecordInstructionDesugaringEventConsumer eventConsumer,
+ ProgramMethod context,
MethodProcessingContext methodProcessingContext) {
localStackAllocator.allocateLocalStack(1);
DexMethod getFieldsAsObjects = getFieldsAsObjectsMethod(recordInvokeDynamic.getRecordType());
@@ -320,7 +346,7 @@
recordHashCodeHelperProto,
RecordCfMethods::RecordMethods_hashCode,
methodProcessingContext);
- eventConsumer.acceptRecordMethod(programMethod);
+ eventConsumer.acceptRecordHashCodeHelperMethod(programMethod, context);
instructions.add(new CfInvoke(Opcodes.INVOKESTATIC, programMethod.getReference(), false));
return instructions;
}
@@ -335,6 +361,7 @@
RecordInvokeDynamic recordInvokeDynamic,
LocalStackAllocator localStackAllocator,
RecordInstructionDesugaringEventConsumer eventConsumer,
+ ProgramMethod context,
MethodProcessingContext methodProcessingContext) {
localStackAllocator.allocateLocalStack(2);
DexMethod getFieldsAsObjects = getFieldsAsObjectsMethod(recordInvokeDynamic.getRecordType());
@@ -357,7 +384,7 @@
recordToStringHelperProto,
RecordCfMethods::RecordMethods_toString,
methodProcessingContext);
- eventConsumer.acceptRecordMethod(programMethod);
+ eventConsumer.acceptRecordToStringHelperMethod(programMethod, context);
instructions.add(new CfInvoke(Opcodes.INVOKESTATIC, programMethod.getReference(), false));
return instructions;
}
@@ -374,6 +401,21 @@
return false;
}
+ private void ensureRecordClass(
+ RecordInstructionDesugaringEventConsumer eventConsumer, ProgramMethod context) {
+ DexProgramClass recordTagClass =
+ internalEnsureRecordClass(eventConsumer, ImmutableList.of(context));
+ eventConsumer.acceptRecordClassContext(recordTagClass, context);
+ }
+
+ private void ensureRecordClass(
+ RecordClassSynthesizerDesugaringEventConsumer eventConsumer,
+ Collection<DexProgramClass> recordClasses) {
+ DexProgramClass recordTagClass = internalEnsureRecordClass(eventConsumer, recordClasses);
+ recordClasses.forEach(
+ recordClass -> eventConsumer.acceptRecordClassContext(recordTagClass, recordClass));
+ }
+
/**
* If java.lang.Record is referenced from a class' supertype or a program method/field signature,
* then the global synthetic is generated upfront of the compilation to avoid confusing D8/R8.
@@ -382,11 +424,12 @@
* contains "x instance of java.lang.Record" but no record type is present, then the global
* synthetic is generated during instruction desugaring scanning.
*/
- private void ensureRecordClass(
- RecordDesugaringEventConsumer eventConsumer, Collection<ProgramDefinition> contexts) {
+ private DexProgramClass internalEnsureRecordClass(
+ RecordDesugaringEventConsumer eventConsumer,
+ Collection<? extends ProgramDefinition> contexts) {
DexItemFactory factory = appView.dexItemFactory();
checkRecordTagNotPresent(factory);
- appView
+ return appView
.getSyntheticItems()
.ensureGlobalClass(
() -> new MissingGlobalSyntheticsConsumerDiagnostic("Record desugaring"),
@@ -401,11 +444,6 @@
eventConsumer::acceptRecordClass);
}
- private void ensureRecordClass(
- RecordDesugaringEventConsumer eventConsumer, ProgramDefinition context) {
- ensureRecordClass(eventConsumer, ImmutableList.of(context));
- }
-
private void checkRecordTagNotPresent(DexItemFactory factory) {
DexClass r8RecordClass =
appView.appInfo().definitionForWithoutExistenceAssert(factory.recordTagType);
@@ -505,7 +543,7 @@
CfClassSynthesizerDesugaringEventConsumer eventConsumer) {
DexApplicationReadFlags flags = appView.appInfo().app().getFlags();
if (flags.hasReadRecordReferenceFromProgramClass()) {
- List<ProgramDefinition> classes = new ArrayList<>();
+ List<DexProgramClass> classes = new ArrayList<>(flags.getRecordWitnesses().size());
for (DexType recordWitness : flags.getRecordWitnesses()) {
DexClass dexClass = appView.contextIndependentDefinitionFor(recordWitness);
assert dexClass != null;
@@ -520,8 +558,7 @@
public void postProcessingDesugaring(
Collection<DexProgramClass> programClasses,
CfPostProcessingDesugaringEventConsumer eventConsumer,
- ExecutorService executorService)
- throws ExecutionException {
+ ExecutorService executorService) {
for (DexProgramClass clazz : programClasses) {
if (clazz.isRecord()) {
assert clazz.superType == factory.recordType;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaringEventConsumer.java
index f81b5d6..469e0de 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordDesugaringEventConsumer.java
@@ -8,10 +8,23 @@
public interface RecordDesugaringEventConsumer {
- void acceptRecordClass(DexProgramClass recordClass);
+ void acceptRecordClass(DexProgramClass recordTagClass);
+
+ interface RecordClassSynthesizerDesugaringEventConsumer extends RecordDesugaringEventConsumer {
+
+ void acceptRecordClassContext(DexProgramClass recordTagClass, DexProgramClass recordClass);
+ }
interface RecordInstructionDesugaringEventConsumer extends RecordDesugaringEventConsumer {
- void acceptRecordMethod(ProgramMethod method);
+ void acceptRecordClassContext(DexProgramClass recordTagClass, ProgramMethod context);
+
+ void acceptRecordEqualsHelperMethod(ProgramMethod method, ProgramMethod context);
+
+ void acceptRecordGetFieldsAsObjectsHelperMethod(ProgramMethod method, ProgramMethod context);
+
+ void acceptRecordHashCodeHelperMethod(ProgramMethod method, ProgramMethod context);
+
+ void acceptRecordToStringHelperMethod(ProgramMethod method, ProgramMethod context);
}
}
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileAdditions.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileAdditions.java
index 988215e..239df06 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileAdditions.java
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileAdditions.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.profile.art.rewriting;
+import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
@@ -47,6 +48,12 @@
this.artProfile = artProfile;
}
+ void applyIfContextIsInProfile(DexType context, Consumer<ArtProfileAdditions> fn) {
+ if (artProfile.containsClassRule(context)) {
+ fn.accept(this);
+ }
+ }
+
void applyIfContextIsInProfile(
DexMethod context, Consumer<ArtProfileAdditionsBuilder> builderConsumer) {
ArtProfileMethodRule contextMethodRule = artProfile.getMethodRule(context);
@@ -88,7 +95,11 @@
}
}
- private void addClassRule(DexType type) {
+ public void addClassRule(DexClass clazz) {
+ addClassRule(clazz.getType());
+ }
+
+ public void addClassRule(DexType type) {
if (artProfile.containsClassRule(type)) {
return;
}
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
new file mode 100644
index 0000000..3cc4631
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingCfClassSynthesizerDesugaringEventConsumer.java
@@ -0,0 +1,90 @@
+// 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 com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringEventConsumer;
+import java.util.Set;
+
+public class ArtProfileRewritingCfClassSynthesizerDesugaringEventConsumer
+ extends CfClassSynthesizerDesugaringEventConsumer {
+
+ private final ConcreteArtProfileCollectionAdditions additionsCollection;
+ private final CfClassSynthesizerDesugaringEventConsumer parent;
+
+ private ArtProfileRewritingCfClassSynthesizerDesugaringEventConsumer(
+ ConcreteArtProfileCollectionAdditions additionsCollection,
+ CfClassSynthesizerDesugaringEventConsumer parent) {
+ this.additionsCollection = additionsCollection;
+ this.parent = parent;
+ }
+
+ public static CfClassSynthesizerDesugaringEventConsumer attach(
+ ArtProfileCollectionAdditions artProfileCollectionAdditions,
+ CfClassSynthesizerDesugaringEventConsumer eventConsumer) {
+ if (artProfileCollectionAdditions.isNop()) {
+ return eventConsumer;
+ }
+ return new ArtProfileRewritingCfClassSynthesizerDesugaringEventConsumer(
+ artProfileCollectionAdditions.asConcrete(), eventConsumer);
+ }
+
+ @Override
+ public void acceptCollectionConversion(ProgramMethod arrayConversion) {
+ parent.acceptCollectionConversion(arrayConversion);
+ }
+
+ @Override
+ public void acceptWrapperProgramClass(DexProgramClass clazz) {
+ parent.acceptWrapperProgramClass(clazz);
+ }
+
+ @Override
+ public void acceptEnumConversionProgramClass(DexProgramClass clazz) {
+ parent.acceptEnumConversionProgramClass(clazz);
+ }
+
+ @Override
+ public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) {
+ parent.acceptDesugaredLibraryRetargeterDispatchProgramClass(clazz);
+ }
+
+ @Override
+ public void acceptProgramEmulatedInterface(DexProgramClass clazz) {
+ parent.acceptProgramEmulatedInterface(clazz);
+ }
+
+ @Override
+ public void acceptRecordClass(DexProgramClass recordClass) {
+ parent.acceptRecordClass(recordClass);
+ }
+
+ @Override
+ public void acceptRecordClassContext(
+ DexProgramClass recordTagClass, DexProgramClass recordClass) {
+ additionsCollection.applyIfContextIsInProfile(
+ recordClass, additions -> additions.addClassRule(recordTagClass));
+ ProgramMethod recordTagInstanceInitializer = recordTagClass.getProgramDefaultInitializer();
+ if (recordTagInstanceInitializer != null) {
+ recordClass.forEachProgramInstanceInitializer(
+ recordInstanceInitializer ->
+ additionsCollection.applyIfContextIsInProfile(
+ recordInstanceInitializer,
+ additionsBuilder -> additionsBuilder.addRule(recordTagInstanceInitializer)));
+ }
+ parent.acceptRecordClassContext(recordTagClass, recordClass);
+ }
+
+ @Override
+ public void acceptVarHandleDesugaringClass(DexProgramClass varHandleClass) {
+ parent.acceptVarHandleDesugaringClass(varHandleClass);
+ }
+
+ @Override
+ public Set<DexProgramClass> getSynthesizedClasses() {
+ return parent.getSynthesizedClasses();
+ }
+}
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 5b54cd3..221f967 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
@@ -217,8 +217,37 @@
}
@Override
- public void acceptRecordMethod(ProgramMethod method) {
- parent.acceptRecordMethod(method);
+ public void acceptRecordClassContext(DexProgramClass recordTagClass, ProgramMethod context) {
+ parent.acceptRecordClassContext(recordTagClass, context);
+ }
+
+ @Override
+ public void acceptRecordEqualsHelperMethod(ProgramMethod method, ProgramMethod context) {
+ additionsCollection.applyIfContextIsInProfile(
+ context, additionsBuilder -> additionsBuilder.addRule(method));
+ parent.acceptRecordEqualsHelperMethod(method, context);
+ }
+
+ @Override
+ public void acceptRecordGetFieldsAsObjectsHelperMethod(
+ ProgramMethod method, ProgramMethod context) {
+ additionsCollection.applyIfContextIsInProfile(
+ context, additionsBuilder -> additionsBuilder.addRule(method));
+ parent.acceptRecordGetFieldsAsObjectsHelperMethod(method, context);
+ }
+
+ @Override
+ public void acceptRecordHashCodeHelperMethod(ProgramMethod method, ProgramMethod context) {
+ additionsCollection.applyIfContextIsInProfile(
+ context, additionsBuilder -> additionsBuilder.addRule(method).addRule(method.getHolder()));
+ parent.acceptRecordHashCodeHelperMethod(method, context);
+ }
+
+ @Override
+ public void acceptRecordToStringHelperMethod(ProgramMethod method, ProgramMethod context) {
+ additionsCollection.applyIfContextIsInProfile(
+ context, additionsBuilder -> additionsBuilder.addRule(method).addRule(method.getHolder()));
+ parent.acceptRecordToStringHelperMethod(method, context);
}
@Override
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 9c75c21..24d6911 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
@@ -5,8 +5,10 @@
package com.android.tools.r8.profile.art.rewriting;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.profile.art.ArtProfile;
import com.android.tools.r8.profile.art.ArtProfileCollection;
import com.android.tools.r8.profile.art.NonEmptyArtProfileCollection;
@@ -35,6 +37,17 @@
}
void applyIfContextIsInProfile(
+ DexClass context, Consumer<ArtProfileAdditions> additionsConsumer) {
+ applyIfContextIsInProfile(context.getType(), additionsConsumer);
+ }
+
+ void applyIfContextIsInProfile(DexType type, Consumer<ArtProfileAdditions> additionsConsumer) {
+ for (ArtProfileAdditions artProfileAdditions : additionsCollection) {
+ artProfileAdditions.applyIfContextIsInProfile(type, additionsConsumer);
+ }
+ }
+
+ void applyIfContextIsInProfile(
DexClassAndMethod context, Consumer<ArtProfileAdditionsBuilder> builderConsumer) {
applyIfContextIsInProfile(context.getReference(), builderConsumer);
}
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 bf4029e..d8ae369 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -91,7 +91,7 @@
new ContextsForGlobalSyntheticsInSingleOutputMode() {
@Override
public void addGlobalContexts(
- DexType globalType, Collection<ProgramDefinition> contexts) {
+ DexType globalType, Collection<? extends ProgramDefinition> contexts) {
throw new Unreachable("Unexpected attempt to add globals to non-desugaring build.");
}
};
@@ -114,7 +114,7 @@
void forEach(BiConsumer<DexType, Set<DexType>> fn);
- void addGlobalContexts(DexType globalType, Collection<ProgramDefinition> contexts);
+ void addGlobalContexts(DexType globalType, Collection<? extends ProgramDefinition> contexts);
}
private static class ContextsForGlobalSyntheticsInSingleOutputMode
@@ -131,7 +131,8 @@
}
@Override
- public void addGlobalContexts(DexType globalType, Collection<ProgramDefinition> contexts) {
+ public void addGlobalContexts(
+ DexType globalType, Collection<? extends ProgramDefinition> contexts) {
// contexts are ignored in single output modes.
}
}
@@ -152,7 +153,8 @@
}
@Override
- public void addGlobalContexts(DexType globalType, Collection<ProgramDefinition> contexts) {
+ public void addGlobalContexts(
+ DexType globalType, Collection<? extends ProgramDefinition> contexts) {
Set<DexType> contextReferences =
globalContexts.computeIfAbsent(globalType, k -> ConcurrentHashMap.newKeySet());
contexts.forEach(definition -> contextReferences.add(definition.getContextType()));
@@ -976,7 +978,7 @@
Supplier<MissingGlobalSyntheticsConsumerDiagnostic> diagnosticSupplier,
SyntheticKindSelector kindSelector,
DexType globalType,
- Collection<ProgramDefinition> contexts,
+ Collection<? extends ProgramDefinition> contexts,
AppView<?> appView,
Consumer<SyntheticProgramClassBuilder> fn,
Consumer<DexProgramClass> onCreationConsumer) {
@@ -1033,7 +1035,8 @@
pending.definitions.put(definition.getHolder().getType(), definition);
}
- private void addGlobalContexts(DexType globalType, Collection<ProgramDefinition> contexts) {
+ private void addGlobalContexts(
+ DexType globalType, Collection<? extends ProgramDefinition> contexts) {
globalContexts.addGlobalContexts(globalType, contexts);
}
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java
index dcf365b..0969070 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java
@@ -267,8 +267,6 @@
assertThat(
toStringMethodSubject, ifThen(!canUseRecords, invokesMethod(toStringHelperMethodSubject)));
- // TODO(b/265729283): Should include all the synthetics from above when there is no native
- // support.
profileInspector
.assertContainsClassRule(personRecordClassSubject)
.assertContainsMethodRules(
@@ -284,6 +282,19 @@
i ->
i.assertContainsMethodRules(
nameNestAccessorMethodSubject, ageNestAccessorMethodSubject))
+ .applyIf(
+ !canUseRecords,
+ i ->
+ i.assertContainsClassRules(
+ recordTagClassSubject,
+ hashCodeHelperClassSubject,
+ toStringHelperClassSubject)
+ .assertContainsMethodRules(
+ recordTagInstanceInitializerSubject,
+ equalsHelperMethodSubject,
+ getFieldsAsObjectsMethodSubject,
+ hashCodeHelperMethodSubject,
+ toStringHelperMethodSubject))
.assertContainsNoOtherRules();
}
}