Require a DexProgramClass in AppInfoWithLiveness where DexType is assumed to be a program class
Change-Id: I7026240b79c10764ea4c24a33017c6e257f348de
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
index fa4cea3..e7ca421 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
@@ -363,7 +363,7 @@
return super.lookupSuperTarget(method, invocationContext);
}
- protected boolean hasAnyInstantiatedLambdas(DexType type) {
+ protected boolean hasAnyInstantiatedLambdas(DexProgramClass clazz) {
assert checkIfObsolete();
return true; // Don't know, there might be.
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 5a89dcf..5904f98 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -244,7 +244,7 @@
if (appInfo.isPinned(type)) {
return false;
}
- return !appInfo.hasSubtypes(type) || !appInfo.isInstantiatedIndirectly(type);
+ return !appInfo.hasSubtypes(type) || !appInfo.isInstantiatedIndirectly(this);
}
return false;
}
@@ -259,6 +259,10 @@
return this;
}
+ public static DexProgramClass asProgramClassOrNull(DexClass clazz) {
+ return clazz != null ? clazz.asProgramClass() : null;
+ }
+
@Override
public boolean isNotProgramClass() {
return false;
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 488b6c7..e3d78cf 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.ir.desugar.DesugaredLibraryWrapperSynthesizer.TYPE_WRAPPER_SUFFIX;
import static com.android.tools.r8.ir.desugar.DesugaredLibraryWrapperSynthesizer.VIVIFIED_TYPE_WRAPPER_SUFFIX;
import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
@@ -74,10 +75,8 @@
public boolean isAlwaysNull(AppView<AppInfoWithLiveness> appView) {
if (isClassType()) {
- DexClass clazz = appView.definitionFor(this);
- return clazz != null
- && clazz.isProgramClass()
- && !appView.appInfo().isInstantiatedDirectlyOrIndirectly(this);
+ DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(this));
+ return clazz != null && !appView.appInfo().isInstantiatedDirectlyOrIndirectly(clazz);
}
return false;
}
diff --git a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
index ec2f8e3..1f8343e 100644
--- a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
+
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.SetUtils;
import com.google.common.collect.Sets;
@@ -85,9 +87,12 @@
// }
//
DexEncodedMethod singleTarget = getSingleTarget();
- if (singleTarget.getCode() != null
- && appInfo.hasAnyInstantiatedLambdas(singleTarget.method.holder)) {
- result.add(singleTarget);
+ if (singleTarget.hasCode()) {
+ DexProgramClass holder =
+ asProgramClassOrNull(appInfo.definitionFor(singleTarget.method.holder));
+ if (appInfo.hasAnyInstantiatedLambdas(holder)) {
+ result.add(singleTarget);
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 3a78425..04dd590 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.optimize;
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
import static com.android.tools.r8.optimize.MemberRebindingAnalysis.isTypeVisibleFromContext;
@@ -19,6 +20,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexItemFactory.ThrowableMethods;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
@@ -1577,10 +1579,9 @@
private boolean isNeverInstantiatedDirectlyOrIndirectly(DexType type) {
assert appView.appInfo().hasLiveness();
assert type.isClassType();
- DexClass clazz = appView.definitionFor(type);
+ DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(type));
return clazz != null
- && clazz.isProgramClass()
- && !appView.appInfo().withLiveness().isInstantiatedDirectlyOrIndirectly(type);
+ && !appView.appInfo().withLiveness().isInstantiatedDirectlyOrIndirectly(clazz);
}
public static void removeOrReplaceByDebugLocalWrite(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
index b14a47a..f94b7a7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
@@ -3,8 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.optimize;
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
+
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.CatchHandlers;
@@ -173,10 +175,8 @@
// We can exploit that a catch handler must be dead if its guard is never instantiated
// directly or indirectly.
if (appInfoWithLiveness != null && appView.options().enableUninstantiatedTypeOptimization) {
- DexClass clazz = appView.definitionFor(guard);
- if (clazz != null
- && clazz.isProgramClass()
- && !appInfoWithLiveness.isInstantiatedDirectlyOrIndirectly(guard)) {
+ DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(guard));
+ if (clazz != null && !appInfoWithLiveness.isInstantiatedDirectlyOrIndirectly(clazz)) {
builder.add(new CatchHandler<>(guard, target));
continue;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
index 11f8a6e..11f0a08 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
@@ -3,12 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.optimize;
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
@@ -106,13 +108,13 @@
}
// Only consider program class, e.g., platform can introduce subtypes in different
// versions.
- DexClass clazz = appView.definitionFor(baseType);
- if (clazz == null || !clazz.isProgramClass()) {
+ DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(baseType));
+ if (clazz == null) {
return null;
}
// Only consider effectively final class. Exception: new Base().getClass().
if (appView.appInfo().hasSubtypes(baseType)
- && appView.appInfo().isInstantiatedIndirectly(baseType)
+ && appView.appInfo().isInstantiatedIndirectly(clazz)
&& (in.isPhi() || !in.definition.isCreatingInstanceOrArray())) {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index d004c90..797d178 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.graph.GraphLense.rewriteReferenceKeys;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
@@ -71,7 +72,7 @@
public final Set<DexType> instantiatedAppServices;
/** Set of types that are actually instantiated. These cannot be abstract. */
final Set<DexType> instantiatedTypes;
- /** Cache for {@link #isInstantiatedDirectlyOrIndirectly(DexType)}. */
+ /** Cache for {@link #isInstantiatedDirectlyOrIndirectly(DexProgramClass)}. */
private final IdentityHashMap<DexType, Boolean> indirectlyInstantiatedTypes =
new IdentityHashMap<>();
/**
@@ -687,24 +688,25 @@
return true;
}
- public boolean isInstantiatedDirectly(DexType type) {
+ public boolean isInstantiatedDirectly(DexProgramClass clazz) {
assert checkIfObsolete();
- assert type.isClassType();
+ DexType type = clazz.type;
return type.isD8R8SynthesizedClassType()
|| instantiatedTypes.contains(type)
|| instantiatedLambdas.contains(type)
|| instantiatedAnnotationTypes.contains(type);
}
- public boolean isInstantiatedIndirectly(DexType type) {
+ public boolean isInstantiatedIndirectly(DexProgramClass clazz) {
assert checkIfObsolete();
- assert type.isClassType();
+ DexType type = clazz.type;
synchronized (indirectlyInstantiatedTypes) {
if (indirectlyInstantiatedTypes.containsKey(type)) {
return indirectlyInstantiatedTypes.get(type).booleanValue();
}
for (DexType directSubtype : allImmediateSubtypes(type)) {
- if (isInstantiatedDirectlyOrIndirectly(directSubtype)) {
+ DexProgramClass directSubClass = asProgramClassOrNull(definitionFor(directSubtype));
+ if (directSubClass == null || isInstantiatedDirectlyOrIndirectly(directSubClass)) {
indirectlyInstantiatedTypes.put(type, Boolean.TRUE);
return true;
}
@@ -714,10 +716,9 @@
}
}
- public boolean isInstantiatedDirectlyOrIndirectly(DexType type) {
+ public boolean isInstantiatedDirectlyOrIndirectly(DexProgramClass clazz) {
assert checkIfObsolete();
- assert type.isClassType();
- return isInstantiatedDirectly(type) || isInstantiatedIndirectly(type);
+ return isInstantiatedDirectly(clazz) || isInstantiatedIndirectly(clazz);
}
public boolean isFieldRead(DexEncodedField encodedField) {
@@ -809,9 +810,9 @@
}
@Override
- protected boolean hasAnyInstantiatedLambdas(DexType type) {
+ protected boolean hasAnyInstantiatedLambdas(DexProgramClass clazz) {
assert checkIfObsolete();
- return instantiatedLambdas.contains(type);
+ return instantiatedLambdas.contains(clazz.type);
}
@Override
@@ -997,10 +998,10 @@
return null;
}
boolean refinedReceiverIsStrictSubType = refinedReceiverType != method.holder;
- DexClass refinedHolder =
- refinedReceiverIsStrictSubType ? definitionFor(refinedReceiverType) : holder;
+ DexProgramClass refinedHolder =
+ (refinedReceiverIsStrictSubType ? definitionFor(refinedReceiverType) : holder)
+ .asProgramClass();
assert refinedHolder != null;
- assert refinedHolder.isProgramClass();
assert !refinedHolder.isInterface();
if (method.isSingleVirtualMethodCached(refinedReceiverType)) {
return method.getSingleVirtualMethodCache(refinedReceiverType);
@@ -1024,7 +1025,7 @@
DexEncodedMethod result =
validateSingleVirtualTarget(
findSingleTargetFromSubtypes(
- refinedReceiverType,
+ refinedHolder,
method,
topSingleTarget,
!refinedHolder.accessFlags.isAbstract(),
@@ -1063,24 +1064,24 @@
* single virtual target otherwise.
*/
private DexEncodedMethod findSingleTargetFromSubtypes(
- DexType type,
+ DexProgramClass clazz,
DexMethod method,
DexEncodedMethod candidate,
boolean candidateIsReachable,
boolean checkForInterfaceConflicts) {
// For kept types we do not know all subtypes, so abort if the method is also kept.
- if (isPinned(type) && isMethodPinnedDirectlyOrInAncestor(candidate.method)) {
+ if (isPinned(clazz.type) && isMethodPinnedDirectlyOrInAncestor(candidate.method)) {
return DexEncodedMethod.SENTINEL;
}
// If the candidate is reachable, we already have a previous result.
DexEncodedMethod result = candidateIsReachable ? candidate : null;
- for (DexType subtype : allImmediateExtendsSubtypes(type)) {
- DexClass clazz = definitionFor(subtype);
- DexEncodedMethod target = clazz.lookupVirtualMethod(method);
+ for (DexType subtype : allImmediateExtendsSubtypes(clazz.type)) {
+ DexProgramClass subclass = definitionFor(subtype).asProgramClass();
+ DexEncodedMethod target = subclass.lookupVirtualMethod(method);
if (target != null && !target.isPrivateMethod()) {
// We found a method on this class. If this class is not abstract it is a runtime
// reachable override and hence a conflict.
- if (!clazz.accessFlags.isAbstract()) {
+ if (!subclass.accessFlags.isAbstract()) {
if (result != null && result != target) {
// We found a new target on this subtype that does not match the previous one. Fail.
return DexEncodedMethod.SENTINEL;
@@ -1091,7 +1092,7 @@
}
if (checkForInterfaceConflicts) {
// We have to check whether there are any default methods in implemented interfaces.
- if (interfacesMayHaveDefaultFor(clazz.interfaces, method)) {
+ if (interfacesMayHaveDefaultFor(subclass.interfaces, method)) {
return DexEncodedMethod.SENTINEL;
}
}
@@ -1101,10 +1102,10 @@
// If we did not find a new target, the candidate is reachable if it was before, or if this
// class is not abstract.
boolean newCandidateIsReachable =
- !clazz.accessFlags.isAbstract() || ((target == null) && candidateIsReachable);
+ !subclass.accessFlags.isAbstract() || ((target == null) && candidateIsReachable);
DexEncodedMethod subtypeTarget =
findSingleTargetFromSubtypes(
- subtype, method, newCandidate, newCandidateIsReachable, checkForInterfaceConflicts);
+ subclass, method, newCandidate, newCandidateIsReachable, checkForInterfaceConflicts);
if (subtypeTarget != null) {
// We found a target in the subclasses. If we already have a different result, fail.
if (result != null && result != subtypeTarget) {
@@ -1181,8 +1182,8 @@
}
}
- DexClass holder = definitionFor(method.holder);
- if ((holder == null) || holder.isNotProgramClass() || !holder.accessFlags.isInterface()) {
+ DexProgramClass holder = asProgramClassOrNull(definitionFor(method.holder));
+ if (holder == null || !holder.accessFlags.isInterface()) {
return null;
}
// First check that there is a target for this invoke-interface to hit. If there is none,
diff --git a/src/main/java/com/android/tools/r8/shaking/LibraryMethodOverrideAnalysis.java b/src/main/java/com/android/tools/r8/shaking/LibraryMethodOverrideAnalysis.java
index bfdfc00..f73139d 100644
--- a/src/main/java/com/android/tools/r8/shaking/LibraryMethodOverrideAnalysis.java
+++ b/src/main/java/com/android/tools/r8/shaking/LibraryMethodOverrideAnalysis.java
@@ -149,7 +149,7 @@
private boolean verifyNoUninstantiatedTypesEscapeIntoLibrary() {
Set<DexType> classesWithLibraryMethodOverrides = getClassesWithLibraryMethodOverrides(appView);
for (DexProgramClass clazz : appView.appInfo().classes()) {
- assert appView.appInfo().isInstantiatedDirectlyOrIndirectly(clazz.type)
+ assert appView.appInfo().isInstantiatedDirectlyOrIndirectly(clazz)
|| !classesWithLibraryMethodOverrides.contains(clazz.type)
|| nonEscapingClassesWithLibraryMethodOverrides.contains(clazz.type);
}