Merge commit '7adcff87c841d7b0c5df48a4a75180d3b9631666' into dev-release
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index e6cc1f5..a6f1b9c 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -45,8 +45,8 @@
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
import com.android.tools.r8.ir.desugar.DesugaredLibraryRetargeter;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
import com.android.tools.r8.ir.desugar.RecordRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.ir.optimize.AssertionsRewriter;
import com.android.tools.r8.ir.optimize.MethodPoolCollection;
import com.android.tools.r8.ir.optimize.NestReducer;
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index 5d62aae..ab55c16 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.MainDexInfo;
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLens.java b/src/main/java/com/android/tools/r8/graph/GraphLens.java
index 610208f..88c0bc7 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLens.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.desugar.InterfaceProcessor.InterfaceProcessorNestedGraphLens;
+import com.android.tools.r8.ir.desugar.itf.InterfaceProcessor.InterfaceProcessorNestedGraphLens;
import com.android.tools.r8.shaking.KeepInfoCollection;
import com.android.tools.r8.utils.Action;
import com.android.tools.r8.utils.IterableUtils;
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 0530046..5a9ee16 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
@@ -3,8 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.conversion;
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor.ExcludeDexResources;
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor.IncludeAllResources;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor.ExcludeDexResources;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor.IncludeAllResources;
import static com.android.tools.r8.ir.desugar.lambda.D8LambdaDesugaring.rewriteEnclosingLambdaMethodAttributes;
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
@@ -51,8 +51,8 @@
import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter;
import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter.Mode;
import com.android.tools.r8.ir.desugar.DesugaredLibraryRetargeter;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor;
import com.android.tools.r8.ir.desugar.lambda.LambdaDeserializationMethodRemover;
import com.android.tools.r8.ir.desugar.nest.D8NestBasedAccessDesugaring;
import com.android.tools.r8.ir.optimize.AssertionsRewriter;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/NeedsIRDesugarUseRegistry.java b/src/main/java/com/android/tools/r8/ir/conversion/NeedsIRDesugarUseRegistry.java
index 9877f8d..750ffb4 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/NeedsIRDesugarUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/NeedsIRDesugarUseRegistry.java
@@ -19,7 +19,7 @@
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter;
import com.android.tools.r8.ir.desugar.DesugaredLibraryRetargeter;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
class NeedsIRDesugarUseRegistry extends UseRegistry {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
similarity index 97%
rename from src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
rename to src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
index 6ef420d..9d9a502 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
@@ -1,13 +1,14 @@
-// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2021, 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.ir.desugar;
+package com.android.tools.r8.ir.desugar.itf;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexAnnotationSet;
+import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassAndMember;
import com.android.tools.r8.graph.DexClassAndMethod;
@@ -22,7 +23,6 @@
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;
import com.android.tools.r8.graph.ResolutionResult;
import com.android.tools.r8.ir.synthetic.ExceptionThrowingSourceCode;
import com.android.tools.r8.ir.synthetic.SynthesizedCode;
@@ -55,7 +55,7 @@
* In other words, the traversal is in top-down (edges from type to its subtypes) topological order.
* The traversal is lazy, starting from the unordered set of program classes.
*/
-final class ClassProcessor {
+final class ClassProcessor implements InterfaceDesugaringProcessor {
// Collection for method signatures that may cause forwarding methods to be created.
private static class MethodSignatures {
@@ -336,7 +336,6 @@
private final AppView<?> appView;
private final DexItemFactory dexItemFactory;
private final InterfaceMethodRewriter rewriter;
- private final Consumer<ProgramMethod> newSynthesizedMethodConsumer;
private final MethodSignatureEquivalence equivalence = MethodSignatureEquivalence.get();
private final boolean needsLibraryInfo;
@@ -353,14 +352,10 @@
private final Map<DexProgramClass, ProgramMethodSet> newSyntheticMethods =
new IdentityHashMap<>();
- ClassProcessor(
- AppView<?> appView,
- InterfaceMethodRewriter rewriter,
- Consumer<ProgramMethod> newSynthesizedMethodConsumer) {
+ ClassProcessor(AppView<?> appView, InterfaceMethodRewriter rewriter) {
this.appView = appView;
this.dexItemFactory = appView.dexItemFactory();
this.rewriter = rewriter;
- this.newSynthesizedMethodConsumer = newSynthesizedMethodConsumer;
needsLibraryInfo =
!appView.options().desugaredLibraryConfiguration.getEmulateLibraryInterface().isEmpty()
|| !appView
@@ -378,15 +373,25 @@
return !needsLibraryInfo;
}
- public void processClass(DexProgramClass clazz) {
+ @Override
+ public void process(DexProgramClass clazz, ProgramMethodSet synthesizedMethods) {
visitClassInfo(clazz, new ReportingContext(clazz, clazz));
}
- final void addSyntheticMethods() {
+ @Override
+ public boolean shouldProcess(DexProgramClass clazz) {
+ return !clazz.isInterface();
+ }
+
+ // We introduce forwarding methods only once all desugaring has been performed to avoid
+ // confusing the look-up with inserted forwarding methods.
+ @Override
+ public final void finalizeProcessing(
+ DexApplication.Builder<?> builder, ProgramMethodSet synthesizedMethods) {
newSyntheticMethods.forEach(
(clazz, newForwardingMethods) -> {
clazz.addVirtualMethods(newForwardingMethods.toDefinitionSet());
- newForwardingMethods.forEach(newSynthesizedMethodConsumer);
+ newForwardingMethods.forEach(synthesizedMethods::add);
});
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DefaultMethodsHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/DefaultMethodsHelper.java
similarity index 92%
rename from src/main/java/com/android/tools/r8/ir/desugar/DefaultMethodsHelper.java
rename to src/main/java/com/android/tools/r8/ir/desugar/itf/DefaultMethodsHelper.java
index 838374d..717f235 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DefaultMethodsHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/DefaultMethodsHelper.java
@@ -1,8 +1,8 @@
-// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2021, 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.ir.desugar;
+package com.android.tools.r8.ir.desugar.itf;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
@@ -25,7 +25,7 @@
// and hidden default interface methods in this interface's hierarchy.
//
// Note that it is assumes that these lists should never be big.
- final static class Collection {
+ static final class Collection {
static final Collection EMPTY =
new Collection(Collections.emptyList(), Collections.emptyList());
@@ -79,7 +79,8 @@
// Create default interface collection based on collected information.
final Collection wrapInCollection() {
candidates.removeAll(hidden);
- return (candidates.isEmpty() && hidden.isEmpty()) ? Collection.EMPTY
+ return (candidates.isEmpty() && hidden.isEmpty())
+ ? Collection.EMPTY
: new Collection(Lists.newArrayList(candidates), Lists.newArrayList(hidden));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java
new file mode 100644
index 0000000..559172a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java
@@ -0,0 +1,375 @@
+// Copyright (c) 2021, 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.ir.desugar.itf;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ClassAccessFlags;
+import com.android.tools.r8.graph.DexAnnotationSet;
+import com.android.tools.r8.graph.DexApplication.Builder;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.graph.GenericSignature;
+import com.android.tools.r8.graph.GenericSignature.ClassSignature;
+import com.android.tools.r8.origin.SynthesizedOrigin;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.IterableUtils;
+import com.android.tools.r8.utils.Pair;
+import com.android.tools.r8.utils.StringDiagnostic;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public final class EmulatedInterfaceProcessor implements InterfaceDesugaringProcessor {
+ private final AppView<?> appView;
+ private final InterfaceMethodRewriter rewriter;
+ private final Map<DexType, DexType> emulatedInterfaces;
+ private final Map<DexType, List<DexType>> emulatedInterfacesHierarchy;
+ // All created emulated interface classes indexed by emulated interface type.
+ final Map<DexProgramClass, DexProgramClass> syntheticClasses = new IdentityHashMap<>();
+
+ EmulatedInterfaceProcessor(AppView<?> appView, InterfaceMethodRewriter rewriter) {
+ this.appView = appView;
+ this.rewriter = rewriter;
+ emulatedInterfaces =
+ appView.options().desugaredLibraryConfiguration.getEmulateLibraryInterface();
+ // Avoid the computation outside L8 since it is not needed.
+ emulatedInterfacesHierarchy =
+ appView.options().isDesugaredLibraryCompilation()
+ ? processEmulatedInterfaceHierarchy()
+ : Collections.emptyMap();
+ }
+
+ private Map<DexType, List<DexType>> processEmulatedInterfaceHierarchy() {
+ Map<DexType, List<DexType>> emulatedInterfacesHierarchy = new IdentityHashMap<>();
+ Set<DexType> processed = Sets.newIdentityHashSet();
+ ArrayList<DexType> emulatedInterfacesSorted = new ArrayList<>(emulatedInterfaces.keySet());
+ emulatedInterfacesSorted.sort(DexType::compareTo);
+ for (DexType interfaceType : emulatedInterfacesSorted) {
+ processEmulatedInterfaceHierarchy(interfaceType, processed, emulatedInterfacesHierarchy);
+ }
+ return emulatedInterfacesHierarchy;
+ }
+
+ private void processEmulatedInterfaceHierarchy(
+ DexType interfaceType,
+ Set<DexType> processed,
+ Map<DexType, List<DexType>> emulatedInterfacesHierarchy) {
+ if (processed.contains(interfaceType)) {
+ return;
+ }
+ emulatedInterfacesHierarchy.put(interfaceType, new ArrayList<>());
+ processed.add(interfaceType);
+ DexClass theInterface = appView.definitionFor(interfaceType);
+ if (theInterface == null) {
+ return;
+ }
+ LinkedList<DexType> workList = new LinkedList<>(Arrays.asList(theInterface.interfaces.values));
+ while (!workList.isEmpty()) {
+ DexType next = workList.removeLast();
+ if (emulatedInterfaces.containsKey(next)) {
+ processEmulatedInterfaceHierarchy(next, processed, emulatedInterfacesHierarchy);
+ emulatedInterfacesHierarchy.get(next).add(interfaceType);
+ DexClass nextClass = appView.definitionFor(next);
+ if (nextClass != null) {
+ workList.addAll(Arrays.asList(nextClass.interfaces.values));
+ }
+ }
+ }
+ }
+
+ // The method transforms emulated interface such as they implement the rewritten version
+ // of each emulated interface they implement. Such change should have no effect on the look-up
+ // results, since each class implementing an emulated interface should also implement the
+ // rewritten one.
+ private void replaceInterfacesInEmulatedInterface(DexProgramClass emulatedInterface) {
+ List<GenericSignature.ClassTypeSignature> newInterfaces = new ArrayList<>();
+ ClassSignature classSignature = emulatedInterface.getClassSignature();
+ for (int i = 0; i < emulatedInterface.interfaces.size(); i++) {
+ DexType itf = emulatedInterface.interfaces.values[i];
+ if (emulatedInterfaces.containsKey(itf)) {
+ List<GenericSignature.FieldTypeSignature> typeArguments;
+ if (classSignature == null) {
+ typeArguments = Collections.emptyList();
+ } else {
+ GenericSignature.ClassTypeSignature classTypeSignature =
+ classSignature.superInterfaceSignatures().get(i);
+ assert itf == classTypeSignature.type();
+ typeArguments = classTypeSignature.typeArguments();
+ }
+ newInterfaces.add(
+ new GenericSignature.ClassTypeSignature(emulatedInterfaces.get(itf), typeArguments));
+ }
+ }
+ emulatedInterface.replaceInterfaces(newInterfaces);
+ }
+
+ private void renameEmulatedInterface(DexProgramClass emulatedInterface) {
+ DexType newType = emulatedInterfaces.get(emulatedInterface.type);
+ assert newType != null;
+ emulatedInterface.type = newType;
+ emulatedInterface.setVirtualMethods(renameHolder(emulatedInterface.virtualMethods(), newType));
+ emulatedInterface.setDirectMethods(renameHolder(emulatedInterface.directMethods(), newType));
+ }
+
+ private DexEncodedMethod[] renameHolder(Iterable<DexEncodedMethod> methods, DexType newName) {
+ List<DexEncodedMethod> methods1 = IterableUtils.toNewArrayList(methods);
+ DexEncodedMethod[] newMethods = new DexEncodedMethod[methods1.size()];
+ for (int i = 0; i < newMethods.length; i++) {
+ newMethods[i] = methods1.get(i).toRenamedHolderMethod(newName, appView.dexItemFactory());
+ }
+ return newMethods;
+ }
+
+ void generateEmulateInterfaceLibrary(DexProgramClass emulatedInterface) {
+ assert rewriter.isEmulatedInterface(emulatedInterface.type);
+ DexProgramClass theProgramInterface = emulatedInterface.asProgramClass();
+ DexProgramClass synthesizedClass = synthesizeEmulateInterfaceLibraryClass(theProgramInterface);
+ if (synthesizedClass != null) {
+ syntheticClasses.put(emulatedInterface, synthesizedClass);
+ }
+ }
+
+ private DexProgramClass synthesizeEmulateInterfaceLibraryClass(DexProgramClass theInterface) {
+ List<DexEncodedMethod> emulationMethods = new ArrayList<>();
+ theInterface.forEachProgramMethodMatching(
+ DexEncodedMethod::isDefaultMethod,
+ method -> {
+ DexMethod libraryMethod =
+ method
+ .getReference()
+ .withHolder(emulatedInterfaces.get(theInterface.type), appView.dexItemFactory());
+ DexMethod companionMethod =
+ method.getAccessFlags().isStatic()
+ ? rewriter.staticAsMethodOfCompanionClass(method)
+ : rewriter.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 =
+ appView.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,
+ appView
+ .dexItemFactory()
+ .createMethod(
+ retargetCoreLibMember.get(methodName).get(inType),
+ appView
+ .dexItemFactory()
+ .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.getReference());
+ if (result != null && !result.isAbstract()) {
+ extraDispatchCases.add(
+ new Pair<>(
+ subInterfaceClass.type,
+ appView
+ .dexItemFactory()
+ .createMethod(
+ rewriter.getCompanionClassType(subInterfaceClass.type),
+ appView
+ .dexItemFactory()
+ .protoWithDifferentFirstParameter(
+ companionMethod.proto, subInterfaceClass.type),
+ companionMethod.name)));
+ }
+ }
+ }
+ emulationMethods.add(
+ DexEncodedMethod.toEmulateDispatchLibraryMethod(
+ method.getHolderType(),
+ rewriter.emulateInterfaceLibraryMethod(method),
+ companionMethod,
+ libraryMethod,
+ extraDispatchCases,
+ appView));
+ });
+ if (emulationMethods.isEmpty()) {
+ return null;
+ }
+ DexType emulateLibraryClassType =
+ InterfaceMethodRewriter.getEmulateLibraryInterfaceClassType(
+ theInterface.type, appView.dexItemFactory());
+ ClassAccessFlags emulateLibraryClassFlags = theInterface.accessFlags.copy();
+ emulateLibraryClassFlags.unsetAbstract();
+ emulateLibraryClassFlags.unsetInterface();
+ emulateLibraryClassFlags.unsetAnnotation();
+ emulateLibraryClassFlags.setFinal();
+ emulateLibraryClassFlags.setSynthetic();
+ emulateLibraryClassFlags.setPublic();
+ DexProgramClass clazz =
+ new DexProgramClass(
+ emulateLibraryClassType,
+ null,
+ new SynthesizedOrigin("interface desugaring (libs)", getClass()),
+ emulateLibraryClassFlags,
+ appView.dexItemFactory().objectType,
+ DexTypeList.empty(),
+ theInterface.sourceFile,
+ null,
+ Collections.emptyList(),
+ null,
+ Collections.emptyList(),
+ ClassSignature.noSignature(),
+ DexAnnotationSet.empty(),
+ DexEncodedField.EMPTY_ARRAY,
+ DexEncodedField.EMPTY_ARRAY,
+ // All synthesized methods are static in this case.
+ emulationMethods.toArray(DexEncodedMethod.EMPTY_ARRAY),
+ DexEncodedMethod.EMPTY_ARRAY,
+ appView.dexItemFactory().getSkipNameValidationForTesting(),
+ DexProgramClass::checksumFromType);
+ return clazz;
+ }
+
+ private boolean implementsInterface(DexClass clazz, DexType interfaceType) {
+ LinkedList<DexType> workList = new LinkedList<>(Arrays.asList(clazz.interfaces.values));
+ while (!workList.isEmpty()) {
+ DexType next = workList.removeLast();
+ if (interfaceType == next) {
+ return true;
+ }
+ DexClass nextClass = appView.definitionFor(next);
+ if (nextClass != null) {
+ workList.addAll(Arrays.asList(nextClass.interfaces.values));
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean shouldProcess(DexProgramClass clazz) {
+ return appView.options().isDesugaredLibraryCompilation()
+ && rewriter.isEmulatedInterface(clazz.type);
+ }
+
+ @Override
+ public void process(DexProgramClass emulatedInterface, ProgramMethodSet synthesizedMethods) {
+ assert rewriter.isEmulatedInterface(emulatedInterface.type);
+ if (appView.isAlreadyLibraryDesugared(emulatedInterface)) {
+ return;
+ }
+ // TODO(b/183998768): Due to sequential dependencies we cannot generateEmulateInterfaceLibrary.
+ // We need to merge this into a single loop. Uncomment the following line instead of running
+ // it separately.
+ // generateEmulateInterfaceLibrary(emulatedInterface);
+ replaceInterfacesInEmulatedInterface(emulatedInterface);
+ renameEmulatedInterface(emulatedInterface);
+ }
+
+ @Override
+ public void finalizeProcessing(Builder<?> builder, ProgramMethodSet synthesizedMethods) {
+ warnMissingEmulatedInterfaces();
+ if (!appView.options().isDesugaredLibraryCompilation()) {
+ assert syntheticClasses.isEmpty();
+ return;
+ }
+ syntheticClasses.forEach(
+ (interfaceClass, synthesizedClass) -> {
+ builder.addSynthesizedClass(synthesizedClass);
+ appView.appInfo().addSynthesizedClass(synthesizedClass, interfaceClass);
+ synthesizedClass.forEachProgramMethod(synthesizedMethods::add);
+ });
+ // TODO(b/183918843): Investigate what to do for the filtering, the minimum would be to make
+ // the rewriting rule explicit instead of using the synthesized class prefix.
+ filterEmulatedInterfaceSubInterfaces(builder);
+ }
+
+ private void filterEmulatedInterfaceSubInterfaces(Builder<?> builder) {
+ ArrayList<DexProgramClass> filteredProgramClasses = new ArrayList<>();
+ for (DexProgramClass clazz : builder.getProgramClasses()) {
+ if (clazz.isInterface()
+ && !rewriter.isEmulatedInterface(clazz.type)
+ && !appView.rewritePrefix.hasRewrittenType(clazz.type, appView)
+ && isEmulatedInterfaceSubInterface(clazz)) {
+ String prefix =
+ DescriptorUtils.getJavaTypeFromBinaryName(
+ appView
+ .options()
+ .desugaredLibraryConfiguration
+ .getSynthesizedLibraryClassesPackagePrefix());
+ String interfaceType = clazz.type.toString();
+ // TODO(b/183918843): We are currently computing a new name for the companion class
+ // by replacing the initial package prefix by the synthesized library class package
+ // prefix, it would be better to make the rewriting explicit in the desugared library
+ // json file.
+ int firstPackage = interfaceType.indexOf('.');
+ String newName = prefix + interfaceType.substring(firstPackage + 1);
+ rewriter.addCompanionClassRewriteRule(clazz.type, newName);
+ } else {
+ filteredProgramClasses.add(clazz);
+ }
+ }
+ builder.replaceProgramClasses(filteredProgramClasses);
+ }
+
+ private boolean isEmulatedInterfaceSubInterface(DexClass subInterface) {
+ assert !rewriter.isEmulatedInterface(subInterface.type);
+ LinkedList<DexType> workList = new LinkedList<>(Arrays.asList(subInterface.interfaces.values));
+ while (!workList.isEmpty()) {
+ DexType next = workList.removeFirst();
+ if (rewriter.isEmulatedInterface(next)) {
+ return true;
+ }
+ DexClass nextClass = appView.definitionFor(next);
+ if (nextClass != null) {
+ workList.addAll(Arrays.asList(nextClass.interfaces.values));
+ }
+ }
+ return false;
+ }
+
+ private void warnMissingEmulatedInterfaces() {
+ for (DexType interfaceType : emulatedInterfaces.keySet()) {
+ DexClass theInterface = appView.definitionFor(interfaceType);
+ if (theInterface == null) {
+ warnMissingEmulatedInterface(interfaceType);
+ }
+ }
+ }
+
+ private void warnMissingEmulatedInterface(DexType interfaceType) {
+ StringDiagnostic warning =
+ new StringDiagnostic(
+ "Cannot emulate interface "
+ + interfaceType.getName()
+ + " because the interface is missing.");
+ appView.options().reporter.warning(warning);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringProcessor.java
new file mode 100644
index 0000000..d85e8a2
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringProcessor.java
@@ -0,0 +1,17 @@
+// Copyright (c) 2021, 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.ir.desugar.itf;
+
+import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
+
+public interface InterfaceDesugaringProcessor {
+ boolean shouldProcess(DexProgramClass clazz);
+
+ void process(DexProgramClass clazz, ProgramMethodSet synthesizedMethods);
+
+ void finalizeProcessing(DexApplication.Builder<?> builder, ProgramMethodSet synthesizedMethods);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
similarity index 72%
rename from src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
rename to src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
index f6a653b..8fd5d23 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -1,8 +1,8 @@
-// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2021, 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.ir.desugar;
+package com.android.tools.r8.ir.desugar.itf;
import static com.android.tools.r8.ir.code.Invoke.Type.DIRECT;
import static com.android.tools.r8.ir.code.Invoke.Type.STATIC;
@@ -25,14 +25,12 @@
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.ClassAccessFlags;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexApplication.Builder;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexClasspathClass;
-import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
@@ -40,10 +38,7 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.DexValue;
-import com.android.tools.r8.graph.GenericSignature;
-import com.android.tools.r8.graph.GenericSignature.ClassSignature;
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.MethodCollection;
@@ -65,32 +60,23 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.conversion.MethodProcessor;
-import com.android.tools.r8.ir.desugar.DefaultMethodsHelper.Collection;
-import com.android.tools.r8.ir.desugar.InterfaceProcessor.InterfaceProcessorNestedGraphLens;
+import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration;
+import com.android.tools.r8.ir.desugar.itf.DefaultMethodsHelper.Collection;
import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations;
import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations.MethodSynthesizerConsumer;
import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations.UtilityMethodForCodeOptimizations;
import com.android.tools.r8.ir.synthetic.ForwardMethodBuilder;
import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.position.MethodPosition;
import com.android.tools.r8.synthesis.SyntheticNaming;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.IteratorUtils;
import com.android.tools.r8.utils.Pair;
-import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.collections.SortedProgramMethodSet;
import com.android.tools.r8.utils.structural.Ordered;
import com.google.common.collect.Sets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.IdentityHashMap;
-import java.util.LinkedList;
-import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
@@ -151,17 +137,11 @@
private final Map<DexType, DefaultMethodsHelper.Collection> cache = new ConcurrentHashMap<>();
private final Predicate<DexType> shouldIgnoreFromReportsPredicate;
- /**
- * Defines a minor variation in desugaring.
- */
+ /** Defines a minor variation in desugaring. */
public enum Flavor {
- /**
- * Process all application resources.
- */
+ /** Process all application resources. */
IncludeAllResources,
- /**
- * Process all but DEX application resources.
- */
+ /** Process all but DEX application resources. */
ExcludeDexResources
}
@@ -213,7 +193,8 @@
Map<DexType, DexType> emulateLibraryInterface =
options.desugaredLibraryConfiguration.getEmulateLibraryInterface();
for (DexType interfaceType : emulateLibraryInterface.keySet()) {
- addRewritePrefix(interfaceType, emulateLibraryInterface.get(interfaceType).toSourceString());
+ addRewriteRulesForEmulatedInterface(
+ interfaceType, emulateLibraryInterface.get(interfaceType).toSourceString());
DexClass emulatedInterfaceClass = appView.definitionFor(interfaceType);
if (emulatedInterfaceClass != null) {
for (DexEncodedMethod encodedMethod :
@@ -224,16 +205,21 @@
}
}
- private void addRewritePrefix(DexType interfaceType, String rewrittenType) {
+ void addRewriteRulesForEmulatedInterface(
+ DexType emulatedInterface, String rewrittenEmulatedInterface) {
+ addCompanionClassRewriteRule(emulatedInterface, rewrittenEmulatedInterface);
+ appView.rewritePrefix.rewriteType(
+ getEmulateLibraryInterfaceClassType(emulatedInterface, factory),
+ factory.createType(
+ DescriptorUtils.javaTypeToDescriptor(
+ rewrittenEmulatedInterface + EMULATE_LIBRARY_CLASS_NAME_SUFFIX)));
+ }
+
+ void addCompanionClassRewriteRule(DexType interfaceType, String rewrittenType) {
appView.rewritePrefix.rewriteType(
getCompanionClassType(interfaceType),
factory.createType(
DescriptorUtils.javaTypeToDescriptor(rewrittenType + COMPANION_CLASS_NAME_SUFFIX)));
- appView.rewritePrefix.rewriteType(
- getEmulateLibraryInterfaceClassType(interfaceType, factory),
- factory.createType(
- DescriptorUtils.javaTypeToDescriptor(
- rewrittenType + EMULATE_LIBRARY_CLASS_NAME_SUFFIX)));
}
boolean isEmulatedInterface(DexType itf) {
@@ -788,204 +774,13 @@
return false;
}
- private void warnMissingEmulatedInterface(DexType interfaceType) {
- StringDiagnostic warning =
- new StringDiagnostic(
- "Cannot emulate interface "
- + interfaceType.getName()
- + " because the interface is missing.");
- options.reporter.warning(warning);
- }
-
- private void generateEmulateInterfaceLibrary(Builder<?> builder) {
- // Emulated library interfaces should generate the Emulated Library EL dispatch class.
- Map<DexType, List<DexType>> emulatedInterfacesHierarchy = processEmulatedInterfaceHierarchy();
- AppInfo appInfo = appView.appInfo();
- for (DexType interfaceType : emulatedInterfaces.keySet()) {
- DexClass theInterface = appInfo.definitionFor(interfaceType);
- if (theInterface == null) {
- warnMissingEmulatedInterface(interfaceType);
- } else if (theInterface.isProgramClass()) {
- DexProgramClass theProgramInterface = theInterface.asProgramClass();
- DexProgramClass synthesizedClass =
- synthesizeEmulateInterfaceLibraryClass(
- theProgramInterface, emulatedInterfacesHierarchy);
- if (synthesizedClass != null) {
- builder.addSynthesizedClass(synthesizedClass);
- appInfo.addSynthesizedClass(synthesizedClass, theProgramInterface);
- }
- }
- }
- }
-
- private Map<DexType, List<DexType>> processEmulatedInterfaceHierarchy() {
- Map<DexType, List<DexType>> emulatedInterfacesHierarchy = new IdentityHashMap<>();
- Set<DexType> processed = Sets.newIdentityHashSet();
- ArrayList<DexType> emulatedInterfacesSorted = new ArrayList<>(emulatedInterfaces.keySet());
- emulatedInterfacesSorted.sort(DexType::compareTo);
- for (DexType interfaceType : emulatedInterfacesSorted) {
- processEmulatedInterfaceHierarchy(interfaceType, processed, emulatedInterfacesHierarchy);
- }
- return emulatedInterfacesHierarchy;
- }
-
- private void processEmulatedInterfaceHierarchy(
- DexType interfaceType,
- Set<DexType> processed,
- Map<DexType, List<DexType>> emulatedInterfacesHierarchy) {
- if (processed.contains(interfaceType)) {
- return;
- }
- emulatedInterfacesHierarchy.put(interfaceType, new ArrayList<>());
- processed.add(interfaceType);
- DexClass theInterface = appView.definitionFor(interfaceType);
- if (theInterface == null) {
- warnMissingEmulatedInterface(interfaceType);
- return;
- }
- LinkedList<DexType> workList = new LinkedList<>(Arrays.asList(theInterface.interfaces.values));
- while (!workList.isEmpty()) {
- DexType next = workList.removeLast();
- if (emulatedInterfaces.containsKey(next)) {
- processEmulatedInterfaceHierarchy(next, processed, emulatedInterfacesHierarchy);
- emulatedInterfacesHierarchy.get(next).add(interfaceType);
- DexClass nextClass = appView.definitionFor(next);
- if (nextClass != null) {
- workList.addAll(Arrays.asList(nextClass.interfaces.values));
- }
- }
- }
- }
-
- private boolean implementsInterface(DexClass clazz, DexType interfaceType) {
- LinkedList<DexType> workList = new LinkedList<>(Arrays.asList(clazz.interfaces.values));
- while (!workList.isEmpty()) {
- DexType next = workList.removeLast();
- if (interfaceType == next) {
- return true;
- }
- DexClass nextClass = appView.definitionFor(next);
- if (nextClass != null) {
- workList.addAll(Arrays.asList(nextClass.interfaces.values));
- }
- }
- return false;
- }
-
- private DexMethod emulateInterfaceLibraryMethod(DexClassAndMethod method) {
+ DexMethod emulateInterfaceLibraryMethod(DexClassAndMethod method) {
return factory.createMethod(
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<>();
- 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.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.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),
- companionMethod,
- libraryMethod,
- extraDispatchCases,
- appView));
- });
- if (emulationMethods.isEmpty()) {
- return null;
- }
- DexType emulateLibraryClassType =
- getEmulateLibraryInterfaceClassType(theInterface.type, factory);
- ClassAccessFlags emulateLibraryClassFlags = theInterface.accessFlags.copy();
- emulateLibraryClassFlags.unsetAbstract();
- emulateLibraryClassFlags.unsetInterface();
- emulateLibraryClassFlags.unsetAnnotation();
- emulateLibraryClassFlags.setFinal();
- emulateLibraryClassFlags.setSynthetic();
- emulateLibraryClassFlags.setPublic();
- DexProgramClass clazz =
- new DexProgramClass(
- emulateLibraryClassType,
- null,
- new SynthesizedOrigin("interface desugaring (libs)", getClass()),
- emulateLibraryClassFlags,
- factory.objectType,
- DexTypeList.empty(),
- theInterface.sourceFile,
- null,
- Collections.emptyList(),
- null,
- Collections.emptyList(),
- ClassSignature.noSignature(),
- DexAnnotationSet.empty(),
- DexEncodedField.EMPTY_ARRAY,
- DexEncodedField.EMPTY_ARRAY,
- // All synthesized methods are static in this case.
- emulationMethods.toArray(DexEncodedMethod.EMPTY_ARRAY),
- DexEncodedMethod.EMPTY_ARRAY,
- factory.getSkipNameValidationForTesting(),
- DexProgramClass::checksumFromType);
- clazz.forEachProgramMethod(synthesizedMethods::add);
- return clazz;
- }
-
private static String getEmulateLibraryInterfaceClassDescriptor(String descriptor) {
return descriptor.substring(0, descriptor.length() - 1)
+ EMULATE_LIBRARY_CLASS_NAME_SUFFIX
@@ -1027,7 +822,7 @@
return factory.createSynthesizedType(ccTypeDescriptor);
}
- DexType getCompanionClassType(DexType type) {
+ public DexType getCompanionClassType(DexType type) {
return getCompanionClassType(type, factory);
}
@@ -1049,8 +844,9 @@
public static DexType getInterfaceClassType(DexType type, DexItemFactory factory) {
assert isCompanionClassType(type);
String descriptor = type.descriptor.toString();
- String interfaceTypeDescriptor = descriptor.substring(0,
- descriptor.length() - 1 - COMPANION_CLASS_NAME_SUFFIX.length()) + ";";
+ String interfaceTypeDescriptor =
+ descriptor.substring(0, descriptor.length() - 1 - COMPANION_CLASS_NAME_SUFFIX.length())
+ + ";";
return factory.createType(interfaceTypeDescriptor);
}
@@ -1082,8 +878,9 @@
// not define this default methods, but inherits it. We are making our best effort
// to find an appropriate method, but still use the original one in case we fail.
private DexMethod amendDefaultMethod(DexClass classToDesugar, DexMethod method) {
- DexMethod singleCandidate = getOrCreateInterfaceInfo(
- classToDesugar, classToDesugar, method.holder).getSingleCandidate(method);
+ DexMethod singleCandidate =
+ getOrCreateInterfaceInfo(classToDesugar, classToDesugar, method.holder)
+ .getSingleCandidate(method);
return singleCandidate != null ? singleCandidate : method;
}
@@ -1093,7 +890,7 @@
return instanceAsMethodOfCompanionClass(method, DEFAULT_METHOD_PREFIX, factory);
}
- final DexMethod defaultAsMethodOfCompanionClass(DexClassAndMethod method) {
+ public final DexMethod defaultAsMethodOfCompanionClass(DexClassAndMethod method) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
DexMethod rewritten = defaultAsMethodOfCompanionClass(method.getReference(), dexItemFactory);
recordCompanionClassReference(appView, method, rewritten);
@@ -1159,107 +956,33 @@
}
}
- private void renameEmulatedInterfaces() {
- // Rename manually the emulated interfaces, we do not use the PrefixRenamingLens
- // because both the normal and emulated interfaces are used.
- for (DexClass clazz : appView.appInfo().classes()) {
- if (clazz.isInterface()) {
- DexType newType = inferEmulatedInterfaceName(clazz);
- if (newType != null && !appView.rewritePrefix.hasRewrittenType(clazz.type, appView)) {
- // We do not rewrite if it is already going to be rewritten using the a rewritingPrefix.
- addRewritePrefix(clazz.type, newType.toString());
- renameEmulatedInterfaces(clazz, newType);
- }
- }
- }
- }
-
- private DexType inferEmulatedInterfaceName(DexClass subInterface) {
- DexType newType = emulatedInterfaces.get(subInterface.type);
- if (newType != null) {
- return newType;
- }
- LinkedList<DexType> workList = new LinkedList<>(Arrays.asList(subInterface.interfaces.values));
- while (!workList.isEmpty()) {
- DexType next = workList.removeFirst();
- if (emulatedInterfaces.get(next) != null) {
- return inferEmulatedInterfaceName(subInterface.type, next);
- }
- DexClass nextClass = appView.definitionFor(next);
- if (nextClass != null) {
- workList.addAll(Arrays.asList(nextClass.interfaces.values));
- }
- }
- return null;
- }
-
- private DexType inferEmulatedInterfaceName(DexType subInterfaceType, DexType interfaceType) {
- String initialPrefix = interfaceType.getPackageName();
- String rewrittenPrefix = emulatedInterfaces.get(interfaceType).getPackageName();
- String suffix = subInterfaceType.toString().substring(initialPrefix.length());
- return factory.createType(DescriptorUtils.javaTypeToDescriptor(rewrittenPrefix + suffix));
- }
-
- private void renameEmulatedInterfaces(DexClass theInterface, DexType renamedInterface) {
- theInterface.type = renamedInterface;
- theInterface.setVirtualMethods(renameHolder(theInterface.virtualMethods(), renamedInterface));
- theInterface.setDirectMethods(renameHolder(theInterface.directMethods(), renamedInterface));
- }
-
- private DexEncodedMethod[] renameHolder(Iterable<DexEncodedMethod> methods, DexType newName) {
- return renameHolder(IterableUtils.toNewArrayList(methods), newName);
- }
-
- private DexEncodedMethod[] renameHolder(List<DexEncodedMethod> methods, DexType newName) {
- DexEncodedMethod[] newMethods = new DexEncodedMethod[methods.size()];
- for (int i = 0; i < newMethods.length; i++) {
- newMethods[i] = methods.get(i).toRenamedHolderMethod(newName, factory);
- }
- return newMethods;
- }
-
/**
* Move static and default interface methods to companion classes, add missing methods to forward
* to moved default methods implementation.
*/
public void desugarInterfaceMethods(
- Builder<?> builder,
- Flavor flavour,
- ExecutorService executorService)
+ Builder<?> builder, Flavor flavour, ExecutorService executorService)
throws ExecutionException {
- if (appView.options().isDesugaredLibraryCompilation()) {
- generateEmulateInterfaceLibrary(builder);
- }
+ // TODO(b/183998768): Merge the following four sequential loops into a single one.
+
+ EmulatedInterfaceProcessor emulatedInterfaceProcessor =
+ new EmulatedInterfaceProcessor(appView, this);
+ // TODO(b/183998768): Move this to emulatedInterfaceProcessor#process
+ forEachProgramEmulatedInterface(emulatedInterfaceProcessor::generateEmulateInterfaceLibrary);
// Process all classes first. Add missing forwarding methods to
// replace desugared default interface methods.
- processClasses(builder, flavour, synthesizedMethods::add);
- transformEmulatedInterfaces();
+ process(new ClassProcessor(appView, this), builder, flavour);
// Process interfaces, create companion or dispatch class if needed, move static
// methods to companion class, copy default interface methods to companion classes,
// make original default methods abstract, remove bridge methods, create dispatch
// classes if needed.
- AppInfo appInfo = appView.appInfo();
- InterfaceProcessorNestedGraphLens.Builder graphLensBuilder =
- InterfaceProcessorNestedGraphLens.builder();
- Map<DexClass, DexProgramClass> classMapping =
- processInterfaces(builder, flavour, graphLensBuilder, synthesizedMethods::add);
- InterfaceProcessorNestedGraphLens graphLens = graphLensBuilder.build(appView);
- if (appView.enableWholeProgramOptimizations() && graphLens != null) {
- appView.setGraphLens(graphLens);
- }
- classMapping.forEach(
- (interfaceClass, synthesizedClass) -> {
- // Don't need to optimize synthesized class since all of its methods
- // are just moved from interfaces and don't need to be re-processed.
- builder.addSynthesizedClass(synthesizedClass);
- appInfo.addSynthesizedClass(synthesizedClass, interfaceClass.asProgramClass());
- });
- new InterfaceMethodRewriterFixup(appView, graphLens).run();
- if (appView.options().isDesugaredLibraryCompilation()) {
- renameEmulatedInterfaces();
- }
+ process(new InterfaceProcessor(appView, this), builder, flavour);
+
+ // During L8 compilation, emulated interfaces are processed to be renamed, to have
+ // their interfaces fixed-up and to generate the emulated dispatch code.
+ process(emulatedInterfaceProcessor, builder, flavour);
converter.processMethodsConcurrently(synthesizedMethods, executorService);
@@ -1267,42 +990,16 @@
clear();
}
- private void transformEmulatedInterfaces() {
- for (DexType dexType : emulatedInterfaces.keySet()) {
- DexClass dexClass = appView.definitionFor(dexType);
- if (dexClass != null && dexClass.isProgramClass()) {
- transformEmulatedInterfaces(dexClass.asProgramClass());
- }
- }
- }
-
- // The method transforms emulated interface such as they implement the rewritten version
- // of each emulated interface they implement. Such change should have no effect on the look-up
- // results, since each class implementing an emulated interface should also implement the
- // rewritten one.
- private void transformEmulatedInterfaces(DexProgramClass clazz) {
- if (appView.isAlreadyLibraryDesugared(clazz)) {
+ private void forEachProgramEmulatedInterface(Consumer<DexProgramClass> consumer) {
+ if (!appView.options().isDesugaredLibraryCompilation()) {
return;
}
- List<GenericSignature.ClassTypeSignature> newInterfaces = new ArrayList<>();
- GenericSignature.ClassSignature classSignature = clazz.getClassSignature();
- for (int i = 0; i < clazz.interfaces.size(); i++) {
- DexType itf = clazz.interfaces.values[i];
- if (emulatedInterfaces.containsKey(itf)) {
- List<GenericSignature.FieldTypeSignature> typeArguments;
- if (classSignature == null) {
- typeArguments = Collections.emptyList();
- } else {
- GenericSignature.ClassTypeSignature classTypeSignature =
- classSignature.superInterfaceSignatures().get(i);
- assert itf == classTypeSignature.type();
- typeArguments = classTypeSignature.typeArguments();
- }
- newInterfaces.add(
- new GenericSignature.ClassTypeSignature(emulatedInterfaces.get(itf), typeArguments));
+ for (DexType interfaceType : emulatedInterfaces.keySet()) {
+ DexClass theInterface = appView.definitionFor(interfaceType);
+ if (theInterface != null && theInterface.isProgramClass()) {
+ consumer.accept(theInterface.asProgramClass());
}
}
- clazz.replaceInterfaces(newInterfaces);
}
private void clear() {
@@ -1310,41 +1007,20 @@
this.synthesizedMethods.clear();
}
- private static boolean shouldProcess(
- DexProgramClass clazz, Flavor flavour, boolean mustBeInterface) {
- return (!clazz.originatesFromDexResource() || flavour == Flavor.IncludeAllResources)
- && clazz.isInterface() == mustBeInterface;
+ private boolean shouldProcess(DexProgramClass clazz, Flavor flavour) {
+ if (appView.isAlreadyLibraryDesugared(clazz)) {
+ return false;
+ }
+ return (!clazz.originatesFromDexResource() || flavour == Flavor.IncludeAllResources);
}
- private Map<DexClass, DexProgramClass> processInterfaces(
- Builder<?> builder,
- Flavor flavour,
- InterfaceProcessorNestedGraphLens.Builder graphLensBuilder,
- Consumer<ProgramMethod> newSynthesizedMethodConsumer) {
- InterfaceProcessor processor = new InterfaceProcessor(appView, this);
+ private void process(InterfaceDesugaringProcessor processor, Builder<?> builder, Flavor flavour) {
for (DexProgramClass clazz : builder.getProgramClasses()) {
- if (shouldProcess(clazz, flavour, true)) {
- processor.process(clazz, graphLensBuilder, newSynthesizedMethodConsumer);
+ if (shouldProcess(clazz, flavour) && processor.shouldProcess(clazz)) {
+ processor.process(clazz, synthesizedMethods);
}
}
- return processor.syntheticClasses;
- }
-
- private void processClasses(
- Builder<?> builder, Flavor flavour, Consumer<ProgramMethod> newSynthesizedMethodConsumer) {
- ClassProcessor processor = new ClassProcessor(appView, this, newSynthesizedMethodConsumer);
- // First we compute all desugaring *without* introducing forwarding methods.
- assert appView.getSyntheticItems().verifyNonLegacySyntheticsAreCommitted();
- for (DexProgramClass clazz : builder.getProgramClasses()) {
- if (shouldProcess(clazz, flavour, false)) {
- if (appView.isAlreadyLibraryDesugared(clazz)) {
- continue;
- }
- processor.processClass(clazz);
- }
- }
- // Then we introduce forwarding methods.
- processor.addSyntheticMethods();
+ processor.finalizeProcessing(builder, synthesizedMethods);
}
final boolean isDefaultMethod(DexEncodedMethod method) {
@@ -1428,9 +1104,7 @@
}
final DefaultMethodsHelper.Collection getOrCreateInterfaceInfo(
- DexClass classToDesugar,
- DexClass implementing,
- DexType iface) {
+ DexClass classToDesugar, DexClass implementing, DexType iface) {
DefaultMethodsHelper.Collection collection = cache.get(iface);
if (collection != null) {
return collection;
@@ -1441,9 +1115,7 @@
}
private DefaultMethodsHelper.Collection createInterfaceInfo(
- DexClass classToDesugar,
- DexClass implementing,
- DexType iface) {
+ DexClass classToDesugar, DexClass implementing, DexType iface) {
DefaultMethodsHelper helper = new DefaultMethodsHelper();
DexClass definedInterface = appView.definitionFor(iface);
if (definedInterface == null) {
@@ -1452,8 +1124,11 @@
}
if (!definedInterface.isInterface()) {
throw new CompilationError(
- "Type " + iface.toSourceString() + " is referenced as an interface from `"
- + implementing.toString() + "`.");
+ "Type "
+ + iface.toSourceString()
+ + " is referenced as an interface from `"
+ + implementing.toString()
+ + "`.");
}
if (isNonDesugaredLibraryClass(definedInterface)) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriterFixup.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriterFixup.java
similarity index 92%
rename from src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriterFixup.java
rename to src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriterFixup.java
index bb0de67..b3d5f1b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriterFixup.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriterFixup.java
@@ -1,14 +1,14 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2021, 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.ir.desugar;
+package com.android.tools.r8.ir.desugar.itf;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.EnclosingMethodAttribute;
import com.android.tools.r8.graph.InnerClassAttribute;
-import com.android.tools.r8.ir.desugar.InterfaceProcessor.InterfaceProcessorNestedGraphLens;
+import com.android.tools.r8.ir.desugar.itf.InterfaceProcessor.InterfaceProcessorNestedGraphLens;
class InterfaceMethodRewriterFixup {
private final AppView<?> appView;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
similarity index 92%
rename from src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
rename to src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
index 0199730..32c8c64 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
@@ -1,8 +1,8 @@
-// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2021, 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.ir.desugar;
+package com.android.tools.r8.ir.desugar.itf;
import static com.android.tools.r8.utils.PredicateUtils.not;
@@ -21,6 +21,7 @@
import com.android.tools.r8.graph.ClassAccessFlags;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexAnnotationSet;
+import com.android.tools.r8.graph.DexApplication.Builder;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -50,6 +51,7 @@
import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.ImmutableList;
import java.util.ArrayDeque;
import java.util.ArrayList;
@@ -60,7 +62,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.function.Consumer;
import org.objectweb.asm.Opcodes;
// Default and static method interface desugaring processor for interfaces.
@@ -69,24 +70,28 @@
// a companion class. Removes bridge default methods.
//
// Also moves static interface methods into a companion class.
-public final class InterfaceProcessor {
+public final class InterfaceProcessor implements InterfaceDesugaringProcessor {
private final AppView<?> appView;
private final InterfaceMethodRewriter rewriter;
+ private final InterfaceProcessorNestedGraphLens.Builder graphLensBuilder;
- // All created companion and dispatch classes indexed by interface type.
+ // All created companion classes indexed by interface type.
final Map<DexClass, DexProgramClass> syntheticClasses = new IdentityHashMap<>();
- InterfaceProcessor(
- AppView<?> appView, InterfaceMethodRewriter rewriter) {
+ InterfaceProcessor(AppView<?> appView, InterfaceMethodRewriter rewriter) {
this.appView = appView;
this.rewriter = rewriter;
+ graphLensBuilder = InterfaceProcessorNestedGraphLens.builder();
}
- void process(
- DexProgramClass iface,
- InterfaceProcessorNestedGraphLens.Builder graphLensBuilder,
- Consumer<ProgramMethod> newSynthesizedMethodConsumer) {
+ @Override
+ public boolean shouldProcess(DexProgramClass clazz) {
+ return clazz.isInterface();
+ }
+
+ @Override
+ public void process(DexProgramClass iface, ProgramMethodSet synthesizedMethods) {
assert iface.isInterface();
// The list of methods to be created in companion class.
List<DexEncodedMethod> companionMethods = new ArrayList<>();
@@ -138,7 +143,7 @@
getChecksumSupplier(iface));
syntheticClasses.put(iface, companionClass);
if (companionClass.hasClassInitializer()) {
- newSynthesizedMethodConsumer.accept(companionClass.getProgramClassInitializer());
+ synthesizedMethods.add(companionClass.getProgramClassInitializer());
}
}
@@ -439,6 +444,22 @@
&& !rewriter.factory.isClassConstructor(method.getReference());
}
+ @Override
+ public void finalizeProcessing(Builder<?> builder, ProgramMethodSet synthesizedMethods) {
+ InterfaceProcessorNestedGraphLens graphLens = graphLensBuilder.build(appView);
+ if (appView.enableWholeProgramOptimizations() && graphLens != null) {
+ appView.setGraphLens(graphLens);
+ }
+ syntheticClasses.forEach(
+ (interfaceClass, synthesizedClass) -> {
+ // Don't need to optimize synthesized class since all of its methods
+ // are just moved from interfaces and don't need to be re-processed.
+ builder.addSynthesizedClass(synthesizedClass);
+ appView.appInfo().addSynthesizedClass(synthesizedClass, interfaceClass.asProgramClass());
+ });
+ new InterfaceMethodRewriterFixup(appView, graphLens).run();
+ }
+
// Specific lens which remaps invocation types to static since all rewrites performed here
// are to static companion methods.
public static class InterfaceProcessorNestedGraphLens extends NestedGraphLens {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/nest/D8NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/nest/D8NestBasedAccessDesugaring.java
index 44a37b0..b622057 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/nest/D8NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/nest/D8NestBasedAccessDesugaring.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.ir.desugar.nest;
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.reportDependencyEdge;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.reportDependencyEdge;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ClasspathMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
index 0f12d78..2f32c5c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -54,7 +54,7 @@
import com.android.tools.r8.ir.code.ValueTypeConstraint;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.SourceCode;
-import com.android.tools.r8.ir.desugar.InterfaceProcessor.InterfaceProcessorNestedGraphLens;
+import com.android.tools.r8.ir.desugar.itf.InterfaceProcessor.InterfaceProcessorNestedGraphLens;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
index 3b2c0d5..92a507b 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
@@ -21,7 +21,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.SubtypingInfo;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.naming.ClassNameMinifier.ClassRenaming;
import com.android.tools.r8.naming.FieldNameMinifier.FieldRenaming;
import com.android.tools.r8.naming.MemberNaming.FieldSignature;
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 4622786..69c27c5 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -47,8 +47,8 @@
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter;
import com.android.tools.r8.ir.desugar.DesugaredLibraryRetargeter;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
import com.android.tools.r8.ir.desugar.LambdaDescriptor;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.synthesis.CommittedItems;
import com.android.tools.r8.utils.CollectionUtils;
import com.android.tools.r8.utils.InternalOptions;
diff --git a/src/main/java/com/android/tools/r8/shaking/GraphReporter.java b/src/main/java/com/android/tools/r8/shaking/GraphReporter.java
index ac0d153..963e036 100644
--- a/src/main/java/com/android/tools/r8/shaking/GraphReporter.java
+++ b/src/main/java/com/android/tools/r8/shaking/GraphReporter.java
@@ -29,7 +29,7 @@
import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.references.TypeReference;
import com.android.tools.r8.utils.DequeUtils;
diff --git a/src/main/java/com/android/tools/r8/shaking/MissingClasses.java b/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
index 2cce6ff..317a4cd 100644
--- a/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
+++ b/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
@@ -6,7 +6,7 @@
import static com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter.DESCRIPTOR_VIVIFIED_PREFIX;
import static com.android.tools.r8.ir.desugar.DesugaredLibraryRetargeter.getRetargetPackageAndClassPrefixDescriptor;
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.EMULATE_LIBRARY_CLASS_NAME_SUFFIX;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.EMULATE_LIBRARY_CLASS_NAME_SUFFIX;
import static com.android.tools.r8.utils.collections.IdentityHashSetFromMap.newProgramDerivedContextSet;
import com.android.tools.r8.diagnostic.MissingDefinitionsDiagnostic;
diff --git a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
index c5ce290..dfca4e2 100644
--- a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.errors.InternalCompilerError;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
diff --git a/src/test/java/com/android/tools/r8/RunExamplesJava9Test.java b/src/test/java/com/android/tools/r8/RunExamplesJava9Test.java
index 7f1940e..fd7a3bd 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesJava9Test.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesJava9Test.java
@@ -13,7 +13,7 @@
import static org.junit.Assume.assumeFalse;
import com.android.tools.r8.ToolHelper.DexVm;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.TestDescriptionWatcher;
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerDebugTestRunner.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerDebugTestRunner.java
index e542559..210967c 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerDebugTestRunner.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerDebugTestRunner.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.classmerging.vertical;
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
diff --git a/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java b/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
index e72cf0a..5f4be39 100644
--- a/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
@@ -7,7 +7,7 @@
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.debug.DebugTestBase.JUnit3Wrapper.Command;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarInnerClassesInInterfaces.java b/src/test/java/com/android/tools/r8/desugar/DesugarInnerClassesInInterfaces.java
index 9a7802f..d65470d 100644
--- a/src/test/java/com/android/tools/r8/desugar/DesugarInnerClassesInInterfaces.java
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarInnerClassesInInterfaces.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.concurrent.Callable;
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmulatedInterfacesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmulatedInterfacesTest.java
index d767975..4e96f57 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmulatedInterfacesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmulatedInterfacesTest.java
@@ -14,7 +14,7 @@
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
diff --git a/src/test/java/com/android/tools/r8/desugar/enclosingmethod/EnclosingMethodRewriteTest.java b/src/test/java/com/android/tools/r8/desugar/enclosingmethod/EnclosingMethodRewriteTest.java
index 3e60058..c61b1fd 100644
--- a/src/test/java/com/android/tools/r8/desugar/enclosingmethod/EnclosingMethodRewriteTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/enclosingmethod/EnclosingMethodRewriteTest.java
@@ -3,8 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.desugar.enclosingmethod;
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.DEFAULT_METHOD_PREFIX;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.DEFAULT_METHOD_PREFIX;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlineFromStaticInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlineFromStaticInterfaceMethodTest.java
index c0267f2..a86ee63 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlineFromStaticInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlineFromStaticInterfaceMethodTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
diff --git a/src/test/java/com/android/tools/r8/jasmin/AnnotationCompanionClassTest.java b/src/test/java/com/android/tools/r8/jasmin/AnnotationCompanionClassTest.java
index 2d0d180..2875a43 100644
--- a/src/test/java/com/android/tools/r8/jasmin/AnnotationCompanionClassTest.java
+++ b/src/test/java/com/android/tools/r8/jasmin/AnnotationCompanionClassTest.java
@@ -7,7 +7,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertFalse;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java
index ad3b7eb..cae1185 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.StringUtils;
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
index a969d1b..961d400 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.shaking.ifrule.interfacemethoddesugaring;
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPublic;
import static com.android.tools.r8.utils.codeinspector.Matchers.isStatic;
diff --git a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
index 46924fd..fe06c06 100644
--- a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
+++ b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
@@ -5,7 +5,7 @@
import static org.hamcrest.CoreMatchers.containsString;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
index ee96d6b..a794e67 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.utils.codeinspector;
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
index c20ccd6..c830cf6 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
@@ -24,7 +24,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.conversion.SwitchPayloadResolver;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.ClassNamingForNameMapper;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
index 0eb0de1..f215cca 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.utils.codeinspector;
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.DEFAULT_METHOD_PREFIX;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.DEFAULT_METHOD_PREFIX;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfPosition;