Revert "Prevent merging of virtual methods outside of main-dex"
This reverts commit 7017bb165ff2c582f2e453684b4b4b60100129f2.
Reason for revert: Fails with "The caller should checked if the holder is a root"
Change-Id: I8f83d2422c3981d0c6644d56866cf3015009b256
diff --git a/src/main/java/com/android/tools/r8/PrintUses.java b/src/main/java/com/android/tools/r8/PrintUses.java
index 80b5ec7..25f4d3b 100644
--- a/src/main/java/com/android/tools/r8/PrintUses.java
+++ b/src/main/java/com/android/tools/r8/PrintUses.java
@@ -364,7 +364,7 @@
AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(
application,
ClassToFeatureSplitMap.createEmptyClassToFeatureSplitMap(),
- MainDexInfo.none());
+ MainDexInfo.createEmptyMainDexClasses());
}
private void analyze() {
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 283e461..eef9f3d 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -535,9 +535,6 @@
}
}
- // Clear traced methods roots to not hold on to the main dex live method set.
- appView.appInfo().getMainDexInfo().clearTracedMethodRoots();
-
// None of the optimizations above should lead to the creation of type lattice elements.
assert appView.dexItemFactory().verifyNoCachedTypeElements();
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
index 21de6ac..23db0d9 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -199,7 +199,7 @@
}
public MainDexInfo readMainDexClasses(DexApplication app) {
- MainDexInfo.Builder builder = MainDexInfo.none().builder();
+ MainDexInfo.Builder builder = MainDexInfo.builder();
if (inputApp.hasMainDexList()) {
for (StringResource resource : inputApp.getMainDexListResources()) {
addToMainDexClasses(app, builder, MainDexListParser.parseList(resource, itemFactory));
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index de3d976..d8785d1 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -28,7 +28,7 @@
private final BooleanBox obsolete;
public static AppInfo createInitialAppInfo(DexApplication application) {
- return createInitialAppInfo(application, MainDexInfo.none());
+ return createInitialAppInfo(application, MainDexInfo.createEmptyMainDexClasses());
}
public static AppInfo createInitialAppInfo(DexApplication application, MainDexInfo mainDexInfo) {
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 b56d682..954580b 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -156,7 +156,7 @@
}
public static AppView<AppInfoWithClassHierarchy> createForR8(DexApplication application) {
- return createForR8(application, MainDexInfo.none());
+ return createForR8(application, MainDexInfo.createEmptyMainDexClasses());
}
public static AppView<AppInfoWithClassHierarchy> createForR8(
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreserveMethodCharacteristics.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreserveMethodCharacteristics.java
index 4a789ba..fcafba0 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreserveMethodCharacteristics.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/PreserveMethodCharacteristics.java
@@ -20,7 +20,6 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
/**
* Policy that enforces that methods are only merged if they have the same visibility and library
@@ -33,10 +32,8 @@
private final MethodAccessFlags accessFlags;
private final boolean isAssumeNoSideEffectsMethod;
private final OptionalBool isLibraryMethodOverride;
- private final boolean isMainDexRoot;
- private MethodCharacteristics(
- DexEncodedMethod method, boolean isAssumeNoSideEffectsMethod, boolean isMainDexRoot) {
+ private MethodCharacteristics(boolean isAssumeNoSideEffectsMethod, DexEncodedMethod method) {
this.accessFlags =
MethodAccessFlags.builder()
.setPrivate(method.getAccessFlags().isPrivate())
@@ -47,24 +44,17 @@
.build();
this.isAssumeNoSideEffectsMethod = isAssumeNoSideEffectsMethod;
this.isLibraryMethodOverride = method.isLibraryMethodOverride();
- this.isMainDexRoot = isMainDexRoot;
}
static MethodCharacteristics create(
AppView<AppInfoWithLiveness> appView, DexEncodedMethod method) {
return new MethodCharacteristics(
- method,
- appView.appInfo().isAssumeNoSideEffectsMethod(method.getReference()),
- appView.appInfo().getMainDexInfo().isTracedMethodRoot(method.getReference()));
+ appView.appInfo().isAssumeNoSideEffectsMethod(method.getReference()), method);
}
@Override
public int hashCode() {
- return Objects.hash(
- accessFlags,
- isAssumeNoSideEffectsMethod,
- isLibraryMethodOverride.ordinal(),
- isMainDexRoot);
+ return (accessFlags.hashCode() << 2) | isLibraryMethodOverride.ordinal();
}
@Override
@@ -78,8 +68,7 @@
MethodCharacteristics characteristics = (MethodCharacteristics) obj;
return accessFlags.equals(characteristics.accessFlags)
&& isAssumeNoSideEffectsMethod == characteristics.isAssumeNoSideEffectsMethod
- && isLibraryMethodOverride == characteristics.isLibraryMethodOverride
- && isMainDexRoot == characteristics.isMainDexRoot;
+ && isLibraryMethodOverride == characteristics.isLibraryMethodOverride;
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 682c3f8..9c672b1 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -3030,13 +3030,8 @@
trace(executorService, timing);
options.reporter.failIfPendingErrors();
// Calculate the automatic main dex list according to legacy multidex constraints.
- MainDexInfo.Builder builder = appView.appInfo().getMainDexInfo().builder();
+ MainDexInfo.Builder builder = MainDexInfo.builder();
liveTypes.getItems().forEach(builder::addRoot);
- if (mode.isInitialMainDexTracing()) {
- liveMethods.getItems().forEach(method -> builder.addRoot(method.method));
- } else {
- assert appView.appInfo().getMainDexInfo().isTracedMethodRootsCleared();
- }
new MainDexListBuilder(appView, builder.getRoots(), builder).run();
MainDexInfo previousMainDexInfo = appInfo.getMainDexInfo();
return builder.build(previousMainDexInfo);
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 e55cc9d..c95ea3b 100644
--- a/src/main/java/com/android/tools/r8/shaking/MainDexInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/MainDexInfo.java
@@ -8,7 +8,6 @@
import static com.android.tools.r8.utils.PredicateUtils.not;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
@@ -19,7 +18,6 @@
import com.android.tools.r8.utils.ConsumerUtils;
import com.android.tools.r8.utils.SetUtils;
import com.google.common.collect.Sets;
-import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -27,14 +25,7 @@
public class MainDexInfo {
- private static final MainDexInfo NONE =
- new MainDexInfo(
- Collections.emptySet(),
- Collections.emptySet(),
- Collections.emptySet(),
- Collections.emptySet(),
- Collections.emptySet(),
- false);
+ private static final MainDexInfo NONE = new MainDexInfo(Sets.newIdentityHashSet());
public enum MainDexGroup {
MAIN_DEX_LIST,
@@ -48,38 +39,24 @@
private final Map<DexType, DexType> synthesizedClassesMap;
// Traced roots are traced main dex references.
private final Set<DexType> tracedRoots;
- // Traced method roots are the methods visited from an initial main dex root set. The set is
- // cleared after the mergers has run.
- private Set<DexMethod> tracedMethodRoots;
// Traced dependencies are those classes that are directly referenced from traced roots, but will
// not be loaded before loading the remaining dex files.
private final Set<DexType> tracedDependencies;
- // Bit indicating if the traced methods are cleared.
- private boolean tracedMethodRootsCleared = false;
private MainDexInfo(Set<DexType> classList) {
this(
- classList,
- Collections.emptySet(),
- Collections.emptySet(),
- Collections.emptySet(),
- /* synthesized classes - cannot be emptyset */ Sets.newIdentityHashSet(),
- false);
+ classList, Sets.newIdentityHashSet(), Sets.newIdentityHashSet(), Sets.newIdentityHashSet());
}
private MainDexInfo(
Set<DexType> classList,
Set<DexType> tracedRoots,
- Set<DexMethod> tracedMethodRoots,
Set<DexType> tracedDependencies,
- Set<DexType> synthesizedClasses,
- boolean tracedMethodRootsCleared) {
+ Set<DexType> synthesizedClasses) {
this.classList = classList;
this.tracedRoots = tracedRoots;
- this.tracedMethodRoots = tracedMethodRoots;
this.tracedDependencies = tracedDependencies;
this.synthesizedClassesMap = new ConcurrentHashMap<>();
- this.tracedMethodRootsCleared = tracedMethodRootsCleared;
synthesizedClasses.forEach(type -> synthesizedClassesMap.put(type, type));
assert tracedDependencies.stream().noneMatch(tracedRoots::contains);
assert tracedRoots.containsAll(synthesizedClasses);
@@ -106,12 +83,6 @@
return isTracedRoot(definition.getContextType());
}
- public boolean isTracedMethodRoot(DexMethod method) {
- assert !tracedMethodRootsCleared : "Traced method roots are cleared after mergers has run";
- assert isTracedRoot(method.holder) : "The caller should checked if the holder is a root";
- return tracedMethodRoots.contains(method);
- }
-
private boolean isTracedRoot(DexReference reference) {
return tracedRoots.contains(reference.getContextType());
}
@@ -124,15 +95,6 @@
return tracedDependencies.contains(reference.getContextType());
}
- public boolean isTracedMethodRootsCleared() {
- return tracedMethodRootsCleared;
- }
-
- public void clearTracedMethodRoots() {
- this.tracedMethodRootsCleared = true;
- this.tracedMethodRoots = Sets.newIdentityHashSet();
- }
-
public boolean canRebindReference(ProgramMethod context, DexReference referenceToTarget) {
MainDexGroup holderGroup = getMainDexGroupInternal(context);
if (holderGroup == MainDexGroup.NOT_IN_MAIN_DEX
@@ -142,7 +104,8 @@
}
if (holderGroup == MainDexGroup.MAIN_DEX_LIST) {
// If the holder is in the class list, we are not allowed to make any assumptions on the
- // holder being a root or a dependency. Therefore we cannot merge.
+ // holder
+ // being a root or a dependency. Therefore we cannot merge.
return false;
}
assert holderGroup == MAIN_DEX_ROOT;
@@ -236,7 +199,7 @@
synthesizedClassesMap.computeIfAbsent(
clazz.type,
type -> {
- tracedRoots.add(type);
+ classList.add(type);
return type;
});
}
@@ -280,12 +243,6 @@
.keySet()
.forEach(type -> ifNotRemoved(type, removedClasses, modifiedSynthesized::add));
tracedRoots.forEach(type -> ifNotRemoved(type, removedClasses, builder::addRoot));
- // TODO(b/169927809): Methods could be pruned without the holder being pruned, however, one has
- // to have a reference for querying a root.
- tracedMethodRoots.forEach(
- method ->
- ifNotRemoved(
- method.getHolderType(), removedClasses, ignored -> builder.addRoot(method)));
tracedDependencies.forEach(type -> ifNotRemoved(type, removedClasses, builder::addDependency));
return builder.build(modifiedClassList, modifiedSynthesized);
}
@@ -304,43 +261,42 @@
classList.forEach(type -> modifiedClassList.add(lens.lookupType(type)));
synthesizedClassesMap.keySet().forEach(type -> modifiedSynthesized.add(lens.lookupType(type)));
tracedRoots.forEach(type -> builder.addRoot(lens.lookupType(type)));
- tracedMethodRoots.forEach(method -> builder.addRoot(lens.getRenamedMethodSignature(method)));
tracedDependencies.forEach(type -> builder.addDependency(lens.lookupType(type)));
return builder.build(modifiedClassList, modifiedSynthesized);
}
- public Builder builder() {
- return new Builder(tracedMethodRootsCleared);
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static MainDexInfo createEmptyMainDexClasses() {
+ return new MainDexInfo(
+ Sets.newIdentityHashSet(),
+ Sets.newIdentityHashSet(),
+ Sets.newIdentityHashSet(),
+ Sets.newIdentityHashSet());
}
public static class Builder {
private final Set<DexType> list = Sets.newIdentityHashSet();
private final Set<DexType> roots = Sets.newIdentityHashSet();
- private final Set<DexMethod> methodRoots = Sets.newIdentityHashSet();
private final Set<DexType> dependencies = Sets.newIdentityHashSet();
- private final boolean tracedMethodRootsCleared;
- private Builder(boolean tracedMethodRootsCleared) {
- this.tracedMethodRootsCleared = tracedMethodRootsCleared;
- }
+ private Builder() {}
public void addList(DexProgramClass clazz) {
list.add(clazz.getType());
}
public void addRoot(DexProgramClass clazz) {
- addRoot(clazz.type);
+ roots.add(clazz.getType());
}
public void addRoot(DexType type) {
roots.add(type);
}
- public void addRoot(DexMethod method) {
- methodRoots.add(method);
- }
-
public void addDependency(DexProgramClass clazz) {
addDependency(clazz.getType());
}
@@ -392,10 +348,8 @@
return new MainDexInfo(
classList,
SetUtils.unionIdentityHashSet(roots, synthesizedClasses),
- methodRoots,
Sets.difference(dependencies, synthesizedClasses),
- synthesizedClasses,
- tracedMethodRootsCleared);
+ synthesizedClasses);
}
public MainDexInfo build(MainDexInfo previous) {
diff --git a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
index 039f28d..2bac333 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
@@ -236,7 +236,7 @@
AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(
application,
ClassToFeatureSplitMap.createEmptyClassToFeatureSplitMap(),
- MainDexInfo.none());
+ MainDexInfo.createEmptyMainDexClasses());
}
void run(TraceReferencesConsumer consumer) {
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index a80cc32..3df21b1 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -710,7 +710,7 @@
return AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(
readApplicationForDexOutput(app, new InternalOptions()),
ClassToFeatureSplitMap.createEmptyClassToFeatureSplitMap(),
- MainDexInfo.none());
+ MainDexInfo.createEmptyMainDexClasses());
}
protected static AppView<AppInfoWithClassHierarchy> computeAppViewWithClassHierachy(
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListMergeInRootTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListMergeInRootTest.java
index 9451f9a..7041c75 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListMergeInRootTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListMergeInRootTest.java
@@ -4,13 +4,17 @@
package com.android.tools.r8.maindexlist;
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static com.android.tools.r8.utils.codeinspector.AssertUtils.assertFailsCompilation;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assume.assumeTrue;
+
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.NoHorizontalClassMerging;
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.HorizontallyMergedClassesInspector;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -23,10 +27,7 @@
@Parameters(name = "{0}")
public static TestParametersCollection data() {
- return getTestParameters()
- .withDexRuntimes()
- .withApiLevelsEndingAtExcluding(apiLevelWithNativeMultiDexSupport())
- .build();
+ return getTestParameters().withDexRuntimes().withAllApiLevels().build();
}
public MainDexListMergeInRootTest(TestParameters parameters) {
@@ -34,26 +35,35 @@
}
@Test
- public void testMainDexTracing() throws Exception {
- testForR8(parameters.getBackend())
- .addProgramClasses(OutsideMainDex.class, InsideA.class, InsideB.class, Main.class)
- .addKeepClassAndMembersRules(Main.class)
- .setMinApi(parameters.getApiLevel())
- .enableNeverClassInliningAnnotations()
- .enableNoHorizontalClassMergingAnnotations()
- .enableInliningAnnotations()
- .noMinification()
- .addMainDexRules(
- "-keep class " + Main.class.getTypeName() + " { public static void main(***); }")
- .addOptionsModification(
- options -> {
- options.testing.checkForNotExpandingMainDexTracingResult = true;
- })
- // TODO(b/178151906): See if we can merge the classes.
- .addHorizontallyMergedClassesInspector(
- HorizontallyMergedClassesInspector::assertNoClassesMerged)
- .run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines("InsideB::live0", "InsideA::live");
+ public void testMainDexTracing() {
+ assumeTrue(parameters.getDexRuntimeVersion().isDalvik());
+ assertFailsCompilation(
+ () ->
+ testForR8(parameters.getBackend())
+ .addProgramClasses(OutsideMainDex.class, InsideA.class, InsideB.class, Main.class)
+ .addKeepClassAndMembersRules(Main.class)
+ .setMinApi(parameters.getApiLevel())
+ .enableNeverClassInliningAnnotations()
+ .enableNoHorizontalClassMergingAnnotations()
+ .enableInliningAnnotations()
+ .noMinification()
+ .addMainDexRules(
+ "-keep class "
+ + Main.class.getTypeName()
+ + " { public static void main(***); }")
+ .addOptionsModification(
+ options -> {
+ options.testing.checkForNotExpandingMainDexTracingResult = true;
+ })
+ .compileWithExpectedDiagnostics(
+ diagnostics -> {
+ diagnostics.assertErrorsMatch(
+ diagnosticMessage(
+ containsString(
+ "Class com.android.tools.r8.maindexlist"
+ + ".MainDexListMergeInRootTest$OutsideMainDex"
+ + " was not a main dex root in the first round")));
+ }));
}
@NoHorizontalClassMerging
@@ -70,7 +80,7 @@
public static class InsideA {
public void bar() {
- System.out.println("InsideA::live");
+ System.out.println("A::live");
}
/* Not a traced root */