Lookup invocation type using lense in inlining constraint visitor
Change-Id: Ifcd2698ebb5cf7b3115377430d764f794dcabcb1
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 1e9566a..073d6ae 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
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.optimize;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfo.ResolutionResult;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
@@ -12,6 +13,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLense;
+import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.optimize.Inliner.Constraint;
import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
import java.util.Collection;
@@ -101,16 +103,37 @@
return Constraint.classIsVisible(invocationContext, type, appInfo);
}
- public Constraint forInvokeCustom() {
- return Constraint.NEVER;
- }
-
public Constraint forInstancePut(DexField field, DexType invocationContext) {
DexField lookup = graphLense.lookupField(field);
return forFieldInstruction(
lookup, appInfo.lookupInstanceTarget(lookup.clazz, lookup), invocationContext);
}
+ public Constraint forInvoke(DexMethod method, Type type, DexType invocationContext) {
+ switch (type) {
+ case DIRECT:
+ return forInvokeDirect(method, invocationContext);
+ case INTERFACE:
+ return forInvokeInterface(method, invocationContext);
+ case STATIC:
+ return forInvokeStatic(method, invocationContext);
+ case SUPER:
+ return forInvokeSuper(method, invocationContext);
+ case VIRTUAL:
+ return forInvokeVirtual(method, invocationContext);
+ case CUSTOM:
+ return forInvokeCustom();
+ case POLYMORPHIC:
+ return forInvokePolymorphic(method, invocationContext);
+ default:
+ throw new Unreachable("Unexpected type: " + type);
+ }
+ }
+
+ public Constraint forInvokeCustom() {
+ return Constraint.NEVER;
+ }
+
public Constraint forInvokeDirect(DexMethod method, DexType invocationContext) {
DexMethod lookup = graphLense.lookupMethod(method);
return forSingleTargetInvoke(lookup, appInfo.lookupDirectTarget(lookup), invocationContext);
diff --git a/src/main/java/com/android/tools/r8/jar/InliningConstraintVisitor.java b/src/main/java/com/android/tools/r8/jar/InliningConstraintVisitor.java
index 4807b89..459d7de 100644
--- a/src/main/java/com/android/tools/r8/jar/InliningConstraintVisitor.java
+++ b/src/main/java/com/android/tools/r8/jar/InliningConstraintVisitor.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.graph.JarApplicationReader;
+import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.ir.conversion.JarSourceCode;
import com.android.tools.r8.ir.optimize.Inliner.Constraint;
import com.android.tools.r8.ir.optimize.InliningConstraints;
@@ -34,6 +35,7 @@
private final JarApplicationReader application;
private final AppInfoWithLiveness appInfo;
+ private final GraphLense graphLense;
private final InliningConstraints inliningConstraints;
private final DexEncodedMethod method;
private final DexType invocationContext;
@@ -47,8 +49,10 @@
DexEncodedMethod method,
DexType invocationContext) {
super(ASM6);
+ assert graphLense.isContextFreeForMethods();
this.application = application;
this.appInfo = appInfo;
+ this.graphLense = graphLense;
this.inliningConstraints = new InliningConstraints(appInfo, graphLense);
this.method = method;
this.invocationContext = invocationContext;
@@ -116,48 +120,73 @@
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
DexType ownerType = application.getTypeFromName(owner);
DexMethod target = application.getMethod(ownerType, name, desc);
+
+ // Find the DEX invocation type.
+ Invoke.Type type;
switch (opcode) {
case Opcodes.INVOKEDYNAMIC:
- if (JarSourceCode.isCallToPolymorphicSignatureMethod(owner, name)) {
- updateConstraint(inliningConstraints.forInvokePolymorphic(target, invocationContext));
- } else {
- updateConstraint(inliningConstraints.forInvokeCustom());
- }
+ type =
+ JarSourceCode.isCallToPolymorphicSignatureMethod(owner, name)
+ ? Invoke.Type.POLYMORPHIC
+ : Invoke.Type.CUSTOM;
+ assert noNeedToUseGraphLense(target, type);
break;
case Opcodes.INVOKEINTERFACE:
- updateConstraint(inliningConstraints.forInvokeInterface(target, invocationContext));
+ // Could have changed to an invoke-virtual instruction due to vertical class merging
+ // (if an interface is merged into a class).
+ type = graphLense.lookupMethod(target, null, Invoke.Type.INTERFACE).getType();
+ assert type == Invoke.Type.INTERFACE || type == Invoke.Type.VIRTUAL;
break;
case Opcodes.INVOKESPECIAL:
- if (name.equals(Constants.INSTANCE_INITIALIZER_NAME) || ownerType == invocationContext) {
- updateConstraint(inliningConstraints.forInvokeDirect(target, invocationContext));
+ if (name.equals(Constants.INSTANCE_INITIALIZER_NAME)) {
+ type = Invoke.Type.DIRECT;
+ assert noNeedToUseGraphLense(target, type);
+ } else if (ownerType == invocationContext) {
+ // The method could have been publicized.
+ type = graphLense.lookupMethod(target, null, Invoke.Type.DIRECT).getType();
+ assert type == Invoke.Type.DIRECT || type == Invoke.Type.VIRTUAL;
} else {
- updateConstraint(inliningConstraints.forInvokeSuper(target, invocationContext));
+ // This is a super call. Note that the vertical class merger translates some invoke-super
+ // instructions to invoke-direct. However, when that happens, the invoke instruction and
+ // the target method end up being in the same class, and therefore, we will allow inlining
+ // it. The result of using type=SUPER below will be the same, since it leads to the
+ // inlining constraint SAMECLASS.
+ // TODO(christofferqa): Consider using graphLense.lookupMethod (to do this, we need the
+ // context for the graph lense, though).
+ type = Invoke.Type.SUPER;
+ assert noNeedToUseGraphLense(target, type);
}
break;
case Opcodes.INVOKESTATIC:
- updateConstraint(inliningConstraints.forInvokeStatic(target, invocationContext));
+ type = Invoke.Type.STATIC;
+ assert noNeedToUseGraphLense(target, type);
break;
case Opcodes.INVOKEVIRTUAL:
- // Instructions that target a private method in the same class are translated to
- // invoke-direct.
+ type = Invoke.Type.VIRTUAL;
+ // Instructions that target a private method in the same class translates to invoke-direct.
if (target.holder == method.method.holder) {
DexClass clazz = appInfo.definitionFor(target.holder);
if (clazz != null && clazz.lookupDirectMethod(target) != null) {
- updateConstraint(inliningConstraints.forInvokeDirect(target, invocationContext));
- break;
+ type = Invoke.Type.DIRECT;
}
}
-
- updateConstraint(inliningConstraints.forInvokeVirtual(target, invocationContext));
+ assert noNeedToUseGraphLense(target, type);
break;
default:
throw new Unreachable("Unexpected opcode " + opcode);
}
+
+ updateConstraint(inliningConstraints.forInvoke(target, type, invocationContext));
+ }
+
+ private boolean noNeedToUseGraphLense(DexMethod method, Invoke.Type type) {
+ assert graphLense.lookupMethod(method, null, type).getType() == type;
+ return true;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 12a2257..0840d91 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -1406,14 +1406,32 @@
@Override
public DexType lookupType(DexType type) {
- return type == source ? target : type;
+ return type == source ? target : mergedClasses.getOrDefault(type, type);
}
@Override
public GraphLenseLookupResult lookupMethod(
DexMethod method, DexEncodedMethod context, Type type) {
- return new GraphLenseLookupResult(
- renamedMembersLense.methodMap.getOrDefault(method, method), type);
+ // First look up the method using the existing graph lense (for example, the type will have
+ // changed if the method was publicized by ClassAndMemberPublicizer).
+ GraphLenseLookupResult lookup = graphLense.lookupMethod(method, context, type);
+ DexMethod previousMethod = lookup.getMethod();
+ Type previousType = lookup.getType();
+ // Then check if there is a renaming due to the vertical class merger.
+ DexMethod newMethod = renamedMembersLense.methodMap.get(previousMethod);
+ if (newMethod != null) {
+ if (previousType == Type.INTERFACE) {
+ // If an interface has been merged into a class, invoke-interface needs to be translated
+ // to invoke-virtual.
+ DexClass clazz = appInfo.definitionFor(newMethod.holder);
+ if (clazz != null && !clazz.accessFlags.isInterface()) {
+ assert appInfo.definitionFor(method.holder).accessFlags.isInterface();
+ return new GraphLenseLookupResult(newMethod, Type.VIRTUAL);
+ }
+ }
+ return new GraphLenseLookupResult(newMethod, previousType);
+ }
+ return new GraphLenseLookupResult(previousMethod, previousType);
}
@Override