Mark methods obsolete after optimizations
Change-Id: If57dbdf8afe7254d0912b706f4a109d6d742bf32
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index cc0041b..83ea812 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -936,7 +936,10 @@
timing.begin("Rewrite AppView");
boolean changed = appView.setGraphLens(lens);
- assert changed;
+
+ // Verify that the lens changed, except in the horizontal class merger case, where we install
+ // the lens prior to lens rewriting AppView.
+ assert changed || lens.isHorizontalClassMergerGraphLens();
assert application.verifyWithLens(appView.appInfo().app().asDirect(), lens);
// The application has already been rewritten with the given applied lens. Therefore, we
@@ -1051,7 +1054,10 @@
private static void rewriteWithD8Lens(
NonIdentityGraphLens lens, Timing timing, AppView<AppInfo> appView) {
boolean changed = appView.setGraphLens(lens);
- assert changed;
+
+ // Verify that the lens changed, except in the horizontal class merger case, where we install
+ // the lens prior to lens rewriting AppView.
+ assert changed || lens.isHorizontalClassMergerGraphLens();
appView.setArtProfileCollection(
appView.getArtProfileCollection().rewrittenWithLens(appView, lens, timing));
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 459cf9a..efbfad4 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -114,6 +114,10 @@
profileCollectionAdditions, syntheticArgumentClass, syntheticInitializerConverterBuilder);
mergeStaticClassInitializers(syntheticInitializerConverterBuilder);
group.forEach(this::mergeDirectMethods);
+ if (!classInitializerMerger.isEmpty() && classInitializerMerger.isTrivialMerge()) {
+ classInitializerMerger.setObsolete();
+ }
+ instanceInitializerMergers.setObsolete();
}
void mergeStaticClassInitializers(
@@ -165,7 +169,10 @@
if (!classMethodsBuilder.isFresh(newMethod)) {
newMethod = renameDirectMethod(method);
}
- classMethodsBuilder.addDirectMethod(definition.toTypeSubstitutedMethod(newMethod));
+ classMethodsBuilder.addDirectMethod(
+ newMethod != method.getReference()
+ ? definition.toTypeSubstitutedMethod(newMethod)
+ : method.getDefinition());
if (definition.getReference() != newMethod) {
lensBuilder.moveMethod(definition.getReference(), newMethod);
}
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 746dbd5..3fa5ee2 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -162,6 +162,21 @@
assert verifyNoCyclesInInterfaceHierarchies(appView, groups);
+ FieldAccessInfoCollectionModifier fieldAccessInfoCollectionModifier = null;
+ if (mode.isInitial()) {
+ fieldAccessInfoCollectionModifier = createFieldAccessInfoCollectionModifier(groups);
+ } else {
+ assert groups.stream().noneMatch(MergeGroup::hasClassIdField);
+ }
+
+ // Set the new graph lens before finalizing any synthetic code.
+ appView.setGraphLens(horizontalClassMergerGraphLens);
+ codeProvider.setGraphLens(horizontalClassMergerGraphLens);
+
+ // Finalize synthetic code.
+ transformIncompleteCode(groups, horizontalClassMergerGraphLens, executorService);
+ syntheticInitializerConverter.convertInstanceInitializers(executorService);
+
// Must rewrite AppInfoWithLiveness before pruning the merged classes, to ensure that allocation
// sites, fields accesses, etc. are correctly transferred to the target classes.
DexApplication newApplication = getNewApplication(mergedClasses);
@@ -188,7 +203,6 @@
.rewrittenWithLens(syntheticItems, horizontalClassMergerGraphLens, timing)));
appView.rewriteWithD8Lens(horizontalClassMergerGraphLens, timing);
}
- codeProvider.setGraphLens(horizontalClassMergerGraphLens);
// Amend art profile collection.
profileCollectionAdditions
@@ -197,15 +211,10 @@
.commit(appView);
// Record where the synthesized $r8$classId fields are read and written.
- if (mode.isInitial()) {
- createFieldAccessInfoCollectionModifier(groups).modify(appView.withLiveness());
- } else {
- assert groups.stream().noneMatch(MergeGroup::hasClassIdField);
+ if (fieldAccessInfoCollectionModifier != null) {
+ fieldAccessInfoCollectionModifier.modify(appView.withLiveness());
}
- transformIncompleteCode(groups, horizontalClassMergerGraphLens, executorService);
- syntheticInitializerConverter.convertInstanceInitializers(executorService);
-
appView.pruneItems(
prunedItems.toBuilder().setPrunedApp(appView.app()).build(), executorService);
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
index 0cf3a94..62def22 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
@@ -412,6 +412,13 @@
}
}
+ void setObsolete() {
+ if (hasInstanceInitializerDescription() || !useSyntheticMethod()) {
+ instanceInitializers.forEach(
+ instanceInitializer -> instanceInitializer.getDefinition().setObsolete());
+ }
+ }
+
private boolean useSyntheticMethod() {
return !isSingleton() || group.hasClassIdField();
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMergerCollection.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMergerCollection.java
index 952421e..4ce1f2f 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMergerCollection.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMergerCollection.java
@@ -141,4 +141,8 @@
instanceInitializerMergers.forEach(consumer);
equivalentInstanceInitializerMergers.values().forEach(consumer);
}
+
+ public void setObsolete() {
+ forEach(InstanceInitializerMerger::setObsolete);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
index 6a030d7..09e9911 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
@@ -75,9 +75,8 @@
}
public Code getCode(DexMethod syntheticMethodReference) {
- assert !classInitializers.isEmpty();
- ProgramMethod firstClassInitializer = ListUtils.first(classInitializers);
- if (firstClassInitializer.getDefinition().getCode().isCfCode()) {
+ assert !isEmpty();
+ if (isTrivialMerge()) {
assert IterableUtils.allIdentical(
classInitializers,
classInitializer -> classInitializer.getDefinition().getCode().isCfCode());
@@ -100,6 +99,11 @@
return null;
}
+ public boolean isTrivialMerge() {
+ ProgramMethod firstClassInitializer = ListUtils.first(classInitializers);
+ return firstClassInitializer.getDefinition().getCode().isCfCode();
+ }
+
public ComputedApiLevel getApiReferenceLevel(AppView<?> appView) {
assert !classInitializers.isEmpty();
return ListUtils.fold(
@@ -108,6 +112,10 @@
(accApiLevel, method) -> accApiLevel.max(method.getDefinition().getApiLevel()));
}
+ public void setObsolete() {
+ classInitializers.forEach(classInitializer -> classInitializer.getDefinition().setObsolete());
+ }
+
public static class Builder {
private final ImmutableList.Builder<ProgramMethod> classInitializers = ImmutableList.builder();
@@ -182,7 +190,7 @@
* Provides a piece of {@link IRCode} that is the concatenation of a collection of class
* initializers.
*/
- private static class IRProvider extends Code {
+ static class IRProvider extends Code {
private final ImmutableList<ProgramMethod> classInitializers;
private final DexMethod syntheticMethodReference;
@@ -261,6 +269,7 @@
callerPosition,
classInitializer.getOrigin(),
RewrittenPrototypeDescription.none());
+ classInitializer.getDefinition().setObsolete();
DexProgramClass downcast = null;
instructionIterator.previous();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
index 940b639..eaa1d40 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
@@ -583,8 +583,10 @@
&& enumDataMap.representativeType(method.getHolderType()) != method.getHolderType()) {
assert method.getDefinition().getCode().isEmptyVoidMethod();
prunedItemsBuilder.addRemovedMethod(method.getReference());
+ method.getDefinition().setObsolete();
} else if (method.getDefinition().isInstanceInitializer()) {
prunedItemsBuilder.addRemovedMethod(method.getReference());
+ method.getDefinition().setObsolete();
} else if (method.getDefinition().isNonPrivateVirtualMethod()) {
nonPrivateVirtualMethods.add(method.getReference());
} else {
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
index 4ad22f3..4441690 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
@@ -100,23 +100,26 @@
return method;
}
- return method.toTypeSubstitutedMethod(
- methodReferenceAfterParameterRemoval,
- builder -> {
- if (graphLens.hasPrototypeChanges(methodReferenceAfterParameterRemoval)) {
- RewrittenPrototypeDescription prototypeChanges =
- graphLens.getPrototypeChanges(methodReferenceAfterParameterRemoval);
- builder
- .apply(prototypeChanges.createParameterAnnotationsRemover(method))
- .setGenericSignature(MethodTypeSignature.noSignature());
- if (method.isInstance()
- && prototypeChanges.getArgumentInfoCollection().isArgumentRemoved(0)) {
- builder
- .modifyAccessFlags(flags -> flags.demoteFromFinal().promoteToStatic())
- .unsetIsLibraryMethodOverride();
- }
- }
- });
+ DexEncodedMethod replacement =
+ method.toTypeSubstitutedMethod(
+ methodReferenceAfterParameterRemoval,
+ builder -> {
+ if (graphLens.hasPrototypeChanges(methodReferenceAfterParameterRemoval)) {
+ RewrittenPrototypeDescription prototypeChanges =
+ graphLens.getPrototypeChanges(methodReferenceAfterParameterRemoval);
+ builder
+ .apply(prototypeChanges.createParameterAnnotationsRemover(method))
+ .setGenericSignature(MethodTypeSignature.noSignature());
+ if (method.isInstance()
+ && prototypeChanges.getArgumentInfoCollection().isArgumentRemoved(0)) {
+ builder
+ .modifyAccessFlags(flags -> flags.demoteFromFinal().promoteToStatic())
+ .unsetIsLibraryMethodOverride();
+ }
+ }
+ });
+ method.setObsolete();
+ return replacement;
});
}