Hygienic type for DesugaredLibraryRetargeter
Bug: 188767735
Change-Id: I52cf1e9c57178575c38d24270e2f8318d265921b
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 fea728d..1843cea 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
@@ -397,10 +397,9 @@
}
}
- private void synthesizeRetargetClass(Builder<?> builder, ExecutorService executorService)
- throws ExecutionException {
+ private void synthesizeRetargetClass(ExecutorService executorService) throws ExecutionException {
if (desugaredLibraryRetargeter != null) {
- desugaredLibraryRetargeter.synthesizeRetargetClasses(builder, executorService, this);
+ desugaredLibraryRetargeter.synthesizeRetargetClasses(executorService, this);
}
}
@@ -442,7 +441,7 @@
Builder<?> builder = application.builder().setHighestSortingString(highestSortingString);
desugarInterfaceMethods(builder, ExcludeDexResources, executor);
- synthesizeRetargetClass(builder, executor);
+ synthesizeRetargetClass(executor);
processCovariantReturnTypeAnnotations(builder);
generateDesugaredLibraryAPIWrappers(builder, executor);
@@ -780,7 +779,7 @@
feedback.updateVisibleOptimizationInfo();
printPhase("Utility classes synthesis");
- synthesizeRetargetClass(builder, executorService);
+ synthesizeRetargetClass(executorService);
synthesizeEnumUnboxingUtilityMethods(executorService);
printPhase("Desugared library API Conversion finalization");
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
index 9ec7242..a069091 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
@@ -153,6 +153,17 @@
return synthesizedLibraryClassesPackagePrefix;
}
+ // TODO(b/183918843): We are currently computing a new name for the 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.
+ public String convertJavaNameToDesugaredLibrary(DexType type) {
+ String prefix =
+ DescriptorUtils.getJavaTypeFromBinaryName(getSynthesizedLibraryClassesPackagePrefix());
+ String interfaceType = type.toString();
+ int firstPackage = interfaceType.indexOf('.');
+ return prefix + interfaceType.substring(firstPackage + 1);
+ }
+
public String getIdentifier() {
return identifier;
}
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 5a96760..2460c25 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
@@ -8,11 +8,9 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.ClassAccessFlags;
+import com.android.tools.r8.graph.ClasspathOrLibraryClass;
import com.android.tools.r8.graph.DexAnnotationSet;
-import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.DexApplication.Builder;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexEncodedField;
@@ -21,7 +19,6 @@
import com.android.tools.r8.graph.DexLibraryClass;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexProgramClass.ChecksumSupplier;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
@@ -45,12 +42,15 @@
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.synthetic.EmulateInterfaceSyntheticCfCodeProvider;
import com.android.tools.r8.origin.SynthesizedOrigin;
-import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.synthesis.SyntheticClassBuilder;
+import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
+import com.android.tools.r8.utils.DescriptorUtils;
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;
@@ -67,10 +67,6 @@
public class DesugaredLibraryRetargeter {
- private static final String RETARGET_PACKAGE = "retarget/";
- public static final String DESUGAR_LIB_RETARGET_CLASS_NAME_PREFIX =
- "$r8$retargetLibraryMember$virtualDispatch";
-
private final AppView<?> appView;
private final Map<DexMethod, DexMethod> retargetLibraryMember = new IdentityHashMap<>();
// Map nonFinalRewrite hold a methodName -> method mapping for methods which are rewritten while
@@ -80,27 +76,16 @@
// Non final virtual library methods requiring generation of emulated dispatch.
private final DexClassAndMethodSet emulatedDispatchMethods = DexClassAndMethodSet.create();
- private final String packageAndClassDescriptorPrefix;
+ private final Set<DexProgramClass> programSynthesizedClasses = Sets.newConcurrentHashSet();
public DesugaredLibraryRetargeter(AppView<?> appView) {
this.appView = appView;
- packageAndClassDescriptorPrefix =
- getRetargetPackageAndClassPrefixDescriptor(appView.options().desugaredLibraryConfiguration);
if (appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()) {
return;
}
new RetargetingSetup().setUpRetargeting();
}
- public static boolean isRetargetType(DexType type, InternalOptions options) {
- if (options.desugaredLibraryConfiguration == null) {
- return false;
- }
- return type.toDescriptorString()
- .startsWith(
- getRetargetPackageAndClassPrefixDescriptor(options.desugaredLibraryConfiguration));
- }
-
public static void checkForAssumedLibraryTypes(AppView<?> appView) {
Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember();
@@ -225,50 +210,6 @@
appView.options().reporter.warning(warning);
}
- private static void synthesizeClassWithUniqueMethod(
- Builder<?> builder,
- ClassAccessFlags accessFlags,
- DexType type,
- DexEncodedMethod uniqueMethod,
- String origin,
- AppView<?> appView) {
- DexItemFactory factory = appView.dexItemFactory();
- DexProgramClass newClass =
- new DexProgramClass(
- type,
- null,
- new SynthesizedOrigin(origin, BackportedMethodRewriter.class),
- accessFlags,
- factory.objectType,
- DexTypeList.empty(),
- null,
- null,
- Collections.emptyList(),
- null,
- Collections.emptyList(),
- ClassSignature.noSignature(),
- DexAnnotationSet.empty(),
- DexEncodedField.EMPTY_ARRAY,
- DexEncodedField.EMPTY_ARRAY,
- uniqueMethod.isStatic()
- ? new DexEncodedMethod[] {uniqueMethod}
- : DexEncodedMethod.EMPTY_ARRAY,
- uniqueMethod.isStatic()
- ? DexEncodedMethod.EMPTY_ARRAY
- : new DexEncodedMethod[] {uniqueMethod},
- factory.getSkipNameValidationForTesting(),
- getChecksumSupplier(uniqueMethod, appView));
- appView.appInfo().addSynthesizedClassForLibraryDesugaring(newClass);
- builder.addSynthesizedClass(newClass);
- }
-
- private static ChecksumSupplier getChecksumSupplier(DexEncodedMethod method, AppView<?> appView) {
- if (!appView.options().encodeChecksums) {
- return DexProgramClass::invalidChecksumRequest;
- }
- return c -> method.getReference().hashCode();
- }
-
// Used by the ListOfBackportedMethods utility.
void visit(Consumer<DexMethod> consumer) {
retargetLibraryMember.keySet().forEach(consumer);
@@ -386,8 +327,9 @@
} else if (!method.getAccessFlags().isFinal()) {
// Virtual rewrites require emulated dispatch for inheritance.
// The call is rewritten to the dispatch holder class instead.
- handleEmulateDispatch(appView, method);
- newHolder = dispatchHolderTypeFor(method);
+ emulatedDispatchMethods.add(method);
+ // TODO(b/188767735): Postpone until needed.
+ newHolder = ensureEmulatedHolderDispatchMethod(method).type;
}
}
}
@@ -476,23 +418,129 @@
assert !found.isEmpty() : "Should have found a method (library specifications).";
return found;
}
-
- 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.
- DexType dispatchInterfaceType = dispatchInterfaceTypeFor(method);
- appView.rewritePrefix.rewriteType(dispatchInterfaceType, dispatchInterfaceType);
- DexType dispatchHolderType = dispatchHolderTypeFor(method);
- appView.rewritePrefix.rewriteType(dispatchHolderType, dispatchHolderType);
- }
- }
}
- public void synthesizeRetargetClasses(
- DexApplication.Builder<?> builder, ExecutorService executorService, IRConverter converter)
+ public void synthesizeRetargetClasses(ExecutorService executorService, IRConverter converter)
throws ExecutionException {
- new EmulatedDispatchTreeFixer().fixApp(builder, executorService, converter);
+ new EmulatedDispatchTreeFixer().fixApp(executorService, converter);
+ converter.optimizeSynthesizedClasses(programSynthesizedClasses, executorService);
+ }
+
+ private void rewriteType(DexType type) {
+ String newName =
+ appView.options().desugaredLibraryConfiguration.convertJavaNameToDesugaredLibrary(type);
+ DexType newType =
+ appView.dexItemFactory().createType(DescriptorUtils.javaTypeToDescriptor(newName));
+ appView.rewritePrefix.rewriteType(type, newType);
+ }
+
+ public DexClass ensureEmulatedHolderDispatchMethod(DexClassAndMethod emulatedDispatchMethod) {
+ DexClass interfaceClass = ensureEmulatedInterfaceDispatchMethod(emulatedDispatchMethod);
+ DexMethod itfMethod =
+ interfaceClass.lookupMethod(emulatedDispatchMethod.getReference()).getReference();
+ DexClass holderDispatch;
+ if (appView.options().isDesugaredLibraryCompilation()) {
+ holderDispatch =
+ appView
+ .getSyntheticItems()
+ .ensureFixedClass(
+ SyntheticKind.RETARGET_CLASS,
+ emulatedDispatchMethod.getHolder(),
+ appView,
+ classBuilder ->
+ buildHolderDispatchMethod(classBuilder, emulatedDispatchMethod, itfMethod));
+ programSynthesizedClasses.add(holderDispatch.asProgramClass());
+ } else {
+ ClasspathOrLibraryClass context =
+ emulatedDispatchMethod.getHolder().asClasspathOrLibraryClass();
+ assert context != null;
+ holderDispatch =
+ appView
+ .getSyntheticItems()
+ .ensureFixedClasspathClass(
+ SyntheticKind.RETARGET_CLASS,
+ context,
+ appView,
+ classBuilder ->
+ buildHolderDispatchMethod(classBuilder, emulatedDispatchMethod, itfMethod));
+ }
+ rewriteType(holderDispatch.type);
+ return holderDispatch;
+ }
+
+ public DexClass ensureEmulatedInterfaceDispatchMethod(DexClassAndMethod emulatedDispatchMethod) {
+ DexClass interfaceDispatch;
+ if (appView.options().isDesugaredLibraryCompilation()) {
+ interfaceDispatch =
+ appView
+ .getSyntheticItems()
+ .ensureFixedClass(
+ SyntheticKind.RETARGET_INTERFACE,
+ emulatedDispatchMethod.getHolder(),
+ appView,
+ classBuilder ->
+ this.buildInterfaceDispatchMethod(classBuilder, emulatedDispatchMethod));
+ programSynthesizedClasses.add(interfaceDispatch.asProgramClass());
+ } else {
+ ClasspathOrLibraryClass context =
+ emulatedDispatchMethod.getHolder().asClasspathOrLibraryClass();
+ assert context != null;
+ interfaceDispatch =
+ appView
+ .getSyntheticItems()
+ .ensureFixedClasspathClass(
+ SyntheticKind.RETARGET_INTERFACE,
+ context,
+ appView,
+ classBuilder ->
+ this.buildInterfaceDispatchMethod(classBuilder, emulatedDispatchMethod));
+ }
+ rewriteType(interfaceDispatch.type);
+ return interfaceDispatch;
+ }
+
+ private void buildInterfaceDispatchMethod(
+ SyntheticClassBuilder<?, ?> classBuilder, DexClassAndMethod emulatedDispatchMethod) {
+ classBuilder
+ .setInterface()
+ .addMethod(
+ methodBuilder -> {
+ MethodAccessFlags flags =
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_ABSTRACT | Constants.ACC_SYNTHETIC,
+ false);
+ methodBuilder
+ .setName(emulatedDispatchMethod.getName())
+ .setProto(emulatedDispatchMethod.getProto())
+ .setAccessFlags(flags);
+ });
+ }
+
+ private <SCB extends SyntheticClassBuilder<?, ?>> void buildHolderDispatchMethod(
+ SCB classBuilder, DexClassAndMethod emulatedDispatchMethod, DexMethod itfMethod) {
+ classBuilder.addMethod(
+ methodBuilder -> {
+ DexMethod desugarMethod =
+ appView
+ .options()
+ .desugaredLibraryConfiguration
+ .retargetMethod(emulatedDispatchMethod, appView);
+ assert desugarMethod
+ != null; // This method is reached only for retarget core lib members.
+ methodBuilder
+ .setName(emulatedDispatchMethod.getName())
+ .setProto(desugarMethod.proto)
+ .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
+ .setCode(
+ methodSig ->
+ new EmulateInterfaceSyntheticCfCodeProvider(
+ emulatedDispatchMethod.getHolderType(),
+ desugarMethod,
+ itfMethod,
+ Collections.emptyList(),
+ appView)
+ .generateCfCode());
+ });
}
// The rewrite of virtual calls requires to go through emulate dispatch. This class is responsible
@@ -500,11 +548,9 @@
// synthesize the interfaces and emulated dispatch classes in the desugared library.
class EmulatedDispatchTreeFixer {
- void fixApp(
- DexApplication.Builder<?> builder, ExecutorService executorService, IRConverter converter)
- throws ExecutionException {
+ void fixApp(ExecutorService executorService, IRConverter converter) throws ExecutionException {
if (appView.options().isDesugaredLibraryCompilation()) {
- synthesizeEmulatedDispatchMethods(builder);
+ synthesizeEmulatedDispatchMethods();
} else {
addInterfacesAndForwardingMethods(executorService, converter);
}
@@ -574,8 +620,8 @@
// We cannot use the ClassProcessor since this applies up to 26, while the ClassProcessor
// applies up to 24.
for (DexClassAndMethod method : methods) {
- clazz.addExtraInterfaces(
- Collections.singletonList(new ClassTypeSignature(dispatchInterfaceTypeFor(method))));
+ DexClass dexClass = ensureEmulatedInterfaceDispatchMethod(method);
+ clazz.addExtraInterfaces(Collections.singletonList(new ClassTypeSignature(dexClass.type)));
if (clazz.lookupVirtualMethod(method.getReference()) == null) {
DexEncodedMethod newMethod = createForwardingMethod(method, clazz);
clazz.addVirtualMethod(newMethod);
@@ -596,156 +642,38 @@
target, clazz, forwardMethod, appView.dexItemFactory());
}
- private void synthesizeEmulatedDispatchMethods(DexApplication.Builder<?> builder) {
+ private void synthesizeEmulatedDispatchMethods() {
assert appView.options().isDesugaredLibraryCompilation();
if (emulatedDispatchMethods.isEmpty()) {
return;
}
- ClassAccessFlags itfAccessFlags =
- ClassAccessFlags.fromSharedAccessFlags(
- Constants.ACC_PUBLIC
- | Constants.ACC_SYNTHETIC
- | Constants.ACC_ABSTRACT
- | Constants.ACC_INTERFACE);
- ClassAccessFlags holderAccessFlags =
- ClassAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC);
for (DexClassAndMethod emulatedDispatchMethod : emulatedDispatchMethods) {
- // Dispatch interface.
- DexType interfaceType = dispatchInterfaceTypeFor(emulatedDispatchMethod);
- DexEncodedMethod itfMethod =
- generateInterfaceDispatchMethod(emulatedDispatchMethod, interfaceType);
- synthesizeClassWithUniqueMethod(
- builder,
- itfAccessFlags,
- interfaceType,
- itfMethod,
- "desugared library dispatch interface",
- appView);
- // Dispatch holder.
- DexType holderType = dispatchHolderTypeFor(emulatedDispatchMethod);
- DexEncodedMethod dispatchMethod =
- generateHolderDispatchMethod(
- emulatedDispatchMethod, holderType, itfMethod.getReference());
- synthesizeClassWithUniqueMethod(
- builder,
- holderAccessFlags,
- holderType,
- dispatchMethod,
- "desugared library dispatch class",
- appView);
+ ensureEmulatedInterfaceDispatchMethod(emulatedDispatchMethod);
+ ensureEmulatedHolderDispatchMethod(emulatedDispatchMethod);
}
}
- private DexEncodedMethod generateInterfaceDispatchMethod(
- DexClassAndMethod emulatedDispatchMethod, DexType interfaceType) {
- MethodAccessFlags flags =
- MethodAccessFlags.fromSharedAccessFlags(
- Constants.ACC_PUBLIC | Constants.ACC_ABSTRACT | Constants.ACC_SYNTHETIC, false);
- DexMethod newMethod =
- appView
- .dexItemFactory()
- .createMethod(
- interfaceType,
- emulatedDispatchMethod.getProto(),
- emulatedDispatchMethod.getName());
- return new DexEncodedMethod(
- newMethod,
- flags,
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- null,
- true);
+ private void reportInvalidLibrarySupertype(
+ DexLibraryClass libraryClass, DexClassAndMethodSet retarget) {
+ DexClass dexClass = appView.definitionFor(libraryClass.superType);
+ String message;
+ if (dexClass == null) {
+ message = "missing";
+ } else if (dexClass.isClasspathClass()) {
+ message = "a classpath class";
+ } else {
+ message = "INVALID";
+ assert false;
+ }
+ appView
+ .options()
+ .warningInvalidLibrarySuperclassForDesugar(
+ dexClass == null ? libraryClass.getOrigin() : dexClass.getOrigin(),
+ libraryClass.type,
+ libraryClass.superType,
+ message,
+ retarget);
}
- private DexEncodedMethod generateHolderDispatchMethod(
- DexClassAndMethod emulatedDispatchMethod, DexType dispatchHolder, DexMethod itfMethod) {
- // The method should look like:
- // static foo(rcvr, arg0, arg1) {
- // if (rcvr instanceof interfaceType) {
- // return invoke-interface receiver.foo(arg0, arg1);
- // } else {
- // return DesugarX.foo(rcvr, arg0, arg1)
- // }
- // We do not deal with complex cases (multiple retargeting of the same signature in the
- // same inheritance tree, etc., since they do not happen in the most common desugared library.
- DexMethod desugarMethod =
- appView
- .options()
- .desugaredLibraryConfiguration
- .retargetMethod(emulatedDispatchMethod, appView);
- assert desugarMethod != null; // This method is reached only for retarget core lib members.
- DexMethod newMethod =
- appView
- .dexItemFactory()
- .createMethod(dispatchHolder, desugarMethod.proto, emulatedDispatchMethod.getName());
- CfCode code =
- new EmulateInterfaceSyntheticCfCodeProvider(
- emulatedDispatchMethod.getHolderType(),
- desugarMethod,
- itfMethod,
- Collections.emptyList(),
- appView)
- .generateCfCode();
- return new DexEncodedMethod(
- newMethod,
- MethodAccessFlags.createPublicStaticSynthetic(),
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- code,
- true);
- }
- }
-
- private void reportInvalidLibrarySupertype(
- DexLibraryClass libraryClass, DexClassAndMethodSet retarget) {
- DexClass dexClass = appView.definitionFor(libraryClass.superType);
- String message;
- if (dexClass == null) {
- message = "missing";
- } else if (dexClass.isClasspathClass()) {
- message = "a classpath class";
- } else {
- message = "INVALID";
- assert false;
- }
- appView
- .options()
- .warningInvalidLibrarySuperclassForDesugar(
- dexClass == null ? libraryClass.getOrigin() : dexClass.getOrigin(),
- libraryClass.type,
- libraryClass.superType,
- message,
- retarget);
- }
-
- private DexType dispatchInterfaceTypeFor(DexClassAndMethod method) {
- return dispatchTypeFor(method, "dispatchInterface");
- }
-
- private DexType dispatchHolderTypeFor(DexClassAndMethod method) {
- return dispatchTypeFor(method, "dispatchHolder");
- }
-
- public static String getRetargetPackageAndClassPrefixDescriptor(
- DesugaredLibraryConfiguration config) {
- return "L"
- + config.getSynthesizedLibraryClassesPackagePrefix()
- + RETARGET_PACKAGE
- + DESUGAR_LIB_RETARGET_CLASS_NAME_PREFIX;
- }
-
- private DexType dispatchTypeFor(DexClassAndMethod method, String suffix) {
- String descriptor =
- packageAndClassDescriptorPrefix
- + '$'
- + method.getHolderType().getName()
- + '$'
- + method.getName()
- + '$'
- + suffix
- + ';';
- return appView.dexItemFactory().createSynthesizedType(descriptor);
}
}
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
index 5929db5..7e029ed 100644
--- 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
@@ -21,7 +21,6 @@
import com.android.tools.r8.ir.synthetic.EmulateInterfaceSyntheticCfCodeProvider;
import com.android.tools.r8.synthesis.SyntheticMethodBuilder;
import com.android.tools.r8.synthesis.SyntheticNaming;
-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;
@@ -308,19 +307,11 @@
&& !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);
+ String newName =
+ appView
+ .options()
+ .desugaredLibraryConfiguration
+ .convertJavaNameToDesugaredLibrary(clazz.type);
rewriter.addCompanionClassRewriteRule(clazz.type, newName);
} else {
filteredProgramClasses.add(clazz);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
index bdd6064..679a099 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -9,7 +9,6 @@
import static com.android.tools.r8.ir.code.Invoke.Type.STATIC;
import static com.android.tools.r8.ir.code.Invoke.Type.SUPER;
import static com.android.tools.r8.ir.code.Invoke.Type.VIRTUAL;
-import static com.android.tools.r8.ir.desugar.DesugaredLibraryRetargeter.getRetargetPackageAndClassPrefixDescriptor;
import static com.android.tools.r8.ir.desugar.DesugaredLibraryWrapperSynthesizer.TYPE_WRAPPER_SUFFIX;
import static com.android.tools.r8.ir.desugar.DesugaredLibraryWrapperSynthesizer.VIVIFIED_TYPE_WRAPPER_SUFFIX;
@@ -1323,9 +1322,6 @@
private Predicate<DexType> getShouldIgnoreFromReportsPredicate(AppView<?> appView) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
InternalOptions options = appView.options();
- DexString retargetPackageAndClassPrefixDescriptor =
- dexItemFactory.createString(
- getRetargetPackageAndClassPrefixDescriptor(options.desugaredLibraryConfiguration));
DexString typeWrapperClassNameDescriptorSuffix =
dexItemFactory.createString(TYPE_WRAPPER_SUFFIX + ';');
DexString vivifiedTypeWrapperClassNameDescriptorSuffix =
@@ -1341,8 +1337,7 @@
|| descriptor.endsWith(companionClassNameDescriptorSuffix)
|| emulatedInterfaces.containsValue(type)
|| options.desugaredLibraryConfiguration.getCustomConversions().containsValue(type)
- || appView.getDontWarnConfiguration().matches(type)
- || descriptor.startsWith(retargetPackageAndClassPrefixDescriptor);
+ || appView.getDontWarnConfiguration().matches(type);
};
}
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 239c0da..a4478d6 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -47,7 +47,6 @@
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
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.LambdaDescriptor;
import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.synthesis.CommittedItems;
@@ -522,7 +521,6 @@
// TODO(b/150693139): Remove these exceptions once fixed.
|| InterfaceMethodRewriter.isCompanionClassType(type)
|| InterfaceMethodRewriter.isEmulatedLibraryClassType(type)
- || DesugaredLibraryRetargeter.isRetargetType(type, options())
// TODO(b/150736225): Not sure how to remove these.
|| DesugaredLibraryAPIConverter.isVivifiedType(type)
: "Failed lookup of non-missing type: " + type;
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 0ec8c27..2cc626d 100644
--- a/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
+++ b/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
@@ -5,7 +5,6 @@
package com.android.tools.r8.shaking;
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.utils.collections.IdentityHashSetFromMap.newProgramDerivedContextSet;
import com.android.tools.r8.diagnostic.MissingDefinitionsDiagnostic;
@@ -23,7 +22,6 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.synthesis.CommittedItems;
import com.android.tools.r8.synthesis.SyntheticItems.SynthesizingContextOracle;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.SetUtils;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
@@ -280,15 +278,10 @@
private static Predicate<DexType> getIsCompilerSynthesizedAllowedMissingClassesPredicate(
AppView<?> appView) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
- InternalOptions options = appView.options();
- DexString retargetPackageAndClassPrefixDescriptor =
- dexItemFactory.createString(
- getRetargetPackageAndClassPrefixDescriptor(options.desugaredLibraryConfiguration));
DexString vivifiedClassNamePrefix = dexItemFactory.createString(DESCRIPTOR_VIVIFIED_PREFIX);
return type -> {
DexString descriptor = type.getDescriptor();
- return descriptor.startsWith(retargetPackageAndClassPrefixDescriptor)
- || descriptor.startsWith(vivifiedClassNamePrefix);
+ return descriptor.startsWith(vivifiedClassNamePrefix);
};
}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
index 8e78b09..65c510c 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
@@ -22,19 +22,23 @@
import com.android.tools.r8.graph.NestHostClassAttribute;
import com.android.tools.r8.graph.NestMemberClassAttribute;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
-abstract class SyntheticClassBuilder<B extends SyntheticClassBuilder<B, C>, C extends DexClass> {
+public abstract class SyntheticClassBuilder<
+ B extends SyntheticClassBuilder<B, C>, C extends DexClass> {
private final DexItemFactory factory;
private final DexType type;
+ private final SyntheticKind syntheticKind;
private final Origin origin;
private boolean isAbstract = false;
+ private boolean isInterface = false;
private Kind originKind;
private DexType superType;
private DexTypeList interfaces = DexTypeList.empty();
@@ -46,9 +50,14 @@
private List<SyntheticMethodBuilder> methods = new ArrayList<>();
private ClassSignature signature = ClassSignature.noSignature();
- SyntheticClassBuilder(DexType type, SynthesizingContext context, DexItemFactory factory) {
+ SyntheticClassBuilder(
+ DexType type,
+ SyntheticKind syntheticKind,
+ SynthesizingContext context,
+ DexItemFactory factory) {
this.factory = factory;
this.type = type;
+ this.syntheticKind = syntheticKind;
this.origin = context.getInputContextOrigin();
this.superType = factory.objectType;
}
@@ -65,6 +74,10 @@
return type;
}
+ public SyntheticKind getSyntheticKind() {
+ return syntheticKind;
+ }
+
public B setInterfaces(List<DexType> interfaces) {
this.interfaces =
interfaces.isEmpty()
@@ -78,6 +91,12 @@
return self();
}
+ public B setInterface() {
+ setAbstract();
+ isInterface = true;
+ return self();
+ }
+
public B setOriginKind(Kind originKind) {
this.originKind = originKind;
return self();
@@ -126,9 +145,11 @@
public C build() {
int flag = isAbstract ? Constants.ACC_ABSTRACT : Constants.ACC_FINAL;
+ int itfFlag = isInterface ? Constants.ACC_INTERFACE : 0;
+ assert !isInterface || isAbstract;
ClassAccessFlags accessFlags =
ClassAccessFlags.fromSharedAccessFlags(
- flag | Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC);
+ flag | itfFlag | Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC);
NestHostClassAttribute nestHost = null;
List<NestMemberClassAttribute> nestMembers = Collections.emptyList();
EnclosingMethodAttribute enclosingMembers = null;
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticClasspathClassBuilder.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticClasspathClassBuilder.java
index 20cd075..b888913 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticClasspathClassBuilder.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticClasspathClassBuilder.java
@@ -8,13 +8,17 @@
import com.android.tools.r8.graph.DexClasspathClass;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
public class SyntheticClasspathClassBuilder
extends SyntheticClassBuilder<SyntheticClasspathClassBuilder, DexClasspathClass> {
SyntheticClasspathClassBuilder(
- DexType type, SynthesizingContext context, DexItemFactory factory) {
- super(type, context, factory);
+ DexType type,
+ SyntheticKind syntheticKind,
+ SynthesizingContext context,
+ DexItemFactory factory) {
+ super(type, syntheticKind, context, factory);
setOriginKind(Kind.CF);
}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
index 15719ce..e1f4b12 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -462,7 +462,7 @@
DexType type,
DexItemFactory factory) {
SyntheticProgramClassBuilder classBuilder =
- new SyntheticProgramClassBuilder(type, outerContext, factory);
+ new SyntheticProgramClassBuilder(type, kind, outerContext, factory);
fn.accept(classBuilder);
DexProgramClass clazz = classBuilder.build();
addPendingDefinition(new SyntheticProgramClassDefinition(kind, outerContext, clazz));
@@ -503,16 +503,19 @@
*/
public DexProgramClass ensureFixedClass(
SyntheticKind kind,
- DexProgramClass context,
+ DexClass context,
AppView<?> appView,
Consumer<SyntheticProgramClassBuilder> fn) {
assert kind.isFixedSuffixSynthetic;
// Obtain the outer synthesizing context in the case the context itself is synthetic.
// This is to ensure a flat input-type -> synthetic-item mapping.
- SynthesizingContext outerContext = getSynthesizingContext(context, appView);
+ SynthesizingContext outerContext =
+ context.isProgramClass()
+ ? getSynthesizingContext(context.asProgramClass(), appView)
+ : SynthesizingContext.fromNonSyntheticInputContext(context.asClasspathOrLibraryClass());
DexType type = SyntheticNaming.createFixedType(kind, outerContext, appView.dexItemFactory());
// Fast path is that the synthetic is already present. If so it must be a program class.
- DexClass clazz = appView.definitionFor(type, context);
+ DexClass clazz = appView.definitionFor(type);
if (clazz != null) {
assert isSyntheticClass(type);
assert clazz.isProgramClass();
@@ -521,7 +524,7 @@
// Slow path creates the class using the context to make it thread safe.
synchronized (context) {
// Recheck if it is present now the lock is held.
- clazz = appView.definitionFor(type, context);
+ clazz = appView.definitionFor(type);
if (clazz != null) {
assert isSyntheticClass(type);
assert clazz.isProgramClass();
@@ -539,12 +542,41 @@
SynthesizingContext outerContext = SynthesizingContext.fromNonSyntheticInputContext(context);
DexType type = SyntheticNaming.createFixedType(kind, outerContext, factory);
SyntheticClasspathClassBuilder classBuilder =
- new SyntheticClasspathClassBuilder(type, outerContext, factory);
+ new SyntheticClasspathClassBuilder(type, kind, outerContext, factory);
DexClasspathClass clazz = classBuilder.build();
addPendingDefinition(new SyntheticClasspathClassDefinition(kind, outerContext, clazz));
return clazz;
}
+ public DexClasspathClass ensureFixedClasspathClass(
+ SyntheticKind kind,
+ ClasspathOrLibraryClass context,
+ AppView<?> appView,
+ Consumer<SyntheticClasspathClassBuilder> classConsumer) {
+ SynthesizingContext outerContext = SynthesizingContext.fromNonSyntheticInputContext(context);
+ DexType type = SyntheticNaming.createFixedType(kind, outerContext, appView.dexItemFactory());
+ DexClass dexClass = appView.appInfo().definitionForWithoutExistenceAssert(type);
+ if (dexClass != null) {
+ assert dexClass.isClasspathClass();
+ return dexClass.asClasspathClass();
+ }
+ synchronized (context) {
+ dexClass = appView.appInfo().definitionForWithoutExistenceAssert(type);
+ if (dexClass != null) {
+ assert dexClass.isClasspathClass();
+ return dexClass.asClasspathClass();
+ }
+ // Obtain the outer synthesizing context in the case the context itself is synthetic.
+ // This is to ensure a flat input-type -> synthetic-item mapping.
+ SyntheticClasspathClassBuilder classBuilder =
+ new SyntheticClasspathClassBuilder(type, kind, outerContext, appView.dexItemFactory());
+ classConsumer.accept(classBuilder);
+ DexClasspathClass clazz = classBuilder.build();
+ addPendingDefinition(new SyntheticClasspathClassDefinition(kind, outerContext, clazz));
+ return clazz;
+ }
+ }
+
// This is a temporary API for migration to the hygienic synthetic, the classes created behave
// like a hygienic synthetic, but use the legacyType passed as parameter instead of the
// hygienic type.
@@ -560,7 +592,8 @@
// This is to ensure a flat input-type -> synthetic-item mapping.
SynthesizingContext outerContext = SynthesizingContext.fromNonSyntheticInputContext(context);
SyntheticClasspathClassBuilder classBuilder =
- new SyntheticClasspathClassBuilder(legacyType, outerContext, appView.dexItemFactory());
+ new SyntheticClasspathClassBuilder(
+ legacyType, kind, outerContext, appView.dexItemFactory());
DexClasspathClass clazz = classBuilder.build();
addPendingDefinition(new SyntheticClasspathClassDefinition(kind, outerContext, clazz));
return clazz;
@@ -584,7 +617,7 @@
return;
}
SyntheticMethodBuilder syntheticMethodBuilder =
- new SyntheticMethodBuilder(appView.dexItemFactory(), syntheticClass.type);
+ new SyntheticMethodBuilder(appView.dexItemFactory(), syntheticClass.type, kind);
builderConsumer.accept(syntheticMethodBuilder);
syntheticClass.addDirectMethod(syntheticMethodBuilder.build());
}
@@ -625,7 +658,7 @@
SyntheticNaming.createInternalType(
kind, outerContext, syntheticIdSupplier.get(), appView.dexItemFactory());
SyntheticProgramClassBuilder classBuilder =
- new SyntheticProgramClassBuilder(type, outerContext, appView.dexItemFactory());
+ new SyntheticProgramClassBuilder(type, kind, outerContext, appView.dexItemFactory());
DexProgramClass clazz =
classBuilder
.addMethod(fn.andThen(m -> m.setName(SyntheticNaming.INTERNAL_SYNTHETIC_METHOD_PREFIX)))
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticMarker.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMarker.java
index ffaad01..a06fdb7 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticMarker.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMarker.java
@@ -128,7 +128,7 @@
return NO_MARKER;
}
for (DexEncodedMethod method : clazz.methods()) {
- if (!SyntheticMethodBuilder.isValidSyntheticMethod(method)) {
+ if (!SyntheticMethodBuilder.isValidSingleSyntheticMethod(method)) {
return NO_MARKER;
}
}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
index 67bd52c..e2cd6eb 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ParameterAnnotationsList;
+import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
import java.util.function.Consumer;
public class SyntheticMethodBuilder {
@@ -25,6 +26,7 @@
private final DexItemFactory factory;
private final DexType holderType;
+ private final SyntheticKind syntheticKind;
private DexString name = null;
private DexProto proto = null;
private CfVersion classFileVersion;
@@ -38,11 +40,13 @@
SyntheticMethodBuilder(SyntheticClassBuilder<?, ?> parent) {
this.factory = parent.getFactory();
this.holderType = parent.getType();
+ this.syntheticKind = parent.getSyntheticKind();
}
- SyntheticMethodBuilder(DexItemFactory factory, DexType holderType) {
+ SyntheticMethodBuilder(DexItemFactory factory, DexType holderType, SyntheticKind syntheticKind) {
this.factory = factory;
this.holderType = holderType;
+ this.syntheticKind = syntheticKind;
}
public SyntheticMethodBuilder setName(String name) {
@@ -101,20 +105,18 @@
assert name != null;
boolean isCompilerSynthesized = true;
DexMethod methodSignature = getMethodSignature();
+ MethodAccessFlags accessFlags = getAccessFlags();
DexEncodedMethod method =
new DexEncodedMethod(
methodSignature,
- getAccessFlags(),
+ accessFlags,
genericSignature,
annotations,
parameterAnnotationsList,
- getCodeObject(methodSignature),
+ accessFlags.isAbstract() ? null : getCodeObject(methodSignature),
isCompilerSynthesized,
classFileVersion);
- // Companion class method may have different properties.
- assert isValidSyntheticMethod(method)
- || SyntheticNaming.isSynthetic(
- holderType.asClassReference(), null, SyntheticNaming.SyntheticKind.COMPANION_CLASS);
+ assert isValidSyntheticMethod(method, syntheticKind);
if (onBuildConsumer != null) {
onBuildConsumer.accept(method);
}
@@ -126,8 +128,16 @@
*
* <p>This method is used when identifying synthetic methods in the program input and should be as
* narrow as possible.
+ *
+ * <p>Methods in fixed suffix synthetics are identified differently (through the class name) and
+ * can have different properties.
*/
- public static boolean isValidSyntheticMethod(DexEncodedMethod method) {
+ public static boolean isValidSyntheticMethod(
+ DexEncodedMethod method, SyntheticKind syntheticKind) {
+ return isValidSingleSyntheticMethod(method) || syntheticKind.isFixedSuffixSynthetic;
+ }
+
+ public static boolean isValidSingleSyntheticMethod(DexEncodedMethod method) {
return method.isStatic()
&& method.isNonAbstractNonNativeMethod()
&& method.isPublic()
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodDefinition.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodDefinition.java
index 87393f7..a9d11c7 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodDefinition.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodDefinition.java
@@ -70,7 +70,7 @@
@Override
public boolean isValid() {
- return SyntheticMethodBuilder.isValidSyntheticMethod(method.getDefinition());
+ return SyntheticMethodBuilder.isValidSyntheticMethod(method.getDefinition(), getKind());
}
@Override
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
index 6ed6c0e..33530e6 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
@@ -26,6 +26,8 @@
RECORD_TAG("", 1, false, true, true),
COMPANION_CLASS("$-CC", 2, false, true),
EMULATED_INTERFACE_CLASS("$-EL", 3, false, true),
+ RETARGET_CLASS("RetargetClass", 20, false, true),
+ RETARGET_INTERFACE("RetargetInterface", 21, false, true),
LAMBDA("Lambda", 4, false),
INIT_TYPE_ARGUMENT("-IA", 5, false, true),
HORIZONTAL_INIT_TYPE_ARGUMENT_1(SYNTHETIC_CLASS_SEPARATOR + "IA$1", 6, false, true),
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticProgramClassBuilder.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticProgramClassBuilder.java
index 6408621..8c07884 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticProgramClassBuilder.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticProgramClassBuilder.java
@@ -7,12 +7,17 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
public class SyntheticProgramClassBuilder
extends SyntheticClassBuilder<SyntheticProgramClassBuilder, DexProgramClass> {
- SyntheticProgramClassBuilder(DexType type, SynthesizingContext context, DexItemFactory factory) {
- super(type, context, factory);
+ SyntheticProgramClassBuilder(
+ DexType type,
+ SyntheticKind syntheticKind,
+ SynthesizingContext context,
+ DexItemFactory factory) {
+ super(type, syntheticKind, context, factory);
}
@Override