Revert "Allow class inlining of merged singleton classes"
This reverts commit 0365eeed2f0d5fb0cfc87103595d2436e4ba52d4.
Reason for revert: Failures
Change-Id: I5e9121ef24a9fe11824c0cd74fb974e88a556c0d
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 37b3796..eb016fe 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
@@ -224,6 +224,8 @@
anyInlinedMethods = true;
}
+ assert inliningIRProvider.verifyIRCacheIsEmpty();
+
// Restore normality.
code.removeAllDeadAndTrivialPhis(affectedValues);
if (!affectedValues.isEmpty()) {
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 23d9242..4b15332 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
@@ -25,12 +25,11 @@
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
-import com.android.tools.r8.ir.analysis.value.AbstractValue;
-import com.android.tools.r8.ir.analysis.value.ObjectState;
import com.android.tools.r8.ir.code.AliasedValueConfiguration;
import com.android.tools.r8.ir.code.AssumeAndCheckCastAliasedValueConfiguration;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.CheckCast;
+import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.If;
import com.android.tools.r8.ir.code.InstanceGet;
@@ -60,6 +59,7 @@
import com.android.tools.r8.kotlin.KotlinClassLevelInfo;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.OptionalBool;
+import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.Timing;
@@ -93,7 +93,6 @@
private Value eligibleInstance;
private DexProgramClass eligibleClass;
- private ObjectState objectState;
private final Map<InvokeMethodWithReceiver, InliningInfo> methodCallsOnInstance =
new IdentityHashMap<>();
@@ -101,6 +100,8 @@
private final ProgramMethodSet indirectMethodCallsOnInstance = ProgramMethodSet.create();
private final Map<InvokeMethod, InliningInfo> extraMethodCalls
= new IdentityHashMap<>();
+ private final List<Pair<InvokeMethod, Integer>> unusedArguments
+ = new ArrayList<>();
private final Map<InvokeMethod, ProgramMethod> directInlinees = new IdentityHashMap<>();
private final List<ProgramMethod> indirectInlinees = new ArrayList<>();
@@ -190,11 +191,6 @@
if (eligibleClass == null) {
return EligibilityStatus.NOT_ELIGIBLE;
}
- AbstractValue abstractValue = optimizationInfo.getAbstractValue();
- objectState =
- abstractValue.isSingleFieldValue()
- ? abstractValue.asSingleFieldValue().getState()
- : ObjectState.empty();
return EligibilityStatus.ELIGIBLE;
}
@@ -386,6 +382,7 @@
// Process inlining, includes the following steps:
//
// * remove linked assume instructions if any so that users of the eligible field are up-to-date.
+ // * replace unused instance usages as arguments which are never used
// * inline extra methods if any, collect new direct method calls
// * inline direct methods if any
// * remove superclass initializer call and field reads
@@ -401,6 +398,7 @@
throws IllegalClassInlinerStateException {
// Verify that `eligibleInstance` is not aliased.
assert eligibleInstance == eligibleInstance.getAliasedValue();
+ replaceUsagesAsUnusedArgument(code);
boolean anyInlinedMethods = forceInlineExtraMethodInvocations(code, inliningIRProvider);
if (anyInlinedMethods) {
@@ -414,6 +412,8 @@
}
assert extraMethodCalls.isEmpty()
: "Remaining extra method calls: " + StringUtils.join(extraMethodCalls.entrySet(), ", ");
+ assert unusedArguments.isEmpty()
+ : "Remaining unused arg: " + StringUtils.join(unusedArguments, ", ");
}
anyInlinedMethods |= forceInlineDirectMethodInvocations(code, inliningIRProvider);
@@ -431,9 +431,26 @@
methodCallsOnInstance.clear();
indirectMethodCallsOnInstance.clear();
extraMethodCalls.clear();
+ unusedArguments.clear();
receivers.reset();
}
+ private void replaceUsagesAsUnusedArgument(IRCode code) {
+ for (Pair<InvokeMethod, Integer> unusedArgument : unusedArguments) {
+ InvokeMethod invoke = unusedArgument.getFirst();
+ BasicBlock block = invoke.getBlock();
+
+ ConstNumber nullValue = code.createConstNull();
+ nullValue.setPosition(invoke.getPosition());
+ block.listIterator(code, invoke).add(nullValue);
+ assert nullValue.getBlock() == block;
+
+ int argIndex = unusedArgument.getSecond();
+ invoke.replaceValue(argIndex, nullValue.outValue());
+ }
+ unusedArguments.clear();
+ }
+
private boolean forceInlineExtraMethodInvocations(
IRCode code, InliningIRProvider inliningIRProvider) {
if (extraMethodCalls.isEmpty()) {
@@ -720,7 +737,6 @@
new TreeSet<>(Comparator.comparingInt(x -> x.outValue().getNumber()));
for (Instruction user : eligibleInstance.uniqueUsers()) {
if (user.isInstanceGet()) {
- assert root.isNewInstance();
if (user.outValue().hasAnyUsers()) {
uniqueInstanceGetUsersWithDeterministicOrder.add(user.asInstanceGet());
} else {
@@ -732,7 +748,6 @@
if (user.isInstancePut()) {
// Skip in this iteration since these instructions are needed to properly calculate what
// value should field reads be replaced with.
- assert root.isNewInstance();
continue;
}
@@ -1096,7 +1111,7 @@
assert root.isStaticGet();
return classInlinerMethodConstraint.isEligibleForStaticGetClassInlining(
- appView, parameter, objectState);
+ singleTarget, parameter);
}
private boolean isExtraMethodCall(InvokeMethod invoke) {
@@ -1121,6 +1136,10 @@
// Analyzes if a method invoke the eligible instance is passed to is eligible. In short,
// it can be eligible if:
//
+ // -- eligible instance is passed as argument #N which is not used in the method,
+ // such cases are collected in 'unusedArguments' parameter and later replaced
+ // with 'null' value
+ //
// -- eligible instance is passed as argument #N which is only used in the method to
// call a method on this object (we call it indirect method call), and method is
// eligible according to the same rules defined for direct method call eligibility
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysFalseClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysFalseClassInlinerMethodConstraint.java
index ff68dfd..0c6d335e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysFalseClassInlinerMethodConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysFalseClassInlinerMethodConstraint.java
@@ -4,11 +4,8 @@
package com.android.tools.r8.ir.optimize.classinliner.constraint;
-import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.analysis.value.ObjectState;
import com.android.tools.r8.ir.optimize.classinliner.analysis.ParameterUsage;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
public class AlwaysFalseClassInlinerMethodConstraint implements ClassInlinerMethodConstraint {
@@ -37,8 +34,7 @@
}
@Override
- public boolean isEligibleForStaticGetClassInlining(
- AppView<AppInfoWithLiveness> appView, int parameter, ObjectState objectState) {
+ public boolean isEligibleForStaticGetClassInlining(ProgramMethod method, int parameter) {
return false;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java
index ce14bb4..c86f373 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java
@@ -4,11 +4,8 @@
package com.android.tools.r8.ir.optimize.classinliner.constraint;
-import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.analysis.value.ObjectState;
import com.android.tools.r8.ir.optimize.classinliner.analysis.ParameterUsage;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
public interface ClassInlinerMethodConstraint {
@@ -18,8 +15,7 @@
boolean isEligibleForNewInstanceClassInlining(ProgramMethod method, int parameter);
- boolean isEligibleForStaticGetClassInlining(
- AppView<AppInfoWithLiveness> appView, int parameter, ObjectState objectState);
+ boolean isEligibleForStaticGetClassInlining(ProgramMethod method, int parameter);
static AlwaysFalseClassInlinerMethodConstraint alwaysFalse() {
return AlwaysFalseClassInlinerMethodConstraint.getInstance();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ConditionalClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ConditionalClassInlinerMethodConstraint.java
index 8ad6b4a..5c384e8 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ConditionalClassInlinerMethodConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ConditionalClassInlinerMethodConstraint.java
@@ -4,18 +4,12 @@
package com.android.tools.r8.ir.optimize.classinliner.constraint;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.analysis.value.ObjectState;
import com.android.tools.r8.ir.optimize.classinliner.analysis.AnalysisContext;
import com.android.tools.r8.ir.optimize.classinliner.analysis.AnalysisState;
import com.android.tools.r8.ir.optimize.classinliner.analysis.NonEmptyParameterUsage;
import com.android.tools.r8.ir.optimize.classinliner.analysis.ParameterUsage;
import com.android.tools.r8.ir.optimize.classinliner.analysis.ParameterUsagePerContext;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
@@ -57,8 +51,7 @@
}
@Override
- public boolean isEligibleForStaticGetClassInlining(
- AppView<AppInfoWithLiveness> appView, int parameter, ObjectState objectState) {
+ public boolean isEligibleForStaticGetClassInlining(ProgramMethod method, int parameter) {
AnalysisContext defaultContext = AnalysisContext.getDefaultContext();
ParameterUsage usage = usages.get(parameter).get(defaultContext);
if (usage.isBottom()) {
@@ -79,13 +72,9 @@
// We will not be able to remove the monitor instruction afterwards.
return false;
}
- for (DexField fieldReadFromParameter : knownUsage.getFieldsReadFromParameter()) {
- DexClass holder = appView.definitionFor(fieldReadFromParameter.getHolderType());
- DexEncodedField definition = fieldReadFromParameter.lookupOnClass(holder);
- if (definition == null
- || !objectState.getAbstractFieldValue(definition).isSingleConstValue()) {
- return false;
- }
+ if (!knownUsage.getFieldsReadFromParameter().isEmpty()) {
+ // We don't know the value of the field.
+ return false;
}
return true;
}