Merge "Revert "Move invocation type mapping to GraphLense""
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLense.java b/src/main/java/com/android/tools/r8/graph/GraphLense.java
index 7d17f11..2c12a90 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLense.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLense.java
@@ -20,35 +20,11 @@
* <li>Renaming private methods/fields.</li>
* <li>Moving methods/fields to a super/subclass.</li>
* <li>Replacing method/field references by the same method/field on a super/subtype</li>
- * <li>Moved methods might require changed invocation type at the call site</li>
* </ul>
* Note that the latter two have to take visibility into account.
*/
public abstract class GraphLense {
- /**
- * Result of a method lookup in a GraphLense.
- *
- * This provide the new target and the invoke type to use.
- */
- public static class GraphLenseLookupResult {
- private final DexMethod method;
- private final Type type;
-
- public GraphLenseLookupResult(DexMethod method, Type type) {
- this.method = method;
- this.type = type;
- }
-
- public DexMethod getMethod() {
- return method;
- }
-
- public Type getType() {
- return type;
- }
- }
-
public static class Builder {
protected Builder() {
@@ -92,11 +68,10 @@
// This overload can be used when the graph lense is known to be context insensitive.
public DexMethod lookupMethod(DexMethod method) {
assert isContextFreeForMethod(method);
- return lookupMethod(method, null, null).getMethod();
+ return lookupMethod(method, null, null);
}
- public abstract GraphLenseLookupResult lookupMethod(
- DexMethod method, DexEncodedMethod context, Type type);
+ public abstract DexMethod lookupMethod(DexMethod method, DexEncodedMethod context, Type type);
// Context sensitive graph lenses should override this method.
public Set<DexMethod> lookupMethodInAllContexts(DexMethod method) {
@@ -151,9 +126,8 @@
}
@Override
- public GraphLenseLookupResult lookupMethod(
- DexMethod method, DexEncodedMethod context, Type type) {
- return new GraphLenseLookupResult(method, type);
+ public DexMethod lookupMethod(DexMethod method, DexEncodedMethod context, Type type) {
+ return method;
}
@Override
@@ -167,29 +141,19 @@
}
}
- /**
- * GraphLense implementation with a parent lense using a simple mapping for type, method and
- * field mapping.
- *
- * Subclasses can override the lookup methods.
- *
- * For method mapping where invocation type can change just override
- * {@link #mapInvocationType(DexMethod, DexMethod, DexEncodedMethod, Type)} if
- * the default name mapping applies, and only invocation type might need to change.
- */
public static class NestedGraphLense extends GraphLense {
- protected final GraphLense previousLense;
+ private final GraphLense previousLense;
protected final DexItemFactory dexItemFactory;
- protected final Map<DexType, DexType> typeMap;
+ private final Map<DexType, DexType> typeMap;
private final Map<DexType, DexType> arrayTypeCache = new IdentityHashMap<>();
- protected final Map<DexMethod, DexMethod> methodMap;
- protected final Map<DexField, DexField> fieldMap;
+ private final Map<DexMethod, DexMethod> methodMap;
+ private final Map<DexField, DexField> fieldMap;
public NestedGraphLense(Map<DexType, DexType> typeMap, Map<DexMethod, DexMethod> methodMap,
Map<DexField, DexField> fieldMap, GraphLense previousLense, DexItemFactory dexItemFactory) {
- this.typeMap = typeMap.isEmpty() ? null : typeMap;
+ this.typeMap = typeMap;
this.methodMap = methodMap;
this.fieldMap = fieldMap;
this.previousLense = previousLense;
@@ -216,58 +180,13 @@
}
}
DexType previous = previousLense.lookupType(type);
- return typeMap != null ? typeMap.getOrDefault(previous, previous) : previous;
+ return typeMap.getOrDefault(previous, previous);
}
@Override
- public GraphLenseLookupResult lookupMethod(
- DexMethod method, DexEncodedMethod context, Type type) {
- GraphLenseLookupResult previous = previousLense.lookupMethod(method, context, type);
- DexMethod newMethod = methodMap.get(previous.getMethod());
- if (newMethod == null) {
- return previous;
- }
- // TODO(sgjesse): Should we always do interface to virtual mapping? Is it a performance win
- // that only subclasses which are known to need it actually do it?
- return new GraphLenseLookupResult(
- newMethod, mapInvocationType(newMethod, method, context, type));
- }
-
- /**
- * Default invocation type mapping.
- *
- * This is an identity mapping. If a subclass need invocation type mapping either override
- * this method or {@link #lookupMethod(DexMethod, DexEncodedMethod, Type)}
- */
- protected Type mapInvocationType(
- DexMethod newMethod, DexMethod originalMethod, DexEncodedMethod context, Type type) {
- return type;
- }
-
- /**
- * Standard mapping between interface and virtual invoke type.
- *
- * Handle methods moved from interface to class or class to interface.
- */
- final protected Type mapVirtualInterfaceInvocationTypes(
- AppInfo appInfo, DexMethod newMethod, DexMethod originalMethod,
- DexEncodedMethod context, Type type) {
- if (type == Type.VIRTUAL || type == Type.INTERFACE) {
- // Get the invoke type of the actual definition.
- DexClass newTargetClass = appInfo.definitionFor(newMethod.holder);
- if (newTargetClass == null) {
- return type;
- }
- DexClass originalTargetClass = appInfo.definitionFor(originalMethod.holder);
- if (originalTargetClass != null
- && (originalTargetClass.isInterface() ^ (type == Type.INTERFACE))) {
- // The invoke was wrong to start with, so we keep it wrong. This is to ensure we get
- // the IncompatibleClassChangeError the original invoke would have triggered.
- return newTargetClass.accessFlags.isInterface() ? Type.VIRTUAL : Type.INTERFACE;
- }
- return newTargetClass.accessFlags.isInterface() ? Type.INTERFACE : Type.VIRTUAL;
- }
- return type;
+ public DexMethod lookupMethod(DexMethod method, DexEncodedMethod context, Type type) {
+ DexMethod previous = previousLense.lookupMethod(method, context, type);
+ return methodMap.getOrDefault(previous, previous);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
index 85506ad..21b8dc4 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
@@ -363,7 +363,7 @@
private void processInvoke(Type type, DexMethod method) {
DexEncodedMethod source = caller.method;
- method = graphLense.lookupMethod(method, source, type).getMethod();
+ method = graphLense.lookupMethod(method, source, type);
DexEncodedMethod definition = appInfo.lookup(type, method, source.method.holder);
if (definition != null) {
assert !source.accessFlags.isBridge() || definition != caller.method;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 52919c6..7d7e5f3 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -141,7 +141,7 @@
this.memberValuePropagation =
options.enableValuePropagation ?
new MemberValuePropagation(appInfo.withLiveness()) : null;
- this.lensCodeRewriter = new LensCodeRewriter(graphLense, appInfo.withSubtyping());
+ this.lensCodeRewriter = new LensCodeRewriter(graphLense, appInfo.withSubtyping(), options);
if (appInfo.hasLiveness()) {
// When disabling the pruner here, also disable the ProtoLiteExtension in R8.java.
this.protoLiteRewriter =
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index 23beded..4c0be09 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexCallSite;
+import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
@@ -15,7 +16,6 @@
import com.android.tools.r8.graph.DexValue;
import com.android.tools.r8.graph.DexValue.DexValueMethodHandle;
import com.android.tools.r8.graph.GraphLense;
-import com.android.tools.r8.graph.GraphLense.GraphLenseLookupResult;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.CheckCast;
import com.android.tools.r8.ir.code.ConstClass;
@@ -35,6 +35,7 @@
import com.android.tools.r8.ir.code.StaticGet;
import com.android.tools.r8.ir.code.StaticPut;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.utils.InternalOptions;
import java.util.List;
import java.util.ListIterator;
import java.util.stream.Collectors;
@@ -43,10 +44,13 @@
private final GraphLense graphLense;
private final AppInfoWithSubtyping appInfo;
+ private final InternalOptions options;
- public LensCodeRewriter(GraphLense graphLense, AppInfoWithSubtyping appInfo) {
+ public LensCodeRewriter(
+ GraphLense graphLense, AppInfoWithSubtyping appInfo, InternalOptions options) {
this.graphLense = graphLense;
this.appInfo = appInfo;
+ this.options = options;
}
private Value makeOutValue(Instruction insn, IRCode code) {
@@ -106,10 +110,8 @@
if (!invokedHolder.isClassType()) {
continue;
}
- GraphLenseLookupResult lenseLookup =
- graphLense.lookupMethod(invokedMethod, method, invoke.getType());
- DexMethod actualTarget = lenseLookup.getMethod();
- Invoke.Type invokeType = lenseLookup.getType();
+ DexMethod actualTarget = graphLense.lookupMethod(invokedMethod, method, invoke.getType());
+ Invoke.Type invokeType = getInvokeType(invoke, actualTarget, invokedMethod, method);
if (actualTarget != invokedMethod || invoke.getType() != invokeType) {
Invoke newInvoke = Invoke.create(invokeType, actualTarget, null,
invoke.outValue(), invoke.inValues());
@@ -228,13 +230,17 @@
DexEncodedMethod method, DexMethodHandle methodHandle) {
if (methodHandle.isMethodHandle()) {
DexMethod invokedMethod = methodHandle.asMethod();
- GraphLenseLookupResult lenseLookup = graphLense.lookupMethod(
- invokedMethod, method, methodHandle.type.toInvokeType());
- DexMethod actualTarget = lenseLookup.getMethod();
+ DexMethod actualTarget =
+ graphLense.lookupMethod(invokedMethod, method, methodHandle.type.toInvokeType());
if (actualTarget != invokedMethod) {
- MethodHandleType newType = lenseLookup.getType() == Type.INTERFACE
- ? MethodHandleType.INVOKE_INTERFACE
- : MethodHandleType.INVOKE_INSTANCE;
+ DexClass clazz = appInfo.definitionFor(actualTarget.holder);
+ MethodHandleType newType = methodHandle.type;
+ if (clazz != null
+ && (newType.isInvokeInterface() || newType.isInvokeInstance())) {
+ newType = clazz.accessFlags.isInterface()
+ ? MethodHandleType.INVOKE_INTERFACE
+ : MethodHandleType.INVOKE_INSTANCE;
+ }
return new DexMethodHandle(newType, actualTarget);
}
} else {
@@ -246,4 +252,55 @@
}
return methodHandle;
}
+
+ private Type getInvokeType(
+ InvokeMethod invoke,
+ DexMethod actualTarget,
+ DexMethod originalTarget,
+ DexEncodedMethod invocationContext) {
+ // We might move methods from interfaces to classes and vice versa. So we have to support
+ // fixing the invoke kind, yet only if it was correct to start with.
+ if (invoke.isInvokeVirtual() || invoke.isInvokeInterface()) {
+ // Get the invoke type of the actual definition.
+ DexClass newTargetClass = appInfo.definitionFor(actualTarget.holder);
+ if (newTargetClass == null) {
+ return invoke.getType();
+ }
+ DexClass originalTargetClass = appInfo.definitionFor(originalTarget.holder);
+ if (originalTargetClass != null
+ && (originalTargetClass.isInterface() ^ (invoke.getType() == Type.INTERFACE))) {
+ // The invoke was wrong to start with, so we keep it wrong. This is to ensure we get
+ // the IncompatibleClassChangeError the original invoke would have triggered.
+ return newTargetClass.accessFlags.isInterface() ? Type.VIRTUAL : Type.INTERFACE;
+ }
+ return newTargetClass.accessFlags.isInterface() ? Type.INTERFACE : Type.VIRTUAL;
+ }
+ if (options.enableClassMerging && invoke.isInvokeSuper()) {
+ if (actualTarget.getHolder() == invocationContext.method.getHolder()) {
+ DexClass targetClass = appInfo.definitionFor(actualTarget.holder);
+ if (targetClass == null) {
+ return invoke.getType();
+ }
+
+ // If the super class A of the enclosing class B (i.e., invocationContext.method.holder)
+ // has been merged into B during vertical class merging, and this invoke-super instruction
+ // was resolving to a method in A, then the target method has been changed to a direct
+ // method and moved into B, so that we need to use an invoke-direct instruction instead of
+ // invoke-super.
+ //
+ // At this point, we have an invoke-super instruction where the static target is the
+ // enclosing class. However, such an instruction could occur even if a subclass has never
+ // been merged into the enclosing class. Therefore, to determine if vertical class merging
+ // has been applied, we look if there is a direct method with the right signature, and only
+ // return Type.DIRECT in that case.
+ DexEncodedMethod method = targetClass.lookupDirectMethod(actualTarget);
+ if (method != null) {
+ // The target method has been moved from the super class into the sub class during class
+ // merging such that we now need to use an invoke-direct instruction.
+ return Type.DIRECT;
+ }
+ }
+ }
+ return invoke.getType();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index 25cd969..029b169 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -271,7 +271,7 @@
Origin origin = appInfo.originFor(target.method.holder);
IRCode code = target.buildInliningIR(appInfo, options, generator, callerPosition, origin);
if (!target.isProcessed()) {
- new LensCodeRewriter(graphLense, appInfo).rewrite(code, target);
+ new LensCodeRewriter(graphLense, appInfo, options).rewrite(code, target);
}
return code;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/BridgeMethodAnalysis.java b/src/main/java/com/android/tools/r8/optimize/BridgeMethodAnalysis.java
index 492bcd0..56089f4 100644
--- a/src/main/java/com/android/tools/r8/optimize/BridgeMethodAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/BridgeMethodAnalysis.java
@@ -46,14 +46,14 @@
assert !method.accessFlags.isPrivate() && !method.accessFlags.isConstructor();
if (kind == InvokeKind.STATIC) {
assert method.accessFlags.isStatic();
- DexMethod actualTarget = lense.lookupMethod(target, method, Type.STATIC).getMethod();
+ DexMethod actualTarget = lense.lookupMethod(target, method, Type.STATIC);
DexEncodedMethod targetMethod = appInfo.lookupStaticTarget(actualTarget);
if (targetMethod != null) {
addForwarding(method, targetMethod);
}
} else if (kind == InvokeKind.VIRTUAL) {
// TODO(herhut): Add support for bridges with multiple targets.
- DexMethod actualTarget = lense.lookupMethod(target, method, Type.VIRTUAL).getMethod();
+ DexMethod actualTarget = lense.lookupMethod(target, method, Type.VIRTUAL);
DexEncodedMethod targetMethod = appInfo.lookupSingleVirtualTarget(actualTarget);
if (targetMethod != null) {
addForwarding(method, targetMethod);
@@ -93,16 +93,15 @@
}
@Override
- public GraphLenseLookupResult lookupMethod(
- DexMethod method, DexEncodedMethod context, Type type) {
- GraphLenseLookupResult previous = previousLense.lookupMethod(method, context, type);
- DexMethod bridge = bridgeTargetToBridgeMap.get(previous.getMethod());
+ public DexMethod lookupMethod(DexMethod method, DexEncodedMethod context, Type type) {
+ DexMethod previous = previousLense.lookupMethod(method, context, type);
+ DexMethod bridge = bridgeTargetToBridgeMap.get(previous);
// Do not forward calls from a bridge method to itself while the bridge method is still
// a bridge.
if (bridge == null || (context.accessFlags.isBridge() && bridge == context.method)) {
return previous;
}
- return new GraphLenseLookupResult(bridge, type);
+ return bridge;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index da7a787..fc408e3 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -26,13 +26,12 @@
private final AppInfoWithLiveness appInfo;
private final GraphLense lense;
- private final MemberRebindingLense.Builder builder;
+ private final GraphLense.Builder builder = GraphLense.builder();
public MemberRebindingAnalysis(AppInfoWithLiveness appInfo, GraphLense lense) {
assert lense.isContextFreeForMethods();
this.appInfo = appInfo;
this.lense = lense;
- this.builder = MemberRebindingLense.builder(appInfo);
}
private DexMethod validTargetFor(DexMethod target, DexMethod original) {
@@ -251,6 +250,6 @@
mergeFieldAccessContexts(appInfo.instanceFieldReads, appInfo.instanceFieldWrites),
appInfo::resolveFieldOn, DexClass::lookupField);
- return builder.build(lense);
+ return builder.build(appInfo.dexItemFactory, lense);
}
}
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingLense.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingLense.java
deleted file mode 100644
index 4ee0cee..0000000
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingLense.java
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (c) 2018, 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.optimize;
-
-import com.android.tools.r8.graph.AppInfo;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.GraphLense;
-import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
-import com.android.tools.r8.ir.code.Invoke.Type;
-import com.google.common.collect.ImmutableMap;
-import java.util.Map;
-
-public class MemberRebindingLense extends NestedGraphLense {
- public static class Builder extends NestedGraphLense.Builder {
- private final AppInfo appInfo;
-
- protected Builder(AppInfo appInfo) {
- this.appInfo = appInfo;
- }
-
- public GraphLense build(GraphLense previousLense) {
- assert typeMap.isEmpty();
- if (methodMap.isEmpty() && fieldMap.isEmpty()) {
- return previousLense;
- }
- return new MemberRebindingLense(appInfo, methodMap, fieldMap, previousLense);
- }
- }
-
- private final AppInfo appInfo;
-
- public MemberRebindingLense(
- AppInfo appInfo,
- Map<DexMethod, DexMethod> methodMap,
- Map<DexField, DexField> fieldMap,
- GraphLense previousLense) {
- super(ImmutableMap.of(), methodMap, fieldMap, previousLense, appInfo.dexItemFactory);
- this.appInfo = appInfo;
- }
-
- public static Builder builder(AppInfo appInfo) {
- return new Builder(appInfo);
- }
-
-
- @Override
- protected Type mapInvocationType(
- DexMethod newMethod, DexMethod originalMethod, DexEncodedMethod context, Type type) {
- return super.mapVirtualInterfaceInvocationTypes(
- appInfo, newMethod, originalMethod, context, type);
- }
-}
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 f0519a1..b11e33d 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -321,7 +321,7 @@
// The resulting graph lense that should be used after class merging.
VerticalClassMergerGraphLense.Builder renamedMembersLense =
- VerticalClassMergerGraphLense.builder(appInfo);
+ new VerticalClassMergerGraphLense.Builder();
Iterator<DexProgramClass> classIterator = classes.iterator();
@@ -490,7 +490,7 @@
private final DexClass source;
private final DexClass target;
private final VerticalClassMergerGraphLense.Builder deferredRenamings =
- VerticalClassMergerGraphLense.builder(appInfo);
+ new VerticalClassMergerGraphLense.Builder();
private boolean abortMerge = false;
private ClassMerger(DexClass source, DexClass target) {
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLense.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLense.java
index 99fb63a..942a857 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLense.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLense.java
@@ -4,13 +4,11 @@
package com.android.tools.r8.shaking;
-import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
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.graph.GraphLense.NestedGraphLense;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -42,57 +40,47 @@
// invocation will hit the same implementation as the original super.m() call.
//
// For the invocation "invoke-virtual A.m()" in B.m2, this graph lense will return the method B.m.
-public class VerticalClassMergerGraphLense extends NestedGraphLense {
- private final AppInfo appInfo;
+public class VerticalClassMergerGraphLense extends GraphLense {
+ private final GraphLense previousLense;
+ private final Map<DexField, DexField> fieldMap;
+ private final Map<DexMethod, DexMethod> methodMap;
private final Set<DexMethod> mergedMethods;
private final Map<DexType, Map<DexMethod, DexMethod>> contextualVirtualToDirectMethodMaps;
public VerticalClassMergerGraphLense(
- AppInfo appInfo,
Map<DexField, DexField> fieldMap,
Map<DexMethod, DexMethod> methodMap,
Set<DexMethod> mergedMethods,
Map<DexType, Map<DexMethod, DexMethod>> contextualVirtualToDirectMethodMaps,
GraphLense previousLense) {
- super(ImmutableMap.of(), methodMap, fieldMap, previousLense, appInfo.dexItemFactory);
- this.appInfo = appInfo;
+ this.previousLense = previousLense;
+ this.fieldMap = fieldMap;
+ this.methodMap = methodMap;
this.mergedMethods = mergedMethods;
this.contextualVirtualToDirectMethodMaps = contextualVirtualToDirectMethodMaps;
}
- public static Builder builder(AppInfo appInfo) {
- return new Builder(appInfo);
+ @Override
+ public DexType lookupType(DexType type) {
+ return previousLense.lookupType(type);
}
@Override
- public GraphLenseLookupResult lookupMethod(
- DexMethod method, DexEncodedMethod context, Type type) {
+ public DexMethod lookupMethod(DexMethod method, DexEncodedMethod context, Type type) {
assert isContextFreeForMethod(method) || (context != null && type != null);
- GraphLenseLookupResult previous = previousLense.lookupMethod(method, context, type);
- if (previous.getType() == Type.SUPER && !mergedMethods.contains(context.method)) {
+ DexMethod previous = previousLense.lookupMethod(method, context, type);
+ if (type == Type.SUPER && !mergedMethods.contains(context.method)) {
Map<DexMethod, DexMethod> virtualToDirectMethodMap =
contextualVirtualToDirectMethodMaps.get(context.method.holder);
if (virtualToDirectMethodMap != null) {
- DexMethod directMethod = virtualToDirectMethodMap.get(previous.getMethod());
+ DexMethod directMethod = virtualToDirectMethodMap.get(previous);
if (directMethod != null) {
- // If the super class A of the enclosing class B (i.e., context.method.holder)
- // has been merged into B during vertical class merging, and this invoke-super instruction
- // was resolving to a method in A, then the target method has been changed to a direct
- // method and moved into B, so that we need to use an invoke-direct instruction instead of
- // invoke-super.
- return new GraphLenseLookupResult(directMethod, Type.DIRECT);
+ return directMethod;
}
}
}
- return super.lookupMethod(previous.getMethod(), context, previous.getType());
- }
-
- @Override
- protected Type mapInvocationType(
- DexMethod newMethod, DexMethod originalMethod, DexEncodedMethod context, Type type) {
- return super.mapVirtualInterfaceInvocationTypes(
- appInfo, newMethod, originalMethod, context, type);
+ return methodMap.getOrDefault(previous, previous);
}
@Override
@@ -112,6 +100,12 @@
}
@Override
+ public DexField lookupField(DexField field) {
+ DexField previous = previousLense.lookupField(field);
+ return fieldMap.getOrDefault(previous, previous);
+ }
+
+ @Override
public boolean isContextFreeForMethods() {
return contextualVirtualToDirectMethodMaps.isEmpty() && previousLense.isContextFreeForMethods();
}
@@ -132,7 +126,6 @@
}
public static class Builder {
- private final AppInfo appInfo;
private final ImmutableMap.Builder<DexField, DexField> fieldMapBuilder = ImmutableMap.builder();
private final ImmutableMap.Builder<DexMethod, DexMethod> methodMapBuilder =
@@ -141,9 +134,7 @@
private final Map<DexType, Map<DexMethod, DexMethod>> contextualVirtualToDirectMethodMaps =
new HashMap<>();
- private Builder(AppInfo appInfo) {
- this.appInfo = appInfo;
- }
+ public Builder() {}
public GraphLense build(GraphLense previousLense) {
Map<DexField, DexField> fieldMap = fieldMapBuilder.build();
@@ -154,7 +145,6 @@
return previousLense;
}
return new VerticalClassMergerGraphLense(
- appInfo,
fieldMap,
methodMap,
mergedMethodsBuilder.build(),