Report resolution target for library modelled methods
Change-Id: I9e6038f6fe91230e6b974ef078c2327761475538
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index 9484c21..9ed88a6 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -19,6 +19,7 @@
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoFactory;
import com.android.tools.r8.ir.optimize.library.LibraryMethodOptimizer;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.LibraryModeledPredicate;
import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OptionalBool;
@@ -32,7 +33,7 @@
import java.util.function.Function;
import java.util.function.Predicate;
-public class AppView<T extends AppInfo> implements DexDefinitionSupplier {
+public class AppView<T extends AppInfo> implements DexDefinitionSupplier, LibraryModeledPredicate {
private enum WholeProgramOptimizations {
ON,
@@ -108,6 +109,11 @@
}
}
+ @Override
+ public boolean isModeled(DexType type) {
+ return libraryMethodOptimizer.isModeled(type);
+ }
+
public static <T extends AppInfo> AppView<T> createForD8(T appInfo, InternalOptions options) {
return new AppView<>(appInfo, WholeProgramOptimizations.OFF, options);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 6c9e84b..58b768d 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -965,8 +965,6 @@
createMethod(npeType, createProto(voidType), constructorMethodName);
public final DexMethod initWithMessage =
createMethod(npeType, createProto(voidType, stringType), constructorMethodName);
-
- private NullPointerExceptionMethods() {}
}
/**
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java b/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
index 8b139ca..e9f3063 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
@@ -95,6 +95,7 @@
getInvokedMethod(),
invocationContext,
true,
+ appView,
TypeAnalysis.getRefinedReceiverType(appViewWithLiveness, this),
getReceiver().getDynamicLowerBoundType(appViewWithLiveness));
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
index 0499be1..1ec8873 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
@@ -99,6 +99,7 @@
getInvokedMethod(),
invocationContext,
false,
+ appView,
TypeAnalysis.getRefinedReceiverType(appViewWithLiveness, this),
getReceiver().getDynamicLowerBoundType(appViewWithLiveness));
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
index ca95080..25ddb6a 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
@@ -174,7 +174,7 @@
}
} else {
DexEncodedMethod singleTarget =
- appView.appInfo().lookupSingleTarget(type, method, context.holder);
+ appView.appInfo().lookupSingleTarget(type, method, context.holder, appView);
if (singleTarget != null) {
assert !source.accessFlags.isBridge() || singleTarget != currentMethod.method;
DexProgramClass clazz =
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 87e317e..44367e0 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -1087,7 +1087,10 @@
}
public DexEncodedMethod lookupSingleTarget(
- Type type, DexMethod target, DexType invocationContext) {
+ Type type,
+ DexMethod target,
+ DexType invocationContext,
+ LibraryModeledPredicate modeledPredicate) {
assert checkIfObsolete();
DexType holder = target.holder;
if (!holder.isClassType()) {
@@ -1095,9 +1098,9 @@
}
switch (type) {
case VIRTUAL:
- return lookupSingleVirtualTarget(target, invocationContext, false);
+ return lookupSingleVirtualTarget(target, invocationContext, false, modeledPredicate);
case INTERFACE:
- return lookupSingleVirtualTarget(target, invocationContext, true);
+ return lookupSingleVirtualTarget(target, invocationContext, true, modeledPredicate);
case DIRECT:
return lookupDirectTarget(target, invocationContext);
case STATIC:
@@ -1138,13 +1141,26 @@
public DexEncodedMethod lookupSingleVirtualTarget(
DexMethod method, DexType invocationContext, boolean isInterface) {
assert checkIfObsolete();
- return lookupSingleVirtualTarget(method, invocationContext, isInterface, method.holder, null);
+ return lookupSingleVirtualTarget(
+ method, invocationContext, isInterface, type -> false, method.holder, null);
+ }
+
+ /** For mapping invoke virtual instruction to single target method. */
+ public DexEncodedMethod lookupSingleVirtualTarget(
+ DexMethod method,
+ DexType invocationContext,
+ boolean isInterface,
+ LibraryModeledPredicate modeledPredicate) {
+ assert checkIfObsolete();
+ return lookupSingleVirtualTarget(
+ method, invocationContext, isInterface, modeledPredicate, method.holder, null);
}
public DexEncodedMethod lookupSingleVirtualTarget(
DexMethod method,
DexType invocationContext,
boolean isInterface,
+ LibraryModeledPredicate modeledPredicate,
DexType refinedReceiverType,
ClassTypeLatticeElement receiverLowerBoundType) {
assert checkIfObsolete();
@@ -1169,6 +1185,14 @@
|| !resolution.isAccessibleForVirtualDispatchFrom(invocationClass, this)) {
return null;
}
+ // If the method is modeled, return the resolution.
+ if (modeledPredicate.isModeled(resolution.getResolvedHolder().type)) {
+ if (resolution.getResolvedHolder().isFinal()
+ || (resolution.getResolvedMethod().isFinal()
+ && resolution.getResolvedMethod().accessFlags.isPublic())) {
+ return resolution.getResolvedMethod();
+ }
+ }
// If the lower-bound on the receiver type is the same as the upper-bound, then we have exact
// runtime type information. In this case, the invoke will dispatch to the resolution result
// from the runtime type of the receiver.
diff --git a/src/main/java/com/android/tools/r8/shaking/LibraryModeledPredicate.java b/src/main/java/com/android/tools/r8/shaking/LibraryModeledPredicate.java
new file mode 100644
index 0000000..39ee67c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/shaking/LibraryModeledPredicate.java
@@ -0,0 +1,13 @@
+// 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.shaking;
+
+import com.android.tools.r8.graph.DexType;
+
+@FunctionalInterface
+public interface LibraryModeledPredicate {
+
+ boolean isModeled(DexType type);
+}