Include holder of startup method rules in startup class checks
Bug: b/274591979
Change-Id: I6a68b889640dfb09681551e2863b2dc527663438
diff --git a/src/main/java/com/android/tools/r8/dex/VirtualFile.java b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
index 270fcf2..d163330 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -1335,7 +1335,7 @@
private static Predicate<DexProgramClass> getStartupClassPredicate(
StartupProfile startupProfile) {
- return clazz -> startupProfile.containsClassRule(clazz.getType());
+ return clazz -> startupProfile.isStartupClass(clazz.getType());
}
public List<DexProgramClass> getStartupClasses() {
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupProfile.java b/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupProfile.java
index 7f2a248..a91c273 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupProfile.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupProfile.java
@@ -59,6 +59,11 @@
}
@Override
+ public boolean isStartupClass(DexType type) {
+ return false;
+ }
+
+ @Override
public EmptyStartupProfile rewrittenWithLens(GraphLens graphLens) {
return this;
}
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java
index b85dbaa..0689d7c 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.origin.Origin;
@@ -130,6 +131,8 @@
return StartupProfile.merge(startupProfiles);
}
+ public abstract boolean isStartupClass(DexType type);
+
public abstract Collection<StartupProfileRule> getRules();
public abstract boolean isEmpty();
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/profile/NonEmptyStartupProfile.java b/src/main/java/com/android/tools/r8/experimental/startup/profile/NonEmptyStartupProfile.java
index ab251a8..4b35a4b 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/profile/NonEmptyStartupProfile.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/profile/NonEmptyStartupProfile.java
@@ -15,28 +15,33 @@
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.synthesis.SyntheticItems;
+import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.ThrowingConsumer;
import java.util.Collection;
import java.util.LinkedHashMap;
+import java.util.Set;
import java.util.function.BiConsumer;
public class NonEmptyStartupProfile extends StartupProfile {
- private final LinkedHashMap<DexReference, StartupProfileRule> startupItems;
+ private final Set<DexType> startupClasses;
+ private final LinkedHashMap<DexReference, StartupProfileRule> startupRules;
- public NonEmptyStartupProfile(LinkedHashMap<DexReference, StartupProfileRule> startupItems) {
- assert !startupItems.isEmpty();
- this.startupItems = startupItems;
- }
-
- @Override
- public boolean containsMethodRule(DexMethod method) {
- return startupItems.containsKey(method);
+ public NonEmptyStartupProfile(LinkedHashMap<DexReference, StartupProfileRule> startupRules) {
+ assert !startupRules.isEmpty();
+ this.startupClasses =
+ SetUtils.mapIdentityHashSet(startupRules.keySet(), DexReference::getContextType);
+ this.startupRules = startupRules;
}
@Override
public boolean containsClassRule(DexType type) {
- return startupItems.containsKey(type);
+ return startupRules.containsKey(type);
+ }
+
+ @Override
+ public boolean containsMethodRule(DexMethod method) {
+ return startupRules.containsKey(method);
}
@Override
@@ -51,17 +56,17 @@
@Override
public StartupProfileClassRule getClassRule(DexType type) {
- return (StartupProfileClassRule) startupItems.get(type);
+ return (StartupProfileClassRule) startupRules.get(type);
}
@Override
public StartupProfileMethodRule getMethodRule(DexMethod method) {
- return (StartupProfileMethodRule) startupItems.get(method);
+ return (StartupProfileMethodRule) startupRules.get(method);
}
@Override
public Collection<StartupProfileRule> getRules() {
- return startupItems.values();
+ return startupRules.values();
}
@Override
@@ -70,6 +75,11 @@
}
@Override
+ public boolean isStartupClass(DexType type) {
+ return startupClasses.contains(type);
+ }
+
+ @Override
public StartupProfile rewrittenWithLens(GraphLens graphLens) {
return transform(
(classRule, builder) ->
@@ -85,7 +95,7 @@
}
public int size() {
- return startupItems.size();
+ return startupRules.size();
}
/**
@@ -176,7 +186,7 @@
private StartupProfile transform(
BiConsumer<StartupProfileClassRule, Builder> classRuleTransformer,
BiConsumer<StartupProfileMethodRule, Builder> methodRuleTransformer) {
- Builder builder = builderWithCapacity(startupItems.size());
+ Builder builder = builderWithCapacity(startupRules.size());
forEachRule(
classRule -> classRuleTransformer.accept(classRule, builder),
methodRule -> methodRuleTransformer.accept(methodRule, builder));
diff --git a/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java b/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java
index dc33db7..88bfb4f 100644
--- a/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java
+++ b/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java
@@ -175,7 +175,7 @@
feature = classToFeatureSplitMap.getOrDefault(type, FeatureSplit.BASE);
}
if (feature.isBase()) {
- return !startupProfile.containsClassRule(type)
+ return !startupProfile.isStartupClass(type)
|| options.getStartupOptions().isStartupBoundaryOptimizationsEnabled()
? FeatureSplit.BASE
: FeatureSplit.BASE_STARTUP;
diff --git a/src/main/java/com/android/tools/r8/features/FeatureSplitBoundaryOptimizationUtils.java b/src/main/java/com/android/tools/r8/features/FeatureSplitBoundaryOptimizationUtils.java
index 37f1494..4c3c809 100644
--- a/src/main/java/com/android/tools/r8/features/FeatureSplitBoundaryOptimizationUtils.java
+++ b/src/main/java/com/android/tools/r8/features/FeatureSplitBoundaryOptimizationUtils.java
@@ -77,8 +77,8 @@
} else if (callerIsStartupMethod.isFalse()) {
// If the caller is not a startup method, then only allow inlining if the caller is not a
// startup class or the callee is a startup class.
- if (startupProfile.containsClassRule(caller.getHolderType())
- && !startupProfile.containsClassRule(callee.getHolderType())) {
+ if (startupProfile.isStartupClass(caller.getHolderType())
+ && !startupProfile.isStartupClass(callee.getHolderType())) {
return false;
}
}
@@ -114,8 +114,8 @@
// If the source class is a startup class then require that the target class is also a startup
// class.
StartupProfile startupProfile = appView.getStartupProfile();
- if (startupProfile.containsClassRule(sourceClass.getType())
- && !startupProfile.containsClassRule(targetClass.getType())) {
+ if (startupProfile.isStartupClass(sourceClass.getType())
+ && !startupProfile.isStartupClass(targetClass.getType())) {
return false;
}
return true;
diff --git a/src/test/java/com/android/tools/r8/startup/MinimalStartupDexFromStartupMethodRuleTest.java b/src/test/java/com/android/tools/r8/startup/MinimalStartupDexFromStartupMethodRuleTest.java
index dcd0191..6034910 100644
--- a/src/test/java/com/android/tools/r8/startup/MinimalStartupDexFromStartupMethodRuleTest.java
+++ b/src/test/java/com/android/tools/r8/startup/MinimalStartupDexFromStartupMethodRuleTest.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.startup;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
@@ -58,17 +57,11 @@
primaryDexInspector -> {
ClassSubject mainClassSubject = primaryDexInspector.clazz(Main.class);
assertThat(mainClassSubject, isPresent());
-
- // TODO(b/274591979): Should be in classes2.dex.
- ClassSubject postStartupClassSubject =
- primaryDexInspector.clazz(PostStartupClass.class);
- assertThat(postStartupClassSubject, isPresent());
},
secondaryDexInspector -> {
- // TODO(b/274591979): Should be present.
ClassSubject postStartupClassSubject =
secondaryDexInspector.clazz(PostStartupClass.class);
- assertThat(postStartupClassSubject, isAbsent());
+ assertThat(postStartupClassSubject, isPresent());
})
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("Hello, world!");