blob: b25186049db847c3cd969024f41dca72d91034f5 [file] [log] [blame]
// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.desugar;
import com.android.tools.r8.ProgramResource.Kind;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
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.DexClass;
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.DexLibraryClass;
import com.android.tools.r8.graph.DexMethod;
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.DirectMappedDexApplication;
import com.android.tools.r8.graph.EnclosingMethodAttribute;
import com.android.tools.r8.graph.InnerClassAttribute;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.NestHostClassAttribute;
import com.android.tools.r8.graph.NestMemberClassAttribute;
import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.origin.SynthesizedOrigin;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
public class DesugaredLibraryRetargeter {
public static DirectMappedDexApplication amendLibraryWithRetargetedMembers(
AppView<AppInfoWithSubtyping> appView) {
Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember();
Map<DexType, DexLibraryClass> synthesizedLibraryClasses =
synthesizeLibraryClassesForRetargetedMembers(appView, retargetCoreLibMember);
Map<DexLibraryClass, Set<DexEncodedMethod>> synthesizedLibraryMethods =
synthesizedMembersForRetargetClasses(
appView, retargetCoreLibMember, synthesizedLibraryClasses);
synthesizedLibraryMethods.forEach(DexLibraryClass::appendDirectMethods);
DirectMappedDexApplication newApplication =
appView
.appInfo()
.app()
.asDirect()
.builder()
.addLibraryClasses(synthesizedLibraryClasses.values())
.build();
appView.setAppInfo(new AppInfoWithSubtyping(newApplication));
return newApplication;
}
private static Map<DexType, DexLibraryClass> synthesizeLibraryClassesForRetargetedMembers(
AppView<AppInfoWithSubtyping> appView,
Map<DexString, Map<DexType, DexType>> retargetCoreLibMember) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
Map<DexType, DexLibraryClass> synthesizedLibraryClasses = new LinkedHashMap<>();
for (Map<DexType, DexType> oldToNewTypeMap : retargetCoreLibMember.values()) {
for (DexType newType : oldToNewTypeMap.values()) {
if (appView.definitionFor(newType) == null) {
synthesizedLibraryClasses.computeIfAbsent(
newType,
type ->
// Synthesize a library class with the given name. Note that this is assuming that
// the library class inherits directly from java.lang.Object, does not implement
// any interfaces, etc.
new DexLibraryClass(
type,
Kind.CF,
new SynthesizedOrigin(
"Desugared library retargeter", DesugaredLibraryRetargeter.class),
ClassAccessFlags.fromCfAccessFlags(Constants.ACC_PUBLIC),
dexItemFactory.objectType,
DexTypeList.empty(),
dexItemFactory.createString("DesugaredLibraryRetargeter"),
NestHostClassAttribute.none(),
NestMemberClassAttribute.emptyList(),
EnclosingMethodAttribute.none(),
InnerClassAttribute.emptyList(),
DexAnnotationSet.empty(),
DexEncodedField.EMPTY_ARRAY,
DexEncodedField.EMPTY_ARRAY,
DexEncodedMethod.EMPTY_ARRAY,
DexEncodedMethod.EMPTY_ARRAY,
dexItemFactory.getSkipNameValidationForTesting()));
}
}
}
return synthesizedLibraryClasses;
}
private static Map<DexLibraryClass, Set<DexEncodedMethod>> synthesizedMembersForRetargetClasses(
AppView<AppInfoWithSubtyping> appView,
Map<DexString, Map<DexType, DexType>> retargetCoreLibMember,
Map<DexType, DexLibraryClass> synthesizedLibraryClasses) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
Map<DexLibraryClass, Set<DexEncodedMethod>> synthesizedMembers = new IdentityHashMap<>();
for (Entry<DexString, Map<DexType, DexType>> entry : retargetCoreLibMember.entrySet()) {
DexString methodName = entry.getKey();
Map<DexType, DexType> types = entry.getValue();
types.forEach(
(oldType, newType) -> {
DexClass oldClass = appView.definitionFor(oldType);
DexLibraryClass newClass = synthesizedLibraryClasses.get(newType);
if (oldClass == null || newClass == null) {
return;
}
for (DexEncodedMethod method :
oldClass.methods(method -> method.getName() == methodName)) {
DexMethod retargetMethod = method.getReference().withHolder(newType, dexItemFactory);
if (!method.isStatic()) {
retargetMethod = retargetMethod.withExtraArgumentPrepended(oldType, dexItemFactory);
}
synthesizedMembers
.computeIfAbsent(
newClass,
ignore ->
new TreeSet<>((x, y) -> x.getReference().slowCompareTo(y.getReference())))
.add(
new DexEncodedMethod(
retargetMethod,
MethodAccessFlags.fromCfAccessFlags(
Constants.ACC_PUBLIC | Constants.ACC_STATIC, false),
DexAnnotationSet.empty(),
ParameterAnnotationsList.empty(),
null,
true));
}
});
}
return synthesizedMembers;
}
}