R8 desugared library first support
- Clean-up specialLibraryConfiguration into a single class.
- First test for R8+desugared lib.
- Support for Naming lens doing both minification and
PrefixRewritting.
Bug:134732760
Change-Id: I8ed7fa16b3917ac1621009f535f0c766d1dedae9
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index f073650..1088e60 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -200,7 +200,7 @@
null,
GraphLense.getIdentityLense(),
PrefixRewritingNamingLens.createPrefixRewritingNamingLens(
- app, converter.getAdditionalRewritePrefix()),
+ options, converter.getAdditionalRewritePrefix()),
null)
.write(executor);
options.printWarnings();
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 6905dbf..717a26f 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -11,12 +11,8 @@
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.List;
-import java.util.Map;
import java.util.function.BiPredicate;
/**
@@ -257,125 +253,8 @@
super(printHelp, printVersion);
}
- private Map<String, String> buildPrefixRewritingForProgramCompilation() {
- return ImmutableMap.<String, String>builder()
- // --rewrite_core_library_prefix.
- // Following flags are ignored (already desugared).
- // .put("java.lang.Double8", "j$.lang.Double8")
- // .put("java.lang.Integer8", "j$.lang.Integer8")
- // .put("java.lang.Long8", "j$.lang.Long8")
- // .put("java.lang.Math8", "j$.lang.Math8")
- .put("java.time.", "j$.time.")
- .put("java.util.stream.", "j$.util.stream.")
- .put("java.util.function.", "j$.util.function.")
- .put("java.util.Desugar", "j$.util.Desugar")
- .put("java.util.DoubleSummaryStatistics", "j$.util.DoubleSummaryStatistics")
- .put("java.util.IntSummaryStatistics", "j$.util.IntSummaryStatistics")
- .put("java.util.LongSummaryStatistics", "j$.util.LongSummaryStatistics")
- .put("java.util.Objects", "j$.util.Objects")
- .put("java.util.Optional", "j$.util.Optional")
- .put("java.util.PrimitiveIterator", "j$.util.PrimitiveIterator")
- .put("java.util.Spliterator", "j$.util.Spliterator")
- .put("java.util.StringJoiner", "j$.util.StringJoiner")
- .put("java.util.concurrent.ConcurrentHashMap", "j$.util.concurrent.ConcurrentHashMap")
- .put("java.util.concurrent.ThreadLocalRandom", "j$.util.concurrent.ThreadLocalRandom")
- .put("java.util.concurrent.atomic.DesugarAtomic", "j$.util.concurrent.atomic.DesugarAtomic")
- .build();
- }
-
- protected Map<String, String> buildRetargetCoreLibraryMemberForProgramCompilation() {
- // --retarget_core_library_member.
- return ImmutableMap.<String, String>builder()
- // We ignore the following flags required by Bazel because desugaring of these methods
- // is done separately.
- // .put("java.lang.Double#max", "java.lang.Double8")
- // .put("java.lang.Double#min", "java.lang.Double8")
- // .put("java.lang.Double#sum", "java.lang.Double8")
- // .put("java.lang.Integer#max", "java.lang.Integer8")
- // .put("java.lang.Integer#min", "java.lang.Integer8")
- // .put("java.lang.Integer#sum", "java.lang.Integer8")
- // .put("java.lang.Long#max", "java.lang.Long")
- // .put("java.lang.Long#min", "java.lang.Long")
- // .put("java.lang.Long#sum", "java.lang.Long")
- // .put("java.lang.Math#toIntExact", "java.lang.Math8")
- .put("java.util.Arrays#stream", "java.util.DesugarArrays")
- .put("java.util.Arrays#spliterator", "java.util.DesugarArrays")
- .put("java.util.Calendar#toInstant", "java.util.DesugarCalendar")
- .put("java.util.Date#from", "java.util.DesugarDate")
- .put("java.util.Date#toInstant", "java.util.DesugarDate")
- .put("java.util.GregorianCalendar#from", "java.util.DesugarGregorianCalendar")
- .put("java.util.GregorianCalendar#toZonedDateTime", "java.util.DesugarGregorianCalendar")
- .put("java.util.LinkedHashSet#spliterator", "java.util.DesugarLinkedHashSet")
- .put(
- "java.util.concurrent.atomic.AtomicInteger#getAndUpdate",
- "java.util.concurrent.atomic.DesugarAtomicInteger")
- .put(
- "java.util.concurrent.atomic.AtomicInteger#updateAndGet",
- "java.util.concurrent.atomic.DesugarAtomicInteger")
- .put(
- "java.util.concurrent.atomic.AtomicInteger#getAndAccumulate",
- "java.util.concurrent.atomic.DesugarAtomicInteger")
- .put(
- "java.util.concurrent.atomic.AtomicInteger#accumulateAndGet",
- "java.util.concurrent.atomic.DesugarAtomicInteger")
- .put(
- "java.util.concurrent.atomic.AtomicLong#getAndUpdate",
- "java.util.concurrent.atomic.DesugarAtomicLong")
- .put(
- "java.util.concurrent.atomic.AtomicLong#updateAndGet",
- "java.util.concurrent.atomic.DesugarAtomicLong")
- .put(
- "java.util.concurrent.atomic.AtomicLong#getAndAccumulate",
- "java.util.concurrent.atomic.DesugarAtomicLong")
- .put(
- "java.util.concurrent.atomic.AtomicLong#accumulateAndGet",
- "java.util.concurrent.atomic.DesugarAtomicLong")
- .put(
- "java.util.concurrent.atomic.AtomicReference#getAndUpdate",
- "java.util.concurrent.atomic.DesugarAtomicReference")
- .put(
- "java.util.concurrent.atomic.AtomicReference#updateAndGet",
- "java.util.concurrent.atomic.DesugarAtomicReference")
- .put(
- "java.util.concurrent.atomic.AtomicReference#getAndAccumulate",
- "java.util.concurrent.atomic.DesugarAtomicReference")
- .put(
- "java.util.concurrent.atomic.AtomicReference#accumulateAndGet",
- "java.util.concurrent.atomic.DesugarAtomicReference")
- .build();
- }
-
- protected List<String> buildDontRewriteInvocations() {
- // --dont_rewrite_core_library_invocation "java/util/Iterator#remove".
- return ImmutableList.of("java.util.Iterator#remove");
- }
-
- protected Map<String, String> buildEmulateLibraryInterface() {
- return ImmutableMap.<String, String>builder()
- // --emulate_core_library_interface.
- // Bazel flags.
- .put("java.util.Map$Entry", "j$.util.Map$Entry")
- .put("java.util.Collection", "j$.util.Collection")
- .put("java.util.Map", "j$.util.Map")
- .put("java.util.Iterator", "j$.util.Iterator")
- .put("java.util.Comparator", "j$.util.Comparator")
- // Extra flags: in R8 we marked as emulated all interfaces
- // with default methods. Emulated interfaces have their
- // companion class moved to j$ and have a dispatch class.
- // Bazel instead analyzes the class hierarchy.
- .put("java.util.List", "j$.util.List")
- .put("java.util.SortedSet", "j$.util.SortedSet")
- .put("java.util.Set", "j$.util.Set")
- .put("java.util.concurrent.ConcurrentMap", "j$.util.concurrent.ConcurrentMap")
- .build();
- }
-
private void configureLibraryDesugaring(InternalOptions options) {
- options.coreLibraryCompilation = false;
- options.retargetCoreLibMember = buildRetargetCoreLibraryMemberForProgramCompilation();
- options.dontRewriteInvocations = buildDontRewriteInvocations();
- options.rewritePrefix = buildPrefixRewritingForProgramCompilation();
- options.emulateLibraryInterface = buildEmulateLibraryInterface();
+ SpecialLibraryConfiguration.configureLibraryDesugaringForProgramCompilation(options);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/L8.java b/src/main/java/com/android/tools/r8/L8.java
index 587329e..4bf785c 100644
--- a/src/main/java/com/android/tools/r8/L8.java
+++ b/src/main/java/com/android/tools/r8/L8.java
@@ -75,7 +75,7 @@
null,
GraphLense.getIdentityLense(),
PrefixRewritingNamingLens.createPrefixRewritingNamingLens(
- app, converter.getAdditionalRewritePrefix()),
+ options, converter.getAdditionalRewritePrefix()),
null)
.write(executor);
options.printWarnings();
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index e6e49bc..3b23ef5 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -10,10 +10,6 @@
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import java.util.List;
-import java.util.Map;
/** Immutable command structure for an invocation of the {@link L8} libray compiler. */
@Keep
@@ -74,7 +70,7 @@
if (getSpecialLibraryConfiguration() == null) {
reporter.error("L8 requires a special library configuration");
} else if (!getSpecialLibraryConfiguration().equals("default")) {
- reporter.error("L8 currently require special library configuration to be \"default\"");
+ reporter.error("L8 currently requires the special library configuration to be \"default\"");
}
if (getProgramConsumer() instanceof ClassFileConsumer) {
reporter.error("L8 does not support compiling to Java class files");
@@ -141,154 +137,8 @@
super(printHelp, printVersion);
}
- private Map<String, String> buildBackportCoreLibraryMembers() {
- // R8 specific to deal with *8 removal.
- return ImmutableMap.<String, String>builder()
- .put("java.lang.Double8", "java.lang.Double")
- .put("java.lang.Integer8", "java.lang.Integer")
- .put("java.lang.Long8", "java.lang.Long")
- .build();
- }
-
- private Map<String, String> buildRetargetCoreLibraryMemberForCoreLibCompilation() {
- /*
- --retarget_core_library_member.
-
- The bazel configuration only have this single --retarget_core_library_member option:
-
- --retarget_core_library_member \
- "java/util/LinkedHashSet#spliterator->java/util/DesugarLinkedHashSet"
-
- The configuration below is the full configuration for programs using the desugared library.
- This should fine, as any calls to these re-targeted methods should be rewritten. The main
- reason for adding all of them is that the additional files added to the desugared library
- for running some of the JDK 11 tests use these APIs.
- */
- return ImmutableMap.<String, String>builder()
- // We ignore the following flags required by Bazel because desugaring of these methods
- // is done separately.
- // .put("java.lang.Double#max", "java.lang.Double8")
- // .put("java.lang.Double#min", "java.lang.Double8")
- // .put("java.lang.Double#sum", "java.lang.Double8")
- // .put("java.lang.Integer#max", "java.lang.Integer8")
- // .put("java.lang.Integer#min", "java.lang.Integer8")
- // .put("java.lang.Integer#sum", "java.lang.Integer8")
- // .put("java.lang.Long#max", "java.lang.Long")
- // .put("java.lang.Long#min", "java.lang.Long")
- // .put("java.lang.Long#sum", "java.lang.Long")
- // .put("java.lang.Math#toIntExact", "java.lang.Math8")
- .put("java.util.Arrays#stream", "java.util.DesugarArrays")
- .put("java.util.Arrays#spliterator", "java.util.DesugarArrays")
- .put("java.util.Calendar#toInstant", "java.util.DesugarCalendar")
- .put("java.util.Date#from", "java.util.DesugarDate")
- .put("java.util.Date#toInstant", "java.util.DesugarDate")
- .put("java.util.GregorianCalendar#from", "java.util.DesugarGregorianCalendar")
- .put("java.util.GregorianCalendar#toZonedDateTime", "java.util.DesugarGregorianCalendar")
- .put("java.util.LinkedHashSet#spliterator", "java.util.DesugarLinkedHashSet")
- .put(
- "java.util.concurrent.atomic.AtomicInteger#getAndUpdate",
- "java.util.concurrent.atomic.DesugarAtomicInteger")
- .put(
- "java.util.concurrent.atomic.AtomicInteger#updateAndGet",
- "java.util.concurrent.atomic.DesugarAtomicInteger")
- .put(
- "java.util.concurrent.atomic.AtomicInteger#getAndAccumulate",
- "java.util.concurrent.atomic.DesugarAtomicInteger")
- .put(
- "java.util.concurrent.atomic.AtomicInteger#accumulateAndGet",
- "java.util.concurrent.atomic.DesugarAtomicInteger")
- .put(
- "java.util.concurrent.atomic.AtomicLong#getAndUpdate",
- "java.util.concurrent.atomic.DesugarAtomicLong")
- .put(
- "java.util.concurrent.atomic.AtomicLong#updateAndGet",
- "java.util.concurrent.atomic.DesugarAtomicLong")
- .put(
- "java.util.concurrent.atomic.AtomicLong#getAndAccumulate",
- "java.util.concurrent.atomic.DesugarAtomicLong")
- .put(
- "java.util.concurrent.atomic.AtomicLong#accumulateAndGet",
- "java.util.concurrent.atomic.DesugarAtomicLong")
- .put(
- "java.util.concurrent.atomic.AtomicReference#getAndUpdate",
- "java.util.concurrent.atomic.DesugarAtomicReference")
- .put(
- "java.util.concurrent.atomic.AtomicReference#updateAndGet",
- "java.util.concurrent.atomic.DesugarAtomicReference")
- .put(
- "java.util.concurrent.atomic.AtomicReference#getAndAccumulate",
- "java.util.concurrent.atomic.DesugarAtomicReference")
- .put(
- "java.util.concurrent.atomic.AtomicReference#accumulateAndGet",
- "java.util.concurrent.atomic.DesugarAtomicReference")
- .build();
- }
-
- private List<String> buildDontRewriteInvocations() {
- // --dont_rewrite_core_library_invocation "java/util/Iterator#remove".
- return ImmutableList.of("java.util.Iterator#remove");
- }
-
- private Map<String, String> buildPrefixRewritingForCoreLibCompilation() {
- return ImmutableMap.<String, String>builder()
- // --rewrite_core_library_prefix.
- // Extra flags for R8
- .put("java.io.DesugarBufferedReader", "j$.io.DesugarBufferedReader")
- .put("java.io.UncheckedIOException", "j$.io.UncheckedIOException")
- // Bazel flags.
- .put("java.lang.Double8", "j$.lang.Double8")
- .put("java.lang.Integer8", "j$.lang.Integer8")
- .put("java.lang.Long8", "j$.lang.Long8")
- .put("java.lang.Math8", "j$.lang.Math8")
- .put("java.time.", "j$.time.")
- .put("java.util.stream.", "j$.util.stream.")
- .put("java.util.function.", "j$.util.function.")
- .put("java.util.Comparators", "j$.util.Comparators")
- .put("java.util.Desugar", "j$.util.Desugar")
- .put("java.util.DoubleSummaryStatistics", "j$.util.DoubleSummaryStatistics")
- .put("java.util.IntSummaryStatistics", "j$.util.IntSummaryStatistics")
- .put("java.util.LongSummaryStatistics", "j$.util.LongSummaryStatistics")
- .put("java.util.Objects", "j$.util.Objects")
- .put("java.util.Optional", "j$.util.Optional")
- .put("java.util.PrimitiveIterator", "j$.util.PrimitiveIterator")
- .put("java.util.SortedSet$1", "j$.util.SortedSet$1")
- .put("java.util.Spliterator", "j$.util.Spliterator")
- .put("java.util.StringJoiner", "j$.util.StringJoiner")
- .put("java.util.Tripwire", "j$.util.Tripwire")
- .put("java.util.concurrent.ConcurrentHashMap", "j$.util.concurrent.ConcurrentHashMap")
- .put("java.util.concurrent.DesugarUnsafe", "j$.util.concurrent.DesugarUnsafe")
- .put("java.util.concurrent.ThreadLocalRandom", "j$.util.concurrent.ThreadLocalRandom")
- .put("java.util.concurrent.atomic.DesugarAtomic", "j$.util.concurrent.atomic.DesugarAtomic")
- .build();
- }
-
- private Map<String, String> buildEmulateLibraryInterface() {
- return ImmutableMap.<String, String>builder()
- // --emulate_core_library_interface.
- // Bazel flags.
- .put("java.util.Map$Entry", "j$.util.Map$Entry")
- .put("java.util.Collection", "j$.util.Collection")
- .put("java.util.Map", "j$.util.Map")
- .put("java.util.Iterator", "j$.util.Iterator")
- .put("java.util.Comparator", "j$.util.Comparator")
- // Extra flags: in R8 we marked as emulated all interfaces
- // with default methods. Emulated interfaces have their
- // companion class moved to j$ and have a dispatch class.
- // Bazel instead analyzes the class hierarchy.
- .put("java.util.List", "j$.util.List")
- .put("java.util.SortedSet", "j$.util.SortedSet")
- .put("java.util.Set", "j$.util.Set")
- .put("java.util.concurrent.ConcurrentMap", "j$.util.concurrent.ConcurrentMap")
- .build();
- }
-
private void configureLibraryDesugaring(InternalOptions options) {
- options.coreLibraryCompilation = true;
- options.backportCoreLibraryMembers = buildBackportCoreLibraryMembers();
- options.retargetCoreLibMember = buildRetargetCoreLibraryMemberForCoreLibCompilation();
- options.dontRewriteInvocations = buildDontRewriteInvocations();
- options.rewritePrefix = buildPrefixRewritingForCoreLibCompilation();
- options.emulateLibraryInterface = buildEmulateLibraryInterface();
+ SpecialLibraryConfiguration.configureLibraryDesugaringForLibraryCompilation(options);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 7ad67a0..0ac2984 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -41,6 +41,7 @@
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.Minifier;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.naming.PrefixRewritingNamingLens;
import com.android.tools.r8.naming.ProguardMapMinifier;
import com.android.tools.r8.naming.ProguardMapSupplier;
import com.android.tools.r8.naming.SeedMapper;
@@ -97,6 +98,7 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -528,12 +530,14 @@
appView.setAppServices(appView.appServices().rewrittenWithLens(appView.graphLense()));
timing.begin("Create IR");
+ Map<String, String> additionalRewritePrefix;
Set<DexCallSite> desugaredCallSites;
CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
try {
IRConverter converter = new IRConverter(appView, timing, printer, mainDexClasses);
application = converter.optimize(executorService);
desugaredCallSites = converter.getDesugaredCallSites();
+ additionalRewritePrefix = converter.getAdditionalRewritePrefix();
} finally {
timing.end();
}
@@ -785,7 +789,8 @@
appView,
application.deadCode,
appView.graphLense(),
- namingLens,
+ PrefixRewritingNamingLens.createPrefixRewritingNamingLens(
+ options, additionalRewritePrefix, namingLens),
options,
proguardMapSupplier);
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index a4194b2..b4043b2 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -387,8 +387,9 @@
if (getProgramConsumer() instanceof ClassFileConsumer && isMinApiLevelSet()) {
reporter.error("R8 does not support --min-api when compiling to class files");
}
- if (getSpecialLibraryConfiguration() != null) {
- reporter.error("R8 does not support special library configuration");
+ if (getSpecialLibraryConfiguration() != null
+ && !getSpecialLibraryConfiguration().equals("default")) {
+ reporter.error("R8 currently require the special library configuration to be \"default\"");
}
super.validate();
}
@@ -830,10 +831,17 @@
assert internal.retargetCoreLibMember.isEmpty();
assert internal.backportCoreLibraryMembers.isEmpty();
assert internal.dontRewriteInvocations.isEmpty();
+ if (getSpecialLibraryConfiguration() != null) {
+ configureLibraryDesugaring(internal);
+ }
return internal;
}
+ private void configureLibraryDesugaring(InternalOptions options) {
+ SpecialLibraryConfiguration.configureLibraryDesugaringForProgramCompilation(options);
+ }
+
private static StringConsumer wrapStringConsumer(
StringConsumer optionConsumer, boolean optionsFlag, Path optionFile) {
if (optionsFlag) {
diff --git a/src/main/java/com/android/tools/r8/SpecialLibraryConfiguration.java b/src/main/java/com/android/tools/r8/SpecialLibraryConfiguration.java
new file mode 100644
index 0000000..6468d16
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/SpecialLibraryConfiguration.java
@@ -0,0 +1,264 @@
+// Copyright (c) 2019, 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;
+
+import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import java.util.List;
+import java.util.Map;
+
+// TODO(134732760): This is still work in progress.
+// The SpecialLibraryConfiguration is a set of flags for experimentation
+// with the desugared JDK libraries which should be replaced by a D8/R8
+// API level flag --coreLibraryDescriptor
+public class SpecialLibraryConfiguration {
+
+ private static Map<String, String> buildPrefixRewritingForProgramCompilation() {
+ return ImmutableMap.<String, String>builder()
+ // --rewrite_core_library_prefix.
+ // Following flags are ignored (already desugared).
+ // .put("java.lang.Double8", "j$.lang.Double8")
+ // .put("java.lang.Integer8", "j$.lang.Integer8")
+ // .put("java.lang.Long8", "j$.lang.Long8")
+ // .put("java.lang.Math8", "j$.lang.Math8")
+ .put("java.time.", "j$.time.")
+ .put("java.util.stream.", "j$.util.stream.")
+ .put("java.util.function.", "j$.util.function.")
+ .put("java.util.Desugar", "j$.util.Desugar")
+ .put("java.util.DoubleSummaryStatistics", "j$.util.DoubleSummaryStatistics")
+ .put("java.util.IntSummaryStatistics", "j$.util.IntSummaryStatistics")
+ .put("java.util.LongSummaryStatistics", "j$.util.LongSummaryStatistics")
+ .put("java.util.Objects", "j$.util.Objects")
+ .put("java.util.Optional", "j$.util.Optional")
+ .put("java.util.PrimitiveIterator", "j$.util.PrimitiveIterator")
+ .put("java.util.Spliterator", "j$.util.Spliterator")
+ .put("java.util.StringJoiner", "j$.util.StringJoiner")
+ .put("java.util.concurrent.ConcurrentHashMap", "j$.util.concurrent.ConcurrentHashMap")
+ .put("java.util.concurrent.ThreadLocalRandom", "j$.util.concurrent.ThreadLocalRandom")
+ .put("java.util.concurrent.atomic.DesugarAtomic", "j$.util.concurrent.atomic.DesugarAtomic")
+ .build();
+ }
+
+ private static Map<String, String> buildPrefixRewritingForCoreLibCompilation() {
+ return ImmutableMap.<String, String>builder()
+ // --rewrite_core_library_prefix.
+ // Extra flags for R8
+ .put("java.io.DesugarBufferedReader", "j$.io.DesugarBufferedReader")
+ .put("java.io.UncheckedIOException", "j$.io.UncheckedIOException")
+ // Bazel flags.
+ .put("java.lang.Double8", "j$.lang.Double8")
+ .put("java.lang.Integer8", "j$.lang.Integer8")
+ .put("java.lang.Long8", "j$.lang.Long8")
+ .put("java.lang.Math8", "j$.lang.Math8")
+ .put("java.time.", "j$.time.")
+ .put("java.util.stream.", "j$.util.stream.")
+ .put("java.util.function.", "j$.util.function.")
+ .put("java.util.Comparators", "j$.util.Comparators")
+ .put("java.util.Desugar", "j$.util.Desugar")
+ .put("java.util.DoubleSummaryStatistics", "j$.util.DoubleSummaryStatistics")
+ .put("java.util.IntSummaryStatistics", "j$.util.IntSummaryStatistics")
+ .put("java.util.LongSummaryStatistics", "j$.util.LongSummaryStatistics")
+ .put("java.util.Objects", "j$.util.Objects")
+ .put("java.util.Optional", "j$.util.Optional")
+ .put("java.util.PrimitiveIterator", "j$.util.PrimitiveIterator")
+ .put("java.util.SortedSet$1", "j$.util.SortedSet$1")
+ .put("java.util.Spliterator", "j$.util.Spliterator")
+ .put("java.util.StringJoiner", "j$.util.StringJoiner")
+ .put("java.util.Tripwire", "j$.util.Tripwire")
+ .put("java.util.concurrent.ConcurrentHashMap", "j$.util.concurrent.ConcurrentHashMap")
+ .put("java.util.concurrent.DesugarUnsafe", "j$.util.concurrent.DesugarUnsafe")
+ .put("java.util.concurrent.ThreadLocalRandom", "j$.util.concurrent.ThreadLocalRandom")
+ .put("java.util.concurrent.atomic.DesugarAtomic", "j$.util.concurrent.atomic.DesugarAtomic")
+ .build();
+ }
+
+ private static Map<String, String> buildRetargetCoreLibraryMemberForProgramCompilation() {
+ // --retarget_core_library_member.
+ return ImmutableMap.<String, String>builder()
+ // We ignore the following flags required by Bazel because desugaring of these methods
+ // is done separately.
+ // .put("java.lang.Double#max", "java.lang.Double8")
+ // .put("java.lang.Double#min", "java.lang.Double8")
+ // .put("java.lang.Double#sum", "java.lang.Double8")
+ // .put("java.lang.Integer#max", "java.lang.Integer8")
+ // .put("java.lang.Integer#min", "java.lang.Integer8")
+ // .put("java.lang.Integer#sum", "java.lang.Integer8")
+ // .put("java.lang.Long#max", "java.lang.Long")
+ // .put("java.lang.Long#min", "java.lang.Long")
+ // .put("java.lang.Long#sum", "java.lang.Long")
+ // .put("java.lang.Math#toIntExact", "java.lang.Math8")
+ .put("java.util.Arrays#stream", "java.util.DesugarArrays")
+ .put("java.util.Arrays#spliterator", "java.util.DesugarArrays")
+ .put("java.util.Calendar#toInstant", "java.util.DesugarCalendar")
+ .put("java.util.Date#from", "java.util.DesugarDate")
+ .put("java.util.Date#toInstant", "java.util.DesugarDate")
+ .put("java.util.GregorianCalendar#from", "java.util.DesugarGregorianCalendar")
+ .put("java.util.GregorianCalendar#toZonedDateTime", "java.util.DesugarGregorianCalendar")
+ .put("java.util.LinkedHashSet#spliterator", "java.util.DesugarLinkedHashSet")
+ .put(
+ "java.util.concurrent.atomic.AtomicInteger#getAndUpdate",
+ "java.util.concurrent.atomic.DesugarAtomicInteger")
+ .put(
+ "java.util.concurrent.atomic.AtomicInteger#updateAndGet",
+ "java.util.concurrent.atomic.DesugarAtomicInteger")
+ .put(
+ "java.util.concurrent.atomic.AtomicInteger#getAndAccumulate",
+ "java.util.concurrent.atomic.DesugarAtomicInteger")
+ .put(
+ "java.util.concurrent.atomic.AtomicInteger#accumulateAndGet",
+ "java.util.concurrent.atomic.DesugarAtomicInteger")
+ .put(
+ "java.util.concurrent.atomic.AtomicLong#getAndUpdate",
+ "java.util.concurrent.atomic.DesugarAtomicLong")
+ .put(
+ "java.util.concurrent.atomic.AtomicLong#updateAndGet",
+ "java.util.concurrent.atomic.DesugarAtomicLong")
+ .put(
+ "java.util.concurrent.atomic.AtomicLong#getAndAccumulate",
+ "java.util.concurrent.atomic.DesugarAtomicLong")
+ .put(
+ "java.util.concurrent.atomic.AtomicLong#accumulateAndGet",
+ "java.util.concurrent.atomic.DesugarAtomicLong")
+ .put(
+ "java.util.concurrent.atomic.AtomicReference#getAndUpdate",
+ "java.util.concurrent.atomic.DesugarAtomicReference")
+ .put(
+ "java.util.concurrent.atomic.AtomicReference#updateAndGet",
+ "java.util.concurrent.atomic.DesugarAtomicReference")
+ .put(
+ "java.util.concurrent.atomic.AtomicReference#getAndAccumulate",
+ "java.util.concurrent.atomic.DesugarAtomicReference")
+ .put(
+ "java.util.concurrent.atomic.AtomicReference#accumulateAndGet",
+ "java.util.concurrent.atomic.DesugarAtomicReference")
+ .build();
+ }
+
+ private static Map<String, String> buildRetargetCoreLibraryMemberForCoreLibCompilation() {
+ /*
+ --retarget_core_library_member.
+
+ The bazel configuration only have this single --retarget_core_library_member option:
+
+ --retarget_core_library_member \
+ "java/util/LinkedHashSet#spliterator->java/util/DesugarLinkedHashSet"
+
+ The configuration below is the full configuration for programs using the desugared library.
+ This should fine, as any calls to these re-targeted methods should be rewritten. The main
+ reason for adding all of them is that the additional files added to the desugared library
+ for running some of the JDK 11 tests use these APIs.
+ */
+ return ImmutableMap.<String, String>builder()
+ // We ignore the following flags required by Bazel because desugaring of these methods
+ // is done separately.
+ // .put("java.lang.Double#max", "java.lang.Double8")
+ // .put("java.lang.Double#min", "java.lang.Double8")
+ // .put("java.lang.Double#sum", "java.lang.Double8")
+ // .put("java.lang.Integer#max", "java.lang.Integer8")
+ // .put("java.lang.Integer#min", "java.lang.Integer8")
+ // .put("java.lang.Integer#sum", "java.lang.Integer8")
+ // .put("java.lang.Long#max", "java.lang.Long")
+ // .put("java.lang.Long#min", "java.lang.Long")
+ // .put("java.lang.Long#sum", "java.lang.Long")
+ // .put("java.lang.Math#toIntExact", "java.lang.Math8")
+ .put("java.util.Arrays#stream", "java.util.DesugarArrays")
+ .put("java.util.Arrays#spliterator", "java.util.DesugarArrays")
+ .put("java.util.Calendar#toInstant", "java.util.DesugarCalendar")
+ .put("java.util.Date#from", "java.util.DesugarDate")
+ .put("java.util.Date#toInstant", "java.util.DesugarDate")
+ .put("java.util.GregorianCalendar#from", "java.util.DesugarGregorianCalendar")
+ .put("java.util.GregorianCalendar#toZonedDateTime", "java.util.DesugarGregorianCalendar")
+ .put("java.util.LinkedHashSet#spliterator", "java.util.DesugarLinkedHashSet")
+ .put(
+ "java.util.concurrent.atomic.AtomicInteger#getAndUpdate",
+ "java.util.concurrent.atomic.DesugarAtomicInteger")
+ .put(
+ "java.util.concurrent.atomic.AtomicInteger#updateAndGet",
+ "java.util.concurrent.atomic.DesugarAtomicInteger")
+ .put(
+ "java.util.concurrent.atomic.AtomicInteger#getAndAccumulate",
+ "java.util.concurrent.atomic.DesugarAtomicInteger")
+ .put(
+ "java.util.concurrent.atomic.AtomicInteger#accumulateAndGet",
+ "java.util.concurrent.atomic.DesugarAtomicInteger")
+ .put(
+ "java.util.concurrent.atomic.AtomicLong#getAndUpdate",
+ "java.util.concurrent.atomic.DesugarAtomicLong")
+ .put(
+ "java.util.concurrent.atomic.AtomicLong#updateAndGet",
+ "java.util.concurrent.atomic.DesugarAtomicLong")
+ .put(
+ "java.util.concurrent.atomic.AtomicLong#getAndAccumulate",
+ "java.util.concurrent.atomic.DesugarAtomicLong")
+ .put(
+ "java.util.concurrent.atomic.AtomicLong#accumulateAndGet",
+ "java.util.concurrent.atomic.DesugarAtomicLong")
+ .put(
+ "java.util.concurrent.atomic.AtomicReference#getAndUpdate",
+ "java.util.concurrent.atomic.DesugarAtomicReference")
+ .put(
+ "java.util.concurrent.atomic.AtomicReference#updateAndGet",
+ "java.util.concurrent.atomic.DesugarAtomicReference")
+ .put(
+ "java.util.concurrent.atomic.AtomicReference#getAndAccumulate",
+ "java.util.concurrent.atomic.DesugarAtomicReference")
+ .put(
+ "java.util.concurrent.atomic.AtomicReference#accumulateAndGet",
+ "java.util.concurrent.atomic.DesugarAtomicReference")
+ .build();
+ }
+
+ private static List<String> buildDontRewriteInvocations() {
+ // --dont_rewrite_core_library_invocation "java/util/Iterator#remove".
+ return ImmutableList.of("java.util.Iterator#remove");
+ }
+
+ private static Map<String, String> buildEmulateLibraryInterface() {
+ return ImmutableMap.<String, String>builder()
+ // --emulate_core_library_interface.
+ // Bazel flags.
+ .put("java.util.Map$Entry", "j$.util.Map$Entry")
+ .put("java.util.Collection", "j$.util.Collection")
+ .put("java.util.Map", "j$.util.Map")
+ .put("java.util.Iterator", "j$.util.Iterator")
+ .put("java.util.Comparator", "j$.util.Comparator")
+ // Extra flags: in R8 we marked as emulated all interfaces
+ // with default methods. Emulated interfaces have their
+ // companion class moved to j$ and have a dispatch class.
+ // Bazel instead analyzes the class hierarchy.
+ .put("java.util.List", "j$.util.List")
+ .put("java.util.SortedSet", "j$.util.SortedSet")
+ .put("java.util.Set", "j$.util.Set")
+ .put("java.util.concurrent.ConcurrentMap", "j$.util.concurrent.ConcurrentMap")
+ .build();
+ }
+
+ private static Map<String, String> buildBackportCoreLibraryMembers() {
+ // R8 specific to deal with *8 removal.
+ return ImmutableMap.<String, String>builder()
+ .put("java.lang.Double8", "java.lang.Double")
+ .put("java.lang.Integer8", "java.lang.Integer")
+ .put("java.lang.Long8", "java.lang.Long")
+ .build();
+ }
+
+ public static void configureLibraryDesugaringForProgramCompilation(InternalOptions options) {
+ options.coreLibraryCompilation = false;
+ options.retargetCoreLibMember = buildRetargetCoreLibraryMemberForProgramCompilation();
+ options.dontRewriteInvocations = buildDontRewriteInvocations();
+ options.rewritePrefix = buildPrefixRewritingForProgramCompilation();
+ options.emulateLibraryInterface = buildEmulateLibraryInterface();
+ }
+
+ public static void configureLibraryDesugaringForLibraryCompilation(InternalOptions options) {
+ options.coreLibraryCompilation = true;
+ options.backportCoreLibraryMembers = buildBackportCoreLibraryMembers();
+ options.retargetCoreLibMember = buildRetargetCoreLibraryMemberForCoreLibCompilation();
+ options.dontRewriteInvocations = buildDontRewriteInvocations();
+ options.rewritePrefix = buildPrefixRewritingForCoreLibCompilation();
+ options.emulateLibraryInterface = buildEmulateLibraryInterface();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java b/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
index a0129de..53f457f 100644
--- a/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
+++ b/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
@@ -105,6 +105,16 @@
}
@Override
+ public boolean verifyNoOverlap(Map<DexType, DexString> map) {
+ for (DexType alreadyRenamedInOtherLens : map.keySet()) {
+ assert !renaming.containsKey(alreadyRenamedInOtherLens);
+ assert !renaming.containsKey(
+ appView.dexItemFactory().createType(map.get(alreadyRenamedInOtherLens)));
+ }
+ return true;
+ }
+
+ @Override
void forAllRenamedTypes(Consumer<DexType> consumer) {
DexReference.filterDexType(DexReference.filterDexReference(renaming.keySet().stream()))
.forEach(consumer);
diff --git a/src/main/java/com/android/tools/r8/naming/NamingLens.java b/src/main/java/com/android/tools/r8/naming/NamingLens.java
index 2dbf703..f1a7d84 100644
--- a/src/main/java/com/android/tools/r8/naming/NamingLens.java
+++ b/src/main/java/com/android/tools/r8/naming/NamingLens.java
@@ -29,14 +29,14 @@
import java.util.function.Predicate;
/**
- * Implements a translation of the Dex graph from original names to new names produced by
- * the {@link Minifier}.
- * <p>
- * The minifier does not actually rename classes and members but instead only produces a mapping
+ * Implements a translation of the Dex graph from original names to new names produced by the {@link
+ * Minifier}.
+ *
+ * <p>The minifier does not actually rename classes and members but instead only produces a mapping
* from original ids to renamed ids. When writing the file, the graph has to be interpreted with
* that mapping in mind, i.e., it should be looked at only through this lens.
- * <p>
- * The translation relies on members being statically dispatched to actual definitions, as done
+ *
+ * <p>The translation relies on members being statically dispatched to actual definitions, as done
* by the {@link MemberRebindingAnalysis} optimization.
*/
public abstract class NamingLens {
@@ -99,6 +99,8 @@
return dexItemFactory.createType(lookupDescriptor(type));
}
+ public abstract boolean verifyNoOverlap(Map<DexType, DexString> map);
+
public boolean hasPrefixRewritingLogic() {
return false;
}
@@ -127,10 +129,9 @@
/**
* Checks whether the target will be translated properly by this lense.
- * <p>
- * Normally, this means that the target corresponds to an actual definition that has been
- * renamed. For identity renamings, we are more relaxed, as no targets will be translated
- * anyway.
+ *
+ * <p>Normally, this means that the target corresponds to an actual definition that has been
+ * renamed. For identity renamings, we are more relaxed, as no targets will be translated anyway.
*/
public abstract boolean checkTargetCanBeTranslated(DexMethod item);
@@ -194,6 +195,11 @@
}
@Override
+ public boolean verifyNoOverlap(Map<DexType, DexString> map) {
+ return true;
+ }
+
+ @Override
public String lookupPackageName(String packageName) {
return packageName;
}
diff --git a/src/main/java/com/android/tools/r8/naming/PrefixRewritingNamingLens.java b/src/main/java/com/android/tools/r8/naming/PrefixRewritingNamingLens.java
index ed5c1bc..6b24a34 100644
--- a/src/main/java/com/android/tools/r8/naming/PrefixRewritingNamingLens.java
+++ b/src/main/java/com/android/tools/r8/naming/PrefixRewritingNamingLens.java
@@ -4,8 +4,7 @@
package com.android.tools.r8.naming;
-import com.android.tools.r8.errors.Unimplemented;
-import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItem;
@@ -26,21 +25,33 @@
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
// Naming lens for rewriting type prefixes.
public class PrefixRewritingNamingLens extends NamingLens {
- Map<DexType, DexString> classRenaming = new IdentityHashMap<>();
+ final Map<DexType, DexString> classRenaming = new IdentityHashMap<>();
+ final NamingLens namingLens;
+ final InternalOptions options;
public static NamingLens createPrefixRewritingNamingLens(
- DexApplication app, Map<String, String> additionalRewritePrefix) {
- if (app.options.rewritePrefix.isEmpty() && additionalRewritePrefix.isEmpty()) {
- return NamingLens.getIdentityLens();
+ InternalOptions options, Map<String, String> additionalRewritePrefix) {
+ return createPrefixRewritingNamingLens(
+ options, additionalRewritePrefix, NamingLens.getIdentityLens());
+ }
+
+ public static NamingLens createPrefixRewritingNamingLens(
+ InternalOptions options, Map<String, String> additionalRewritePrefix, NamingLens namingLens) {
+ if (options.rewritePrefix.isEmpty() && additionalRewritePrefix.isEmpty()) {
+ return namingLens;
}
- return new PrefixRewritingNamingLens(app, additionalRewritePrefix);
+ return new PrefixRewritingNamingLens(namingLens, options, additionalRewritePrefix);
}
public PrefixRewritingNamingLens(
- DexApplication app, Map<String, String> additionalRewritePrefix) {
+ NamingLens namingLens, InternalOptions options, Map<String, String> additionalRewritePrefix) {
+ this.namingLens = namingLens;
+ this.options = options;
// Create a map of descriptor prefix remappings.
Map<String, String> descriptorPrefixRewriting = new TreeMap<>(Collections.reverseOrder());
BiConsumer<String, String> lambda =
@@ -48,12 +59,11 @@
descriptorPrefixRewriting.put(
"L" + DescriptorUtils.getBinaryNameFromJavaType(from),
"L" + DescriptorUtils.getBinaryNameFromJavaType(to));
- app.options.rewritePrefix.forEach(lambda);
+ options.rewritePrefix.forEach(lambda);
additionalRewritePrefix.forEach(lambda);
-
// Run over all types and remap types with matching prefixes.
// TODO(134732760): Use a more efficient data structure (prefix tree/trie).
- DexItemFactory itemFactory = app.options.itemFactory;
+ DexItemFactory itemFactory = options.itemFactory;
itemFactory.forAllTypes(
type -> {
String descriptor = type.descriptor.toString();
@@ -75,6 +85,8 @@
}
}
});
+ // Verify that no type would have been renamed by both lenses.
+ assert namingLens.verifyNoOverlap(classRenaming);
}
@Override
@@ -89,53 +101,103 @@
@Override
public DexString lookupDescriptor(DexType type) {
- return classRenaming.getOrDefault(type, type.descriptor);
+ return classRenaming.getOrDefault(type, namingLens.lookupDescriptor(type));
}
@Override
public DexString lookupInnerName(InnerClassAttribute attribute, InternalOptions options) {
- return attribute.getInnerName();
+ if (classRenaming.containsKey(attribute.getInner())) {
+ // Prefix rewriting does not influence the inner name.
+ return attribute.getInnerName();
+ }
+ return namingLens.lookupInnerName(attribute, options);
}
@Override
public DexString lookupName(DexMethod method) {
- return method.name;
+ if (classRenaming.containsKey(method.holder)) {
+ // Prefix rewriting does not influence the method name.
+ return method.name;
+ }
+ return namingLens.lookupName(method);
}
@Override
public DexString lookupMethodName(DexCallSite callSite) {
- return callSite.methodName;
+ if (classRenaming.containsKey(callSite.bootstrapMethod.rewrittenTarget.holder)) {
+ // Prefix rewriting does not influence the inner name.
+ return callSite.methodName;
+ }
+ return namingLens.lookupMethodName(callSite);
}
@Override
public DexString lookupName(DexField field) {
- return field.name;
+ if (classRenaming.containsKey(field.holder)) {
+ // Prefix rewriting does not influence the field name.
+ return field.name;
+ }
+ return namingLens.lookupName(field);
+ }
+
+ @Override
+ public boolean verifyNoOverlap(Map<DexType, DexString> map) {
+ throw new Unreachable("Multiple prefix rewriting lens not supported.");
}
@Override
public String lookupPackageName(String packageName) {
- throw new Unimplemented();
+ // Used for resource shrinking.
+ // Desugared libraries do not have resources.
+ // Hence this call is necessarily for the minifyingLens.
+ // TODO(b/134732760): This assertion does not hold with ressources with renamed prefixes.
+ // Write a test where the assertion does not hold and fix it.
+ assert verifyNotPrefixRewrittenPackage(packageName);
+ return namingLens.lookupPackageName(packageName);
+ }
+
+ private boolean verifyNotPrefixRewrittenPackage(String packageName) {
+ for (DexType dexType : classRenaming.keySet()) {
+ assert !dexType.getPackageDescriptor().equals(packageName);
+ }
+ return true;
}
@Override
public void forAllRenamedTypes(Consumer<DexType> consumer) {
- throw new Unimplemented();
+ // Used for printing the applyMapping map.
+ // If compiling the program using a desugared library, nothing needs to be printed.
+ // If compiling the desugared library, the mapping needs to be printed.
+ // When debugging the program, both mapping files need to be merged.
+ if (options.coreLibraryCompilation) {
+ classRenaming.keySet().forEach(consumer);
+ }
+ namingLens.forAllRenamedTypes(consumer);
}
@Override
public <T extends DexItem> Map<String, T> getRenamedItems(
Class<T> clazz, Predicate<T> predicate, Function<T, String> namer) {
+ Map<String, T> renamedItemsPrefixRewritting;
if (clazz == DexType.class) {
- return classRenaming.keySet().stream()
- .filter(item -> predicate.test(clazz.cast(item)))
- .map(clazz::cast)
- .collect(ImmutableMap.toImmutableMap(namer, i -> i));
+ renamedItemsPrefixRewritting =
+ classRenaming.keySet().stream()
+ .filter(item -> predicate.test(clazz.cast(item)))
+ .map(clazz::cast)
+ .collect(ImmutableMap.toImmutableMap(namer, i -> i));
+ } else {
+ renamedItemsPrefixRewritting = ImmutableMap.of();
}
- return ImmutableMap.of();
+ Map<String, T> renamedItemsMinifier = namingLens.getRenamedItems(clazz, predicate, namer);
+ // The Collector throws an exception for duplicated keys.
+ return Stream.concat(
+ renamedItemsPrefixRewritting.entrySet().stream(),
+ renamedItemsMinifier.entrySet().stream())
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
@Override
public boolean checkTargetCanBeTranslated(DexMethod item) {
- return true;
+ return namingLens.checkTargetCanBeTranslated(item);
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/Box.java b/src/main/java/com/android/tools/r8/utils/Box.java
index ecf2b6f..8d3ec1e 100644
--- a/src/main/java/com/android/tools/r8/utils/Box.java
+++ b/src/main/java/com/android/tools/r8/utils/Box.java
@@ -8,6 +8,12 @@
private T value;
+ public Box() {}
+
+ public Box(T initialValue) {
+ set(initialValue);
+ }
+
public T get() {
return value;
}
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/EmulateLibraryInterfaceTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/EmulateLibraryInterfaceTest.java
index ee5a8d0..7f748f4 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/EmulateLibraryInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/EmulateLibraryInterfaceTest.java
@@ -8,9 +8,13 @@
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertTrue;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.AnyOf.anyOf;
+import static org.hamcrest.core.IsNot.not;
+import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertFalse;
import com.android.tools.r8.D8TestRunResult;
+import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
@@ -20,6 +24,8 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -135,9 +141,9 @@
}
@Test
- public void testProgram() throws Exception {
+ public void testProgramD8() throws Exception {
Assume.assumeTrue("No desugaring for high API levels", requiresCoreLibDesugaring(parameters));
- String[] keepRulesHolder = new String[] {""};
+ Box<String> keepRulesHolder = new Box<>("");
D8TestRunResult d8TestRunResult =
testForD8()
.addProgramFiles(Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR + "stream.jar"))
@@ -146,7 +152,7 @@
.addOptionsModification(
options ->
options.testing.desugaredLibraryKeepRuleConsumer =
- (string, handler) -> keepRulesHolder[0] += string)
+ (string, handler) -> keepRulesHolder.set(keepRulesHolder.get() + string))
.enableCoreLibraryDesugaring()
.compile()
.inspect(this::checkRewrittenInvokes)
@@ -154,7 +160,7 @@
.run(parameters.getRuntime(), "stream.TestClass")
.assertSuccess();
assertLines2By2Correct(d8TestRunResult.getStdOut());
- assertGeneratedKeepRulesAreCorrect(keepRulesHolder[0]);
+ assertGeneratedKeepRulesAreCorrect(keepRulesHolder.get());
String stdErr = d8TestRunResult.getStdErr();
if (parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
// Flaky: There might be a missing method on lambda deserialization.
@@ -166,6 +172,42 @@
}
}
+ @Test
+ public void testProgramR8() throws Exception {
+ Assume.assumeTrue("No desugaring for high API levels", requiresCoreLibDesugaring(parameters));
+ Box<String> keepRulesHolder = new Box<>("");
+ for (Boolean minifying : BooleanUtils.values()) {
+ R8TestRunResult r8TestRunResult =
+ testForR8(parameters.getBackend())
+ .minification(minifying)
+ .addKeepMainRule("stream.TestClass")
+ .addProgramFiles(Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR + "stream.jar"))
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(
+ options ->
+ options.testing.desugaredLibraryKeepRuleConsumer =
+ (string, handler) -> keepRulesHolder.set(keepRulesHolder.get() + string))
+ .enableCoreLibraryDesugaring()
+ .compile()
+ .inspect(this::checkRewrittenInvokes)
+ .addRunClasspathFiles(buildDesugaredLibrary(parameters.getApiLevel()))
+ .run(parameters.getRuntime(), "stream.TestClass")
+ .assertSuccess();
+ assertLines2By2Correct(r8TestRunResult.getStdOut());
+ assertGeneratedKeepRulesAreCorrect(keepRulesHolder.get());
+ if (parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
+ // Flaky: There might be a missing method on lambda deserialization.
+ r8TestRunResult.assertStderrMatches(
+ anyOf(
+ not(containsString("Could not find method")),
+ containsString("Could not find method java.lang.invoke.SerializedLambda")));
+ } else {
+ r8TestRunResult.assertStderrMatches(not(containsString("Could not find method")));
+ }
+ }
+ }
+
private void assertGeneratedKeepRulesAreCorrect(String keepRules) {
String expectedResult =
StringUtils.lines(