Introduce deduplicate flags for Human flags
- Move as many common flags in the common flags section
Bug: 184026720
Change-Id: Iea63747191e0a1ec933946f1d46042d8c9afd76b
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
index 8adb9b7..bf87cd8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
@@ -176,14 +176,17 @@
this.retargetCoreLibMember = new IdentityHashMap<>(retargetCoreLibMember);
this.backportCoreLibraryMember = new IdentityHashMap<>(backportCoreLibraryMember);
this.customConversions = new IdentityHashMap<>(customConversions);
- this.dontRewriteInvocation = dontRewriteInvocation;
- this.dontRetargetLibMember = dontRetargetLibMember;
- this.wrapperConversions = wrapperConversions;
+ this.dontRewriteInvocation = Sets.newIdentityHashSet();
+ this.dontRewriteInvocation.addAll(dontRewriteInvocation);
+ this.dontRetargetLibMember = Sets.newIdentityHashSet();
+ this.dontRetargetLibMember.addAll(dontRetargetLibMember);
+ this.wrapperConversions = Sets.newIdentityHashSet();
+ this.wrapperConversions.addAll(wrapperConversions);
}
- // Utility to set values. Currently assumes the key is fresh.
+ // Utility to set values.
private <K, V> void put(Map<K, V> map, K key, V value, String desc) {
- if (map.containsKey(key)) {
+ if (map.containsKey(key) && !map.get(key).equals(value)) {
throw reporter.fatalError(
new StringDiagnostic(
"Invalid desugared library configuration. "
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecification.java
index 6ea4fd1..2ade60c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecification.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification;
+import com.android.tools.r8.origin.Origin;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import java.util.Map;
@@ -52,4 +53,9 @@
public Map<Integer, HumanRewritingFlags> getProgramFlagsForTesting() {
return programFlags;
}
+
+ public Origin getOrigin() {
+ // TODO(b/184026720): Maintain the origin.
+ return Origin.unknown();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationFlagDeduplicator.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationFlagDeduplicator.java
new file mode 100644
index 0000000..18a0ed2
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationFlagDeduplicator.java
@@ -0,0 +1,171 @@
+// 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 com.android.tools.r8.graph.DexItem;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.Reporter;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.IntArraySet;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+public class MultiAPILevelHumanDesugaredLibrarySpecificationFlagDeduplicator {
+
+ public static Origin createOrigin(String source) {
+ return new Origin(Origin.root()) {
+ @Override
+ public String part() {
+ return source;
+ }
+ };
+ }
+
+ public static void deduplicateFlags(
+ MultiAPILevelHumanDesugaredLibrarySpecification specification,
+ DexItemFactory factory,
+ Reporter reporter) {
+
+ IntArraySet apis = new IntArraySet();
+ apis.addAll(specification.getCommonFlags().keySet());
+ apis.addAll(specification.getLibraryFlags().keySet());
+ apis.addAll(specification.getProgramFlags().keySet());
+
+ for (Integer api : apis) {
+ deduplicateFlags(api, specification, factory, reporter);
+ }
+ }
+
+ private static void deduplicateFlags(
+ int api,
+ MultiAPILevelHumanDesugaredLibrarySpecification specification,
+ DexItemFactory factory,
+ Reporter reporter) {
+
+ Int2ObjectMap<HumanRewritingFlags> commonFlags = specification.getCommonFlags();
+ Int2ObjectMap<HumanRewritingFlags> libraryFlags = specification.getLibraryFlags();
+ Int2ObjectMap<HumanRewritingFlags> programFlags = specification.getProgramFlags();
+
+ HumanRewritingFlags library = libraryFlags.get(api);
+ HumanRewritingFlags program = programFlags.get(api);
+
+ if (library == null || program == null) {
+ return;
+ }
+
+ Origin origin = specification.getOrigin();
+ HumanRewritingFlags.Builder commonBuilder =
+ commonFlags.get(api) == null
+ ? HumanRewritingFlags.builder(factory, reporter, origin)
+ : commonFlags.get(api).newBuilder(factory, reporter, origin);
+ HumanRewritingFlags.Builder libraryBuilder =
+ HumanRewritingFlags.builder(factory, reporter, origin);
+ HumanRewritingFlags.Builder programBuilder =
+ HumanRewritingFlags.builder(factory, reporter, origin);
+
+ // Iterate over all library/program flags, add them in common if also in the other, else add
+ // them to library/program.
+ deduplicateFlags(library, program, commonBuilder, libraryBuilder);
+ deduplicateFlags(program, library, commonBuilder, programBuilder);
+
+ commonFlags.put(api, commonBuilder.build());
+ libraryFlags.put(api, libraryBuilder.build());
+ programFlags.put(api, programBuilder.build());
+ }
+
+ private static void deduplicateFlags(
+ HumanRewritingFlags flags,
+ HumanRewritingFlags otherFlags,
+ HumanRewritingFlags.Builder commonBuilder,
+ HumanRewritingFlags.Builder builder) {
+ deduplicateRewritePrefix(flags, otherFlags, commonBuilder, builder);
+
+ deduplicateFlags(
+ flags.getEmulateLibraryInterface(),
+ otherFlags.getEmulateLibraryInterface(),
+ commonBuilder::putEmulateLibraryInterface,
+ builder::putEmulateLibraryInterface);
+ deduplicateFlags(
+ flags.getRetargetCoreLibMember(),
+ otherFlags.getRetargetCoreLibMember(),
+ commonBuilder::putRetargetCoreLibMember,
+ builder::putRetargetCoreLibMember);
+ deduplicateFlags(
+ flags.getBackportCoreLibraryMember(),
+ otherFlags.getBackportCoreLibraryMember(),
+ commonBuilder::putBackportCoreLibraryMember,
+ builder::putBackportCoreLibraryMember);
+ deduplicateFlags(
+ flags.getCustomConversions(),
+ otherFlags.getCustomConversions(),
+ commonBuilder::putCustomConversion,
+ builder::putCustomConversion);
+
+ deduplicateFlags(
+ flags.getDontRewriteInvocation(),
+ otherFlags.getDontRewriteInvocation(),
+ commonBuilder::addDontRewriteInvocation,
+ builder::addDontRewriteInvocation);
+ deduplicateFlags(
+ flags.getDontRetargetLibMember(),
+ otherFlags.getDontRetargetLibMember(),
+ commonBuilder::addDontRetargetLibMember,
+ builder::addDontRetargetLibMember);
+ deduplicateFlags(
+ flags.getWrapperConversions(),
+ otherFlags.getWrapperConversions(),
+ commonBuilder::addWrapperConversion,
+ builder::addWrapperConversion);
+ }
+
+ private static void deduplicateRewritePrefix(
+ HumanRewritingFlags flags,
+ HumanRewritingFlags otherFlags,
+ HumanRewritingFlags.Builder commonBuilder,
+ HumanRewritingFlags.Builder builder) {
+ flags
+ .getRewritePrefix()
+ .forEach(
+ (k, v) -> {
+ if (otherFlags.getRewritePrefix().get(k) != null
+ && otherFlags.getRewritePrefix().get(k).equals(v)) {
+ commonBuilder.putRewritePrefix(k, v);
+ } else {
+ builder.putRewritePrefix(k, v);
+ }
+ });
+ }
+
+ private static <T extends DexItem> void deduplicateFlags(
+ Map<T, DexType> flags,
+ Map<T, DexType> otherFlags,
+ BiConsumer<T, DexType> common,
+ BiConsumer<T, DexType> specific) {
+ flags.forEach(
+ (k, v) -> {
+ if (otherFlags.get(k) == v) {
+ common.accept(k, v);
+ } else {
+ specific.accept(k, v);
+ }
+ });
+ }
+
+ private static <T extends DexItem> void deduplicateFlags(
+ Set<T> flags, Set<T> otherFlags, Consumer<T> common, Consumer<T> specific) {
+ flags.forEach(
+ e -> {
+ if (otherFlags.contains(e)) {
+ common.accept(e);
+ } else {
+ specific.accept(e);
+ }
+ });
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
index 6e26eff..ebdc9a1 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanTopLevelFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.MultiAPILevelHumanDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.MultiAPILevelHumanDesugaredLibrarySpecificationFlagDeduplicator;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter;
import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyRewritingFlags;
@@ -55,6 +56,8 @@
.parseMultiLevelConfiguration(inputSpecification);
MultiAPILevelHumanDesugaredLibrarySpecification humanSpec =
convertAllAPILevels(legacySpec, androidLib, options);
+ MultiAPILevelHumanDesugaredLibrarySpecificationFlagDeduplicator.deduplicateFlags(
+ humanSpec, options.dexItemFactory(), options.reporter);
MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.export(humanSpec, output);
}
@@ -94,7 +97,8 @@
private void legacyLibraryFlagHacks(
Int2ObjectArrayMap<HumanRewritingFlags> libraryFlags, DexApplication app) {
- HumanRewritingFlags humanRewritingFlags = libraryFlags.get(AndroidApiLevel.N_MR1.getLevel());
+ int level = AndroidApiLevel.N_MR1.getLevel();
+ HumanRewritingFlags humanRewritingFlags = libraryFlags.get(level);
HumanRewritingFlags.Builder builder =
humanRewritingFlags.newBuilder(
app.dexItemFactory(), app.options.reporter, Origin.unknown());
@@ -122,7 +126,7 @@
target = itemFactory.createType("Ljava/util/DesugarTimeZone;");
builder.putRetargetCoreLibMember(source, target);
- libraryFlags.put(25, builder.build());
+ libraryFlags.put(level, builder.build());
}
private DirectMappedDexApplication readApp(Path androidLib, InternalOptions options)