Account for indirect definitely unsafe casts in class inliner
Change-Id: Ic02b6216f933f6fa7320d20bbea98adb9cb9e8c0
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 e6494f3..514eae8 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
@@ -1046,12 +1046,12 @@
int parameter = 0;
if (root.isNewInstance()) {
return classInlinerMethodConstraint.isEligibleForNewInstanceClassInlining(
- singleTarget, parameter);
+ appView, eligibleClass, singleTarget, parameter);
}
assert root.isStaticGet();
return classInlinerMethodConstraint.isEligibleForStaticGetClassInlining(
- appView, parameter, objectState, method);
+ appView, eligibleClass, parameter, objectState, method);
}
// Analyzes if a method invoke the eligible instance is passed to is eligible. In short,
@@ -1155,13 +1155,13 @@
singleTarget.getDefinition().getOptimizationInfo().getClassInlinerMethodConstraint();
if (root.isNewInstance()) {
if (!classInlinerMethodConstraint.isEligibleForNewInstanceClassInlining(
- singleTarget, parameter)) {
+ appView, eligibleClass, singleTarget, parameter)) {
return false;
}
} else {
assert root.isStaticGet();
if (!classInlinerMethodConstraint.isEligibleForStaticGetClassInlining(
- appView, parameter, objectState, method)) {
+ appView, eligibleClass, parameter, objectState, method)) {
return false;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/BottomParameterUsage.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/BottomParameterUsage.java
index 930edc5..5d7f1e3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/BottomParameterUsage.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/BottomParameterUsage.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.ir.optimize.classinliner.analysis;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.code.InvokeMethodWithReceiver;
class BottomParameterUsage extends ParameterUsage {
@@ -18,6 +19,11 @@
}
@Override
+ ParameterUsage addCastWithParameter(DexType castType) {
+ return InternalNonEmptyParameterUsage.builder().addCastWithParameter(castType).build();
+ }
+
+ @Override
ParameterUsage addFieldReadFromParameter(DexField field) {
return InternalNonEmptyParameterUsage.builder().addFieldReadFromParameter(field).build();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/InternalNonEmptyParameterUsage.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/InternalNonEmptyParameterUsage.java
index 4bba181..29274b2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/InternalNonEmptyParameterUsage.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/InternalNonEmptyParameterUsage.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.code.InvokeMethodWithReceiver;
import com.android.tools.r8.utils.BooleanUtils;
import com.google.common.collect.ImmutableMultiset;
@@ -23,6 +24,7 @@
*/
public class InternalNonEmptyParameterUsage extends ParameterUsage {
+ private Set<DexType> castsWithParameter;
private Set<DexField> fieldsReadFromParameter;
private Set<InvokeMethodWithReceiver> methodCallsWithParameterAsReceiver;
@@ -31,16 +33,19 @@
private boolean isParameterUsedAsLock;
InternalNonEmptyParameterUsage(
+ Set<DexType> castsWithParameter,
Set<DexField> fieldsReadFromParameter,
Set<InvokeMethodWithReceiver> methodCallsWithParameterAsReceiver,
boolean isParameterMutated,
boolean isParameterReturned,
boolean isParameterUsedAsLock) {
- assert !fieldsReadFromParameter.isEmpty()
+ assert !castsWithParameter.isEmpty()
+ || !fieldsReadFromParameter.isEmpty()
|| !methodCallsWithParameterAsReceiver.isEmpty()
|| isParameterMutated
|| isParameterReturned
|| isParameterUsedAsLock;
+ this.castsWithParameter = castsWithParameter;
this.fieldsReadFromParameter = fieldsReadFromParameter;
this.methodCallsWithParameterAsReceiver = methodCallsWithParameterAsReceiver;
this.isParameterMutated = isParameterMutated;
@@ -57,11 +62,26 @@
}
@Override
+ ParameterUsage addCastWithParameter(DexType castType) {
+ ImmutableSet.Builder<DexType> newCastsWithParameter = ImmutableSet.builder();
+ newCastsWithParameter.addAll(castsWithParameter);
+ newCastsWithParameter.add(castType);
+ return new InternalNonEmptyParameterUsage(
+ newCastsWithParameter.build(),
+ fieldsReadFromParameter,
+ methodCallsWithParameterAsReceiver,
+ isParameterMutated,
+ isParameterReturned,
+ isParameterUsedAsLock);
+ }
+
+ @Override
InternalNonEmptyParameterUsage addFieldReadFromParameter(DexField field) {
ImmutableSet.Builder<DexField> newFieldsReadFromParameterBuilder = ImmutableSet.builder();
newFieldsReadFromParameterBuilder.addAll(fieldsReadFromParameter);
newFieldsReadFromParameterBuilder.add(field);
return new InternalNonEmptyParameterUsage(
+ castsWithParameter,
newFieldsReadFromParameterBuilder.build(),
methodCallsWithParameterAsReceiver,
isParameterMutated,
@@ -77,6 +97,7 @@
newMethodCallsWithParameterAsReceiverBuilder.addAll(methodCallsWithParameterAsReceiver);
newMethodCallsWithParameterAsReceiverBuilder.add(invoke);
return new InternalNonEmptyParameterUsage(
+ castsWithParameter,
fieldsReadFromParameter,
newMethodCallsWithParameterAsReceiverBuilder.build(),
isParameterMutated,
@@ -96,6 +117,7 @@
methodCallsWithParameterAsReceiver.forEach(
invoke -> methodCallsWithParameterAsReceiverBuilder.add(invoke.getInvokedMethod()));
return new NonEmptyParameterUsage(
+ castsWithParameter,
fieldsReadFromParameter,
methodCallsWithParameterAsReceiverBuilder.build(),
isParameterMutated,
@@ -120,6 +142,7 @@
InternalNonEmptyParameterUsage join(InternalNonEmptyParameterUsage other) {
return builderFromInstance()
+ .addCastsWithParameter(other.castsWithParameter)
.addFieldsReadFromParameter(other.fieldsReadFromParameter)
.addMethodCallsWithParameterAsReceiver(other.methodCallsWithParameterAsReceiver)
.joinIsReceiverMutated(other.isParameterMutated)
@@ -134,6 +157,7 @@
return this;
}
return new InternalNonEmptyParameterUsage(
+ castsWithParameter,
fieldsReadFromParameter,
methodCallsWithParameterAsReceiver,
true,
@@ -147,6 +171,7 @@
return this;
}
return new InternalNonEmptyParameterUsage(
+ castsWithParameter,
fieldsReadFromParameter,
methodCallsWithParameterAsReceiver,
isParameterMutated,
@@ -160,6 +185,7 @@
return this;
}
return new InternalNonEmptyParameterUsage(
+ castsWithParameter,
fieldsReadFromParameter,
methodCallsWithParameterAsReceiver,
isParameterMutated,
@@ -169,6 +195,9 @@
@Override
public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
if (obj == null || obj.getClass() != getClass()) {
return false;
}
@@ -176,6 +205,7 @@
return isParameterMutated == knownParameterUsage.isParameterMutated
&& isParameterReturned == knownParameterUsage.isParameterReturned
&& isParameterUsedAsLock == knownParameterUsage.isParameterUsedAsLock
+ && castsWithParameter.equals(knownParameterUsage.castsWithParameter)
&& fieldsReadFromParameter.equals(knownParameterUsage.fieldsReadFromParameter)
&& methodCallsWithParameterAsReceiver.equals(
knownParameterUsage.methodCallsWithParameterAsReceiver);
@@ -184,9 +214,11 @@
@Override
public int hashCode() {
int hash =
- 31 * (31 + fieldsReadFromParameter.hashCode())
+ 31 * (31 * (31 + castsWithParameter.hashCode()) + fieldsReadFromParameter.hashCode())
+ methodCallsWithParameterAsReceiver.hashCode();
- assert hash == Objects.hash(fieldsReadFromParameter, methodCallsWithParameterAsReceiver);
+ assert hash
+ == Objects.hash(
+ castsWithParameter, fieldsReadFromParameter, methodCallsWithParameterAsReceiver);
hash = (hash << 1) | BooleanUtils.intValue(isParameterMutated);
hash = (hash << 1) | BooleanUtils.intValue(isParameterReturned);
hash = (hash << 1) | BooleanUtils.intValue(isParameterUsedAsLock);
@@ -195,6 +227,7 @@
static class Builder {
+ private ImmutableSet.Builder<DexType> castsWithParameterBuilder;
private ImmutableSet.Builder<DexField> fieldsReadFromParameterBuilder;
private ImmutableSet.Builder<InvokeMethodWithReceiver>
methodCallsWithParameterAsReceiverBuilder;
@@ -203,11 +236,14 @@
private boolean isParameterUsedAsLock;
Builder() {
+ castsWithParameterBuilder = ImmutableSet.builder();
fieldsReadFromParameterBuilder = ImmutableSet.builder();
methodCallsWithParameterAsReceiverBuilder = ImmutableSet.builder();
}
Builder(InternalNonEmptyParameterUsage methodBehavior) {
+ castsWithParameterBuilder =
+ ImmutableSet.<DexType>builder().addAll(methodBehavior.castsWithParameter);
fieldsReadFromParameterBuilder =
ImmutableSet.<DexField>builder().addAll(methodBehavior.fieldsReadFromParameter);
methodCallsWithParameterAsReceiverBuilder =
@@ -218,6 +254,16 @@
isParameterUsedAsLock = methodBehavior.isParameterUsedAsLock;
}
+ Builder addCastWithParameter(DexType castType) {
+ castsWithParameterBuilder.add(castType);
+ return this;
+ }
+
+ Builder addCastsWithParameter(Collection<DexType> castTypes) {
+ castsWithParameterBuilder.addAll(castTypes);
+ return this;
+ }
+
Builder addFieldReadFromParameter(DexField fieldReadFromParameter) {
fieldsReadFromParameterBuilder.add(fieldReadFromParameter);
return this;
@@ -272,6 +318,7 @@
InternalNonEmptyParameterUsage build() {
return new InternalNonEmptyParameterUsage(
+ castsWithParameterBuilder.build(),
fieldsReadFromParameterBuilder.build(),
methodCallsWithParameterAsReceiverBuilder.build(),
isParameterMutated,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/NonEmptyParameterUsage.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/NonEmptyParameterUsage.java
index d377305..38056c8 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/NonEmptyParameterUsage.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/NonEmptyParameterUsage.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.code.InvokeMethodWithReceiver;
import com.android.tools.r8.utils.BooleanUtils;
import com.google.common.collect.Multiset;
@@ -15,6 +16,7 @@
public class NonEmptyParameterUsage extends ParameterUsage {
+ private Set<DexType> castsWithParameter;
private Set<DexField> fieldsReadFromParameter;
private Multiset<DexMethod> methodCallsWithParameterAsReceiver;
@@ -23,16 +25,19 @@
private boolean isParameterUsedAsLock;
NonEmptyParameterUsage(
+ Set<DexType> castsWithParameter,
Set<DexField> fieldsReadFromParameter,
Multiset<DexMethod> methodCallsWithParameterAsReceiver,
boolean isParameterMutated,
boolean isParameterReturned,
boolean isParameterUsedAsLock) {
- assert !fieldsReadFromParameter.isEmpty()
+ assert !castsWithParameter.isEmpty()
+ || !fieldsReadFromParameter.isEmpty()
|| !methodCallsWithParameterAsReceiver.isEmpty()
|| isParameterMutated
|| isParameterReturned
|| isParameterUsedAsLock;
+ this.castsWithParameter = castsWithParameter;
this.fieldsReadFromParameter = fieldsReadFromParameter;
this.methodCallsWithParameterAsReceiver = methodCallsWithParameterAsReceiver;
this.isParameterMutated = isParameterMutated;
@@ -41,6 +46,11 @@
}
@Override
+ ParameterUsage addCastWithParameter(DexType castType) {
+ throw new Unreachable();
+ }
+
+ @Override
ParameterUsage addFieldReadFromParameter(DexField field) {
throw new Unreachable();
}
@@ -64,6 +74,10 @@
return !getFieldsReadFromParameter().isEmpty();
}
+ public Set<DexType> getCastsWithParameter() {
+ return castsWithParameter;
+ }
+
public Set<DexField> getFieldsReadFromParameter() {
return fieldsReadFromParameter;
}
@@ -104,6 +118,9 @@
@Override
public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
if (obj == null || obj.getClass() != getClass()) {
return false;
}
@@ -111,6 +128,7 @@
return isParameterMutated == knownParameterUsage.isParameterMutated
&& isParameterReturned == knownParameterUsage.isParameterReturned
&& isParameterUsedAsLock == knownParameterUsage.isParameterUsedAsLock
+ && castsWithParameter.equals(knownParameterUsage.castsWithParameter)
&& fieldsReadFromParameter.equals(knownParameterUsage.fieldsReadFromParameter)
&& methodCallsWithParameterAsReceiver.equals(
knownParameterUsage.methodCallsWithParameterAsReceiver);
@@ -119,9 +137,11 @@
@Override
public int hashCode() {
int hash =
- 31 * (31 + fieldsReadFromParameter.hashCode())
+ 31 * (31 * (31 + castsWithParameter.hashCode()) + fieldsReadFromParameter.hashCode())
+ methodCallsWithParameterAsReceiver.hashCode();
- assert hash == Objects.hash(fieldsReadFromParameter, methodCallsWithParameterAsReceiver);
+ assert hash
+ == Objects.hash(
+ castsWithParameter, fieldsReadFromParameter, methodCallsWithParameterAsReceiver);
hash = (hash << 1) | BooleanUtils.intValue(isParameterMutated);
hash = (hash << 1) | BooleanUtils.intValue(isParameterReturned);
hash = (hash << 1) | BooleanUtils.intValue(isParameterUsedAsLock);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ParameterUsage.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ParameterUsage.java
index e2ad8da..2822d6f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ParameterUsage.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/ParameterUsage.java
@@ -5,10 +5,13 @@
package com.android.tools.r8.ir.optimize.classinliner.analysis;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.code.InvokeMethodWithReceiver;
public abstract class ParameterUsage {
+ abstract ParameterUsage addCastWithParameter(DexType castType);
+
abstract ParameterUsage addFieldReadFromParameter(DexField field);
abstract ParameterUsage addMethodCallWithParameterAsReceiver(InvokeMethodWithReceiver invoke);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
index 152c212..4d45a08 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/TransferFunction.java
@@ -171,7 +171,11 @@
private ParameterUsages analyzeCheckCast(CheckCast checkCast, NonEmptyParameterUsages state) {
// Mark the value as ineligible for class inlining if it has phi users.
- return checkCast.outValue().hasPhiUsers() ? fail(checkCast, state) : state;
+ if (checkCast.outValue().hasPhiUsers()) {
+ return fail(checkCast, state);
+ }
+ return state.rebuildParameter(
+ checkCast.object(), (context, usage) -> usage.addCastWithParameter(checkCast.getType()));
}
private ParameterUsages analyzeIf(If theIf, NonEmptyParameterUsages state) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/UnknownParameterUsage.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/UnknownParameterUsage.java
index 93577ad..bf49e63 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/UnknownParameterUsage.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/analysis/UnknownParameterUsage.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.ir.optimize.classinliner.analysis;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.code.InvokeMethodWithReceiver;
class UnknownParameterUsage extends ParameterUsage {
@@ -18,6 +19,11 @@
}
@Override
+ ParameterUsage addCastWithParameter(DexType castType) {
+ return this;
+ }
+
+ @Override
UnknownParameterUsage addFieldReadFromParameter(DexField field) {
return this;
}
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 1826502..f46ae29 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
@@ -5,6 +5,7 @@
package com.android.tools.r8.ir.optimize.classinliner.constraint;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
@@ -34,13 +35,18 @@
}
@Override
- public boolean isEligibleForNewInstanceClassInlining(ProgramMethod method, int parameter) {
+ public boolean isEligibleForNewInstanceClassInlining(
+ AppView<AppInfoWithLiveness> appView,
+ DexProgramClass candidateClass,
+ ProgramMethod method,
+ int parameter) {
return false;
}
@Override
public boolean isEligibleForStaticGetClassInlining(
AppView<AppInfoWithLiveness> appView,
+ DexProgramClass candidateClass,
int parameter,
ObjectState objectState,
ProgramMethod context) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysTrueClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysTrueClassInlinerMethodConstraint.java
index 1f33962..8efec57 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysTrueClassInlinerMethodConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysTrueClassInlinerMethodConstraint.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.ir.optimize.classinliner.constraint;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
@@ -34,13 +35,18 @@
}
@Override
- public boolean isEligibleForNewInstanceClassInlining(ProgramMethod method, int parameter) {
+ public boolean isEligibleForNewInstanceClassInlining(
+ AppView<AppInfoWithLiveness> appView,
+ DexProgramClass candidateClass,
+ ProgramMethod method,
+ int parameter) {
return true;
}
@Override
public boolean isEligibleForStaticGetClassInlining(
AppView<AppInfoWithLiveness> appView,
+ DexProgramClass candidateClass,
int parameter,
ObjectState objectState,
ProgramMethod context) {
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 5bc6317..994cdaa 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
@@ -5,6 +5,7 @@
package com.android.tools.r8.ir.optimize.classinliner.constraint;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
@@ -18,10 +19,15 @@
ParameterUsage getParameterUsage(int parameter);
- boolean isEligibleForNewInstanceClassInlining(ProgramMethod method, int parameter);
+ boolean isEligibleForNewInstanceClassInlining(
+ AppView<AppInfoWithLiveness> appView,
+ DexProgramClass candidateClass,
+ ProgramMethod method,
+ int parameter);
boolean isEligibleForStaticGetClassInlining(
AppView<AppInfoWithLiveness> appView,
+ DexProgramClass candidateClass,
int parameter,
ObjectState objectState,
ProgramMethod context);
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 eaae1fe..bd524a5 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
@@ -8,6 +8,8 @@
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.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.proto.ArgumentInfo;
import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
@@ -68,15 +70,30 @@
}
@Override
- public boolean isEligibleForNewInstanceClassInlining(ProgramMethod method, int parameter) {
+ public boolean isEligibleForNewInstanceClassInlining(
+ AppView<AppInfoWithLiveness> appView,
+ DexProgramClass candidateClass,
+ ProgramMethod method,
+ int parameter) {
AnalysisContext defaultContext = AnalysisContext.getDefaultContext();
ParameterUsage usage = usages.get(parameter).get(defaultContext);
- return !usage.isTop();
+ if (usage.isBottom()) {
+ return true;
+ }
+ if (usage.isTop()) {
+ return false;
+ }
+ NonEmptyParameterUsage knownUsage = usage.asNonEmpty();
+ if (hasUnsafeCast(appView, candidateClass, knownUsage)) {
+ return false;
+ }
+ return true;
}
@Override
public boolean isEligibleForStaticGetClassInlining(
AppView<AppInfoWithLiveness> appView,
+ DexProgramClass candidateClass,
int parameter,
ObjectState objectState,
ProgramMethod context) {
@@ -100,6 +117,9 @@
// We will not be able to remove the monitor instruction afterwards.
return false;
}
+ if (hasUnsafeCast(appView, candidateClass, knownUsage)) {
+ return false;
+ }
for (DexField fieldReadFromParameter : knownUsage.getFieldsReadFromParameter()) {
DexClass holder = appView.definitionFor(fieldReadFromParameter.getHolderType());
DexEncodedField definition = fieldReadFromParameter.lookupOnClass(holder);
@@ -117,4 +137,20 @@
}
return true;
}
+
+ private boolean hasUnsafeCast(
+ AppView<AppInfoWithLiveness> appView,
+ DexProgramClass candidateClass,
+ NonEmptyParameterUsage knownUsage) {
+ for (DexType castType : knownUsage.getCastsWithParameter()) {
+ if (!castType.isClassType()) {
+ return true;
+ }
+ DexClass castClass = appView.definitionFor(castType);
+ if (castClass == null || !appView.appInfo().isSubtype(candidateClass, castClass)) {
+ return true;
+ }
+ }
+ return false;
+ }
}