blob: 97749d6fac9221b53507450c8489dd4be8f21de3 [file] [log] [blame]
// 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.desugaredlibrary.humanspecification;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser.CONFIGURATION_FORMAT_VERSION_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.AMEND_LIBRARY_METHOD_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.API_LEVEL_BELOW_OR_EQUAL_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.BACKPORT_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.COMMON_FLAGS_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.CURRENT_HUMAN_CONFIGURATION_FORMAT_VERSION;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.CUSTOM_CONVERSION_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.DONT_RETARGET_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.DONT_REWRITE_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.EMULATE_INTERFACE_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.IDENTIFIER_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.LIBRARY_FLAGS_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.PROGRAM_FLAGS_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.REQUIRED_COMPILATION_API_LEVEL_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.RETARGET_METHOD_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.REWRITE_DERIVED_PREFIX_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.REWRITE_PREFIX_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.SHRINKER_CONFIG_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.SUPPORT_ALL_CALLBACKS_FROM_LIBRARY_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.SYNTHESIZED_LIBRARY_CLASSES_PACKAGE_PREFIX_KEY;
import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.WRAPPER_CONVERSION_KEY;
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.StringConsumer;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexItem;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.google.common.collect.Sets;
import com.google.gson.Gson;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter {
public static void export(
MultiAPILevelHumanDesugaredLibrarySpecification specification, StringConsumer output) {
new MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter()
.internalExport(specification, output);
}
private void internalExport(
MultiAPILevelHumanDesugaredLibrarySpecification humanSpec, StringConsumer output) {
HashMap<String, Object> toJson = new LinkedHashMap<>();
toJson.put(IDENTIFIER_KEY, humanSpec.getTopLevelFlags().getIdentifier());
toJson.put(CONFIGURATION_FORMAT_VERSION_KEY, CURRENT_HUMAN_CONFIGURATION_FORMAT_VERSION);
toJson.put(
REQUIRED_COMPILATION_API_LEVEL_KEY,
humanSpec.getTopLevelFlags().getRequiredCompilationAPILevel().getLevel());
toJson.put(
SYNTHESIZED_LIBRARY_CLASSES_PACKAGE_PREFIX_KEY,
humanSpec.getTopLevelFlags().getSynthesizedLibraryClassesPackagePrefix().replace('/', '.'));
toJson.put(
SUPPORT_ALL_CALLBACKS_FROM_LIBRARY_KEY,
humanSpec.getTopLevelFlags().supportAllCallbacksFromLibrary());
toJson.put(COMMON_FLAGS_KEY, rewritingFlagsToString(humanSpec.getCommonFlags()));
toJson.put(PROGRAM_FLAGS_KEY, rewritingFlagsToString(humanSpec.getProgramFlags()));
toJson.put(LIBRARY_FLAGS_KEY, rewritingFlagsToString(humanSpec.getLibraryFlags()));
toJson.put(SHRINKER_CONFIG_KEY, humanSpec.getTopLevelFlags().getExtraKeepRules());
Gson gson = new Gson();
String export = gson.toJson(toJson);
output.accept(export, new DiagnosticsHandler() {});
}
private List<Object> rewritingFlagsToString(
Int2ObjectMap<HumanRewritingFlags> rewritingFlagsMap) {
ArrayList<Object> list = new ArrayList<>();
ArrayList<Integer> apis = new ArrayList<>(rewritingFlagsMap.keySet());
apis.sort(Comparator.reverseOrder());
for (int apiBelowOrEqual : apis) {
HumanRewritingFlags flags = rewritingFlagsMap.get(apiBelowOrEqual);
HashMap<String, Object> toJson = new LinkedHashMap<>();
toJson.put(API_LEVEL_BELOW_OR_EQUAL_KEY, apiBelowOrEqual);
if (!flags.getRewritePrefix().isEmpty()) {
toJson.put(REWRITE_PREFIX_KEY, new TreeMap<>(flags.getRewritePrefix()));
}
if (!flags.getRewriteDerivedPrefix().isEmpty()) {
TreeMap<String, Map<String, String>> rewriteDerivedPrefix = new TreeMap<>();
flags
.getRewriteDerivedPrefix()
.forEach((k, v) -> rewriteDerivedPrefix.put(k, new TreeMap<>(v)));
toJson.put(REWRITE_DERIVED_PREFIX_KEY, rewriteDerivedPrefix);
}
if (!flags.getEmulatedInterfaces().isEmpty()) {
toJson.put(EMULATE_INTERFACE_KEY, mapToString(flags.getEmulatedInterfaces()));
}
if (!flags.getDontRewriteInvocation().isEmpty()) {
toJson.put(DONT_REWRITE_KEY, setToString(flags.getDontRewriteInvocation()));
}
if (!flags.getRetargetMethod().isEmpty()) {
toJson.put(RETARGET_METHOD_KEY, mapToString(flags.getRetargetMethod()));
}
if (!flags.getDontRetarget().isEmpty()) {
toJson.put(DONT_RETARGET_KEY, setToString(flags.getDontRetarget()));
}
if (!flags.getLegacyBackport().isEmpty()) {
toJson.put(BACKPORT_KEY, mapToString(flags.getLegacyBackport()));
}
if (!flags.getWrapperConversions().isEmpty()) {
toJson.put(WRAPPER_CONVERSION_KEY, setToString(flags.getWrapperConversions()));
}
if (!flags.getCustomConversions().isEmpty()) {
toJson.put(CUSTOM_CONVERSION_KEY, mapToString(flags.getCustomConversions()));
}
if (!flags.getAmendLibraryMethod().isEmpty()) {
toJson.put(AMEND_LIBRARY_METHOD_KEY, amendLibraryToString(flags.getAmendLibraryMethod()));
}
list.add(toJson);
}
return list;
}
private Set<String> amendLibraryToString(Map<DexMethod, MethodAccessFlags> amendLibraryMembers) {
Set<String> stringSet = Sets.newHashSet();
amendLibraryMembers.forEach(
(member, flags) -> stringSet.add(flags.toString() + " " + toString(member)));
return stringSet;
}
private Set<String> setToString(Set<? extends DexItem> set) {
Set<String> stringSet = Sets.newHashSet();
set.forEach(e -> stringSet.add(toString(e)));
return stringSet;
}
private Map<String, String> mapToString(Map<? extends DexItem, ? extends DexItem> map) {
Map<String, String> stringMap = new TreeMap<>();
map.forEach((k, v) -> stringMap.put(toString(k), toString(v)));
return stringMap;
}
private String toString(DexItem o) {
if (o instanceof DexType) {
return o.toString();
}
if (o instanceof DexMethod) {
DexMethod method = (DexMethod) o;
StringBuilder sb =
new StringBuilder()
.append(method.getReturnType())
.append(" ")
.append(method.getHolderType())
.append("#")
.append(method.getName())
.append("(");
for (int i = 0; i < method.getParameters().size(); i++) {
sb.append(method.getParameter(i));
if (i != method.getParameters().size() - 1) {
sb.append(", ");
}
}
sb.append(")");
return sb.toString();
}
throw new Unreachable();
}
}