Refactor utils to check if value/type is always null.
Bug: 72443802, 124246610
Change-Id: I3d4811a4931051c377ef974ce6971faec3f44d13
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index 0e92913..c97e609 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.ir.desugar.Java8MethodRewriter;
import com.android.tools.r8.ir.desugar.TwrCloseResourceRewriter;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
import com.google.common.base.Predicates;
@@ -63,6 +64,16 @@
return clazz == null || clazz.initializationOfParentTypesMayHaveSideEffects(appInfo, ignore);
}
+ public boolean isAlwaysNull(AppView<AppInfoWithLiveness> appView) {
+ if (isClassType()) {
+ DexClass clazz = appView.definitionFor(this);
+ return clazz != null
+ && clazz.isProgramClass()
+ && !appView.appInfo().isInstantiatedDirectlyOrIndirectly(this);
+ }
+ return false;
+ }
+
public boolean isSamePackage(DexType other) {
return getPackageDescriptor().equals(other.getPackageDescriptor());
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java
index d120911..23d3621 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Value.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.ir.regalloc.LiveIntervals;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.MethodPosition;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.LongInterval;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
@@ -445,6 +446,20 @@
return !users.isEmpty() || !phiUsers.isEmpty() || numberOfDebugUsers() > 0;
}
+ public boolean isAlwaysNull(AppView<AppInfoWithLiveness> appView) {
+ if (hasLocalInfo()) {
+ // Not always null as the value can be changed via the debugger.
+ return false;
+ }
+ if (typeLattice.isDefinitelyNull()) {
+ return true;
+ }
+ if (typeLattice.isClassType()) {
+ return typeLattice.asClassTypeLatticeElement().getClassType().isAlwaysNull(appView);
+ }
+ return false;
+ }
+
public boolean usedInMonitorOperation() {
for (Instruction instruction : uniqueUsers()) {
if (instruction.isMonitor()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
index de060cf..7ca48ed 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
@@ -162,7 +162,7 @@
for (DexEncodedMethod virtualMethod : clazz.virtualMethods()) {
RewrittenPrototypeDescription prototypeChanges =
new RewrittenPrototypeDescription(
- isAlwaysNull(virtualMethod.method.proto.returnType),
+ virtualMethod.method.proto.returnType.isAlwaysNull(appView),
getRemovedArgumentsInfo(virtualMethod, ALLOW_ARGUMENT_REMOVAL));
if (!prototypeChanges.isEmpty()) {
DexMethod newMethod = getNewMethodSignature(virtualMethod, prototypeChanges);
@@ -283,7 +283,7 @@
return RewrittenPrototypeDescription.none();
}
return new RewrittenPrototypeDescription(
- isAlwaysNull(encodedMethod.method.proto.returnType),
+ encodedMethod.method.proto.returnType.isAlwaysNull(appView),
getRemovedArgumentsInfo(encodedMethod, strategy));
}
@@ -298,7 +298,7 @@
int offset = encodedMethod.isStatic() ? 0 : 1;
for (int i = 0; i < proto.parameters.size(); ++i) {
DexType type = proto.parameters.values[i];
- if (isAlwaysNull(type)) {
+ if (type.isAlwaysNull(appView)) {
if (removedArgumentsInfo == null) {
removedArgumentsInfo = new ArrayList<>();
}
@@ -420,7 +420,7 @@
boolean replacedByThrowNull = false;
Value receiver = instruction.inValues().get(0);
- if (isAlwaysNull(receiver)) {
+ if (receiver.isAlwaysNull(appView)) {
// Unable to rewrite instruction if the receiver is defined from "const-number 0", since this
// would lead to an IncompatibleClassChangeError (see MemberResolutionTest#lookupStaticField-
// WithFieldGetFromNullReferenceDirectly).
@@ -456,7 +456,7 @@
IRCode code,
Set<BasicBlock> blocksToBeRemoved) {
DexType fieldType = instruction.getField().type;
- if (isAlwaysNull(fieldType)) {
+ if (fieldType.isAlwaysNull(appView)) {
// Before trying to remove this instruction, we need to be sure that the field actually
// exists. Otherwise this instruction would throw a NoSuchFieldError exception.
DexEncodedField field = appView.definitionFor(instruction.getField());
@@ -511,7 +511,7 @@
Set<BasicBlock> blocksToBeRemoved) {
if (invoke.isInvokeMethodWithReceiver()) {
Value receiver = invoke.asInvokeMethodWithReceiver().getReceiver();
- if (isAlwaysNull(receiver)) {
+ if (receiver.isAlwaysNull(appView)) {
replaceCurrentInstructionWithThrowNull(
invoke, blockIterator, instructionIterator, code, blocksToBeRemoved);
++numberOfInvokesWithNullReceiver;
@@ -529,7 +529,7 @@
if (facts != null) {
for (int i = 0; i < invoke.arguments().size(); i++) {
Value argument = invoke.arguments().get(i);
- if (isAlwaysNull(argument) && facts.get(i)) {
+ if (argument.isAlwaysNull(appView) && facts.get(i)) {
replaceCurrentInstructionWithThrowNull(
invoke, blockIterator, instructionIterator, code, blocksToBeRemoved);
++numberOfInvokesWithNullArgument;
@@ -598,28 +598,4 @@
}
}
- private boolean isAlwaysNull(Value value) {
- if (value.hasLocalInfo()) {
- // Not always null as the value can be changed via the debugger.
- return false;
- }
- TypeLatticeElement typeLatticeElement = value.getTypeLattice();
- if (typeLatticeElement.isDefinitelyNull()) {
- return true;
- }
- if (typeLatticeElement.isClassType()) {
- return isAlwaysNull(typeLatticeElement.asClassTypeLatticeElement().getClassType());
- }
- return false;
- }
-
- private boolean isAlwaysNull(DexType type) {
- if (type.isClassType()) {
- DexClass clazz = appView.definitionFor(type);
- return clazz != null
- && clazz.isProgramClass()
- && !appView.appInfo().isInstantiatedDirectlyOrIndirectly(type);
- }
- return false;
- }
}