Deprecated support for deriving main-dex list synthetics.
Bug: 181858113
Change-Id: Ibeba3c2b1f8fa26e909d1143de326fea3ccf8009
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexInfo.java b/src/main/java/com/android/tools/r8/shaking/MainDexInfo.java
index 5d3309a..96e263c 100644
--- a/src/main/java/com/android/tools/r8/shaking/MainDexInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/MainDexInfo.java
@@ -76,6 +76,11 @@
assert tracedDependencies.stream().noneMatch(tracedRoots::contains);
}
+ // TODO(b/181858113): Remove once deprecated main-dex-list is removed.
+ public boolean isSyntheticContextOnMainDexList(DexType syntheticContextType) {
+ return classList.contains(syntheticContextType);
+ }
+
public boolean isNone() {
assert none() == NONE;
return this == NONE;
@@ -389,5 +394,18 @@
public MainDexInfo build(MainDexInfo previous) {
return build(previous.classList);
}
+
+ public MainDexInfo build() {
+ return new MainDexInfo(list, roots, methodRoots, dependencies, tracedMethodRootsCleared);
+ }
+ }
+
+ public Builder builderFromCopy() {
+ Builder builder = new Builder(tracedMethodRootsCleared);
+ builder.list.addAll(classList);
+ builder.roots.addAll(tracedRoots);
+ builder.methodRoots.addAll(tracedMethodRoots);
+ builder.dependencies.addAll(tracedDependencies);
+ return builder;
}
}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java b/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
index 3e8f334..04ec40a 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.shaking.MainDexInfo;
import java.util.Comparator;
/**
@@ -129,4 +130,9 @@
public String toString() {
return "SynthesizingContext{" + getSynthesizingContextType() + "}";
}
+
+ // TODO(b/181858113): Remove once deprecated main-dex-list is removed.
+ boolean isDerivedFromMainDexList(MainDexInfo mainDexInfo) {
+ return mainDexInfo.isSyntheticContextOnMainDexList(inputContextType);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
index 916daac..0204788 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
@@ -22,6 +22,7 @@
import com.android.tools.r8.graph.TreeFixerBase;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.MainDexInfo;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.SetUtils;
@@ -52,12 +53,17 @@
public final CommittedItems commit;
public final NonIdentityGraphLens lens;
public final PrunedItems prunedItems;
+ public final MainDexInfo mainDexInfo;
public Result(
- CommittedItems commit, SyntheticFinalizationGraphLens lens, PrunedItems prunedItems) {
+ CommittedItems commit,
+ SyntheticFinalizationGraphLens lens,
+ PrunedItems prunedItems,
+ MainDexInfo mainDexInfo) {
this.commit = commit;
this.lens = lens;
this.prunedItems = prunedItems;
+ this.mainDexInfo = mainDexInfo;
}
}
@@ -229,7 +235,7 @@
assert !appView.appInfo().hasClassHierarchy();
assert !appView.appInfo().hasLiveness();
Result result = appView.getSyntheticItems().computeFinalSynthetics(appView);
- appView.setAppInfo(new AppInfo(result.commit, appView.appInfo().getMainDexInfo()));
+ appView.setAppInfo(new AppInfo(result.commit, result.mainDexInfo));
if (result.lens != null) {
appView.setAppInfo(
appView
@@ -245,6 +251,7 @@
assert !appView.appInfo().hasLiveness();
Result result = appView.getSyntheticItems().computeFinalSynthetics(appView);
appView.setAppInfo(appView.appInfo().rebuildWithClassHierarchy(result.commit));
+ appView.setAppInfo(appView.appInfo().rebuildWithMainDexInfo(result.mainDexInfo));
if (result.lens != null) {
appView.setGraphLens(result.lens);
appView.setAppInfo(
@@ -259,6 +266,7 @@
public static void finalizeWithLiveness(AppView<AppInfoWithLiveness> appView) {
Result result = appView.getSyntheticItems().computeFinalSynthetics(appView);
appView.setAppInfo(appView.appInfo().rebuildWithLiveness(result.commit));
+ appView.setAppInfo(appView.appInfo().rebuildWithMainDexInfo(result.mainDexInfo));
appView.rewriteWithLens(result.lens);
appView.pruneItems(result.prunedItems);
}
@@ -272,6 +280,7 @@
ImmutableMap.Builder<DexType, SyntheticProgramClassReference> finalClassesBuilder =
ImmutableMap.builder();
List<DexProgramClass> finalSyntheticProgramDefinitions = new ArrayList<>();
+ Set<DexType> derivedMainDexTypes = Sets.newIdentityHashSet();
{
Map<String, NumberGenerator> generators = new HashMap<>();
application =
@@ -287,7 +296,8 @@
(clazz, reference) -> {
finalSyntheticProgramDefinitions.add(clazz);
finalMethodsBuilder.put(clazz.getType(), reference);
- });
+ },
+ derivedMainDexTypes);
}
ImmutableMap<DexType, SyntheticMethodReference> finalMethods = finalMethodsBuilder.build();
ImmutableMap<DexType, SyntheticProgramClassReference> finalClasses =
@@ -302,6 +312,10 @@
}
});
+ // TODO(b/181858113): Remove once deprecated main-dex-list is removed.
+ MainDexInfo.Builder mainDexInfoBuilder = appView.appInfo().getMainDexInfo().builderFromCopy();
+ derivedMainDexTypes.forEach(mainDexInfoBuilder::addList);
+
return new Result(
new CommittedItems(
SyntheticItems.INVALID_ID_AFTER_SYNTHETIC_FINALIZATION,
@@ -310,10 +324,8 @@
committed.getLegacyTypes(), finalMethods, finalClasses),
ImmutableList.of()),
lensBuilder.build(appView.graphLens(), appView.dexItemFactory()),
- PrunedItems.builder()
- .setPrunedApp(application)
- .addRemovedClasses(prunedSynthetics)
- .build());
+ PrunedItems.builder().setPrunedApp(application).addRemovedClasses(prunedSynthetics).build(),
+ mainDexInfoBuilder.build());
}
private <R extends SyntheticReference<R, D, ?>, D extends SyntheticDefinition<R, D, ?>>
@@ -359,9 +371,11 @@
Map<DexType, EquivalenceGroup<SyntheticProgramClassDefinition>> syntheticClassGroups,
Builder lensBuilder,
BiConsumer<DexProgramClass, SyntheticProgramClassReference> addFinalSyntheticClass,
- BiConsumer<DexProgramClass, SyntheticMethodReference> addFinalSyntheticMethod) {
+ BiConsumer<DexProgramClass, SyntheticMethodReference> addFinalSyntheticMethod,
+ Set<DexType> derivedMainDexSynthetics) {
DexApplication application = appView.appInfo().app();
DexItemFactory factory = appView.dexItemFactory();
+ MainDexInfo mainDexInfo = appView.appInfo().getMainDexInfo();
List<DexProgramClass> newProgramClasses = new ArrayList<>();
Set<DexType> pruned = Sets.newIdentityHashSet();
@@ -383,6 +397,9 @@
if (memberReference != externalSyntheticMethod.method) {
lensBuilder.moveSyntheticMethod(memberReference, externalSyntheticMethod.method);
}
+ if (member.getContext().isDerivedFromMainDexList(mainDexInfo)) {
+ derivedMainDexSynthetics.add(syntheticType);
+ }
}
});
@@ -406,6 +423,9 @@
if (member != representative) {
deduplicatedClasses.add(memberClass);
}
+ if (member.getContext().isDerivedFromMainDexList(mainDexInfo)) {
+ derivedMainDexSynthetics.add(syntheticType);
+ }
}
});
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index 26477d3..e9cd5ff 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -285,13 +285,6 @@
return setMinApi(minApi);
}
- public T setMinApiThreshold(TestRuntime runtime) {
- if (runtime.isDex()) {
- setMinApiThreshold(runtime.asDex().getMinApiLevel());
- }
- return self();
- }
-
public T setMinApi(AndroidApiLevel minApiLevel) {
return setMinApi(minApiLevel.getLevel());
}
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexWithSynthesizedClassesTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexWithSynthesizedClassesTest.java
index 6c2ad2e..8252f4d 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexWithSynthesizedClassesTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexWithSynthesizedClassesTest.java
@@ -8,11 +8,14 @@
import com.android.tools.r8.D8TestCompileResult;
import com.android.tools.r8.OutputMode;
+import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompileResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.nio.file.Files;
@@ -54,7 +57,7 @@
testForD8()
.addInnerClasses(MainDexWithSynthesizedClassesTest.class)
.addMainDexKeepClassAndMemberRules(TestClass.class)
- .setMinApiThreshold(parameters.getApiLevel())
+ .setMinApi(parameters.getApiLevel())
.compile();
checkCompilationResult(compileResult);
}
@@ -66,19 +69,67 @@
D8TestCompileResult intermediateResult =
testForD8()
.addInnerClasses(MainDexWithSynthesizedClassesTest.class)
- .setMinApiThreshold(parameters.getApiLevel())
+ .setMinApi(parameters.getApiLevel())
.setIntermediate(true)
.compile();
D8TestCompileResult compileResult =
testForD8()
.addProgramFiles(intermediateResult.writeToZip())
- .addMainDexKeepClassRules(TestClass.class, A.class)
- .setMinApiThreshold(parameters.getApiLevel())
+ .addMainDexKeepClassAndMemberRules(TestClass.class)
+ .setMinApi(parameters.getApiLevel())
.compile();
checkCompilationResult(compileResult);
}
+ /**
+ * This test checks for maintained support of including synthetics from main-dex-list entries in
+ * the main-dex file. This test simulates that the tracing done at the class-file level has
+ * determined that TestClass and A are both traced. Thus the synthetic lambda from A will be
+ * included in the main-dex file.
+ *
+ * <p>TODO(b/181858113): Remove once deprecated main-dex-list is removed.
+ */
+ @Test
+ public void testDeprecatedSyntheticsFromMainDexListD8() throws Exception {
+ assumeTrue(parameters.isDexRuntime());
+ D8TestCompileResult compileResult =
+ testForD8()
+ .addInnerClasses(MainDexWithSynthesizedClassesTest.class)
+ .addMainDexListClasses(TestClass.class, A.class)
+ .setMinApi(parameters.getApiLevel())
+ .compile();
+ checkCompilationResult(compileResult);
+ }
+
+ /**
+ * This test checks for maintained support of including synthetics from main-dex-list entries in
+ * the main-dex file. This test simulates that the tracing done at the class-file level has
+ * determined that TestClass and A are both traced. Thus the synthetic lambda from A will be
+ * included in the main-dex file.
+ *
+ * <p>TODO(b/181858113): Remove once deprecated main-dex-list is removed.
+ */
+ @Test
+ public void testDeprecatedSyntheticsFromMainDexListR8() throws Exception {
+ assumeTrue(parameters.isDexRuntime());
+ R8TestCompileResult compileResult =
+ testForR8(parameters.getBackend())
+ .addInnerClasses(MainDexWithSynthesizedClassesTest.class)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(o -> o.minimalMainDex = true)
+ .addMainDexListClasses(TestClass.class, A.class)
+ .noMinification()
+ .noTreeShaking()
+ .compile();
+ checkCompilationResult(compileResult, compileResult.app);
+ }
+
private void checkCompilationResult(D8TestCompileResult compileResult) throws Exception {
+ checkCompilationResult(compileResult, compileResult.app);
+ }
+
+ private void checkCompilationResult(TestCompileResult compileResult, AndroidApp app)
+ throws Exception {
if (parameters.getRuntime().asDex().getMinApiLevel().getLevel()
< nativeMultiDexLevel.getLevel()) {
compileResult.runDex2Oat(parameters.getRuntime()).assertNoVerificationErrors();
@@ -86,7 +137,7 @@
compileResult.run(parameters.getRuntime(), TestClass.class).assertSuccessWithOutput(EXPECTED);
}
Path out = temp.newFolder().toPath();
- compileResult.apply(b -> b.app.writeToDirectory(out, OutputMode.DexIndexed));
+ app.writeToDirectory(out, OutputMode.DexIndexed);
Path classes = out.resolve("classes.dex");
Path classes2 = out.resolve("classes2.dex");
assertTrue(Files.exists(classes));