Include horizontal class merging virtual method bridges in profiles
Bug: b/265729283
Change-Id: I415c65ebd24b53c3b261c199cd07b02d945fe1eb
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
index ff9cb9e..9a52be0 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -29,6 +29,7 @@
import com.android.tools.r8.ir.analysis.value.NumberFromIntervalValue;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
+import com.android.tools.r8.profile.art.rewriting.ArtProfileCollectionAdditions;
import com.android.tools.r8.utils.SetUtils;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
@@ -196,19 +197,22 @@
}
void mergeMethods(
+ ArtProfileCollectionAdditions artProfileCollectionAdditions,
SyntheticArgumentClass syntheticArgumentClass,
SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder,
Consumer<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfoConsumer) {
- mergeVirtualMethods(virtuallyMergedMethodsKeepInfoConsumer);
+ mergeVirtualMethods(artProfileCollectionAdditions, virtuallyMergedMethodsKeepInfoConsumer);
mergeDirectMethods(syntheticArgumentClass, syntheticInitializerConverterBuilder);
classMethodsBuilder.setClassMethods(group.getTarget());
}
void mergeVirtualMethods(
+ ArtProfileCollectionAdditions artProfileCollectionAdditions,
Consumer<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfoConsumer) {
virtualMethodMergers.forEach(
merger ->
merger.merge(
+ artProfileCollectionAdditions,
classMethodsBuilder,
lensBuilder,
classIdentifiers,
@@ -327,6 +331,7 @@
}
public void mergeGroup(
+ ArtProfileCollectionAdditions artProfileCollectionAdditions,
PrunedItems.Builder prunedItemsBuilder,
SyntheticArgumentClass syntheticArgumentClass,
SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder,
@@ -337,6 +342,7 @@
mergeInterfaces();
mergeFields(prunedItemsBuilder);
mergeMethods(
+ artProfileCollectionAdditions,
syntheticArgumentClass,
syntheticInitializerConverterBuilder,
virtuallyMergedMethodsKeepInfoConsumer);
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
index 3608975..8050e50 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.horizontalclassmerging.code.SyntheticInitializerConverter;
import com.android.tools.r8.ir.code.Invoke.Type;
+import com.android.tools.r8.profile.art.rewriting.ArtProfileCollectionAdditions;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.FieldAccessInfoCollectionModifier;
import com.android.tools.r8.shaking.KeepInfoCollection;
@@ -122,6 +123,8 @@
// Merge the classes.
List<ClassMerger> classMergers = initializeClassMergers(codeProvider, lensBuilder, groups);
+ ArtProfileCollectionAdditions artProfileCollectionAdditions =
+ ArtProfileCollectionAdditions.create(appView);
SyntheticArgumentClass syntheticArgumentClass =
mode.isInitial()
? new SyntheticArgumentClass.Builder(appView.withLiveness()).build(groups)
@@ -132,6 +135,7 @@
PrunedItems prunedItems =
applyClassMergers(
classMergers,
+ artProfileCollectionAdditions,
syntheticArgumentClass,
syntheticInitializerConverterBuilder,
virtuallyMergedMethodsKeepInfos::add);
@@ -148,6 +152,9 @@
HorizontalClassMergerGraphLens horizontalClassMergerGraphLens =
createLens(mergedClasses, lensBuilder, mode, syntheticArgumentClass);
+ artProfileCollectionAdditions =
+ artProfileCollectionAdditions.rewriteMethodReferences(
+ horizontalClassMergerGraphLens::getNextMethodToInvoke);
assert verifyNoCyclesInInterfaceHierarchies(appView, groups);
@@ -179,6 +186,11 @@
}
codeProvider.setGraphLens(horizontalClassMergerGraphLens);
+ // Amend art profile collection.
+ artProfileCollectionAdditions
+ .setArtProfileCollection(appView.getArtProfileCollection())
+ .commit(appView);
+
// Record where the synthesized $r8$classId fields are read and written.
if (mode.isInitial()) {
createFieldAccessInfoCollectionModifier(groups).modify(appView.withLiveness());
@@ -352,12 +364,14 @@
/** Merges all class groups using {@link ClassMerger}. */
private PrunedItems applyClassMergers(
Collection<ClassMerger> classMergers,
+ ArtProfileCollectionAdditions artProfileCollectionAdditions,
SyntheticArgumentClass syntheticArgumentClass,
SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder,
Consumer<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfoConsumer) {
PrunedItems.Builder prunedItemsBuilder = PrunedItems.builder().setPrunedApp(appView.app());
for (ClassMerger merger : classMergers) {
merger.mergeGroup(
+ artProfileCollectionAdditions,
prunedItemsBuilder,
syntheticArgumentClass,
syntheticInitializerConverterBuilder,
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
index 14465fd..51b4939 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
@@ -44,6 +44,11 @@
this.mergedClasses = mergedClasses;
}
+ DexMethod getNextMethodToInvoke(DexMethod method) {
+ DexMethod nextMethod = methodMap.apply(method);
+ return nextMethod != null ? nextMethod : method;
+ }
+
@Override
public boolean isHorizontalClassMergerGraphLens() {
return true;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
index 4e3227a..7d26bd1 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.profile.art.rewriting.ArtProfileCollectionAdditions;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.OptionalBool;
import com.android.tools.r8.utils.structural.Ordered;
@@ -244,6 +245,7 @@
}
public void merge(
+ ArtProfileCollectionAdditions artProfileCollectionAdditions,
ClassMethodsBuilder classMethodsBuilder,
HorizontalClassMergerGraphLens.Builder lensBuilder,
Reference2IntMap<DexType> classIdentifiers,
@@ -324,6 +326,15 @@
// Add a mapping from a synthetic name to the synthetic merged method.
lensBuilder.recordNewMethodSignature(bridgeMethodReference, newMethodReference);
+ // Amend the art profile collection.
+ if (!artProfileCollectionAdditions.isNop()) {
+ for (ProgramMethod oldMethod : methods) {
+ artProfileCollectionAdditions.applyIfContextIsInProfile(
+ oldMethod.getReference(),
+ additionsBuilder -> additionsBuilder.addRule(newMethodReference));
+ }
+ }
+
classMethodsBuilder.addVirtualMethod(newMethod);
if (!virtuallyMergedMethodsKeepInfo.getKeepInfo().isBottom()) {
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 b4e5881..988215e 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
@@ -20,6 +20,7 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
+import java.util.function.Function;
/** Mutable extension of an existing ArtProfile. */
public class ArtProfileAdditions {
@@ -34,7 +35,7 @@
ProgramMethod oldMethod, ProgramMethod newMethod);
}
- private final ArtProfile artProfile;
+ private ArtProfile artProfile;
private final Map<DexType, ArtProfileClassRule.Builder> classRuleAdditions =
new ConcurrentHashMap<>();
@@ -156,4 +157,23 @@
private boolean hasRemovals() {
return !methodRuleRemovals.isEmpty();
}
+
+ ArtProfileAdditions rewriteMethodReferences(Function<DexMethod, DexMethod> methodFn) {
+ ArtProfileAdditions rewrittenAdditions = new ArtProfileAdditions(artProfile);
+ assert classRuleAdditions.isEmpty();
+ assert methodRuleRemovals.isEmpty();
+ methodRuleAdditions.forEach(
+ (method, methodRuleBuilder) -> {
+ DexMethod newMethod = methodFn.apply(method);
+ ArtProfileMethodRule.Builder existingMethodRuleBuilder =
+ rewrittenAdditions.methodRuleAdditions.put(
+ newMethod, methodRuleBuilder.setMethod(newMethod));
+ assert existingMethodRuleBuilder == null;
+ });
+ return rewrittenAdditions;
+ }
+
+ void setArtProfile(ArtProfile artProfile) {
+ this.artProfile = artProfile;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileCollectionAdditions.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileCollectionAdditions.java
index ebc3584..858de9d 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileCollectionAdditions.java
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileCollectionAdditions.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.profile.art.ArtProfileCollection;
import com.android.tools.r8.profile.art.rewriting.ArtProfileAdditions.ArtProfileAdditionsBuilder;
import java.util.function.Consumer;
+import java.util.function.Function;
/**
* Interface for adding (synthetic) items to an existing ArtProfileCollection.
@@ -45,4 +46,10 @@
ConcreteArtProfileCollectionAdditions asConcrete() {
return null;
}
+
+ public abstract ArtProfileCollectionAdditions rewriteMethodReferences(
+ Function<DexMethod, DexMethod> methodFn);
+
+ public abstract ArtProfileCollectionAdditions setArtProfileCollection(
+ ArtProfileCollection artProfileCollection);
}
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 4868638..9c75c21 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
@@ -13,14 +13,21 @@
import com.android.tools.r8.profile.art.rewriting.ArtProfileAdditions.ArtProfileAdditionsBuilder;
import com.google.common.collect.Iterables;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
+import java.util.function.Function;
public class ConcreteArtProfileCollectionAdditions extends ArtProfileCollectionAdditions {
- private final List<ArtProfileAdditions> additionsCollection = new ArrayList<>();
+ private final List<ArtProfileAdditions> additionsCollection;
+
+ private ConcreteArtProfileCollectionAdditions(List<ArtProfileAdditions> additionsCollection) {
+ this.additionsCollection = additionsCollection;
+ }
ConcreteArtProfileCollectionAdditions(NonEmptyArtProfileCollection artProfileCollection) {
+ additionsCollection = new ArrayList<>();
for (ArtProfile artProfile : artProfileCollection) {
additionsCollection.add(new ArtProfileAdditions(artProfile));
}
@@ -64,4 +71,26 @@
private boolean hasAdditions() {
return Iterables.any(additionsCollection, ArtProfileAdditions::hasAdditions);
}
+
+ @Override
+ public ConcreteArtProfileCollectionAdditions rewriteMethodReferences(
+ Function<DexMethod, DexMethod> methodFn) {
+ List<ArtProfileAdditions> rewrittenAdditionsCollection =
+ new ArrayList<>(additionsCollection.size());
+ for (ArtProfileAdditions additions : additionsCollection) {
+ rewrittenAdditionsCollection.add(additions.rewriteMethodReferences(methodFn));
+ }
+ return new ConcreteArtProfileCollectionAdditions(rewrittenAdditionsCollection);
+ }
+
+ @Override
+ public ConcreteArtProfileCollectionAdditions setArtProfileCollection(
+ ArtProfileCollection artProfileCollection) {
+ assert artProfileCollection.isNonEmpty();
+ Iterator<ArtProfile> artProfileIterator = artProfileCollection.asNonEmpty().iterator();
+ for (ArtProfileAdditions additions : additionsCollection) {
+ additions.setArtProfile(artProfileIterator.next());
+ }
+ return this;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/NopArtProfileCollectionAdditions.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/NopArtProfileCollectionAdditions.java
index 8d73389..a0c6925 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/NopArtProfileCollectionAdditions.java
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/NopArtProfileCollectionAdditions.java
@@ -6,8 +6,10 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.profile.art.ArtProfileCollection;
import com.android.tools.r8.profile.art.rewriting.ArtProfileAdditions.ArtProfileAdditionsBuilder;
import java.util.function.Consumer;
+import java.util.function.Function;
public class NopArtProfileCollectionAdditions extends ArtProfileCollectionAdditions {
@@ -35,4 +37,18 @@
public boolean isNop() {
return true;
}
+
+ @Override
+ public NopArtProfileCollectionAdditions rewriteMethodReferences(
+ Function<DexMethod, DexMethod> methodFn) {
+ // Intentionally empty.
+ return this;
+ }
+
+ @Override
+ public NopArtProfileCollectionAdditions setArtProfileCollection(
+ ArtProfileCollection artProfileCollection) {
+ // Intentionally empty.
+ return this;
+ }
}
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/HorizontallyMergedVirtualMethodProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/HorizontallyMergedVirtualMethodProfileRewritingTest.java
index 29e39f9..28707d1 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/HorizontallyMergedVirtualMethodProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/HorizontallyMergedVirtualMethodProfileRewritingTest.java
@@ -6,6 +6,7 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -35,11 +36,11 @@
switch (this) {
case A_METHOD:
return ExternalArtProfile.builder()
- .addMethodRule(Reference.methodFromMethod(A.class.getDeclaredMethod("m")))
+ .addMethodRule(Reference.methodFromMethod(A.class.getDeclaredMethod("m", B.class)))
.build();
case B_METHOD:
return ExternalArtProfile.builder()
- .addMethodRule(Reference.methodFromMethod(B.class.getDeclaredMethod("m")))
+ .addMethodRule(Reference.methodFromMethod(B.class.getDeclaredMethod("m", B.class)))
.build();
default:
throw new RuntimeException();
@@ -64,9 +65,11 @@
MethodSubject syntheticBridgeMethodSubject =
aClassSubject.uniqueMethodThatMatches(FoundMethodSubject::isVirtual);
assertThat(syntheticBridgeMethodSubject, isPresent());
+ assertEquals(aClassSubject.asTypeSubject(), syntheticBridgeMethodSubject.getParameter(0));
- // TODO(b/265729283): Should contain the synthetic bridge method from above.
- profileInspector.assertContainsMethodRule(movedMethodSubject).assertContainsNoOtherRules();
+ profileInspector
+ .assertContainsMethodRules(movedMethodSubject, syntheticBridgeMethodSubject)
+ .assertContainsNoOtherRules();
}
}
@@ -92,7 +95,7 @@
inspector -> inspector.assertMergedInto(B.class, A.class).assertNoOtherClassesMerged())
.addOptionsModification(InlinerOptions::setOnlyForceInlining)
.addOptionsModification(
- options -> options.callSiteOptimizationOptions().setEnableMethodStaticizing(false))
+ options -> options.callSiteOptimizationOptions().disableOptimization())
.setMinApi(parameters.getApiLevel())
.compile()
.inspectResidualArtProfile(artProfileInputOutput::inspect)
@@ -103,21 +106,21 @@
static class Main {
public static void main(String[] args) {
- new A().m();
- new B().m();
+ new A().m(null);
+ new B().m(null);
}
}
static class A {
- public void m() {
+ public void m(B b) {
System.out.print("Hello");
}
}
static class B {
- public void m() {
+ public void m(B b) {
System.out.println(", world!");
}
}