Simplify and optimize relevant candidates for if rule
Change-Id: Ic1c007cbe51c2f4cf5a6c7ea7381be306c8eadda
diff --git a/src/main/java/com/android/tools/r8/graph/ImmediateSubtypingInfo.java b/src/main/java/com/android/tools/r8/graph/ImmediateSubtypingInfo.java
index 7313380..a7f48e7 100644
--- a/src/main/java/com/android/tools/r8/graph/ImmediateSubtypingInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/ImmediateSubtypingInfo.java
@@ -11,14 +11,12 @@
import com.android.tools.r8.utils.WorkList;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
@@ -64,11 +62,6 @@
(supertype, superclass) -> consumer.accept(superclass));
}
- public void forEachImmediateSuperClass(
- DexClass clazz, BiConsumer<? super DexType, ? super DexClass> consumer) {
- forEachImmediateSuperClassMatching(clazz, (supertype, superclass) -> true, consumer);
- }
-
public void forEachImmediateSuperClassMatching(
DexClass clazz,
BiPredicate<? super DexType, ? super DexClass> predicate,
@@ -175,21 +168,6 @@
Objects::nonNull);
}
- public Set<DexProgramClass> getTransitiveProgramSubclasses(S clazz) {
- return getTransitiveProgramSubclassesMatching(clazz, Predicates.alwaysTrue());
- }
-
- public Set<DexProgramClass> getTransitiveProgramSubclassesMatching(
- S clazz, Predicate<DexProgramClass> predicate) {
- Set<DexProgramClass> classes = Sets.newIdentityHashSet();
- forEachTransitiveProgramSubclassMatching(clazz, predicate, classes::add);
- return classes;
- }
-
- public boolean hasSubclasses(S clazz) {
- return !getSubclasses(clazz).isEmpty();
- }
-
public <TB, TC> TraversalContinuation<TB, TC> traverseTransitiveSubclasses(
S clazz, Function<? super DexClass, TraversalContinuation<TB, TC>> fn) {
TraversalContinuation<TB, TC> traversalContinuation = TraversalContinuation.doContinue();
diff --git a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
index d08d948..b79bd90 100644
--- a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
+++ b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
@@ -33,6 +33,7 @@
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.function.BiPredicate;
+import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -72,13 +73,16 @@
// Depending on which types that trigger the -if rule, the application of the subsequent
// -keep rule may vary (due to back references). So, we need to try all pairs of -if
// rule and live types.
- for (DexClass clazz :
- getRelevantCandidatesForRule(
- ifRuleKey, classKind, classesWithNewlyLiveMembers, isEffectivelyLive)) {
- assert !clazz.isProgramClass() || isEffectivelyLive.test(clazz.asProgramClass());
- processActiveIfRulesWithMembersAndSameClassPrecondition(
- ifRuleKey, ifRulesInEquivalence, clazz, toRemove);
- }
+ forEachRelevantCandidate(
+ ifRuleKey,
+ classKind,
+ classesWithNewlyLiveMembers,
+ isEffectivelyLive,
+ clazz -> {
+ assert !clazz.isProgramClass() || isEffectivelyLive.test(clazz.asProgramClass());
+ processActiveIfRulesWithMembersAndSameClassPrecondition(
+ ifRuleKey, ifRulesInEquivalence, clazz, toRemove);
+ });
if (ifRulesInEquivalence.size() == toRemove.size()) {
return true;
}
@@ -89,19 +93,22 @@
}
@SuppressWarnings("unchecked")
- Iterable<? extends DexClass> getRelevantCandidatesForRule(
+ void forEachRelevantCandidate(
ProguardIfRule ifRule,
ClassKind<?> classKind,
Iterable<? extends DexClass> classesWithNewlyLiveMembers,
- Predicate<DexProgramClass> isEffectivelyLive) {
+ Predicate<DexProgramClass> isEffectivelyLive,
+ Consumer<DexClass> consumer) {
if (classKind == ClassKind.PROGRAM) {
- return ifRule.relevantCandidatesForRule(
+ ifRule.forEachRelevantCandidate(
appView,
enqueuer.getSubtypingInfo(),
(Iterable<DexProgramClass>) classesWithNewlyLiveMembers,
- isEffectivelyLive);
+ isEffectivelyLive,
+ consumer);
+ } else {
+ classesWithNewlyLiveMembers.forEach(consumer);
}
- return classesWithNewlyLiveMembers;
}
private void processActiveIfRulesWithMembersAndSameClassPrecondition(
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
index bfd3024..2adc592 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
@@ -6,13 +6,9 @@
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.google.common.base.Predicates.alwaysTrue;
-import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.ClassResolutionResult;
import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexDefinitionSupplier;
-import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ImmediateAppSubtypingInfo;
@@ -23,9 +19,9 @@
import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.Iterables;
-import java.util.Collections;
import java.util.List;
import java.util.Objects;
+import java.util.function.Consumer;
import java.util.function.Predicate;
public abstract class ProguardConfigurationRule extends ProguardClassSpecification {
@@ -150,63 +146,41 @@
this.canReferenceDeadTypes = true;
}
- Iterable<DexProgramClass> relevantCandidatesForRule(
+ void forEachRelevantCandidate(
AppView<? extends AppInfoWithClassHierarchy> appView,
ImmediateAppSubtypingInfo subtypingInfo,
Iterable<DexProgramClass> defaultValue,
- Predicate<DexProgramClass> isRelevant) {
- Iterable<DexType> specificTypes;
+ Predicate<DexProgramClass> isRelevant,
+ Consumer<DexClass> consumer) {
if (getClassNames().hasSpecificTypes()) {
- specificTypes = getClassNames().getSpecificTypes();
+ for (DexType type : getClassNames().getSpecificTypes()) {
+ DexProgramClass clazz =
+ asProgramClassOrNull(
+ canReferenceDeadTypes
+ ? appView.appInfo().definitionForWithoutExistenceAssert(type)
+ : appView.definitionFor(type));
+ if (clazz != null && isRelevant.test(clazz)) {
+ consumer.accept(clazz);
+ }
+ }
} else if (hasInheritanceClassName() && getInheritanceClassName().hasSpecificType()) {
DexType type = getInheritanceClassName().getSpecificType();
DexClass clazz = appView.definitionFor(type);
- if (clazz == null) {
- return Collections.emptyList();
- }
- Iterable<DexProgramClass> relevantSubclasses =
- subtypingInfo.getTransitiveProgramSubclassesMatching(clazz, isRelevant);
- if (appView.getVerticallyMergedClasses() != null
- && appView.getVerticallyMergedClasses().hasBeenMergedIntoSubtype(type)) {
- DexType targetType = appView.getVerticallyMergedClasses().getTargetFor(type);
- DexProgramClass targetClass = asProgramClassOrNull(appView.definitionFor(targetType));
- assert targetClass != null;
- if (isRelevant.test(targetClass)) {
- return IterableUtils.append(relevantSubclasses, targetClass);
+ if (clazz != null) {
+ subtypingInfo.forEachTransitiveProgramSubclassMatching(clazz, isRelevant, consumer);
+ if (appView.getVerticallyMergedClasses() != null
+ && appView.getVerticallyMergedClasses().hasBeenMergedIntoSubtype(type)) {
+ DexType targetType = appView.getVerticallyMergedClasses().getTargetFor(type);
+ DexProgramClass targetClass = asProgramClassOrNull(appView.definitionFor(targetType));
+ assert targetClass != null;
+ if (isRelevant.test(targetClass)) {
+ consumer.accept(targetClass);
+ }
}
}
- return relevantSubclasses;
} else {
- return defaultValue;
+ defaultValue.forEach(consumer);
}
- assert specificTypes != null;
- return DexProgramClass.asProgramClasses(
- specificTypes,
- new DexDefinitionSupplier() {
- @Override
- public ClassResolutionResult contextIndependentDefinitionForWithResolutionResult(
- DexType type) {
- throw new Unreachable("Add support for multiple definitions with rule evaluation");
- }
-
- @Override
- public DexProgramClass definitionFor(DexType type) {
- DexProgramClass result =
- asProgramClassOrNull(
- canReferenceDeadTypes
- ? appView.appInfo().definitionForWithoutExistenceAssert(type)
- : appView.definitionFor(type));
- if (result != null && isRelevant.test(result)) {
- return result;
- }
- return null;
- }
-
- @Override
- public DexItemFactory dexItemFactory() {
- return appView.dexItemFactory();
- }
- });
}
abstract String typeString();
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 acc89d1..6eec044 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -442,11 +442,12 @@
tasks.submit(
() -> {
- for (DexProgramClass clazz :
- rule.relevantCandidatesForRule(
- appView, subtypingInfo, application.classes(), alwaysTrue())) {
- process(clazz, rule, ifRulePreconditionMatch);
- }
+ rule.forEachRelevantCandidate(
+ appView,
+ subtypingInfo,
+ application.classes(),
+ alwaysTrue(),
+ clazz -> process(clazz, rule, ifRulePreconditionMatch));
if (rule.applyToNonProgramClasses()) {
for (DexLibraryClass clazz : application.libraryClasses()) {
process(clazz, rule, ifRulePreconditionMatch);