Introduce AppInfoWithClassHierarchy
- rewrite lookupStaticTarget to use resolution.
Bug:147471606
Change-Id: I2bad5097e0429e8f4d94e6ba883bda15c18895e7
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index cf5e6c8..bd49aa1 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexProgramClass;
@@ -155,7 +156,8 @@
DexApplication app = new ApplicationReader(inputApp, options, timing).read(executor);
PrefixRewritingMapper rewritePrefix =
options.desugaredLibraryConfiguration.createPrefixRewritingMapper(options.itemFactory);
- AppInfo appInfo = new AppInfo(app);
+ AppInfo appInfo =
+ options.enableDesugaring ? new AppInfoWithClassHierarchy(app) : new AppInfo(app);
final CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
diff --git a/src/main/java/com/android/tools/r8/L8.java b/src/main/java/com/android/tools/r8/L8.java
index a692e1d..45cb778 100644
--- a/src/main/java/com/android/tools/r8/L8.java
+++ b/src/main/java/com/android/tools/r8/L8.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.GraphLense;
@@ -116,7 +117,7 @@
options.desugaredLibraryConfiguration.createPrefixRewritingMapper(options.itemFactory);
app = new L8TreePruner(options).prune(app, rewritePrefix);
- AppInfo appInfo = new AppInfo(app);
+ AppInfo appInfo = new AppInfoWithClassHierarchy(app);
AppView<?> appView = AppView.createForL8(appInfo, options, rewritePrefix);
IRConverter converter = new IRConverter(appView, timing);
diff --git a/src/main/java/com/android/tools/r8/graph/AccessControl.java b/src/main/java/com/android/tools/r8/graph/AccessControl.java
index 3b4d52f..d775cb3 100644
--- a/src/main/java/com/android/tools/r8/graph/AccessControl.java
+++ b/src/main/java/com/android/tools/r8/graph/AccessControl.java
@@ -22,7 +22,7 @@
DexEncodedMethod method,
DexClass holder,
DexProgramClass context,
- AppInfoWithSubtyping appInfo) {
+ AppInfoWithClassHierarchy appInfo) {
return isMemberAccessible(method.accessFlags, holder, context, appInfo);
}
@@ -38,7 +38,7 @@
AccessFlags<?> memberFlags,
DexClass holder,
DexProgramClass context,
- AppInfoWithSubtyping appInfo) {
+ AppInfoWithClassHierarchy appInfo) {
if (!isClassAccessible(holder, context)) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index ad19ed4..9bf667b 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -201,15 +201,20 @@
definitions.remove(type);
}
+ // TODO(b/147578480): RemoveDeprecation Use AppInfoWithClassHierarchy and
+ // lookupXX(DexMethod, DexProgramClass). The following 3 methods should either be removed or
+ // return null.
+
/**
* Lookup static method following the super chain from the holder of {@code method}.
- * <p>
- * This method will resolve the method on the holder of {@code method} and only return a non-null
- * value if the result of resolution was a static, non-abstract method.
+ *
+ * <p>This method will resolve the method on the holder of {@code method} and only return a
+ * non-null value if the result of resolution was a static, non-abstract method.
*
* @param method the method to lookup
* @return The actual target for {@code method} or {@code null} if none found.
*/
+ @Deprecated // TODO(b/147578480): Remove
public DexEncodedMethod lookupStaticTarget(DexMethod method) {
assert checkIfObsolete();
ResolutionResult resolutionResult = resolveMethod(method.holder, method);
@@ -227,6 +232,7 @@
* @param invocationContext the class the invoke is contained in, i.e., the holder of the caller.
* @return The actual target for {@code method} or {@code null} if none found.
*/
+ @Deprecated // TODO(b/147578480): Remove
public DexEncodedMethod lookupSuperTarget(DexMethod method, DexType invocationContext) {
assert checkIfObsolete();
assert invocationContext.isClassType();
@@ -234,6 +240,7 @@
return context == null ? null : lookupSuperTarget(method, context);
}
+ @Deprecated // TODO(b/147578480): Remove
public DexEncodedMethod lookupSuperTarget(DexMethod method, DexClass invocationContext) {
assert checkIfObsolete();
return resolveMethod(method.holder, method).lookupInvokeSuperTarget(invocationContext, this);
@@ -596,6 +603,16 @@
return null;
}
+ public boolean hasClassHierarchy() {
+ assert checkIfObsolete();
+ return false;
+ }
+
+ public AppInfoWithClassHierarchy withClassHierarchy() {
+ assert checkIfObsolete();
+ return null;
+ }
+
public boolean hasSubtyping() {
assert checkIfObsolete();
return false;
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
new file mode 100644
index 0000000..6963898
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
@@ -0,0 +1,119 @@
+// Copyright (c) 2020, 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.graph;
+
+import java.util.LinkedList;
+
+/* Specific subclass of AppInfo designed to support desugaring in D8. Desugaring requires a
+ * minimal amount of knowledge in the overall program, provided through classpath. Basic
+ * features are present, such as static and super look-ups, or isSubtype.
+ */
+public class AppInfoWithClassHierarchy extends AppInfo {
+
+ public AppInfoWithClassHierarchy(DexApplication application) {
+ super(application);
+ }
+
+ public AppInfoWithClassHierarchy(AppInfo previous) {
+ super(previous);
+ }
+
+ @Override
+ public boolean hasClassHierarchy() {
+ assert checkIfObsolete();
+ return true;
+ }
+
+ @Override
+ public AppInfoWithClassHierarchy withClassHierarchy() {
+ assert checkIfObsolete();
+ return this;
+ }
+
+ public boolean isSubtype(DexType subtype, DexType supertype) {
+ LinkedList<DexType> workList = new LinkedList<>();
+ workList.add(subtype);
+ while (!workList.isEmpty()) {
+ DexClass subtypeClass = definitionFor(subtype);
+ if (subtypeClass == null) {
+ // What to do here? Report missing type?
+ continue;
+ }
+ if (subtypeClass.superType == supertype) {
+ return true;
+ } else {
+ workList.add(subtypeClass.superType);
+ }
+ for (DexType itf : subtypeClass.interfaces.values) {
+ if (itf == supertype) {
+ return true;
+ } else {
+ workList.add(itf);
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Lookup static method following the super chain from the holder of {@code method}.
+ *
+ * <p>This method will resolve the method on the holder of {@code method} and only return a
+ * non-null value if the result of resolution was a static, non-abstract method.
+ *
+ * @param method the method to lookup
+ * @return The actual target for {@code method} or {@code null} if none found.
+ */
+
+ @Deprecated // TODO(b/147578480): Remove
+ public DexEncodedMethod lookupStaticTarget(DexMethod method, DexType invocationContext) {
+ assert checkIfObsolete();
+ assert invocationContext.isClassType();
+ DexClass context = definitionFor(invocationContext);
+ if (context == null) {
+ return null;
+ }
+ assert context.isProgramClass();
+ return lookupStaticTarget(method, context.asProgramClass());
+ }
+
+ public final DexEncodedMethod lookupStaticTarget(
+ DexMethod method, DexProgramClass invocationContext) {
+ assert checkIfObsolete();
+ return resolveMethod(method.holder, method).lookupInvokeStaticTarget(invocationContext, this);
+ }
+
+ /**
+ * Lookup super method following the super chain from the holder of {@code method}.
+ *
+ * <p>This method will resolve the method on the holder of {@code method} and only return a
+ * non-null value if the result of resolution was an instance (i.e. non-static) method.
+ *
+ * @param method the method to lookup
+ * @param invocationContext the class the invoke is contained in, i.e., the holder of the caller.
+ * @return The actual target for {@code method} or {@code null} if none found.
+ */
+ @Deprecated // TODO(b/147578480): Remove
+ public DexEncodedMethod lookupSuperTarget(DexMethod method, DexType invocationContext) {
+ assert checkIfObsolete();
+ assert invocationContext.isClassType();
+ DexClass context = definitionFor(invocationContext);
+ if (context == null) {
+ return null;
+ }
+ if (context.isProgramClass()){
+ return lookupSuperTarget(method, context.asProgramClass());
+ }
+ // TODO(clement): find out when this happens and remove it,
+ // Should be assert context.isProgramClass().
+ return lookupSuperTarget(method, context);
+ }
+
+ public final DexEncodedMethod lookupSuperTarget(
+ DexMethod method, DexProgramClass invocationContext) {
+ assert checkIfObsolete();
+ return resolveMethod(method.holder, method).lookupInvokeSuperTarget(invocationContext, this);
+ }
+}
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 a24212f..71b2235 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
@@ -26,7 +26,7 @@
import java.util.function.Consumer;
import java.util.function.Function;
-public class AppInfoWithSubtyping extends AppInfo implements ClassHierarchy {
+public class AppInfoWithSubtyping extends AppInfoWithClassHierarchy {
private static final int ROOT_LEVEL = 0;
private static final int UNKNOWN_LEVEL = -1;
@@ -463,7 +463,6 @@
return getTypeInfo(type).isInterface();
}
- @Override
public boolean hasSubtypes(DexType type) {
return !getTypeInfo(type).directSubtypes.isEmpty();
}
@@ -651,13 +650,6 @@
}
}
- @Override
- public boolean isDirectSubtype(DexType subtype, DexType supertype) {
- TypeInfo info = getTypeInfo(supertype);
- assert info.hierarchyLevel != UNKNOWN_LEVEL;
- return info.directSubtypes.contains(subtype);
- }
-
// TODO(b/130636783): inconsistent location
public DexType computeLeastUpperBoundOfClasses(DexType subtype, DexType other) {
if (subtype == other) {
diff --git a/src/main/java/com/android/tools/r8/graph/ClassHierarchy.java b/src/main/java/com/android/tools/r8/graph/ClassHierarchy.java
deleted file mode 100644
index bcf56bb..0000000
--- a/src/main/java/com/android/tools/r8/graph/ClassHierarchy.java
+++ /dev/null
@@ -1,12 +0,0 @@
-// 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.graph;
-
-public interface ClassHierarchy extends DexDefinitionSupplier {
- boolean hasSubtypes(DexType type);
-
- boolean isDirectSubtype(DexType subtype, DexType supertype);
-
- boolean isSubtype(DexType subtype, DexType supertype);
-}
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 4854741..2b70ca2 100644
--- a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
@@ -49,10 +49,11 @@
return isSingleResolution() ? asSingleResolution().getResolvedMethod() : null;
}
- public abstract boolean isAccessibleFrom(DexProgramClass context, AppInfoWithSubtyping appInfo);
+ public abstract boolean isAccessibleFrom(
+ DexProgramClass context, AppInfoWithClassHierarchy appInfo);
public abstract boolean isAccessibleForVirtualDispatchFrom(
- DexProgramClass context, AppInfoWithSubtyping appInfo);
+ DexProgramClass context, AppInfoWithClassHierarchy appInfo);
// TODO(b/145187573): Remove this and use proper access checks.
@Deprecated
@@ -60,15 +61,19 @@
/** Lookup the single target of an invoke-special on this resolution result if possible. */
public abstract DexEncodedMethod lookupInvokeSpecialTarget(
- DexProgramClass context, AppInfoWithSubtyping appInfo);
+ DexProgramClass context, AppInfoWithClassHierarchy appInfo);
/** Lookup the single target of an invoke-super on this resolution result if possible. */
public abstract DexEncodedMethod lookupInvokeSuperTarget(
- DexProgramClass context, AppInfoWithSubtyping appInfo);
+ DexProgramClass context, AppInfoWithClassHierarchy appInfo);
@Deprecated
public abstract DexEncodedMethod lookupInvokeSuperTarget(DexClass context, AppInfo appInfo);
+ /** Lookup the single target of an invoke-static on this resolution result if possible. */
+ public abstract DexEncodedMethod lookupInvokeStaticTarget(
+ DexProgramClass context, AppInfoWithClassHierarchy appInfo);
+
public final Set<DexEncodedMethod> lookupVirtualDispatchTargets(
boolean isInterface, AppInfoWithSubtyping appInfo) {
return isInterface ? lookupInterfaceTargets(appInfo) : lookupVirtualTargets(appInfo);
@@ -116,14 +121,14 @@
}
@Override
- public boolean isAccessibleFrom(DexProgramClass context, AppInfoWithSubtyping appInfo) {
+ public boolean isAccessibleFrom(DexProgramClass context, AppInfoWithClassHierarchy appInfo) {
return AccessControl.isMethodAccessible(
resolvedMethod, initialResolutionHolder, context, appInfo);
}
@Override
public boolean isAccessibleForVirtualDispatchFrom(
- DexProgramClass context, AppInfoWithSubtyping appInfo) {
+ DexProgramClass context, AppInfoWithClassHierarchy appInfo) {
return resolvedMethod.isVirtualMethod() && isAccessibleFrom(context, appInfo);
}
@@ -140,7 +145,7 @@
*/
@Override
public DexEncodedMethod lookupInvokeSpecialTarget(
- DexProgramClass context, AppInfoWithSubtyping appInfo) {
+ DexProgramClass context, AppInfoWithClassHierarchy appInfo) {
// If the resolution is non-accessible then no target exists.
if (!isAccessibleFrom(context, appInfo)) {
return null;
@@ -176,7 +181,7 @@
*/
@Override
public DexEncodedMethod lookupInvokeSuperTarget(
- DexProgramClass context, AppInfoWithSubtyping appInfo) {
+ DexProgramClass context, AppInfoWithClassHierarchy appInfo) {
if (!isAccessibleFrom(context, appInfo)) {
return null;
}
@@ -192,6 +197,28 @@
return target;
}
+ /**
+ * Lookup the target of an invoke-static.
+ *
+ * <p>This method will resolve the method on the holder and only return a non-null value if the
+ * result of resolution was a static, non-abstract method.
+ *
+ * @param context Class the invoke is contained in, i.e., the holder of the caller.
+ * * @param appInfo Application info.
+ * @return The actual target or {@code null} if none found.
+ */
+ @Override
+ public DexEncodedMethod lookupInvokeStaticTarget(DexProgramClass context,
+ AppInfoWithClassHierarchy appInfo) {
+ if (!isAccessibleFrom(context, appInfo)) {
+ return null;
+ }
+ if (resolvedMethod.isStatic()) {
+ return resolvedMethod;
+ }
+ return null;
+ }
+
@Override
public DexEncodedMethod lookupInvokeSuperTarget(DexClass context, AppInfo appInfo) {
assert context != null;
@@ -276,7 +303,8 @@
return target;
}
- private static boolean isSuperclass(DexClass sup, DexClass sub, AppInfoWithSubtyping appInfo) {
+ private static boolean isSuperclass(
+ DexClass sup, DexClass sub, AppInfoWithClassHierarchy appInfo) {
return sup != sub && appInfo.isSubtype(sub.type, sup.type);
}
@@ -391,13 +419,13 @@
@Override
public final DexEncodedMethod lookupInvokeSpecialTarget(
- DexProgramClass context, AppInfoWithSubtyping appInfo) {
+ DexProgramClass context, AppInfoWithClassHierarchy appInfo) {
return null;
}
@Override
public DexEncodedMethod lookupInvokeSuperTarget(
- DexProgramClass context, AppInfoWithSubtyping appInfo) {
+ DexProgramClass context, AppInfoWithClassHierarchy appInfo) {
return null;
}
@@ -407,6 +435,12 @@
}
@Override
+ public DexEncodedMethod lookupInvokeStaticTarget(DexProgramClass context,
+ AppInfoWithClassHierarchy appInfo) {
+ return null;
+ }
+
+ @Override
public final Set<DexEncodedMethod> lookupVirtualTargets(AppInfoWithSubtyping appInfo) {
return null;
}
@@ -427,13 +461,13 @@
}
@Override
- public boolean isAccessibleFrom(DexProgramClass context, AppInfoWithSubtyping appInfo) {
+ public boolean isAccessibleFrom(DexProgramClass context, AppInfoWithClassHierarchy appInfo) {
return true;
}
@Override
public boolean isAccessibleForVirtualDispatchFrom(
- DexProgramClass context, AppInfoWithSubtyping appInfo) {
+ DexProgramClass context, AppInfoWithClassHierarchy appInfo) {
return true;
}
@@ -461,13 +495,13 @@
}
@Override
- public boolean isAccessibleFrom(DexProgramClass context, AppInfoWithSubtyping appInfo) {
+ public boolean isAccessibleFrom(DexProgramClass context, AppInfoWithClassHierarchy appInfo) {
return false;
}
@Override
public boolean isAccessibleForVirtualDispatchFrom(
- DexProgramClass context, AppInfoWithSubtyping appInfo) {
+ DexProgramClass context, AppInfoWithClassHierarchy appInfo) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
index 0c4671e..6893f5f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
@@ -105,7 +105,7 @@
DexMethod invokedMethod = getInvokedMethod();
if (appView.appInfo().hasLiveness()) {
AppInfoWithLiveness appInfo = appView.appInfo().withLiveness();
- return appInfo.lookupStaticTarget(invokedMethod);
+ return appInfo.lookupStaticTarget(invokedMethod, invocationContext);
}
// In D8, we can treat invoke-static instructions as having a single target if the invoke is
// targeting a method in the enclosing class.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
index b95f69e..fd4b0ca 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
@@ -183,7 +183,7 @@
public ConstraintWithTarget forInvokeStatic(DexMethod method, DexType invocationContext) {
DexMethod lookup = graphLense.lookupMethod(method);
return forSingleTargetInvoke(
- lookup, appView.appInfo().lookupStaticTarget(lookup), invocationContext);
+ lookup, appView.appInfo().lookupStaticTarget(lookup, invocationContext), invocationContext);
}
public ConstraintWithTarget forInvokeSuper(DexMethod method, DexType invocationContext) {
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 9b5029f..bba68bf 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -968,7 +968,7 @@
case DIRECT:
return lookupDirectTarget(target);
case STATIC:
- return lookupStaticTarget(target);
+ return lookupStaticTarget(target, invocationContext);
case SUPER:
return lookupSuperTarget(target, invocationContext);
default:
diff --git a/src/test/java/com/android/tools/r8/jasmin/MemberResolutionTest.java b/src/test/java/com/android/tools/r8/jasmin/MemberResolutionTest.java
index b4dc614..c55b3a5 100644
--- a/src/test/java/com/android/tools/r8/jasmin/MemberResolutionTest.java
+++ b/src/test/java/com/android/tools/r8/jasmin/MemberResolutionTest.java
@@ -293,8 +293,7 @@
" invokespecial SubClass/<init>()V",
" invokespecial SubClass/aMethod()V",
" return");
- ensureExceptionOrCompilerError(builder, IllegalAccessError.class,
- compiler -> compiler.equals(CompilerUnderTest.R8));
+ ensureIAE(builder);
}
@Test