blob: 92efb2432fc748644e59c024352722368663615b [file] [log] [blame]
// Copyright (c) 2022, 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.desugaredlibrary.specificationconversion;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.DexClass;
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.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
import com.android.tools.r8.utils.DescriptorUtils;
import com.google.common.collect.ImmutableMap;
import java.util.IdentityHashMap;
import java.util.Map;
public class HumanToMachinePrefixConverter {
private final AppInfoWithClassHierarchy appInfo;
private final MachineRewritingFlags.Builder builder;
private final String synthesizedPrefix;
private final Map<DexType, DexType> reverse = new IdentityHashMap<>();
public HumanToMachinePrefixConverter(
AppInfoWithClassHierarchy appInfo,
MachineRewritingFlags.Builder builder,
String synthesizedPrefix) {
this.appInfo = appInfo;
this.builder = builder;
this.synthesizedPrefix = synthesizedPrefix;
}
private DexString toDescriptorPrefix(String prefix) {
return appInfo
.dexItemFactory()
.createString("L" + DescriptorUtils.getBinaryNameFromJavaType(prefix));
}
public void convertPrefixFlags(HumanRewritingFlags rewritingFlags) {
Map<DexString, DexString> descriptorPrefix = convertRewritePrefix(rewritingFlags);
rewriteClasses(descriptorPrefix);
rewriteValues(descriptorPrefix, rewritingFlags.getRetargetCoreLibMember());
rewriteValues(descriptorPrefix, rewritingFlags.getCustomConversions());
rewriteEmulatedInterface(rewritingFlags.getEmulateLibraryInterface());
rewriteRetargetKeys(rewritingFlags.getRetargetCoreLibMember());
rewriteReverse(descriptorPrefix);
}
// For custom conversions, this is responsible in rewriting backward.
private void rewriteReverse(Map<DexString, DexString> descriptorPrefix) {
reverse.forEach(
(rewrittenType, type) -> {
DexType backwardRewrittenType = rewrittenType(descriptorPrefix, rewrittenType);
if (backwardRewrittenType != null) {
assert backwardRewrittenType == type;
builder.rewriteType(rewrittenType, type);
}
});
}
public DexType convertJavaNameToDesugaredLibrary(DexType type) {
String convertedPrefix = DescriptorUtils.getJavaTypeFromBinaryName(synthesizedPrefix);
String interfaceType = type.toString();
int firstPackage = interfaceType.indexOf('.');
return appInfo
.dexItemFactory()
.createType(
DescriptorUtils.javaTypeToDescriptor(
convertedPrefix + interfaceType.substring(firstPackage + 1)));
}
private void rewriteRetargetKeys(Map<DexMethod, DexType> retarget) {
for (DexMethod dexMethod : retarget.keySet()) {
DexType type = convertJavaNameToDesugaredLibrary(dexMethod.holder);
builder.rewriteDerivedTypeOnly(dexMethod.holder, type);
}
}
private void rewriteEmulatedInterface(Map<DexType, DexType> emulateLibraryInterface) {
emulateLibraryInterface.forEach(builder::rewriteDerivedTypeOnly);
}
private void rewriteType(DexType type, DexType rewrittenType) {
builder.rewriteType(type, rewrittenType);
reverse.put(rewrittenType, type);
}
private void rewriteValues(
Map<DexString, DexString> descriptorPrefix,
Map<?, DexType> flags) {
for (DexType type : flags.values()) {
DexType rewrittenType = rewrittenType(descriptorPrefix, type);
if (rewrittenType != null) {
rewriteType(type, rewrittenType);
}
}
}
private void rewriteClasses(Map<DexString, DexString> descriptorPrefix) {
for (DexClass clazz : appInfo.app().asDirect().libraryClasses()) {
rewriteClass(descriptorPrefix, clazz);
}
for (DexClass clazz : appInfo.classes()) {
rewriteClass(descriptorPrefix, clazz);
}
}
private void rewriteClass(Map<DexString, DexString> descriptorPrefix, DexClass clazz) {
DexType type = clazz.type;
DexType rewrittenType = rewrittenType(descriptorPrefix, type);
if (rewrittenType == null) {
return;
}
rewriteType(type, rewrittenType);
}
private DexType rewrittenType(Map<DexString, DexString> descriptorPrefix, DexType type) {
DexString prefixToMatch = type.descriptor.withoutArray(appInfo.dexItemFactory());
for (DexString prefix : descriptorPrefix.keySet()) {
if (prefixToMatch.startsWith(prefix)) {
DexString rewrittenTypeDescriptor =
type.descriptor.withNewPrefix(
prefix, descriptorPrefix.get(prefix), appInfo.dexItemFactory());
return appInfo.dexItemFactory().createType(rewrittenTypeDescriptor);
}
}
return null;
}
private ImmutableMap<DexString, DexString> convertRewritePrefix(
HumanRewritingFlags rewritingFlags) {
Map<String, String> rewritePrefix = rewritingFlags.getRewritePrefix();
ImmutableMap.Builder<DexString, DexString> mapBuilder = ImmutableMap.builder();
for (String key : rewritePrefix.keySet()) {
mapBuilder.put(toDescriptorPrefix(key), toDescriptorPrefix(rewritePrefix.get(key)));
}
return mapBuilder.build();
}
}