Towards using DexClassAndMethod in desugaring
Change-Id: I49207ae20080114590ab90fedba49418b699a948
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 70bad80..22a830e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.graph;
import static com.google.common.base.Predicates.alwaysFalse;
+import static com.google.common.base.Predicates.alwaysTrue;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.CompilationError;
@@ -121,6 +122,16 @@
}
}
+ public void forEachClassMethod(Consumer<? super DexClassAndMethod> consumer) {
+ forEachClassMethodMatching(alwaysTrue(), consumer);
+ }
+
+ public void forEachClassMethodMatching(
+ Predicate<DexEncodedMethod> predicate, Consumer<? super DexClassAndMethod> consumer) {
+ methodCollection.forEachMethodMatching(
+ predicate, method -> consumer.accept(DexClassAndMethod.create(this, method)));
+ }
+
@Override
public ClassAccessFlags getAccessFlags() {
return accessFlags;
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
index 0a17134..0446e09 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
@@ -27,11 +27,23 @@
}
}
+ public boolean isDefaultMethod() {
+ return getHolder().isInterface() && getDefinition().isDefaultMethod();
+ }
+
+ public boolean isStructurallyEqualTo(DexClassAndMethod other) {
+ return getDefinition() == other.getDefinition() && getHolder() == other.getHolder();
+ }
+
@Override
public MethodAccessFlags getAccessFlags() {
return getDefinition().getAccessFlags();
}
+ public DexProto getProto() {
+ return getReference().getProto();
+ }
+
@Override
public boolean isMethodTarget() {
return true;
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 4fcd92b..91203c8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -1383,13 +1383,13 @@
}
public static DexEncodedMethod createDesugaringForwardingMethod(
- DexEncodedMethod target, DexClass clazz, DexMethod forwardMethod, DexItemFactory factory) {
- DexMethod method = target.method;
+ DexClassAndMethod target, DexClass clazz, DexMethod forwardMethod, DexItemFactory factory) {
+ DexMethod method = target.getReference();
assert forwardMethod != null;
// New method will have the same name, proto, and also all the flags of the
// default method, including bridge flag.
DexMethod newMethod = factory.createMethod(clazz.type, method.proto, method.name);
- MethodAccessFlags newFlags = target.accessFlags.copy();
+ MethodAccessFlags newFlags = target.getAccessFlags().copy();
// Some debuggers (like IntelliJ) automatically skip synthetic methods on single step.
newFlags.setSynthetic();
newFlags.unsetAbstract();
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
index 33063ba..3dc807c 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -52,10 +52,6 @@
definition.parameterAnnotationsList.collectIndexedItems(indexedItems);
}
- public boolean isStructurallyEqualTo(ProgramMethod other) {
- return getDefinition() == other.getDefinition() && getHolder() == other.getHolder();
- }
-
public void registerCodeReferences(UseRegistry registry) {
Code code = getDefinition().getCode();
if (code != null) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
index 1e3b81f..6200603 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClassAndMember;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
@@ -18,6 +19,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GenericSignature;
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
+import com.android.tools.r8.graph.LibraryMethod;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ProgramMethod;
@@ -25,6 +27,7 @@
import com.android.tools.r8.ir.synthetic.ExceptionThrowingSourceCode;
import com.android.tools.r8.ir.synthetic.SynthesizedCode;
import com.android.tools.r8.position.MethodPosition;
+import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.MethodSignatureEquivalence;
import com.android.tools.r8.utils.WorkList;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
@@ -39,7 +42,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.function.BiConsumer;
import java.util.function.Consumer;
import org.objectweb.asm.Opcodes;
@@ -105,14 +107,14 @@
// List of methods that are known to be forwarded to by a forwarding method at this point in the
// class hierarchy. This set consists of the default interface methods, i.e., the targets of the
// forwarding methods, *not* the forwarding methods themselves.
- final ImmutableList<DexEncodedMethod> forwardedMethodTargets;
+ final ImmutableList<DexClassAndMethod> forwardedMethodTargets;
// If the forwarding methods for the emulated interface methods have not been added yet,
// this contains the information to add it in the subclasses.
final EmulatedInterfaceInfo emulatedInterfaceInfo;
ClassInfo(
ClassInfo parent,
- ImmutableList<DexEncodedMethod> forwardedMethodTargets,
+ ImmutableList<DexClassAndMethod> forwardedMethodTargets,
EmulatedInterfaceInfo emulatedInterfaceInfo) {
this.parent = parent;
this.forwardedMethodTargets = forwardedMethodTargets;
@@ -121,7 +123,7 @@
static ClassInfo create(
ClassInfo parent,
- ImmutableList<DexEncodedMethod> forwardedMethodTargets,
+ ImmutableList<DexClassAndMethod> forwardedMethodTargets,
EmulatedInterfaceInfo emulatedInterfaceInfo) {
return forwardedMethodTargets.isEmpty()
? parent
@@ -132,8 +134,11 @@
return this == EMPTY;
}
- boolean isTargetedByForwards(DexEncodedMethod method) {
- return forwardedMethodTargets.contains(method)
+ boolean isTargetedByForwards(DexClassAndMethod method) {
+ return IterableUtils.any(
+ forwardedMethodTargets,
+ DexClassAndMember::getDefinition,
+ definition -> definition == method.getDefinition())
|| (parent != null && parent.isTargetedByForwards(method));
}
}
@@ -394,7 +399,7 @@
// The computation of a class information and the insertions of forwarding methods.
private ClassInfo computeClassInfo(
DexClass clazz, ClassInfo superInfo, SignaturesInfo signatureInfo) {
- Builder<DexEncodedMethod> additionalForwards = ImmutableList.builder();
+ ImmutableList.Builder<DexClassAndMethod> additionalForwards = ImmutableList.builder();
// First we deal with non-emulated interface desugaring.
resolveForwardingMethods(clazz, superInfo, signatureInfo.signatures, additionalForwards);
// Second we deal with emulated interface, if one method has override in the current class,
@@ -507,7 +512,7 @@
DexClass clazz,
ClassInfo superInfo,
MethodSignatures signatures,
- Builder<DexEncodedMethod> additionalForwards) {
+ Builder<DexClassAndMethod> additionalForwards) {
if (clazz.isProgramClass() && appView.isAlreadyLibraryDesugared(clazz.asProgramClass())) {
return;
}
@@ -515,10 +520,10 @@
resolveForwardForSignature(
clazz,
wrapper.get(),
- (targetHolder, target) -> {
+ target -> {
if (!superInfo.isTargetedByForwards(target)) {
additionalForwards.add(target);
- addForwardingMethod(targetHolder, target, clazz);
+ addForwardingMethod(target, clazz);
}
});
}
@@ -527,7 +532,7 @@
// Looks up a method signature from the point of 'clazz', if it can dispatch to a default method
// the 'addForward' call-back is called with the target of the forward.
private void resolveForwardForSignature(
- DexClass clazz, DexMethod method, BiConsumer<DexClass, DexEncodedMethod> addForward) {
+ DexClass clazz, DexMethod method, Consumer<DexClassAndMethod> addForward) {
// Resolve the default method with base type as the symbolic holder as call sites are not known.
// The dispatch target is then looked up from the possible "instance" class.
// Doing so can cause an invalid invoke to become valid (at runtime resolution at a subtype
@@ -550,54 +555,52 @@
return;
}
- DexEncodedMethod target = virtualDispatchTarget.getDefinition();
- DexClass targetHolder = virtualDispatchTarget.getHolder();
// Don't forward if the target is explicitly marked as 'dont-rewrite'
- if (dontRewrite(targetHolder, target)) {
+ if (dontRewrite(virtualDispatchTarget)) {
return;
}
// If resolution targets a default interface method, forward it.
- if (targetHolder.isInterface() && target.isDefaultMethod()) {
- addForward.accept(targetHolder, target);
+ if (virtualDispatchTarget.isDefaultMethod()) {
+ addForward.accept(virtualDispatchTarget);
return;
}
// Remaining edge cases only pertain to desugaring of library methods.
- DexLibraryClass libraryHolder = targetHolder.asLibraryClass();
- if (libraryHolder == null || ignoreLibraryInfo()) {
+ if (!virtualDispatchTarget.isLibraryMethod() || ignoreLibraryInfo()) {
return;
}
- if (isRetargetMethod(libraryHolder, target)) {
- addForward.accept(targetHolder, target);
+ LibraryMethod libraryMethod = virtualDispatchTarget.asLibraryMethod();
+ if (isRetargetMethod(libraryMethod)) {
+ addForward.accept(virtualDispatchTarget);
return;
}
// If target is a non-interface library class it may be an emulated interface,
// except on a rewritten type, where L8 has already dealt with the desugaring.
- if (!libraryHolder.isInterface()
- && !appView.rewritePrefix.hasRewrittenType(libraryHolder.type, appView)) {
+ if (!libraryMethod.getHolder().isInterface()
+ && !appView.rewritePrefix.hasRewrittenType(libraryMethod.getHolderType(), appView)) {
// Here we use step-3 of resolution to find a maximally specific default interface method.
- DexClassAndMethod result = appInfo.lookupMaximallySpecificMethod(libraryHolder, method);
- if (result != null && rewriter.isEmulatedInterface(result.getHolder().type)) {
- addForward.accept(result.getHolder(), result.getDefinition());
+ DexClassAndMethod result =
+ appInfo.lookupMaximallySpecificMethod(libraryMethod.getHolder(), method);
+ if (result != null && rewriter.isEmulatedInterface(result.getHolderType())) {
+ addForward.accept(result);
}
}
}
- private boolean isRetargetMethod(DexLibraryClass holder, DexEncodedMethod method) {
+ private boolean isRetargetMethod(LibraryMethod method) {
assert needsLibraryInfo();
- assert holder.type == method.getHolderType();
- assert method.isNonPrivateVirtualMethod();
- if (method.isFinal()) {
- return false;
- }
- return appView.options().desugaredLibraryConfiguration.retargetMethod(method, appView) != null;
+ assert method.getDefinition().isNonPrivateVirtualMethod();
+ return !method.getAccessFlags().isFinal()
+ && appView.options().desugaredLibraryConfiguration.retargetMethod(method, appView) != null;
}
- private boolean dontRewrite(DexClass clazz, DexEncodedMethod method) {
- return needsLibraryInfo() && clazz.isLibraryClass() && rewriter.dontRewrite(method.method);
+ private boolean dontRewrite(DexClassAndMethod method) {
+ return needsLibraryInfo()
+ && method.getHolder().isLibraryClass()
+ && rewriter.dontRewrite(method);
}
// Construction of actual forwarding methods.
@@ -630,13 +633,12 @@
// Note: The parameter 'target' may be a public method on a class in case of desugared
// library retargeting (See below target.isInterface check).
- private void addForwardingMethod(DexClass targetHolder, DexEncodedMethod target, DexClass clazz) {
- assert targetHolder != null;
+ private void addForwardingMethod(DexClassAndMethod target, DexClass clazz) {
if (!clazz.isProgramClass()) {
return;
}
- DexEncodedMethod methodOnSelf = clazz.lookupMethod(target.method);
+ DexEncodedMethod methodOnSelf = clazz.lookupMethod(target.getReference());
if (methodOnSelf != null) {
throw new CompilationError(
"Attempt to add forwarding method that conflicts with existing method.",
@@ -645,13 +647,12 @@
new MethodPosition(methodOnSelf.method.asMethodReference()));
}
- DexMethod method = target.method;
// NOTE: Never add a forwarding method to methods of classes unknown or coming from android.jar
// even if this results in invalid code, these classes are never desugared.
// In desugared library, emulated interface methods can be overridden by retarget lib members.
DexMethod forwardMethod =
- targetHolder.isInterface()
- ? rewriter.defaultAsMethodOfCompanionClass(method)
+ target.getHolder().isInterface()
+ ? rewriter.defaultAsMethodOfCompanionClass(target)
: appView.options().desugaredLibraryConfiguration.retargetMethod(target, appView);
DexEncodedMethod desugaringForwardingMethod =
DexEncodedMethod.createDesugaringForwardingMethod(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
index c2b151c..3dc74ac 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
@@ -44,9 +44,10 @@
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.utils.StringDiagnostic;
+import com.android.tools.r8.utils.WorkList;
+import com.android.tools.r8.utils.collections.DexClassAndMethodSet;
import com.android.tools.r8.utils.collections.SortedProgramMethodSet;
import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -73,7 +74,7 @@
// the invoke needs to be rewritten.
private final Map<DexString, List<DexMethod>> nonFinalHolderRewrites = new IdentityHashMap<>();
// Non final virtual library methods requiring generation of emulated dispatch.
- private final Set<DexEncodedMethod> emulatedDispatchMethods = Sets.newIdentityHashSet();
+ private final DexClassAndMethodSet emulatedDispatchMethods = DexClassAndMethodSet.create();
public DesugaredLibraryRetargeter(AppView<?> appView) {
this.appView = appView;
@@ -316,9 +317,6 @@
DexEncodedMethod singleTarget = resolutionResult.getSingleTarget();
assert singleTarget != null;
retarget = getRetargetLibraryMember(singleTarget.method);
- if (retarget == null) {
- return null;
- }
}
return retarget;
}
@@ -356,52 +354,80 @@
DexClass typeClass = appView.definitionFor(inType);
if (typeClass != null) {
DexType newHolder = retargetCoreLibMember.get(methodName).get(inType);
- List<DexEncodedMethod> found = findDexEncodedMethodsWithName(methodName, typeClass);
- for (DexEncodedMethod encodedMethod : found) {
+ List<DexClassAndMethod> found = findMethodsWithName(methodName, typeClass);
+ for (DexClassAndMethod method : found) {
+ DexMethod methodReference = method.getReference();
if (!typeClass.isFinal()) {
- nonFinalHolderRewrites.putIfAbsent(encodedMethod.method.name, new ArrayList<>());
- nonFinalHolderRewrites.get(encodedMethod.method.name).add(encodedMethod.method);
- if (!encodedMethod.isStatic()) {
- if (InterfaceMethodRewriter.isEmulatedInterfaceDispatch(appView, encodedMethod)) {
+ nonFinalHolderRewrites.putIfAbsent(method.getName(), new ArrayList<>());
+ nonFinalHolderRewrites.get(method.getName()).add(methodReference);
+ if (!method.getAccessFlags().isStatic()) {
+ if (isEmulatedInterfaceDispatch(method)) {
// In this case interface method rewriter takes care of it.
continue;
- } else if (!encodedMethod.isFinal()) {
+ } else if (!method.getAccessFlags().isFinal()) {
// Virtual rewrites require emulated dispatch for inheritance.
// The call is rewritten to the dispatch holder class instead.
- handleEmulateDispatch(appView, encodedMethod);
- newHolder = dispatchHolderTypeFor(encodedMethod);
+ handleEmulateDispatch(appView, method);
+ newHolder = dispatchHolderTypeFor(method);
}
}
}
- DexProto proto = encodedMethod.method.proto;
- DexMethod method = appView.dexItemFactory().createMethod(inType, proto, methodName);
- retargetLibraryMember.put(
- method, computeRetargetMethod(method, encodedMethod.isStatic(), newHolder));
+ retargetLibraryMember.put(methodReference, computeRetargetMethod(method, newHolder));
}
}
}
}
}
- private DexMethod computeRetargetMethod(DexMethod method, boolean isStatic, DexType newHolder) {
- DexItemFactory factory = appView.dexItemFactory();
- DexProto newProto = isStatic ? method.proto : factory.prependHolderToProto(method);
- return factory.createMethod(newHolder, newProto, method.name);
+ private boolean isEmulatedInterfaceDispatch(DexClassAndMethod method) {
+ // Answers true if this method is already managed through emulated interface dispatch.
+ Map<DexType, DexType> emulateLibraryInterface =
+ appView.options().desugaredLibraryConfiguration.getEmulateLibraryInterface();
+ if (emulateLibraryInterface.isEmpty()) {
+ return false;
+ }
+ DexMethod methodToFind = method.getReference();
+
+ // Look-up all superclass and interfaces, if an emulated interface is found, and it implements
+ // the method, answers true.
+ WorkList<DexClass> worklist = WorkList.newIdentityWorkList(method.getHolder());
+ while (worklist.hasNext()) {
+ DexClass clazz = worklist.next();
+ if (clazz.isInterface()
+ && emulateLibraryInterface.containsKey(clazz.getType())
+ && clazz.lookupMethod(methodToFind) != null) {
+ return true;
+ }
+ // All super types are library class, or we are doing L8 compilation.
+ clazz.forEachImmediateSupertype(
+ superType -> {
+ DexClass superClass = appView.definitionFor(superType);
+ if (superClass != null) {
+ worklist.addIfNotSeen(superClass);
+ }
+ });
+ }
+ return false;
}
- private List<DexEncodedMethod> findDexEncodedMethodsWithName(
- DexString methodName, DexClass clazz) {
- List<DexEncodedMethod> found = new ArrayList<>();
- for (DexEncodedMethod encodedMethod : clazz.methods()) {
- if (encodedMethod.method.name == methodName) {
- found.add(encodedMethod);
- }
- }
- assert found.size() > 0 : "Should have found a method (library specifications).";
+ private DexMethod computeRetargetMethod(DexClassAndMethod method, DexType newHolder) {
+ DexItemFactory factory = appView.dexItemFactory();
+ DexProto newProto =
+ method.getAccessFlags().isStatic()
+ ? method.getProto()
+ : factory.prependHolderToProto(method.getReference());
+ return factory.createMethod(newHolder, newProto, method.getName());
+ }
+
+ private List<DexClassAndMethod> findMethodsWithName(DexString methodName, DexClass clazz) {
+ List<DexClassAndMethod> found = new ArrayList<>();
+ clazz.forEachClassMethodMatching(
+ definition -> definition.getName() == methodName, found::add);
+ assert !found.isEmpty() : "Should have found a method (library specifications).";
return found;
}
- private void handleEmulateDispatch(AppView<?> appView, DexEncodedMethod method) {
+ private void handleEmulateDispatch(AppView<?> appView, DexClassAndMethod method) {
emulatedDispatchMethods.add(method);
if (!appView.options().isDesugaredLibraryCompilation()) {
// Add rewrite rules so keeps rules are correctly generated in the program.
@@ -437,8 +463,8 @@
private void addInterfacesAndForwardingMethods(
ExecutorService executorService, IRConverter converter) throws ExecutionException {
assert !appView.options().isDesugaredLibraryCompilation();
- Map<DexType, List<DexEncodedMethod>> map = Maps.newIdentityHashMap();
- for (DexEncodedMethod emulatedDispatchMethod : emulatedDispatchMethods) {
+ Map<DexType, List<DexClassAndMethod>> map = Maps.newIdentityHashMap();
+ for (DexClassAndMethod emulatedDispatchMethod : emulatedDispatchMethods) {
map.putIfAbsent(emulatedDispatchMethod.getHolderType(), new ArrayList<>(1));
map.get(emulatedDispatchMethod.getHolderType()).add(emulatedDispatchMethod);
}
@@ -470,7 +496,7 @@
}
private boolean inherit(
- DexLibraryClass clazz, DexType typeToInherit, Set<DexEncodedMethod> retarget) {
+ DexLibraryClass clazz, DexType typeToInherit, DexClassAndMethodSet retarget) {
DexLibraryClass current = clazz;
while (current.type != appView.dexItemFactory().objectType) {
if (current.type == typeToInherit) {
@@ -491,13 +517,13 @@
private void addInterfacesAndForwardingMethods(
DexProgramClass clazz,
- List<DexEncodedMethod> methods,
+ List<DexClassAndMethod> methods,
Consumer<DexEncodedMethod> newForwardingMethodsConsumer) {
// DesugaredLibraryRetargeter emulate dispatch: insertion of a marker interface & forwarding
// methods.
// We cannot use the ClassProcessor since this applies up to 26, while the ClassProcessor
// applies up to 24.
- for (DexEncodedMethod method : methods) {
+ for (DexClassAndMethod method : methods) {
clazz.addExtraInterfaces(
Collections.singletonList(new ClassTypeSignature(dispatchInterfaceTypeFor(method))));
if (clazz.lookupVirtualMethod(method.getReference()) == null) {
@@ -508,7 +534,7 @@
}
}
- private DexEncodedMethod createForwardingMethod(DexEncodedMethod target, DexClass clazz) {
+ private DexEncodedMethod createForwardingMethod(DexClassAndMethod target, DexClass clazz) {
// NOTE: Never add a forwarding method to methods of classes unknown or coming from
// android.jar
// even if this results in invalid code, these classes are never desugared.
@@ -533,7 +559,7 @@
| Constants.ACC_INTERFACE);
ClassAccessFlags holderAccessFlags =
ClassAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC);
- for (DexEncodedMethod emulatedDispatchMethod : emulatedDispatchMethods) {
+ for (DexClassAndMethod emulatedDispatchMethod : emulatedDispatchMethods) {
// Dispatch interface.
DexType interfaceType = dispatchInterfaceTypeFor(emulatedDispatchMethod);
DexEncodedMethod itfMethod =
@@ -560,7 +586,7 @@
}
private DexEncodedMethod generateInterfaceDispatchMethod(
- DexEncodedMethod emulatedDispatchMethod, DexType interfaceType) {
+ DexClassAndMethod emulatedDispatchMethod, DexType interfaceType) {
MethodAccessFlags flags =
MethodAccessFlags.fromSharedAccessFlags(
Constants.ACC_PUBLIC | Constants.ACC_ABSTRACT | Constants.ACC_SYNTHETIC, false);
@@ -582,7 +608,7 @@
}
private DexEncodedMethod generateHolderDispatchMethod(
- DexEncodedMethod emulatedDispatchMethod, DexType dispatchHolder, DexMethod itfMethod) {
+ DexClassAndMethod emulatedDispatchMethod, DexType dispatchHolder, DexMethod itfMethod) {
// The method should look like:
// static foo(rcvr, arg0, arg1) {
// if (rcvr instanceof interfaceType) {
@@ -613,7 +639,7 @@
}
private void reportInvalidLibrarySupertype(
- DexLibraryClass libraryClass, Set<DexEncodedMethod> retarget) {
+ DexLibraryClass libraryClass, DexClassAndMethodSet retarget) {
DexClass dexClass = appView.definitionFor(libraryClass.superType);
String message;
if (dexClass == null) {
@@ -634,15 +660,15 @@
retarget);
}
- private DexType dispatchInterfaceTypeFor(DexEncodedMethod method) {
+ private DexType dispatchInterfaceTypeFor(DexClassAndMethod method) {
return dispatchTypeFor(method, "dispatchInterface");
}
- private DexType dispatchHolderTypeFor(DexEncodedMethod method) {
+ private DexType dispatchHolderTypeFor(DexClassAndMethod method) {
return dispatchTypeFor(method, "dispatchHolder");
}
- private DexType dispatchTypeFor(DexEncodedMethod method, String suffix) {
+ private DexType dispatchTypeFor(DexClassAndMethod method, String suffix) {
String descriptor =
"L"
+ appView
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index 47793a8..18d0352 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -216,18 +216,19 @@
return emulatedInterfaces.get(itf);
}
- private void leavingStaticInvokeToInterface(
- DexProgramClass holder, DexEncodedMethod encodedMethod) {
+ private void leavingStaticInvokeToInterface(ProgramMethod method) {
// When leaving static interface method invokes possibly upgrade the class file
// version, but don't go above the initial class file version. If the input was
// 1.7 or below, this will make a VerificationError on the input a VerificationError
// on the output. If the input was 1.8 or above the runtime behaviour (potential ICCE)
// will remain the same.
- if (holder.hasClassFileVersion()) {
- encodedMethod.upgradeClassFileVersion(
- Ordered.min(CfVersion.V1_8, holder.getInitialClassFileVersion()));
+ if (method.getHolder().hasClassFileVersion()) {
+ method
+ .getDefinition()
+ .upgradeClassFileVersion(
+ Ordered.min(CfVersion.V1_8, method.getHolder().getInitialClassFileVersion()));
} else {
- encodedMethod.upgradeClassFileVersion(CfVersion.V1_8);
+ method.getDefinition().upgradeClassFileVersion(CfVersion.V1_8);
}
}
@@ -235,8 +236,7 @@
// NOTE: can be called for different methods concurrently.
public void rewriteMethodReferences(IRCode code) {
ProgramMethod context = code.context();
- DexEncodedMethod encodedMethod = context.getDefinition();
- if (synthesizedMethods.contains(encodedMethod)) {
+ if (synthesizedMethods.contains(context)) {
return;
}
@@ -252,11 +252,10 @@
// Check that static interface methods are not referenced
// from invoke-custom instructions via method handles.
DexCallSite callSite = instruction.asInvokeCustom().getCallSite();
- reportStaticInterfaceMethodHandle(encodedMethod.method, callSite.bootstrapMethod);
+ reportStaticInterfaceMethodHandle(context, callSite.bootstrapMethod);
for (DexValue arg : callSite.bootstrapArgs) {
if (arg.isDexValueMethodHandle()) {
- reportStaticInterfaceMethodHandle(
- encodedMethod.method, arg.asDexValueMethodHandle().value);
+ reportStaticInterfaceMethodHandle(context, arg.asDexValueMethodHandle().value);
}
}
continue;
@@ -275,9 +274,9 @@
// exception but we can not report it as error since it can also be the intended
// behavior.
if (invokeStatic.getInterfaceBit()) {
- leavingStaticInvokeToInterface(context.getHolder(), encodedMethod);
+ leavingStaticInvokeToInterface(context);
}
- warnMissingType(encodedMethod.method, method.holder);
+ warnMissingType(context, method.holder);
} else if (clazz.isInterface()) {
if (isNonDesugaredLibraryClass(clazz)) {
// NOTE: we intentionally don't desugar static calls into static interface
@@ -302,22 +301,21 @@
.createMethod(
context.getHolder(),
factory,
- syntheticMethodBuilder -> {
- syntheticMethodBuilder
- .setProto(method.proto)
- .setAccessFlags(
- MethodAccessFlags.fromSharedAccessFlags(
- Constants.ACC_PUBLIC
- | Constants.ACC_STATIC
- | Constants.ACC_SYNTHETIC,
- false))
- .setCode(
- m ->
- ForwardMethodBuilder.builder(factory)
- .setStaticTarget(method, true)
- .setStaticSource(m)
- .build());
- });
+ syntheticMethodBuilder ->
+ syntheticMethodBuilder
+ .setProto(method.proto)
+ .setAccessFlags(
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC
+ | Constants.ACC_STATIC
+ | Constants.ACC_SYNTHETIC,
+ false))
+ .setCode(
+ m ->
+ ForwardMethodBuilder.builder(factory)
+ .setStaticTarget(method, true)
+ .setStaticSource(m)
+ .build()));
instructions.replaceCurrentInstruction(
new InvokeStatic(
newProgramMethod.getReference(),
@@ -331,7 +329,7 @@
}
} else {
// When leaving static interface method invokes upgrade the class file version.
- encodedMethod.upgradeClassFileVersion(CfVersion.V1_8);
+ context.getDefinition().upgradeClassFileVersion(CfVersion.V1_8);
}
} else {
instructions.replaceCurrentInstruction(
@@ -341,7 +339,7 @@
} else {
assert !clazz.isInterface();
if (invokeStatic.getInterfaceBit()) {
- leavingStaticInvokeToInterface(context.getHolder(), encodedMethod);
+ leavingStaticInvokeToInterface(context);
}
}
continue;
@@ -355,7 +353,7 @@
// NOTE: leave unchanged those calls to undefined targets. This may lead to runtime
// exception but we can not report it as error since it can also be the intended
// behavior.
- warnMissingType(encodedMethod.method, invokedMethod.holder);
+ warnMissingType(context, invokedMethod.holder);
} else if (clazz.isInterface() && !clazz.isLibraryClass()) {
// NOTE: we intentionally don't desugar super calls into interface methods
// coming from android.jar since it is only possible in case v24+ version
@@ -366,15 +364,13 @@
//
// WARNING: This may result in incorrect code on older platforms!
// Retarget call to an appropriate method of companion class.
- DexMethod amendedMethod =
- amendDefaultMethod(
- appInfo.definitionFor(encodedMethod.getHolderType()), invokedMethod);
+ DexMethod amendedMethod = amendDefaultMethod(context.getHolder(), invokedMethod);
instructions.replaceCurrentInstruction(
new InvokeStatic(defaultAsMethodOfCompanionClass(amendedMethod),
invokeSuper.outValue(), invokeSuper.arguments()));
} else {
- DexType dexType = maximallySpecificEmulatedInterfaceOrNull(invokedMethod);
- if (dexType == null) {
+ DexType emulatedItf = maximallySpecificEmulatedInterfaceOrNull(invokedMethod);
+ if (emulatedItf == null) {
if (clazz.isInterface()
&& appView.rewritePrefix.hasRewrittenType(clazz.type, appView)) {
DexClassAndMethod target =
@@ -411,9 +407,9 @@
superTarget.getReference(), DEFAULT_METHOD_PREFIX, factory);
DexMethod companionMethod =
factory.createMethod(
- getCompanionClassType(dexType),
+ getCompanionClassType(emulatedItf),
factory.protoWithDifferentFirstParameter(
- originalCompanionMethod.proto, dexType),
+ originalCompanionMethod.proto, emulatedItf),
originalCompanionMethod.name);
instructions.replaceCurrentInstruction(
new InvokeStatic(
@@ -436,15 +432,17 @@
continue;
}
- DexClass clazz = appInfo.definitionForHolder(method);
+ DexClass clazz = appInfo.definitionForHolder(method, context);
if (clazz == null) {
// Report missing class since we don't know if it is an interface.
- warnMissingType(encodedMethod.method, method.holder);
+ warnMissingType(context, method.holder);
} else if (clazz.isInterface()) {
if (clazz.isLibraryClass()) {
- throw new CompilationError("Unexpected call to a private method " +
- "defined in library class " + clazz.toSourceString(),
- getMethodOrigin(encodedMethod.method));
+ throw new CompilationError(
+ "Unexpected call to a private method "
+ + "defined in library class "
+ + clazz.toSourceString(),
+ getMethodOrigin(context.getReference()));
}
DexEncodedMethod directTarget = clazz.lookupMethod(method);
if (directTarget != null) {
@@ -487,8 +485,8 @@
if (instruction.isInvokeVirtual() || instruction.isInvokeInterface()) {
InvokeMethod invokeMethod = instruction.asInvokeMethod();
DexMethod invokedMethod = invokeMethod.getInvokedMethod();
- DexType dexType = maximallySpecificEmulatedInterfaceOrNull(invokedMethod);
- if (dexType != null) {
+ DexType emulatedItf = maximallySpecificEmulatedInterfaceOrNull(invokedMethod);
+ if (emulatedItf != null) {
// The call potentially ends up in a library class, in which case we need to rewrite,
// since the code may be in the desugared library.
SingleResolutionResult resolution =
@@ -500,7 +498,7 @@
&& (resolution.getResolvedHolder().isLibraryClass()
|| appView.options().isDesugaredLibraryCompilation())) {
rewriteCurrentInstructionToEmulatedInterfaceCall(
- dexType, invokedMethod, invokeMethod, instructions);
+ emulatedItf, invokedMethod, invokeMethod, instructions);
}
}
}
@@ -547,12 +545,13 @@
DexMethod invokedMethod,
InvokeMethod invokeMethod,
InstructionListIterator instructions) {
- DexEncodedMethod defaultMethod = appView.definitionFor(emulatedItf).lookupMethod(invokedMethod);
- if (defaultMethod != null && !dontRewrite(defaultMethod.method)) {
- assert !defaultMethod.isAbstract();
+ DexClassAndMethod defaultMethod =
+ appView.definitionFor(emulatedItf).lookupClassMethod(invokedMethod);
+ if (defaultMethod != null && !dontRewrite(defaultMethod)) {
+ assert !defaultMethod.getAccessFlags().isAbstract();
instructions.replaceCurrentInstruction(
new InvokeStatic(
- emulateInterfaceLibraryMethod(invokedMethod, emulatedItf, factory),
+ emulateInterfaceLibraryMethod(defaultMethod),
invokeMethod.outValue(),
invokeMethod.arguments()));
}
@@ -570,10 +569,11 @@
return appView.rewritePrefix.hasRewrittenType(clazz.type, appView);
}
- boolean dontRewrite(DexMethod method) {
+ boolean dontRewrite(DexClassAndMethod method) {
for (Pair<DexType, DexString> dontRewrite :
options.desugaredLibraryConfiguration.getDontRewriteInvocation()) {
- if (method.holder == dontRewrite.getFirst() && method.name == dontRewrite.getSecond()) {
+ if (method.getHolderType() == dontRewrite.getFirst()
+ && method.getName() == dontRewrite.getSecond()) {
return true;
}
}
@@ -666,87 +666,82 @@
return false;
}
- private static DexMethod emulateInterfaceLibraryMethod(
- DexMethod method, DexType holder, DexItemFactory factory) {
+ private DexMethod emulateInterfaceLibraryMethod(DexClassAndMethod method) {
return factory.createMethod(
- getEmulateLibraryInterfaceClassType(holder, factory),
- factory.prependTypeToProto(holder, method.proto),
- factory.createString(method.name.toString()));
+ getEmulateLibraryInterfaceClassType(method.getHolderType(), factory),
+ factory.prependTypeToProto(method.getHolderType(), method.getProto()),
+ method.getName());
}
private DexProgramClass synthesizeEmulateInterfaceLibraryClass(
DexProgramClass theInterface, Map<DexType, List<DexType>> emulatedInterfacesHierarchy) {
List<DexEncodedMethod> emulationMethods = new ArrayList<>();
- for (DexEncodedMethod method : theInterface.methods()) {
- if (method.isDefaultMethod()) {
- DexMethod libraryMethod =
- factory.createMethod(
- emulatedInterfaces.get(theInterface.type), method.method.proto, method.method.name);
- DexMethod originalCompanionMethod =
- method.isStatic()
- ? staticAsMethodOfCompanionClass(method.method)
- : instanceAsMethodOfCompanionClass(method.method, DEFAULT_METHOD_PREFIX, factory);
- DexMethod companionMethod =
- factory.createMethod(
- getCompanionClassType(theInterface.type),
- originalCompanionMethod.proto,
- originalCompanionMethod.name);
+ theInterface.forEachProgramMethodMatching(
+ DexEncodedMethod::isDefaultMethod,
+ method -> {
+ DexMethod libraryMethod =
+ method.getReference().withHolder(emulatedInterfaces.get(theInterface.type), factory);
+ DexMethod companionMethod =
+ method.getAccessFlags().isStatic()
+ ? staticAsMethodOfCompanionClass(method)
+ : defaultAsMethodOfCompanionClass(method);
- // To properly emulate the library interface call, we need to compute the interfaces
- // inheriting from the interface and manually implement the dispatch with instance of.
- // The list guarantees that an interface is always after interfaces it extends,
- // hence reverse iteration.
- List<DexType> subInterfaces = emulatedInterfacesHierarchy.get(theInterface.type);
- List<Pair<DexType, DexMethod>> extraDispatchCases = new ArrayList<>();
- // In practice, there is usually a single case (except for tests),
- // so we do not bother to make the following loop more clever.
- Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
- options.desugaredLibraryConfiguration.getRetargetCoreLibMember();
- for (DexString methodName : retargetCoreLibMember.keySet()) {
- if (method.method.name == methodName) {
- for (DexType inType : retargetCoreLibMember.get(methodName).keySet()) {
- DexClass inClass = appView.definitionFor(inType);
- if (inClass != null && implementsInterface(inClass, theInterface.type)) {
- extraDispatchCases.add(
- new Pair<>(
- inType,
- factory.createMethod(
- retargetCoreLibMember.get(methodName).get(inType),
- factory.protoWithDifferentFirstParameter(
- originalCompanionMethod.proto, inType),
- method.method.name)));
+ // To properly emulate the library interface call, we need to compute the interfaces
+ // inheriting from the interface and manually implement the dispatch with instance of.
+ // The list guarantees that an interface is always after interfaces it extends,
+ // hence reverse iteration.
+ List<DexType> subInterfaces = emulatedInterfacesHierarchy.get(theInterface.type);
+ List<Pair<DexType, DexMethod>> extraDispatchCases = new ArrayList<>();
+ // In practice, there is usually a single case (except for tests),
+ // so we do not bother to make the following loop more clever.
+ Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
+ options.desugaredLibraryConfiguration.getRetargetCoreLibMember();
+ for (DexString methodName : retargetCoreLibMember.keySet()) {
+ if (method.getName() == methodName) {
+ for (DexType inType : retargetCoreLibMember.get(methodName).keySet()) {
+ DexClass inClass = appView.definitionFor(inType);
+ if (inClass != null && implementsInterface(inClass, theInterface.type)) {
+ extraDispatchCases.add(
+ new Pair<>(
+ inType,
+ factory.createMethod(
+ retargetCoreLibMember.get(methodName).get(inType),
+ factory.protoWithDifferentFirstParameter(
+ companionMethod.proto, inType),
+ method.getName())));
+ }
}
}
}
- }
- if (subInterfaces != null) {
- for (int i = subInterfaces.size() - 1; i >= 0; i--) {
- DexClass subInterfaceClass = appView.definitionFor(subInterfaces.get(i));
- assert subInterfaceClass != null; // Else computation of subInterface would have failed.
- // if the method is implemented, extra dispatch is required.
- DexEncodedMethod result = subInterfaceClass.lookupVirtualMethod(method.method);
- if (result != null && !result.isAbstract()) {
- extraDispatchCases.add(
- new Pair<>(
- subInterfaceClass.type,
- factory.createMethod(
- getCompanionClassType(subInterfaceClass.type),
- factory.protoWithDifferentFirstParameter(
- originalCompanionMethod.proto, subInterfaceClass.type),
- originalCompanionMethod.name)));
+ if (subInterfaces != null) {
+ for (int i = subInterfaces.size() - 1; i >= 0; i--) {
+ DexClass subInterfaceClass = appView.definitionFor(subInterfaces.get(i));
+ assert subInterfaceClass
+ != null; // Else computation of subInterface would have failed.
+ // if the method is implemented, extra dispatch is required.
+ DexEncodedMethod result =
+ subInterfaceClass.lookupVirtualMethod(method.getReference());
+ if (result != null && !result.isAbstract()) {
+ extraDispatchCases.add(
+ new Pair<>(
+ subInterfaceClass.type,
+ factory.createMethod(
+ getCompanionClassType(subInterfaceClass.type),
+ factory.protoWithDifferentFirstParameter(
+ companionMethod.proto, subInterfaceClass.type),
+ companionMethod.name)));
+ }
}
}
- }
- emulationMethods.add(
- DexEncodedMethod.toEmulateDispatchLibraryMethod(
- method.getHolderType(),
- emulateInterfaceLibraryMethod(method.method, method.getHolderType(), factory),
- companionMethod,
- libraryMethod,
- extraDispatchCases,
- appView));
- }
- }
+ emulationMethods.add(
+ DexEncodedMethod.toEmulateDispatchLibraryMethod(
+ method.getHolderType(),
+ emulateInterfaceLibraryMethod(method),
+ companionMethod,
+ libraryMethod,
+ extraDispatchCases,
+ appView));
+ });
if (emulationMethods.isEmpty()) {
return null;
}
@@ -799,17 +794,17 @@
return factory.createSynthesizedType(elTypeDescriptor);
}
- private void reportStaticInterfaceMethodHandle(DexMethod referencedFrom, DexMethodHandle handle) {
+ private void reportStaticInterfaceMethodHandle(ProgramMethod context, DexMethodHandle handle) {
if (handle.type.isInvokeStatic()) {
DexClass holderClass = appView.definitionFor(handle.asMethod().holder);
// NOTE: If the class definition is missing we can't check. Let it be handled as any other
// missing call target.
if (holderClass == null) {
- warnMissingType(referencedFrom, handle.asMethod().holder);
+ warnMissingType(context, handle.asMethod().holder);
} else if (holderClass.isInterface()) {
throw new Unimplemented(
"Desugaring of static interface method handle in `"
- + referencedFrom.toSourceString()
+ + context.toSourceString()
+ "` is not yet supported.");
}
}
@@ -864,6 +859,10 @@
}
// Represent a static interface method as a method of companion class.
+ final DexMethod staticAsMethodOfCompanionClass(DexClassAndMethod method) {
+ return staticAsMethodOfCompanionClass(method.getReference());
+ }
+
final DexMethod staticAsMethodOfCompanionClass(DexMethod method) {
// No changes for static methods.
return factory.createMethod(getCompanionClassType(method.holder), method.proto, method.name);
@@ -913,6 +912,10 @@
return defaultAsMethodOfCompanionClass(method, factory);
}
+ DexMethod defaultAsMethodOfCompanionClass(DexClassAndMethod method) {
+ return defaultAsMethodOfCompanionClass(method.getReference(), factory);
+ }
+
// Represent a private instance interface method as a method of companion class.
static DexMethod privateAsMethodOfCompanionClass(DexMethod method, DexItemFactory factory) {
// Add an implicit argument to represent the receiver.
@@ -1135,37 +1138,6 @@
return true;
}
- public static boolean isEmulatedInterfaceDispatch(AppView<?> appView, DexEncodedMethod method) {
- // Answers true if this method is already managed through emulated interface dispatch.
- Map<DexType, DexType> emulateLibraryInterface =
- appView.options().desugaredLibraryConfiguration.getEmulateLibraryInterface();
- if (emulateLibraryInterface.isEmpty()) {
- return false;
- }
- DexMethod methodToFind = method.method;
-
- // Look-up all superclass and interfaces, if an emulated interface is found, and it implements
- // the method, answers true.
- LinkedList<DexType> workList = new LinkedList<>();
- workList.add(methodToFind.holder);
- while (!workList.isEmpty()) {
- DexType dexType = workList.removeFirst();
- DexClass dexClass = appView.definitionFor(dexType);
- assert dexClass != null; // It is a library class, or we are doing L8 compilation.
- if (dexClass.isInterface() && emulateLibraryInterface.containsKey(dexType)) {
- DexEncodedMethod dexEncodedMethod = dexClass.lookupMethod(methodToFind);
- if (dexEncodedMethod != null) {
- return true;
- }
- }
- Collections.addAll(workList, dexClass.interfaces.values);
- if (dexClass.superType != appView.dexItemFactory().objectType) {
- workList.add(dexClass.superType);
- }
- }
- return false;
- }
-
private boolean shouldIgnoreFromReports(DexType missing) {
return appView.rewritePrefix.hasRewrittenType(missing, appView)
|| missing.isD8R8SynthesizedClassType()
@@ -1187,13 +1159,13 @@
options.warningMissingInterfaceForDesugar(classToDesugar, implementing, missing);
}
- private void warnMissingType(DexMethod referencedFrom, DexType missing) {
+ private void warnMissingType(ProgramMethod context, DexType missing) {
// Companion/Emulated interface/Conversion classes for desugared library won't be missing,
// they are in the desugared library.
if (shouldIgnoreFromReports(missing)) {
return;
}
- DexMethod method = appView.graphLens().getOriginalMethodSignature(referencedFrom);
+ DexMethod method = appView.graphLens().getOriginalMethodSignature(context.getReference());
Origin origin = getMethodOrigin(method);
MethodPosition position = new MethodPosition(method.asMethodReference());
options.warningMissingTypeForDesugar(origin, position, missing, method);
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 985090a..db914a4 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -63,12 +63,15 @@
import com.android.tools.r8.shaking.ProguardConfigurationRule;
import com.android.tools.r8.utils.IROrdering.IdentityIROrdering;
import com.android.tools.r8.utils.IROrdering.NondeterministicIROrdering;
+import com.android.tools.r8.utils.collections.DexClassAndMethodSet;
import com.android.tools.r8.utils.collections.SortedProgramMethodSet;
import com.android.tools.r8.utils.structural.Ordered;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Equivalence.Wrapper;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.io.IOException;
import java.io.PrintStream;
@@ -990,7 +993,7 @@
DexType libraryType,
DexType invalidSuperType,
String message,
- Set<DexEncodedMethod> retarget) {
+ DexClassAndMethodSet retarget) {
if (invalidLibraryClasses.add(invalidSuperType)) {
reporter.warning(
new InvalidLibrarySuperclassDiagnostic(
@@ -998,7 +1001,9 @@
Reference.classFromDescriptor(libraryType.toDescriptorString()),
Reference.classFromDescriptor(invalidSuperType.toDescriptorString()),
message,
- ListUtils.map(retarget, method -> method.getReference().asMethodReference())));
+ Lists.newArrayList(
+ Iterables.transform(
+ retarget, method -> method.getReference().asMethodReference()))));
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/IterableUtils.java b/src/main/java/com/android/tools/r8/utils/IterableUtils.java
index ebbef95..cd1c0a0 100644
--- a/src/main/java/com/android/tools/r8/utils/IterableUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/IterableUtils.java
@@ -15,6 +15,16 @@
public class IterableUtils {
+ public static <S, T> boolean any(
+ Iterable<S> iterable, Function<S, T> transform, Predicate<T> predicate) {
+ for (S element : iterable) {
+ if (predicate.test(transform.apply(element))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public static <T> Iterable<T> append(Iterable<T> iterable, T element) {
return Iterables.concat(iterable, singleton(element));
}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMethodSet.java b/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMethodSet.java
new file mode 100644
index 0000000..ad7c3fe
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMethodSet.java
@@ -0,0 +1,66 @@
+// 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.utils.collections;
+
+import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.google.common.collect.ImmutableMap;
+import java.util.IdentityHashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Supplier;
+
+public class DexClassAndMethodSet extends DexClassAndMethodSetBase<DexClassAndMethod> {
+
+ private static final DexClassAndMethodSet EMPTY = new DexClassAndMethodSet(ImmutableMap::of);
+
+ protected DexClassAndMethodSet(
+ Supplier<? extends Map<DexMethod, DexClassAndMethod>> backingFactory) {
+ super(backingFactory);
+ }
+
+ protected DexClassAndMethodSet(
+ Supplier<? extends Map<DexMethod, DexClassAndMethod>> backingFactory,
+ Map<DexMethod, DexClassAndMethod> backing) {
+ super(backingFactory, backing);
+ }
+
+ public static DexClassAndMethodSet create() {
+ return new DexClassAndMethodSet(IdentityHashMap::new);
+ }
+
+ public static DexClassAndMethodSet create(int capacity) {
+ return new DexClassAndMethodSet(IdentityHashMap::new, new IdentityHashMap<>(capacity));
+ }
+
+ public static DexClassAndMethodSet create(DexClassAndMethod element) {
+ DexClassAndMethodSet result = create();
+ result.add(element);
+ return result;
+ }
+
+ public static DexClassAndMethodSet create(DexClassAndMethodSet methodSet) {
+ DexClassAndMethodSet newMethodSet = create();
+ newMethodSet.addAll(methodSet);
+ return newMethodSet;
+ }
+
+ public static DexClassAndMethodSet createConcurrent() {
+ return new DexClassAndMethodSet(ConcurrentHashMap::new);
+ }
+
+ public static DexClassAndMethodSet createLinked() {
+ return new DexClassAndMethodSet(LinkedHashMap::new);
+ }
+
+ public static DexClassAndMethodSet empty() {
+ return EMPTY;
+ }
+
+ public void addAll(DexClassAndMethodSet methods) {
+ backing.putAll(methods.backing);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMethodSetBase.java b/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMethodSetBase.java
new file mode 100644
index 0000000..797d8b6
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/DexClassAndMethodSetBase.java
@@ -0,0 +1,87 @@
+// 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.utils.collections;
+
+import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.google.common.collect.Sets;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+public abstract class DexClassAndMethodSetBase<T extends DexClassAndMethod> implements Iterable<T> {
+
+ protected final Map<DexMethod, T> backing;
+ protected final Supplier<? extends Map<DexMethod, T>> backingFactory;
+
+ protected DexClassAndMethodSetBase(Supplier<? extends Map<DexMethod, T>> backingFactory) {
+ this(backingFactory, backingFactory.get());
+ }
+
+ protected DexClassAndMethodSetBase(
+ Supplier<? extends Map<DexMethod, T>> backingFactory, Map<DexMethod, T> backing) {
+ this.backing = backing;
+ this.backingFactory = backingFactory;
+ }
+
+ public boolean add(T method) {
+ T existing = backing.put(method.getReference(), method);
+ assert existing == null || existing.isStructurallyEqualTo(method);
+ return existing == null;
+ }
+
+ public void addAll(Iterable<T> methods) {
+ methods.forEach(this::add);
+ }
+
+ public boolean contains(DexEncodedMethod method) {
+ return backing.containsKey(method.getReference());
+ }
+
+ public boolean contains(T method) {
+ return backing.containsKey(method.getReference());
+ }
+
+ public void clear() {
+ backing.clear();
+ }
+
+ public boolean isEmpty() {
+ return backing.isEmpty();
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return backing.values().iterator();
+ }
+
+ public boolean remove(DexMethod method) {
+ T existing = backing.remove(method);
+ return existing != null;
+ }
+
+ public boolean remove(DexEncodedMethod method) {
+ return remove(method.getReference());
+ }
+
+ public int size() {
+ return backing.size();
+ }
+
+ public Stream<T> stream() {
+ return backing.values().stream();
+ }
+
+ public Set<DexEncodedMethod> toDefinitionSet() {
+ assert backing instanceof IdentityHashMap;
+ Set<DexEncodedMethod> definitions = Sets.newIdentityHashSet();
+ forEach(method -> definitions.add(method.getDefinition()));
+ return definitions;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java b/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java
index f058bf1..d36d207 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java
@@ -11,32 +11,24 @@
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Sets;
import java.util.IdentityHashMap;
-import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
-import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
-import java.util.stream.Stream;
-public class ProgramMethodSet implements Iterable<ProgramMethod> {
+public class ProgramMethodSet extends DexClassAndMethodSetBase<ProgramMethod> {
private static final ProgramMethodSet EMPTY = new ProgramMethodSet(ImmutableMap::of);
- private final Map<DexMethod, ProgramMethod> backing;
- private final Supplier<? extends Map<DexMethod, ProgramMethod>> backingFactory;
-
protected ProgramMethodSet(Supplier<? extends Map<DexMethod, ProgramMethod>> backingFactory) {
- this(backingFactory, backingFactory.get());
+ super(backingFactory);
}
protected ProgramMethodSet(
Supplier<? extends Map<DexMethod, ProgramMethod>> backingFactory,
Map<DexMethod, ProgramMethod> backing) {
- this.backing = backing;
- this.backingFactory = backingFactory;
+ super(backingFactory, backing);
}
public static ProgramMethodSet create() {
@@ -71,16 +63,6 @@
return EMPTY;
}
- public boolean add(ProgramMethod method) {
- ProgramMethod existing = backing.put(method.getReference(), method);
- assert existing == null || existing.isStructurallyEqualTo(method);
- return existing == null;
- }
-
- public void addAll(Iterable<ProgramMethod> methods) {
- methods.forEach(this::add);
- }
-
public void addAll(ProgramMethodSet methods) {
backing.putAll(methods.backing);
}
@@ -89,36 +71,6 @@
return add(new ProgramMethod(clazz, definition));
}
- public boolean contains(DexEncodedMethod method) {
- return backing.containsKey(method.getReference());
- }
-
- public boolean contains(ProgramMethod method) {
- return backing.containsKey(method.getReference());
- }
-
- public void clear() {
- backing.clear();
- }
-
- public boolean isEmpty() {
- return backing.isEmpty();
- }
-
- @Override
- public Iterator<ProgramMethod> iterator() {
- return backing.values().iterator();
- }
-
- public boolean remove(DexMethod method) {
- ProgramMethod existing = backing.remove(method);
- return existing != null;
- }
-
- public boolean remove(DexEncodedMethod method) {
- return remove(method.getReference());
- }
-
public ProgramMethodSet rewrittenWithLens(DexDefinitionSupplier definitions, GraphLens lens) {
ProgramMethodSet rewritten = new ProgramMethodSet(backingFactory);
forEach(
@@ -130,19 +82,4 @@
});
return rewritten;
}
-
- public int size() {
- return backing.size();
- }
-
- public Stream<ProgramMethod> stream() {
- return backing.values().stream();
- }
-
- public Set<DexEncodedMethod> toDefinitionSet() {
- assert backing instanceof IdentityHashMap;
- Set<DexEncodedMethod> definitions = Sets.newIdentityHashSet();
- forEach(method -> definitions.add(method.getDefinition()));
- return definitions;
- }
}
diff --git a/tools/run_on_app_dump.py b/tools/run_on_app_dump.py
index fd57fad..c4de6e3 100755
--- a/tools/run_on_app_dump.py
+++ b/tools/run_on_app_dump.py
@@ -5,6 +5,7 @@
import adb
import apk_masseur
+import as_utils
import compiledump
import gradle
import optparse