Compute main dex rootset annotation prior to annotation removal
Bug: 190623364
Bug: 190941270
Change-Id: I8e610fc8c202bdc3818ea6eb099a46521acefd90
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index e02ccfb..f35ee68 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -361,6 +361,17 @@
appView.rootSet().checkAllRulesAreUsed(options);
+ // Compute the main dex rootset that will be the base of first and final main dex tracing
+ // before pruning the application.
+ if (!options.mainDexKeepRules.isEmpty()) {
+ assert appView.graphLens().isIdentityLens();
+ // Find classes which may have code executed before secondary dex files installation.
+ MainDexRootSet mainDexRootSet =
+ MainDexRootSet.builder(appView, subtypingInfo, options.mainDexKeepRules)
+ .build(executorService);
+ appView.setMainDexRootSet(mainDexRootSet);
+ appView.appInfo().unsetObsolete();
+ }
if (options.proguardSeedsConsumer != null) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
PrintStream out = new PrintStream(bytes);
@@ -423,6 +434,7 @@
// Build conservative main dex content after first round of tree shaking. This is used
// by certain optimizations to avoid introducing additional class references into main dex
// classes, as that can cause the final number of main dex methods to grow.
+ // TODO(b/190941270): See if we can move this up before treepruning.
performInitialMainDexTracing(appView, executorService);
// The class type lattice elements include information about the interfaces that a class
@@ -853,16 +865,12 @@
return;
}
assert appView.graphLens().isIdentityLens();
- // Find classes which may have code executed before secondary dex files installation.
- SubtypingInfo subtypingInfo = new SubtypingInfo(appView);
- MainDexRootSet mainDexRootSet =
- MainDexRootSet.builder(appView, subtypingInfo, options.mainDexKeepRules)
- .build(executorService);
- appView.setMainDexRootSet(mainDexRootSet);
- appView.appInfo().unsetObsolete();
- // Live types is the tracing result.
+
+ // Find classes which may have code executed before secondary dex files installation by
+ // computing from the initially computed main dex root set.
MainDexInfo mainDexInfo =
- EnqueuerFactory.createForInitialMainDexTracing(appView, executorService, subtypingInfo)
+ EnqueuerFactory.createForInitialMainDexTracing(
+ appView, executorService, new SubtypingInfo(appView))
.traceMainDex(executorService, timing);
appView.setAppInfo(appView.appInfo().rebuildWithMainDexInfo(mainDexInfo));
}
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
index 72a0a0b..e4890a0 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -149,6 +149,10 @@
this(appView, subtypingInfo, null);
}
+ boolean isMainDexRootSetBuilder() {
+ return false;
+ }
+
void handleMatchedAnnotation(AnnotationMatchResult annotation) {
// Intentionally empty.
}
@@ -517,7 +521,8 @@
// fullmode.
if (clazz.isProgramClass()
&& rule.isProguardKeepRule()
- && !rule.asProguardKeepRule().getModifiers().allowsShrinking) {
+ && !rule.asProguardKeepRule().getModifiers().allowsShrinking
+ && !isMainDexRootSetBuilder()) {
new SynthesizeMissingInterfaceMethodsForMemberRules(
clazz.asProgramClass(), memberKeepRules, rule, preconditionSupplier, ifRule)
.run();
@@ -2241,6 +2246,11 @@
}
@Override
+ boolean isMainDexRootSetBuilder() {
+ return true;
+ }
+
+ @Override
public MainDexRootSet build(ExecutorService executorService) throws ExecutionException {
// Call the super builder to have if-tests calculated automatically.
RootSet rootSet = super.build(executorService);
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java
index 827684d..3bb1ffd 100644
--- a/src/test/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -42,6 +42,7 @@
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
+import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -118,6 +119,12 @@
return self();
}
+ public final CR inspectMainDexClasses(BiConsumer<CodeInspector, Set<String>> consumer)
+ throws IOException {
+ consumer.accept(inspector(), getMainDexClasses());
+ return self();
+ }
+
public abstract String getStdout();
public abstract String getStderr();
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexRemovedAnnotationTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexRemovedAnnotationTest.java
index 67b113c..589a1e2 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexRemovedAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexRemovedAnnotationTest.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -43,7 +44,7 @@
@Test
public void testMainDexTracing() throws Exception {
testForR8(parameters.getBackend())
- .addProgramClasses(MainDex.class, Inside.class, Main.class)
+ .addProgramClasses(MainDex.class, Inside.class, Dead.class, Main.class)
.addKeepClassAndMembersRules(Main.class)
.setMinApi(parameters.getApiLevel())
.enableInliningAnnotations()
@@ -51,13 +52,11 @@
.collectMainDexClasses()
.compile()
.inspectMainDexClasses(
- mainDexClasses -> {
- // TODO(b/190623364): Should not be empty.
- assertTrue(mainDexClasses.isEmpty());
- })
- .inspect(
- codeInspector -> {
- assertThat(codeInspector.clazz(MainDex.class), not(isPresent()));
+ (inspector, mainDexClasses) -> {
+ ClassSubject inside = inspector.clazz(Inside.class);
+ assertThat(inside, isPresent());
+ assertTrue(mainDexClasses.contains(inside.getFinalName()));
+ assertThat(inspector.clazz(MainDex.class), not(isPresent()));
})
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("Hello World!");
@@ -76,6 +75,11 @@
}
}
+ @MainDex
+ public static class Dead {
+ // Will be removed during first round of tree-pruning.
+ }
+
public static class Main {
public static void main(String[] args) {