Move class inliner receiver sets to separate structure
Change-Id: Ic9a3eafaa17ea0cd5aeb79f42eb239baf9a3af1d
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
index b3a13b5..3a29023 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
@@ -220,9 +220,7 @@
continue;
}
- assert Sets.intersection(
- processor.getMaybeReceiverAliases(), processor.getDefiniteReceiverAliases())
- .isEmpty();
+ assert processor.getReceivers().verifyReceiverSetsAreDisjoint();
// Is inlining allowed.
if (processor.getEstimatedCombinedSizeForInlining()
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerReceiverSet.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerReceiverSet.java
new file mode 100644
index 0000000..5a8c59d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerReceiverSet.java
@@ -0,0 +1,127 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.classinliner;
+
+import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.optimize.classinliner.InlineCandidateProcessor.AliasKind;
+import com.android.tools.r8.utils.SetUtils;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BooleanSupplier;
+
+class ClassInlinerReceiverSet {
+
+ private final Value root;
+
+ private final Set<Value> definiteReceiverAliases;
+ private final Set<Value> maybeReceiverAliases = Sets.newIdentityHashSet();
+
+ // Set of values that are not allowed to become an alias of the receiver.
+ private final Set<Value> illegalReceiverAliases = Sets.newIdentityHashSet();
+
+ // Set of values that are allowed to become an alias of the receiver under certain circumstances.
+ private final Map<Value, List<BooleanSupplier>> deferredAliasValidityChecks =
+ new IdentityHashMap<>();
+
+ ClassInlinerReceiverSet(Value root) {
+ this.definiteReceiverAliases = SetUtils.newIdentityHashSet(root);
+ this.root = root;
+ }
+
+ Set<Value> getDefiniteReceiverAliases() {
+ return definiteReceiverAliases;
+ }
+
+ Set<Value> getMaybeReceiverAliases() {
+ return maybeReceiverAliases;
+ }
+
+ boolean addReceiverAlias(Value alias, AliasKind kind) {
+ if (isIllegalReceiverAlias(alias)) {
+ return false; // Not allowed.
+ }
+ // All checks passed.
+ deferredAliasValidityChecks.remove(alias);
+ boolean changed;
+ if (kind == AliasKind.DEFINITE) {
+ assert !maybeReceiverAliases.contains(alias);
+ changed = definiteReceiverAliases.add(alias);
+ } else {
+ assert !definiteReceiverAliases.contains(alias);
+ changed = maybeReceiverAliases.add(alias);
+ }
+ // Verify that the state changed. Otherwise, we are analyzing the same instruction more than
+ // once.
+ assert changed : alias.toString() + " already added as an alias";
+ return true;
+ }
+
+ boolean addIllegalReceiverAlias(Value value) {
+ if (isReceiverAlias(value)) {
+ return false;
+ }
+ illegalReceiverAliases.add(value);
+ // Since `value` is never allowed as a receiver, there is no need to keep the validity checks
+ // around.
+ deferredAliasValidityChecks.remove(value);
+ return true;
+ }
+
+ void addDeferredAliasValidityCheck(Value value, BooleanSupplier deferredValidityCheck) {
+ assert !isReceiverAlias(value);
+ // Only add the deferred validity check if `value` may be allowed as a receiver (i.e., it is not
+ // already illegal).
+ if (illegalReceiverAliases.contains(value)) {
+ assert !deferredAliasValidityChecks.containsKey(value);
+ } else {
+ deferredAliasValidityChecks
+ .computeIfAbsent(value, ignore -> new ArrayList<>())
+ .add(deferredValidityCheck);
+ }
+ }
+
+ boolean isReceiverAlias(Value value) {
+ return isDefiniteReceiverAlias(value) || isMaybeReceiverAlias(value);
+ }
+
+ boolean isDefiniteReceiverAlias(Value value) {
+ return definiteReceiverAliases.contains(value);
+ }
+
+ private boolean isMaybeReceiverAlias(Value value) {
+ return maybeReceiverAliases.contains(value);
+ }
+
+ private boolean isIllegalReceiverAlias(Value value) {
+ if (illegalReceiverAliases.contains(value)) {
+ return true;
+ }
+ List<BooleanSupplier> deferredValidityChecks = deferredAliasValidityChecks.get(value);
+ if (deferredValidityChecks != null) {
+ for (BooleanSupplier deferredValidityCheck : deferredValidityChecks) {
+ if (!deferredValidityCheck.getAsBoolean()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ void reset() {
+ deferredAliasValidityChecks.clear();
+ definiteReceiverAliases.clear();
+ definiteReceiverAliases.add(root);
+ maybeReceiverAliases.clear();
+ }
+
+ boolean verifyReceiverSetsAreDisjoint() {
+ assert Sets.intersection(getMaybeReceiverAliases(), getDefiniteReceiverAliases()).isEmpty();
+ return true;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index abcfb51..4c9b415 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -44,7 +44,6 @@
import com.android.tools.r8.kotlin.KotlinInfo;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.Pair;
-import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@@ -57,7 +56,6 @@
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
-import java.util.function.BooleanSupplier;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
@@ -96,15 +94,7 @@
// Sets of values that must/may be an alias of the "root" instance (including the root instance
// itself).
- private final Set<Value> definiteReceiverAliases;
- private final Set<Value> maybeReceiverAliases = Sets.newIdentityHashSet();
-
- // Set of values that are not allowed to become an alias of the receiver.
- private final Set<Value> illegalReceiverAliases = Sets.newIdentityHashSet();
-
- // Set of values that are allowed to become an alias of the receiver under certain circumstances.
- private final Map<Value, List<BooleanSupplier>> deferredAliasValidityChecks =
- new IdentityHashMap<>();
+ private final ClassInlinerReceiverSet receivers;
InlineCandidateProcessor(
AppView<AppInfoWithLiveness> appView,
@@ -121,90 +111,15 @@
this.method = method;
this.root = root;
this.isProcessedConcurrently = isProcessedConcurrently;
- this.definiteReceiverAliases = SetUtils.newIdentityHashSet(root.outValue());
+ this.receivers = new ClassInlinerReceiverSet(root.outValue());
}
int getEstimatedCombinedSizeForInlining() {
return estimatedCombinedSizeForInlining;
}
- Set<Value> getDefiniteReceiverAliases() {
- return definiteReceiverAliases;
- }
-
- Set<Value> getMaybeReceiverAliases() {
- return maybeReceiverAliases;
- }
-
- private boolean addReceiverAlias(Value alias, AliasKind kind) {
- if (isIllegalReceiverAlias(alias)) {
- return false; // Not allowed.
- }
- // All checks passed.
- deferredAliasValidityChecks.remove(alias);
- boolean changed;
- if (kind == AliasKind.DEFINITE) {
- assert !maybeReceiverAliases.contains(alias);
- changed = definiteReceiverAliases.add(alias);
- } else {
- assert !definiteReceiverAliases.contains(alias);
- changed = maybeReceiverAliases.add(alias);
- }
- // Verify that the state changed. Otherwise, we are analyzing the same instruction more than
- // once.
- assert changed : alias.toString() + " already added as an alias";
- return true;
- }
-
- private boolean addIllegalReceiverAlias(Value value) {
- if (isReceiverAlias(value)) {
- return false;
- }
- illegalReceiverAliases.add(value);
- // Since `value` is never allowed as a receiver, there is no need to keep the validity checks
- // around.
- deferredAliasValidityChecks.remove(value);
- return true;
- }
-
- private void addDeferredAliasValidityCheck(Value value, BooleanSupplier deferredValidityCheck) {
- assert !isReceiverAlias(value);
- // Only add the deferred validity check if `value` may be allowed as a receiver (i.e., it is not
- // already illegal).
- if (illegalReceiverAliases.contains(value)) {
- assert !deferredAliasValidityChecks.containsKey(value);
- } else {
- deferredAliasValidityChecks
- .computeIfAbsent(value, ignore -> new ArrayList<>())
- .add(deferredValidityCheck);
- }
- }
-
- private boolean isReceiverAlias(Value value) {
- return isDefiniteReceiverAlias(value) || isMaybeReceiverAlias(value);
- }
-
- private boolean isDefiniteReceiverAlias(Value value) {
- return definiteReceiverAliases.contains(value);
- }
-
- private boolean isMaybeReceiverAlias(Value value) {
- return maybeReceiverAliases.contains(value);
- }
-
- private boolean isIllegalReceiverAlias(Value value) {
- if (illegalReceiverAliases.contains(value)) {
- return true;
- }
- List<BooleanSupplier> deferredValidityChecks = deferredAliasValidityChecks.get(value);
- if (deferredValidityChecks != null) {
- for (BooleanSupplier deferredValidityCheck : deferredValidityChecks) {
- if (!deferredValidityCheck.getAsBoolean()) {
- return true;
- }
- }
- }
- return false;
+ ClassInlinerReceiverSet getReceivers() {
+ return receivers;
}
// Checks if the root instruction defines eligible value, i.e. the value
@@ -370,13 +285,13 @@
for (Instruction user : currentUsers) {
if (user.isAssume()) {
Value alias = user.outValue();
- if (isReceiverAlias(alias)) {
+ if (receivers.isReceiverAlias(alias)) {
continue; // Already processed.
}
if (alias.hasPhiUsers()) {
return alias.firstPhiUser(); // Not eligible.
}
- if (!addReceiverAlias(alias, AliasKind.DEFINITE)) {
+ if (!receivers.addReceiverAlias(alias, AliasKind.DEFINITE)) {
return user; // Not eligible.
}
indirectUsers.addAll(alias.uniqueUsers());
@@ -384,7 +299,8 @@
}
// Field read/write.
if (user.isInstanceGet()
- || (user.isInstancePut() && addIllegalReceiverAlias(user.asInstancePut().value()))) {
+ || (user.isInstancePut()
+ && receivers.addIllegalReceiverAlias(user.asInstancePut().value()))) {
DexField field = user.asFieldInstruction().getField();
if (field.holder == eligibleClass
&& eligibleClassDefinition.lookupInstanceField(field) != null) {
@@ -486,10 +402,7 @@
methodCallsOnInstance.clear();
extraMethodCalls.clear();
unusedArguments.clear();
- definiteReceiverAliases.clear();
- definiteReceiverAliases.add(eligibleInstance);
- maybeReceiverAliases.clear();
- deferredAliasValidityChecks.clear();
+ receivers.reset();
estimatedCombinedSizeForInlining = 0;
// Repeat user analysis
@@ -552,7 +465,7 @@
}
assert methodCallsOnInstance.keySet().stream()
.map(InvokeMethodWithReceiver::getReceiver)
- .allMatch(this::isReceiverAlias);
+ .allMatch(receivers::isReceiverAlias);
inliner.performForcedInlining(method, code, methodCallsOnInstance, inliningIRProvider);
return true;
}
@@ -565,7 +478,7 @@
Assume<?> assumeInstruction = user.asAssume();
Value src = assumeInstruction.src();
Value dest = assumeInstruction.outValue();
- assert isReceiverAlias(dest);
+ assert receivers.isReceiverAlias(dest);
assert !dest.hasPhiUsers();
dest.replaceUsers(src);
removeInstruction(user);
@@ -715,14 +628,14 @@
assert isEligibleSingleTarget(singleTarget);
// Must be a constructor called on the receiver.
- if (!isDefiniteReceiverAlias(invoke.getReceiver())) {
+ if (!receivers.isDefiniteReceiverAlias(invoke.getReceiver())) {
return null;
}
// None of the subsequent arguments may be an alias of the receiver.
List<Value> inValues = invoke.inValues();
for (int i = 1; i < inValues.size(); i++) {
- if (!addIllegalReceiverAlias(inValues.get(i))) {
+ if (!receivers.addIllegalReceiverAlias(inValues.get(i))) {
return null;
}
}
@@ -808,7 +721,7 @@
// receiver. Otherwise, the out-value may be an alias of the receiver, and it is added to the
// may-alias set.
AliasKind kind = eligibility.returnsReceiver.isTrue() ? AliasKind.DEFINITE : AliasKind.MAYBE;
- if (!addReceiverAlias(outValue, kind)) {
+ if (!receivers.addReceiverAlias(outValue, kind)) {
return false;
}
@@ -821,7 +734,7 @@
if (outValueAlias.hasPhiUsers() || outValueAlias.hasDebugUsers()) {
return false;
}
- if (!addReceiverAlias(outValueAlias, kind)) {
+ if (!receivers.addReceiverAlias(outValueAlias, kind)) {
return false;
}
indirectOutValueUsers.addAll(outValueAlias.uniqueUsers());
@@ -860,7 +773,7 @@
// None of the none-receiver arguments may be an alias of the receiver.
List<Value> inValues = invoke.inValues();
for (int i = 1; i < inValues.size(); i++) {
- if (!addIllegalReceiverAlias(inValues.get(i))) {
+ if (!receivers.addIllegalReceiverAlias(inValues.get(i))) {
return null;
}
}
@@ -938,7 +851,7 @@
}
if (invoke.isInvokeMethodWithReceiver()) {
Value receiver = invoke.asInvokeMethodWithReceiver().getReceiver();
- if (!addIllegalReceiverAlias(receiver)) {
+ if (!receivers.addIllegalReceiverAlias(receiver)) {
return false;
}
}
@@ -982,7 +895,7 @@
if (invoke.isInvokeMethodWithReceiver()) {
InvokeMethodWithReceiver invokeMethodWithReceiver = invoke.asInvokeMethodWithReceiver();
Value receiver = invokeMethodWithReceiver.getReceiver();
- if (!addIllegalReceiverAlias(receiver)) {
+ if (!receivers.addIllegalReceiverAlias(receiver)) {
return false;
}
@@ -1001,7 +914,7 @@
for (int argIndex = 0; argIndex < arguments.size(); argIndex++) {
Value argument = arguments.get(argIndex).getAliasedValue();
- if (isDefiniteReceiverAlias(argument)
+ if (receivers.isDefiniteReceiverAlias(argument)
&& optimizationInfo.getParameterUsages(argIndex).notUsed()) {
// Reference can be removed since it's not used.
unusedArguments.add(new Pair<>(invoke, argIndex));
@@ -1026,14 +939,14 @@
ParameterUsage parameterUsage = optimizationInfo.getParameterUsages(argIndex);
Value argument = arguments.get(argIndex);
- if (isReceiverAlias(argument)) {
+ if (receivers.isReceiverAlias(argument)) {
// Have parameter usage info?
if (!isEligibleParameterUsage(parameterUsage, invoke, defaultOracle)) {
return false;
}
} else {
// Nothing to worry about, unless `argument` becomes an alias of the receiver later.
- addDeferredAliasValidityCheck(
+ receivers.addDeferredAliasValidityCheck(
argument, () -> isEligibleParameterUsage(parameterUsage, invoke, defaultOracle));
}
}