Merge commit '8177130a276737d0ca4001f2d425eab588fb6450' into dev-release
diff --git a/.gitignore b/.gitignore
index dbe9747..c97f9a0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -77,6 +77,8 @@
third_party/framework.tar.gz
third_party/gmail/*
third_party/gmscore/*
+third_party/google/google-java-format/1.14.0
+third_party/google/google-java-format/1.14.0.tar.gz
third_party/google-java-format
third_party/google-java-format.tar.gz
third_party/goyt
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 8fbb76e..088b42f 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -8,8 +8,10 @@
FMT_CMD = path.join(
'third_party',
+ 'google',
'google-java-format',
- 'google-java-format-google-java-format-1.7',
+ '1.14.0',
+ 'google-java-format-1.14.0',
'scripts',
'google-java-format-diff.py')
diff --git a/build.gradle b/build.gradle
index 560c1de..bd5538a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -345,6 +345,7 @@
"dart-sdk",
"ddmlib",
"gradle/gradle",
+ "google/google-java-format/1.14.0",
"google-java-format",
"iosched_2019",
"jacoco/0.8.2",
diff --git a/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json b/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json
index f3a4daa..f240706 100644
--- a/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json
+++ b/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json
@@ -1,33 +1,28 @@
{
- "configuration_format_version": 3,
- "group_id" : "com.tools.android",
- "artifact_id" : "chm_only_desugar_jdk_libs",
- "version": "1.0.12",
+ "identifier": "com.tools.android:chm_only_desugar_jdk_libs:1.0.12",
+ "configuration_format_version": 100,
"required_compilation_api_level": 30,
"synthesized_library_classes_package_prefix": "j$.",
"support_all_callbacks_from_library": false,
"common_flags": [
+ {
+ "api_level_below_or_equal": 23,
+ "rewrite_prefix": {
+ "java.util.concurrent.ConcurrentHashMap": "j$.util.concurrent.ConcurrentHashMap",
+ "java.util.concurrent.ThreadLocalRandom": "j$.util.concurrent.ThreadLocalRandom"
+ }
+ }
],
+ "program_flags": [],
"library_flags": [
{
"api_level_below_or_equal": 23,
"rewrite_prefix": {
"java.util.concurrent.Helpers": "j$.util.concurrent.Helpers",
- "java.util.concurrent.ThreadLocalRandom": "j$.util.concurrent.ThreadLocalRandom",
- "java.util.concurrent.ConcurrentHashMap": "j$.util.concurrent.ConcurrentHashMap",
"sun.misc.Desugar": "j$.sun.misc.Desugar"
}
}
],
- "program_flags": [
- {
- "api_level_below_or_equal": 23,
- "rewrite_prefix": {
- "java.util.concurrent.ThreadLocalRandom": "j$.util.concurrent.ThreadLocalRandom",
- "java.util.concurrent.ConcurrentHashMap": "j$.util.concurrent.ConcurrentHashMap"
- }
- }
- ],
"shrinker_config": [
"-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$TreeBin { int lockState; }",
"-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { int sizeCtl; int transferIndex; long baseCount; int cellsBusy; }",
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs.json b/src/library_desugar/jdk11/desugar_jdk_libs.json
index b075745..778274a 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs.json
@@ -1,216 +1,11 @@
{
- "configuration_format_version": 3,
- "group_id" : "com.tools.android",
- "artifact_id" : "desugar_jdk_libs",
- "version": "2.0.0",
+ "identifier": "com.tools.android:desugar_jdk_libs:2.0.0",
+ "configuration_format_version": 100,
"required_compilation_api_level": 30,
"synthesized_library_classes_package_prefix": "j$.",
"support_all_callbacks_from_library": true,
"common_flags": [
{
- "api_level_below_or_equal": 25,
- "wrapper_conversion": [
- "java.time.Clock"
- ]
- },
- {
- "api_level_below_or_equal": 23,
- "wrapper_conversion": [
- "java.util.PrimitiveIterator$OfDouble",
- "java.util.PrimitiveIterator$OfInt",
- "java.util.PrimitiveIterator$OfLong",
- "java.util.Spliterator",
- "java.util.Spliterator$OfDouble",
- "java.util.Spliterator$OfInt",
- "java.util.Spliterator$OfLong",
- "java.util.Spliterator$OfPrimitive",
- "java.util.function.BiConsumer",
- "java.util.function.BiFunction",
- "java.util.function.BiPredicate",
- "java.util.function.BinaryOperator",
- "java.util.function.Consumer",
- "java.util.function.DoubleBinaryOperator",
- "java.util.function.DoubleConsumer",
- "java.util.function.DoubleFunction",
- "java.util.function.DoublePredicate",
- "java.util.function.DoubleToIntFunction",
- "java.util.function.DoubleToLongFunction",
- "java.util.function.DoubleUnaryOperator",
- "java.util.function.Function",
- "java.util.function.IntBinaryOperator",
- "java.util.function.IntConsumer",
- "java.util.function.IntFunction",
- "java.util.function.IntPredicate",
- "java.util.function.IntToDoubleFunction",
- "java.util.function.IntToLongFunction",
- "java.util.function.IntUnaryOperator",
- "java.util.function.LongBinaryOperator",
- "java.util.function.LongConsumer",
- "java.util.function.LongFunction",
- "java.util.function.LongPredicate",
- "java.util.function.LongToDoubleFunction",
- "java.util.function.LongToIntFunction",
- "java.util.function.LongUnaryOperator",
- "java.util.function.ObjDoubleConsumer",
- "java.util.function.ObjIntConsumer",
- "java.util.function.ObjLongConsumer",
- "java.util.function.Predicate",
- "java.util.function.Supplier",
- "java.util.function.ToDoubleFunction",
- "java.util.function.ToIntFunction",
- "java.util.function.ToLongFunction",
- "java.util.function.UnaryOperator",
- "java.util.stream.BaseStream",
- "java.util.stream.Collector",
- "java.util.stream.DoubleStream",
- "java.util.stream.IntStream",
- "java.util.stream.LongStream",
- "java.util.stream.Stream"
- ]
- }
- ],
- "library_flags": [
- {
- "api_level_below_or_equal": 10000,
- "rewrite_prefix": {
- "desugar.": "j$.desugar.",
- "libcore.": "j$.libcore.",
- "java.net.URLDecoder": "j$.net.URLDecoder",
- "java.net.URLEncoder": "j$.net.URLEncoder",
- "java.lang.Desugar": "j$.lang.Desugar",
- "java.lang.ref.Cleaner": "j$.lang.ref.Cleaner",
- "sun.security.action.": "j$.sun.security.action."
- }
- },
- {
- "api_level_below_or_equal": 30,
- "rewrite_prefix": {
- "j$.time.": "java.time.",
- "java.time.": "j$.time.",
- "java.util.Desugar": "j$.util.Desugar"
- },
- "retarget_lib_member": {
- "java.util.Date#toInstant": "java.util.DesugarDate",
- "java.util.GregorianCalendar#toZonedDateTime": "java.util.DesugarGregorianCalendar",
- "java.util.TimeZone#toZoneId": "java.util.DesugarTimeZone"
- },
- "custom_conversion": {
- "java.time.ZonedDateTime": "java.time.TimeConversions",
- "java.time.LocalDate": "java.time.TimeConversions",
- "java.time.Duration": "java.time.TimeConversions",
- "java.time.ZoneId": "java.time.TimeConversions",
- "java.time.MonthDay": "java.time.TimeConversions",
- "java.time.Instant": "java.time.TimeConversions"
- }
- },
- {
- "api_level_below_or_equal": 29,
- "rewrite_prefix": {
- "java.util.concurrent.Flow": "j$.util.concurrent.Flow"
- }
- },
- {
- "api_level_below_or_equal": 25,
- "rewrite_prefix": {
- "java.io.DesugarFile" : "j$.io.DesugarFile",
- "sun.misc.Desugar": "j$.sun.misc.Desugar",
- "jdk.internal.": "j$.jdk.internal.",
- "java.nio.Desugar": "j$.nio.Desugar",
- "java.nio.channels.AsynchronousChannel": "j$.nio.channels.AsynchronousChannel",
- "java.nio.channels.AsynchronousFileChannel": "j$.nio.channels.AsynchronousFileChannel",
- "java.nio.channels.CompletionHandler": "j$.nio.channels.CompletionHandler",
- "java.nio.channels.Desugar": "j$.nio.channels.Desugar",
- "java.nio.file.": "j$.nio.file.",
- "sun.nio.cs." : "j$.sun.nio.cs.",
- "sun.nio.fs.AbstractFileSystemProvider": "j$.sun.nio.fs.AbstractFileSystemProvider",
- "sun.nio.fs.AbstractFileTypeDetector": "j$.sun.nio.fs.AbstractFileTypeDetector",
- "sun.nio.fs.BasicFileAttributesHolder": "j$.sun.nio.fs.BasicFileAttributesHolder",
- "sun.nio.fs.DynamicFileAttributeView": "j$.sun.nio.fs.DynamicFileAttributeView",
- "sun.util.PreHashedMap": "j$.sun.util.PreHashedMap"
- },
- "backport": {
- "java.lang.DesugarDouble": "java.lang.Double",
- "java.lang.DesugarInteger": "java.lang.Integer",
- "java.lang.DesugarLong": "java.lang.Long",
- "java.lang.DesugarMath": "java.lang.Math"
- },
- "retarget_lib_member": {
- "java.io.File#toPath": "java.io.DesugarFile"
- }
- },
- {
- "api_level_below_or_equal": 23,
- "rewrite_prefix": {
- "java.lang.FunctionalInterface": "j$.lang.FunctionalInterface",
- "java.io.DesugarInputStream": "j$.io.DesugarInputStream",
- "j$.util.Optional": "java.util.Optional",
- "j$.util.LongSummaryStatistics": "java.util.LongSummaryStatistics",
- "j$.util.IntSummaryStatistics": "java.util.IntSummaryStatistics",
- "j$.util.DoubleSummaryStatistics": "java.util.DoubleSummaryStatistics",
- "java.nio.channels.SeekableByteChannel": "j$.nio.channels.SeekableByteChannel",
- "java.util.stream.": "j$.util.stream.",
- "java.util.function.": "j$.util.function.",
- "java.util.Comparators": "j$.util.Comparators",
- "java.util.DoubleSummaryStatistics": "j$.util.DoubleSummaryStatistics",
- "java.util.IntSummaryStatistics": "j$.util.IntSummaryStatistics",
- "java.util.LongSummaryStatistics": "j$.util.LongSummaryStatistics",
- "java.util.Optional": "j$.util.Optional",
- "java.util.PrimitiveIterator": "j$.util.PrimitiveIterator",
- "java.util.SortedSet$1": "j$.util.SortedSet$1",
- "java.util.Spliterator": "j$.util.Spliterator",
- "java.util.StringJoiner": "j$.util.StringJoiner",
- "java.util.Tripwire": "j$.util.Tripwire",
- "java.util.concurrent.Helpers": "j$.util.concurrent.Helpers",
- "java.util.concurrent.ThreadLocalRandom": "j$.util.concurrent.ThreadLocalRandom",
- "java.util.concurrent.atomic.DesugarAtomic": "j$.util.concurrent.atomic.DesugarAtomic",
- "java.util.concurrent.ConcurrentHashMap": "j$.util.concurrent.ConcurrentHashMap",
- "java.util.AbstractList": "j$.util.AbstractList",
- "java.util.CollSer": "j$.util.CollSer",
- "java.util.ImmutableCollections": "j$.util.ImmutableCollections",
- "java.util.KeyValueHolder": "j$.util.KeyValueHolder"
- },
- "retarget_lib_member": {
- "java.util.Arrays#stream": "java.util.DesugarArrays",
- "java.util.Arrays#spliterator": "java.util.DesugarArrays",
- "java.util.LinkedHashSet#spliterator": "java.util.DesugarLinkedHashSet"
- },
- "dont_rewrite": [
- "java.util.Iterator#remove"
- ],
- "emulate_interface": {
- "java.lang.Iterable": "j$.lang.Iterable",
- "java.util.Map$Entry": "j$.util.Map$Entry",
- "java.util.Collection": "j$.util.Collection",
- "java.util.Map": "j$.util.Map",
- "java.util.Iterator": "j$.util.Iterator",
- "java.util.Comparator": "j$.util.Comparator",
- "java.util.List": "j$.util.List",
- "java.util.SortedSet": "j$.util.SortedSet",
- "java.util.Set": "j$.util.Set",
- "java.util.concurrent.ConcurrentMap": "j$.util.concurrent.ConcurrentMap"
- },
- "custom_conversion": {
- "java.util.Optional": "java.util.OptionalConversions",
- "java.util.OptionalDouble": "java.util.OptionalConversions",
- "java.util.OptionalInt": "java.util.OptionalConversions",
- "java.util.OptionalLong": "java.util.OptionalConversions",
- "java.util.LongSummaryStatistics": "java.util.LongSummaryStatisticsConversions",
- "java.util.IntSummaryStatistics": "java.util.IntSummaryStatisticsConversions",
- "java.util.DoubleSummaryStatistics": "java.util.DoubleSummaryStatisticsConversions"
- }
- },
- {
- "api_level_below_or_equal": 18,
- "rewrite_prefix": {
- "java.nio.charset.StandardCharsets": "j$.nio.charset.StandardCharsets"
- },
- "retarget_lib_member": {
- "java.lang.Character#isBmpCodePoint": "java.lang.DesugarCharacter"
- }
- }
- ],
- "program_flags": [
- {
"api_level_below_or_equal": 10000,
"rewrite_prefix": {
"java.net.URLDecoder": "j$.net.URLDecoder",
@@ -223,29 +18,29 @@
"java.time.": "j$.time.",
"java.util.Desugar": "j$.util.Desugar"
},
- "retarget_lib_member": {
- "java.util.Calendar#toInstant": "java.util.DesugarCalendar",
- "java.util.Date#from": "java.util.DesugarDate",
- "java.util.Date#toInstant": "java.util.DesugarDate",
- "java.util.GregorianCalendar#from": "java.util.DesugarGregorianCalendar",
- "java.util.GregorianCalendar#toZonedDateTime": "java.util.DesugarGregorianCalendar",
- "java.util.TimeZone#getTimeZone": "java.util.DesugarTimeZone",
- "java.util.TimeZone#toZoneId": "java.util.DesugarTimeZone"
+ "retarget_method": {
+ "java.time.Instant java.util.Date#toInstant()": "java.util.DesugarDate",
+ "java.time.ZoneId java.util.TimeZone#toZoneId()": "java.util.DesugarTimeZone",
+ "java.time.ZonedDateTime java.util.GregorianCalendar#toZonedDateTime()": "java.util.DesugarGregorianCalendar"
},
"custom_conversion": {
- "java.time.ZonedDateTime": "java.time.TimeConversions",
- "java.time.LocalDate": "java.time.TimeConversions",
"java.time.Duration": "java.time.TimeConversions",
- "java.time.ZoneId": "java.time.TimeConversions",
+ "java.time.Instant": "java.time.TimeConversions",
+ "java.time.LocalDate": "java.time.TimeConversions",
"java.time.MonthDay": "java.time.TimeConversions",
- "java.time.Instant": "java.time.TimeConversions"
+ "java.time.ZoneId": "java.time.TimeConversions",
+ "java.time.ZonedDateTime": "java.time.TimeConversions"
}
},
{
+ "api_level_below_or_equal": 25,
+ "wrapper_conversion": [
+ "java.time.Clock"
+ ]
+ },
+ {
"api_level_below_or_equal": 23,
"rewrite_prefix": {
- "java.util.stream.": "j$.util.stream.",
- "java.util.function.": "j$.util.function.",
"java.util.DoubleSummaryStatistics": "j$.util.DoubleSummaryStatistics",
"java.util.IntSummaryStatistics": "j$.util.IntSummaryStatistics",
"java.util.LongSummaryStatistics": "j$.util.LongSummaryStatistics",
@@ -253,61 +48,245 @@
"java.util.PrimitiveIterator": "j$.util.PrimitiveIterator",
"java.util.Spliterator": "j$.util.Spliterator",
"java.util.StringJoiner": "j$.util.StringJoiner",
+ "java.util.concurrent.ConcurrentHashMap": "j$.util.concurrent.ConcurrentHashMap",
"java.util.concurrent.ThreadLocalRandom": "j$.util.concurrent.ThreadLocalRandom",
"java.util.concurrent.atomic.DesugarAtomic": "j$.util.concurrent.atomic.DesugarAtomic",
- "java.util.concurrent.ConcurrentHashMap": "j$.util.concurrent.ConcurrentHashMap"
+ "java.util.function.": "j$.util.function.",
+ "java.util.stream.": "j$.util.stream."
},
- "retarget_lib_member": {
- "java.util.Arrays#stream": "java.util.DesugarArrays",
- "java.util.Arrays#spliterator": "java.util.DesugarArrays",
- "java.util.LinkedHashSet#spliterator": "java.util.DesugarLinkedHashSet",
- "java.util.concurrent.atomic.AtomicInteger#getAndUpdate": "java.util.concurrent.atomic.DesugarAtomicInteger",
- "java.util.concurrent.atomic.AtomicInteger#updateAndGet": "java.util.concurrent.atomic.DesugarAtomicInteger",
- "java.util.concurrent.atomic.AtomicInteger#getAndAccumulate": "java.util.concurrent.atomic.DesugarAtomicInteger",
- "java.util.concurrent.atomic.AtomicInteger#accumulateAndGet": "java.util.concurrent.atomic.DesugarAtomicInteger",
- "java.util.concurrent.atomic.AtomicLong#getAndUpdate": "java.util.concurrent.atomic.DesugarAtomicLong",
- "java.util.concurrent.atomic.AtomicLong#updateAndGet": "java.util.concurrent.atomic.DesugarAtomicLong",
- "java.util.concurrent.atomic.AtomicLong#getAndAccumulate": "java.util.concurrent.atomic.DesugarAtomicLong",
- "java.util.concurrent.atomic.AtomicLong#accumulateAndGet": "java.util.concurrent.atomic.DesugarAtomicLong",
- "java.util.concurrent.atomic.AtomicReference#getAndUpdate": "java.util.concurrent.atomic.DesugarAtomicReference",
- "java.util.concurrent.atomic.AtomicReference#updateAndGet": "java.util.concurrent.atomic.DesugarAtomicReference",
- "java.util.concurrent.atomic.AtomicReference#getAndAccumulate": "java.util.concurrent.atomic.DesugarAtomicReference",
- "java.util.concurrent.atomic.AtomicReference#accumulateAndGet": "java.util.concurrent.atomic.DesugarAtomicReference",
- "java.util.Collections#synchronizedMap": "java.util.DesugarCollections",
- "java.util.Collections#synchronizedSortedMap": "java.util.DesugarCollections"
- },
- "dont_rewrite": [
- "java.util.Iterator#remove"
- ],
"emulate_interface": {
"java.lang.Iterable": "j$.lang.Iterable",
- "java.util.Map$Entry": "j$.util.Map$Entry",
"java.util.Collection": "j$.util.Collection",
- "java.util.Map": "j$.util.Map",
- "java.util.Iterator": "j$.util.Iterator",
"java.util.Comparator": "j$.util.Comparator",
+ "java.util.Iterator": "j$.util.Iterator",
"java.util.List": "j$.util.List",
- "java.util.SortedSet": "j$.util.SortedSet",
+ "java.util.Map": "j$.util.Map",
+ "java.util.Map$Entry": "j$.util.Map$Entry",
"java.util.Set": "j$.util.Set",
+ "java.util.SortedSet": "j$.util.SortedSet",
"java.util.concurrent.ConcurrentMap": "j$.util.concurrent.ConcurrentMap"
},
+ "dont_rewrite": [
+ "void java.util.Iterator#remove()"
+ ],
+ "retarget_method": {
+ "java.util.Spliterator java.util.Arrays#spliterator(java.lang.Object[])": "java.util.DesugarArrays",
+ "java.util.Spliterator java.util.Arrays#spliterator(java.lang.Object[], int, int)": "java.util.DesugarArrays",
+ "java.util.Spliterator java.util.LinkedHashSet#spliterator()": "java.util.DesugarLinkedHashSet",
+ "java.util.Spliterator$OfDouble java.util.Arrays#spliterator(double[])": "java.util.DesugarArrays",
+ "java.util.Spliterator$OfDouble java.util.Arrays#spliterator(double[], int, int)": "java.util.DesugarArrays",
+ "java.util.Spliterator$OfInt java.util.Arrays#spliterator(int[])": "java.util.DesugarArrays",
+ "java.util.Spliterator$OfInt java.util.Arrays#spliterator(int[], int, int)": "java.util.DesugarArrays",
+ "java.util.Spliterator$OfLong java.util.Arrays#spliterator(long[])": "java.util.DesugarArrays",
+ "java.util.Spliterator$OfLong java.util.Arrays#spliterator(long[], int, int)": "java.util.DesugarArrays",
+ "java.util.stream.DoubleStream java.util.Arrays#stream(double[])": "java.util.DesugarArrays",
+ "java.util.stream.DoubleStream java.util.Arrays#stream(double[], int, int)": "java.util.DesugarArrays",
+ "java.util.stream.IntStream java.util.Arrays#stream(int[])": "java.util.DesugarArrays",
+ "java.util.stream.IntStream java.util.Arrays#stream(int[], int, int)": "java.util.DesugarArrays",
+ "java.util.stream.LongStream java.util.Arrays#stream(long[])": "java.util.DesugarArrays",
+ "java.util.stream.LongStream java.util.Arrays#stream(long[], int, int)": "java.util.DesugarArrays",
+ "java.util.stream.Stream java.util.Arrays#stream(java.lang.Object[])": "java.util.DesugarArrays",
+ "java.util.stream.Stream java.util.Arrays#stream(java.lang.Object[], int, int)": "java.util.DesugarArrays"
+ },
+ "wrapper_conversion": [
+ "java.util.function.IntUnaryOperator",
+ "java.util.function.BiFunction",
+ "java.util.function.IntConsumer",
+ "java.util.function.IntBinaryOperator",
+ "java.util.function.UnaryOperator",
+ "java.util.function.DoubleConsumer",
+ "java.util.function.IntPredicate",
+ "java.util.Spliterator$OfLong",
+ "java.util.stream.Collector",
+ "java.util.function.LongPredicate",
+ "java.util.function.ToLongFunction",
+ "java.util.function.LongToDoubleFunction",
+ "java.util.PrimitiveIterator$OfInt",
+ "java.util.function.LongToIntFunction",
+ "java.util.function.Predicate",
+ "java.util.Spliterator$OfPrimitive",
+ "java.util.function.DoubleToIntFunction",
+ "java.util.function.ObjDoubleConsumer",
+ "java.util.function.BinaryOperator",
+ "java.util.stream.DoubleStream",
+ "java.util.Spliterator$OfInt",
+ "java.util.stream.Stream",
+ "java.util.function.ObjLongConsumer",
+ "java.util.function.ToDoubleFunction",
+ "java.util.Spliterator",
+ "java.util.stream.IntStream",
+ "java.util.function.LongBinaryOperator",
+ "java.util.Spliterator$OfDouble",
+ "java.util.function.DoubleFunction",
+ "java.util.function.ObjIntConsumer",
+ "java.util.function.Function",
+ "java.util.function.Supplier",
+ "java.util.function.DoubleUnaryOperator",
+ "java.util.function.BiPredicate",
+ "java.util.PrimitiveIterator$OfDouble",
+ "java.util.function.DoubleBinaryOperator",
+ "java.util.PrimitiveIterator$OfLong",
+ "java.util.function.BiConsumer",
+ "java.util.function.IntFunction",
+ "java.util.stream.LongStream",
+ "java.util.function.IntToDoubleFunction",
+ "java.util.function.LongFunction",
+ "java.util.function.ToIntFunction",
+ "java.util.function.LongConsumer",
+ "java.util.function.Consumer",
+ "java.util.function.IntToLongFunction",
+ "java.util.function.DoubleToLongFunction",
+ "java.util.function.LongUnaryOperator",
+ "java.util.stream.BaseStream",
+ "java.util.function.DoublePredicate"
+ ],
"custom_conversion": {
+ "java.util.DoubleSummaryStatistics": "java.util.DoubleSummaryStatisticsConversions",
+ "java.util.IntSummaryStatistics": "java.util.IntSummaryStatisticsConversions",
+ "java.util.LongSummaryStatistics": "java.util.LongSummaryStatisticsConversions",
"java.util.Optional": "java.util.OptionalConversions",
"java.util.OptionalDouble": "java.util.OptionalConversions",
"java.util.OptionalInt": "java.util.OptionalConversions",
- "java.util.OptionalLong": "java.util.OptionalConversions",
- "java.util.LongSummaryStatistics": "java.util.LongSummaryStatisticsConversions",
- "java.util.IntSummaryStatistics": "java.util.IntSummaryStatisticsConversions",
- "java.util.DoubleSummaryStatistics": "java.util.DoubleSummaryStatisticsConversions"
+ "java.util.OptionalLong": "java.util.OptionalConversions"
}
},
{
"api_level_below_or_equal": 18,
"rewrite_prefix": {
"java.nio.charset.StandardCharsets": "j$.nio.charset.StandardCharsets"
+ }
+ }
+ ],
+ "program_flags": [
+ {
+ "api_level_below_or_equal": 30,
+ "retarget_method": {
+ "java.time.Instant java.util.Calendar#toInstant()": "java.util.DesugarCalendar",
+ "java.util.Date java.util.Date#from(java.time.Instant)": "java.util.DesugarDate",
+ "java.util.GregorianCalendar java.util.GregorianCalendar#from(java.time.ZonedDateTime)": "java.util.DesugarGregorianCalendar",
+ "java.util.TimeZone java.util.TimeZone#getTimeZone(java.lang.String)": "java.util.DesugarTimeZone",
+ "java.util.TimeZone java.util.TimeZone#getTimeZone(java.time.ZoneId)": "java.util.DesugarTimeZone"
+ }
+ },
+ {
+ "api_level_below_or_equal": 23,
+ "retarget_method": {
+ "int java.util.concurrent.atomic.AtomicInteger#accumulateAndGet(int, java.util.function.IntBinaryOperator)": "java.util.concurrent.atomic.DesugarAtomicInteger",
+ "int java.util.concurrent.atomic.AtomicInteger#getAndAccumulate(int, java.util.function.IntBinaryOperator)": "java.util.concurrent.atomic.DesugarAtomicInteger",
+ "int java.util.concurrent.atomic.AtomicInteger#getAndUpdate(java.util.function.IntUnaryOperator)": "java.util.concurrent.atomic.DesugarAtomicInteger",
+ "int java.util.concurrent.atomic.AtomicInteger#updateAndGet(java.util.function.IntUnaryOperator)": "java.util.concurrent.atomic.DesugarAtomicInteger",
+ "java.lang.Object java.util.concurrent.atomic.AtomicReference#accumulateAndGet(java.lang.Object, java.util.function.BinaryOperator)": "java.util.concurrent.atomic.DesugarAtomicReference",
+ "java.lang.Object java.util.concurrent.atomic.AtomicReference#getAndAccumulate(java.lang.Object, java.util.function.BinaryOperator)": "java.util.concurrent.atomic.DesugarAtomicReference",
+ "java.lang.Object java.util.concurrent.atomic.AtomicReference#getAndUpdate(java.util.function.UnaryOperator)": "java.util.concurrent.atomic.DesugarAtomicReference",
+ "java.lang.Object java.util.concurrent.atomic.AtomicReference#updateAndGet(java.util.function.UnaryOperator)": "java.util.concurrent.atomic.DesugarAtomicReference",
+ "java.util.Map java.util.Collections#synchronizedMap(java.util.Map)": "java.util.DesugarCollections",
+ "java.util.SortedMap java.util.Collections#synchronizedSortedMap(java.util.SortedMap)": "java.util.DesugarCollections",
+ "long java.util.concurrent.atomic.AtomicLong#accumulateAndGet(long, java.util.function.LongBinaryOperator)": "java.util.concurrent.atomic.DesugarAtomicLong",
+ "long java.util.concurrent.atomic.AtomicLong#getAndAccumulate(long, java.util.function.LongBinaryOperator)": "java.util.concurrent.atomic.DesugarAtomicLong",
+ "long java.util.concurrent.atomic.AtomicLong#getAndUpdate(java.util.function.LongUnaryOperator)": "java.util.concurrent.atomic.DesugarAtomicLong",
+ "long java.util.concurrent.atomic.AtomicLong#updateAndGet(java.util.function.LongUnaryOperator)": "java.util.concurrent.atomic.DesugarAtomicLong"
+ }
+ },
+ {
+ "api_level_below_or_equal": 18,
+ "retarget_method": {
+ "boolean java.lang.Character#isBmpCodePoint(int)": "j$.lang.DesugarCharacter"
+ }
+ }
+ ],
+ "library_flags": [
+ {
+ "api_level_below_or_equal": 10000,
+ "rewrite_prefix": {
+ "desugar.": "j$.desugar.",
+ "java.lang.Desugar": "j$.lang.Desugar",
+ "java.lang.ref.Cleaner": "j$.lang.ref.Cleaner",
+ "libcore.": "j$.libcore.",
+ "sun.security.action.": "j$.sun.security.action."
+ }
+ },
+ {
+ "api_level_below_or_equal": 30,
+ "rewrite_derived_prefix": {
+ "java.time.": {
+ "j$.time.": "java.time."
+ }
+ }
+ },
+ {
+ "api_level_below_or_equal": 29,
+ "rewrite_prefix": {
+ "java.util.concurrent.Flow": "j$.util.concurrent.Flow"
+ }
+ },
+ {
+ "api_level_below_or_equal": 25,
+ "rewrite_prefix": {
+ "java.io.DesugarFile": "j$.io.DesugarFile",
+ "java.nio.Desugar": "j$.nio.Desugar",
+ "java.nio.channels.AsynchronousChannel": "j$.nio.channels.AsynchronousChannel",
+ "java.nio.channels.AsynchronousFileChannel": "j$.nio.channels.AsynchronousFileChannel",
+ "java.nio.channels.CompletionHandler": "j$.nio.channels.CompletionHandler",
+ "java.nio.channels.Desugar": "j$.nio.channels.Desugar",
+ "java.nio.file.": "j$.nio.file.",
+ "jdk.internal.": "j$.jdk.internal.",
+ "sun.misc.Desugar": "j$.sun.misc.Desugar",
+ "sun.nio.cs.": "j$.sun.nio.cs.",
+ "sun.nio.fs.AbstractFileSystemProvider": "j$.sun.nio.fs.AbstractFileSystemProvider",
+ "sun.nio.fs.AbstractFileTypeDetector": "j$.sun.nio.fs.AbstractFileTypeDetector",
+ "sun.nio.fs.BasicFileAttributesHolder": "j$.sun.nio.fs.BasicFileAttributesHolder",
+ "sun.nio.fs.DynamicFileAttributeView": "j$.sun.nio.fs.DynamicFileAttributeView",
+ "sun.util.PreHashedMap": "j$.sun.util.PreHashedMap"
},
- "retarget_lib_member": {
- "java.lang.Character#isBmpCodePoint": "j$.lang.DesugarCharacter"
+ "retarget_method": {
+ "boolean java.util.Arrays#deepEquals0(java.lang.Object, java.lang.Object)": "java.util.DesugarArrays",
+ "java.nio.file.Path java.io.File#toPath()": "java.io.DesugarFile",
+ "java.util.TimeZone java.util.TimeZone#getTimeZone(java.time.ZoneId)": "java.util.DesugarTimeZone"
+ },
+ "backport": {
+ "java.lang.DesugarDouble": "java.lang.Double",
+ "java.lang.DesugarInteger": "java.lang.Integer",
+ "java.lang.DesugarLong": "java.lang.Long",
+ "java.lang.DesugarMath": "java.lang.Math"
+ },
+ "amend_library_method": [
+ "private static boolean java.util.Arrays#deepEquals0(java.lang.Object, java.lang.Object)"
+ ]
+ },
+ {
+ "api_level_below_or_equal": 23,
+ "rewrite_prefix": {
+ "java.io.DesugarInputStream": "j$.io.DesugarInputStream",
+ "java.lang.FunctionalInterface": "j$.lang.FunctionalInterface",
+ "java.nio.channels.SeekableByteChannel": "j$.nio.channels.SeekableByteChannel",
+ "java.util.AbstractList": "j$.util.AbstractList",
+ "java.util.CollSer": "j$.util.CollSer",
+ "java.util.Comparators": "j$.util.Comparators",
+ "java.util.ImmutableCollections": "j$.util.ImmutableCollections",
+ "java.util.KeyValueHolder": "j$.util.KeyValueHolder",
+ "java.util.SortedSet$1": "j$.util.SortedSet$1",
+ "java.util.Tripwire": "j$.util.Tripwire",
+ "java.util.concurrent.Helpers": "j$.util.concurrent.Helpers"
+ },
+ "rewrite_derived_prefix": {
+ "java.util.DoubleSummaryStatistics": {
+ "j$.util.DoubleSummaryStatistics": "java.util.DoubleSummaryStatistics"
+ },
+ "java.util.IntSummaryStatistics": {
+ "j$.util.IntSummaryStatistics": "java.util.IntSummaryStatistics"
+ },
+ "java.util.LongSummaryStatistics": {
+ "j$.util.LongSummaryStatistics": "java.util.LongSummaryStatistics"
+ },
+ "java.util.Optional": {
+ "j$.util.Optional": "java.util.Optional"
+ }
+ }
+ },
+ {
+ "api_level_below_or_equal": 18,
+ "retarget_method": {
+ "boolean java.lang.Character#isBmpCodePoint(int)": "java.lang.DesugarCharacter"
}
}
],
@@ -326,4 +305,4 @@
"-keepattributes InnerClasses",
"-dontwarn sun.misc.Unsafe"
]
-}
+}
\ No newline at end of file
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json b/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
index 1482909..faf4817 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
@@ -1,220 +1,11 @@
{
- "configuration_format_version": 3,
- "group_id" : "com.tools.android",
- "artifact_id" : "desugar_jdk_libs_alternative_3",
- "version": "2.0.0",
+ "identifier": "com.tools.android:desugar_jdk_libs_alternative_3:2.0.0",
+ "configuration_format_version": 100,
"required_compilation_api_level": 30,
"synthesized_library_classes_package_prefix": "j$.",
"support_all_callbacks_from_library": false,
"common_flags": [
{
- "api_level_below_or_equal": 25,
- "wrapper_conversion": [
- "java.time.Clock"
- ]
- },
- {
- "api_level_below_or_equal": 23,
- "wrapper_conversion": [
- "java.util.PrimitiveIterator$OfDouble",
- "java.util.PrimitiveIterator$OfInt",
- "java.util.PrimitiveIterator$OfLong",
- "java.util.Spliterator",
- "java.util.Spliterator$OfDouble",
- "java.util.Spliterator$OfInt",
- "java.util.Spliterator$OfLong",
- "java.util.Spliterator$OfPrimitive",
- "java.util.function.BiConsumer",
- "java.util.function.BiFunction",
- "java.util.function.BiPredicate",
- "java.util.function.BinaryOperator",
- "java.util.function.Consumer",
- "java.util.function.DoubleBinaryOperator",
- "java.util.function.DoubleConsumer",
- "java.util.function.DoubleFunction",
- "java.util.function.DoublePredicate",
- "java.util.function.DoubleToIntFunction",
- "java.util.function.DoubleToLongFunction",
- "java.util.function.DoubleUnaryOperator",
- "java.util.function.Function",
- "java.util.function.IntBinaryOperator",
- "java.util.function.IntConsumer",
- "java.util.function.IntFunction",
- "java.util.function.IntPredicate",
- "java.util.function.IntToDoubleFunction",
- "java.util.function.IntToLongFunction",
- "java.util.function.IntUnaryOperator",
- "java.util.function.LongBinaryOperator",
- "java.util.function.LongConsumer",
- "java.util.function.LongFunction",
- "java.util.function.LongPredicate",
- "java.util.function.LongToDoubleFunction",
- "java.util.function.LongToIntFunction",
- "java.util.function.LongUnaryOperator",
- "java.util.function.ObjDoubleConsumer",
- "java.util.function.ObjIntConsumer",
- "java.util.function.ObjLongConsumer",
- "java.util.function.Predicate",
- "java.util.function.Supplier",
- "java.util.function.ToDoubleFunction",
- "java.util.function.ToIntFunction",
- "java.util.function.ToLongFunction",
- "java.util.function.UnaryOperator",
- "java.util.stream.BaseStream",
- "java.util.stream.Collector",
- "java.util.stream.DoubleStream",
- "java.util.stream.IntStream",
- "java.util.stream.LongStream",
- "java.util.stream.Stream"
- ]
- }
- ],
- "library_flags": [
- {
- "api_level_below_or_equal": 10000,
- "rewrite_prefix": {
- "desugar.": "j$.desugar.",
- "libcore.": "j$.libcore.",
- "java.net.URLDecoder": "j$.net.URLDecoder",
- "java.net.URLEncoder": "j$.net.URLEncoder",
- "java.lang.Desugar": "j$.lang.Desugar",
- "java.lang.ref.Cleaner": "j$.lang.ref.Cleaner",
- "sun.security.action.": "j$.sun.security.action."
- }
- },
- {
- "api_level_below_or_equal": 30,
- "rewrite_prefix": {
- "j$.time.": "java.time.",
- "java.time.": "j$.time.",
- "java.util.Desugar": "j$.util.Desugar"
- },
- "retarget_lib_member": {
- "java.util.Date#toInstant": "java.util.DesugarDate",
- "java.util.GregorianCalendar#toZonedDateTime": "java.util.DesugarGregorianCalendar",
- "java.util.TimeZone#toZoneId": "java.util.DesugarTimeZone"
- },
- "custom_conversion": {
- "java.time.ZonedDateTime": "java.time.TimeConversions",
- "java.time.LocalDate": "java.time.TimeConversions",
- "java.time.Duration": "java.time.TimeConversions",
- "java.time.ZoneId": "java.time.TimeConversions",
- "java.time.MonthDay": "java.time.TimeConversions",
- "java.time.Instant": "java.time.TimeConversions"
- }
- },
- {
- "api_level_below_or_equal": 29,
- "rewrite_prefix": {
- "java.util.concurrent.Flow": "j$.util.concurrent.Flow"
- }
- },
- {
- "api_level_below_or_equal": 30,
- "rewrite_prefix": {
- "java.io.DesugarFile" : "j$.io.DesugarFile",
- "sun.misc.Desugar": "j$.sun.misc.Desugar",
- "jdk.internal.": "j$.jdk.internal.",
- "java.nio.Desugar": "j$.nio.Desugar",
- "java.nio.channels.AsynchronousChannel": "j$.nio.channels.AsynchronousChannel",
- "java.nio.channels.AsynchronousFileChannel": "j$.nio.channels.AsynchronousFileChannel",
- "java.nio.channels.CompletionHandler": "j$.nio.channels.CompletionHandler",
- "java.nio.channels.Desugar": "j$.nio.channels.Desugar",
- "java.nio.file.": "j$.nio.file.",
- "sun.nio.cs." : "j$.sun.nio.cs.",
- "sun.nio.fs.AbstractFileSystemProvider": "j$.sun.nio.fs.AbstractFileSystemProvider",
- "sun.nio.fs.AbstractFileTypeDetector": "j$.sun.nio.fs.AbstractFileTypeDetector",
- "sun.nio.fs.BasicFileAttributesHolder": "j$.sun.nio.fs.BasicFileAttributesHolder",
- "sun.nio.fs.DynamicFileAttributeView": "j$.sun.nio.fs.DynamicFileAttributeView",
- "sun.util.PreHashedMap": "j$.sun.util.PreHashedMap"
- },
- "backport": {
- "java.lang.DesugarDouble": "java.lang.Double",
- "java.lang.DesugarInteger": "java.lang.Integer",
- "java.lang.DesugarLong": "java.lang.Long",
- "java.lang.DesugarMath": "java.lang.Math"
- },
- "retarget_lib_member": {
- "java.io.File#toPath": "java.io.DesugarFile"
- }
- },
- {
- "api_level_below_or_equal": 23,
- "rewrite_prefix": {
- "java.lang.FunctionalInterface": "j$.lang.FunctionalInterface",
- "java.io.DesugarBufferedReader": "j$.io.DesugarBufferedReader",
- "java.io.DesugarInputStream": "j$.io.DesugarInputStream",
- "java.io.UncheckedIOException": "j$.io.UncheckedIOException",
- "j$.util.Optional": "java.util.Optional",
- "j$.util.LongSummaryStatistics": "java.util.LongSummaryStatistics",
- "j$.util.IntSummaryStatistics": "java.util.IntSummaryStatistics",
- "j$.util.DoubleSummaryStatistics": "java.util.DoubleSummaryStatistics",
- "java.nio.channels.SeekableByteChannel": "j$.nio.channels.SeekableByteChannel",
- "java.util.stream.": "j$.util.stream.",
- "java.util.function.": "j$.util.function.",
- "java.util.Comparators": "j$.util.Comparators",
- "java.util.DoubleSummaryStatistics": "j$.util.DoubleSummaryStatistics",
- "java.util.IntSummaryStatistics": "j$.util.IntSummaryStatistics",
- "java.util.LongSummaryStatistics": "j$.util.LongSummaryStatistics",
- "java.util.Objects": "j$.util.Objects",
- "java.util.Optional": "j$.util.Optional",
- "java.util.PrimitiveIterator": "j$.util.PrimitiveIterator",
- "java.util.SortedSet$1": "j$.util.SortedSet$1",
- "java.util.Spliterator": "j$.util.Spliterator",
- "java.util.StringJoiner": "j$.util.StringJoiner",
- "java.util.Tripwire": "j$.util.Tripwire",
- "java.util.concurrent.Helpers": "j$.util.concurrent.Helpers",
- "java.util.concurrent.ThreadLocalRandom": "j$.util.concurrent.ThreadLocalRandom",
- "java.util.concurrent.atomic.DesugarAtomic": "j$.util.concurrent.atomic.DesugarAtomic",
- "java.util.concurrent.ConcurrentHashMap": "j$.util.concurrent.ConcurrentHashMap",
- "java.util.AbstractList": "j$.util.AbstractList",
- "java.util.CollSer": "j$.util.CollSer",
- "java.util.ImmutableCollections": "j$.util.ImmutableCollections",
- "java.util.KeyValueHolder": "j$.util.KeyValueHolder"
- },
- "retarget_lib_member": {
- "java.util.Arrays#stream": "java.util.DesugarArrays",
- "java.util.Arrays#spliterator": "java.util.DesugarArrays",
- "java.util.LinkedHashSet#spliterator": "java.util.DesugarLinkedHashSet",
- "java.io.BufferedReader#lines": "java.io.DesugarBufferedReader"
- },
- "dont_rewrite": [
- "java.util.Iterator#remove"
- ],
- "emulate_interface": {
- "java.lang.Iterable": "j$.lang.Iterable",
- "java.util.Map$Entry": "j$.util.Map$Entry",
- "java.util.Collection": "j$.util.Collection",
- "java.util.Map": "j$.util.Map",
- "java.util.Iterator": "j$.util.Iterator",
- "java.util.Comparator": "j$.util.Comparator",
- "java.util.List": "j$.util.List",
- "java.util.SortedSet": "j$.util.SortedSet",
- "java.util.Set": "j$.util.Set",
- "java.util.concurrent.ConcurrentMap": "j$.util.concurrent.ConcurrentMap"
- },
- "custom_conversion": {
- "java.util.Optional": "java.util.OptionalConversions",
- "java.util.OptionalDouble": "java.util.OptionalConversions",
- "java.util.OptionalInt": "java.util.OptionalConversions",
- "java.util.OptionalLong": "java.util.OptionalConversions",
- "java.util.LongSummaryStatistics": "java.util.LongSummaryStatisticsConversions",
- "java.util.IntSummaryStatistics": "java.util.IntSummaryStatisticsConversions",
- "java.util.DoubleSummaryStatistics": "java.util.DoubleSummaryStatisticsConversions"
- }
- },
- {
- "api_level_below_or_equal": 18,
- "rewrite_prefix": {
- "java.nio.charset.StandardCharsets": "j$.nio.charset.StandardCharsets"
- },
- "retarget_lib_member": {
- "java.lang.Character#isBmpCodePoint": "java.lang.DesugarCharacter"
- }
- }
- ],
- "program_flags": [
- {
"api_level_below_or_equal": 10000,
"rewrite_prefix": {
"java.net.URLDecoder": "j$.net.URLDecoder",
@@ -227,29 +18,30 @@
"java.time.": "j$.time.",
"java.util.Desugar": "j$.util.Desugar"
},
- "retarget_lib_member": {
- "java.util.Calendar#toInstant": "java.util.DesugarCalendar",
- "java.util.Date#from": "java.util.DesugarDate",
- "java.util.Date#toInstant": "java.util.DesugarDate",
- "java.util.GregorianCalendar#from": "java.util.DesugarGregorianCalendar",
- "java.util.GregorianCalendar#toZonedDateTime": "java.util.DesugarGregorianCalendar",
- "java.util.TimeZone#getTimeZone": "java.util.DesugarTimeZone",
- "java.util.TimeZone#toZoneId": "java.util.DesugarTimeZone"
+ "retarget_method": {
+ "java.time.Instant java.util.Date#toInstant()": "java.util.DesugarDate",
+ "java.time.ZoneId java.util.TimeZone#toZoneId()": "java.util.DesugarTimeZone",
+ "java.time.ZonedDateTime java.util.GregorianCalendar#toZonedDateTime()": "java.util.DesugarGregorianCalendar"
},
"custom_conversion": {
- "java.time.ZonedDateTime": "java.time.TimeConversions",
- "java.time.LocalDate": "java.time.TimeConversions",
"java.time.Duration": "java.time.TimeConversions",
- "java.time.ZoneId": "java.time.TimeConversions",
+ "java.time.Instant": "java.time.TimeConversions",
+ "java.time.LocalDate": "java.time.TimeConversions",
"java.time.MonthDay": "java.time.TimeConversions",
- "java.time.Instant": "java.time.TimeConversions"
+ "java.time.ZoneId": "java.time.TimeConversions",
+ "java.time.ZonedDateTime": "java.time.TimeConversions"
}
},
{
+ "api_level_below_or_equal": 25,
+ "wrapper_conversion": [
+ "java.time.Clock"
+ ]
+ },
+ {
"api_level_below_or_equal": 23,
"rewrite_prefix": {
- "java.util.stream.": "j$.util.stream.",
- "java.util.function.": "j$.util.function.",
+ "java.io.UncheckedIOException": "j$.io.UncheckedIOException",
"java.util.DoubleSummaryStatistics": "j$.util.DoubleSummaryStatistics",
"java.util.IntSummaryStatistics": "j$.util.IntSummaryStatistics",
"java.util.LongSummaryStatistics": "j$.util.LongSummaryStatistics",
@@ -258,63 +50,248 @@
"java.util.PrimitiveIterator": "j$.util.PrimitiveIterator",
"java.util.Spliterator": "j$.util.Spliterator",
"java.util.StringJoiner": "j$.util.StringJoiner",
+ "java.util.concurrent.ConcurrentHashMap": "j$.util.concurrent.ConcurrentHashMap",
"java.util.concurrent.ThreadLocalRandom": "j$.util.concurrent.ThreadLocalRandom",
"java.util.concurrent.atomic.DesugarAtomic": "j$.util.concurrent.atomic.DesugarAtomic",
- "java.util.concurrent.ConcurrentHashMap": "j$.util.concurrent.ConcurrentHashMap",
- "java.io.UncheckedIOException": "j$.io.UncheckedIOException"
+ "java.util.function.": "j$.util.function.",
+ "java.util.stream.": "j$.util.stream."
},
- "retarget_lib_member": {
- "java.util.Arrays#stream": "java.util.DesugarArrays",
- "java.util.Arrays#spliterator": "java.util.DesugarArrays",
- "java.util.LinkedHashSet#spliterator": "java.util.DesugarLinkedHashSet",
- "java.util.concurrent.atomic.AtomicInteger#getAndUpdate": "java.util.concurrent.atomic.DesugarAtomicInteger",
- "java.util.concurrent.atomic.AtomicInteger#updateAndGet": "java.util.concurrent.atomic.DesugarAtomicInteger",
- "java.util.concurrent.atomic.AtomicInteger#getAndAccumulate": "java.util.concurrent.atomic.DesugarAtomicInteger",
- "java.util.concurrent.atomic.AtomicInteger#accumulateAndGet": "java.util.concurrent.atomic.DesugarAtomicInteger",
- "java.util.concurrent.atomic.AtomicLong#getAndUpdate": "java.util.concurrent.atomic.DesugarAtomicLong",
- "java.util.concurrent.atomic.AtomicLong#updateAndGet": "java.util.concurrent.atomic.DesugarAtomicLong",
- "java.util.concurrent.atomic.AtomicLong#getAndAccumulate": "java.util.concurrent.atomic.DesugarAtomicLong",
- "java.util.concurrent.atomic.AtomicLong#accumulateAndGet": "java.util.concurrent.atomic.DesugarAtomicLong",
- "java.util.concurrent.atomic.AtomicReference#getAndUpdate": "java.util.concurrent.atomic.DesugarAtomicReference",
- "java.util.concurrent.atomic.AtomicReference#updateAndGet": "java.util.concurrent.atomic.DesugarAtomicReference",
- "java.util.concurrent.atomic.AtomicReference#getAndAccumulate": "java.util.concurrent.atomic.DesugarAtomicReference",
- "java.util.concurrent.atomic.AtomicReference#accumulateAndGet": "java.util.concurrent.atomic.DesugarAtomicReference",
- "java.util.Collections#synchronizedMap": "java.util.DesugarCollections",
- "java.util.Collections#synchronizedSortedMap": "java.util.DesugarCollections",
- "java.io.BufferedReader#lines": "java.io.DesugarBufferedReader"
- },
- "dont_rewrite": [
- "java.util.Iterator#remove"
- ],
"emulate_interface": {
"java.lang.Iterable": "j$.lang.Iterable",
- "java.util.Map$Entry": "j$.util.Map$Entry",
"java.util.Collection": "j$.util.Collection",
- "java.util.Map": "j$.util.Map",
- "java.util.Iterator": "j$.util.Iterator",
"java.util.Comparator": "j$.util.Comparator",
+ "java.util.Iterator": "j$.util.Iterator",
"java.util.List": "j$.util.List",
- "java.util.SortedSet": "j$.util.SortedSet",
+ "java.util.Map": "j$.util.Map",
+ "java.util.Map$Entry": "j$.util.Map$Entry",
"java.util.Set": "j$.util.Set",
+ "java.util.SortedSet": "j$.util.SortedSet",
"java.util.concurrent.ConcurrentMap": "j$.util.concurrent.ConcurrentMap"
},
+ "dont_rewrite": [
+ "void java.util.Iterator#remove()"
+ ],
+ "retarget_method": {
+ "java.util.Spliterator java.util.Arrays#spliterator(java.lang.Object[])": "java.util.DesugarArrays",
+ "java.util.Spliterator java.util.Arrays#spliterator(java.lang.Object[], int, int)": "java.util.DesugarArrays",
+ "java.util.Spliterator java.util.LinkedHashSet#spliterator()": "java.util.DesugarLinkedHashSet",
+ "java.util.Spliterator$OfDouble java.util.Arrays#spliterator(double[])": "java.util.DesugarArrays",
+ "java.util.Spliterator$OfDouble java.util.Arrays#spliterator(double[], int, int)": "java.util.DesugarArrays",
+ "java.util.Spliterator$OfInt java.util.Arrays#spliterator(int[])": "java.util.DesugarArrays",
+ "java.util.Spliterator$OfInt java.util.Arrays#spliterator(int[], int, int)": "java.util.DesugarArrays",
+ "java.util.Spliterator$OfLong java.util.Arrays#spliterator(long[])": "java.util.DesugarArrays",
+ "java.util.Spliterator$OfLong java.util.Arrays#spliterator(long[], int, int)": "java.util.DesugarArrays",
+ "java.util.stream.DoubleStream java.util.Arrays#stream(double[])": "java.util.DesugarArrays",
+ "java.util.stream.DoubleStream java.util.Arrays#stream(double[], int, int)": "java.util.DesugarArrays",
+ "java.util.stream.IntStream java.util.Arrays#stream(int[])": "java.util.DesugarArrays",
+ "java.util.stream.IntStream java.util.Arrays#stream(int[], int, int)": "java.util.DesugarArrays",
+ "java.util.stream.LongStream java.util.Arrays#stream(long[])": "java.util.DesugarArrays",
+ "java.util.stream.LongStream java.util.Arrays#stream(long[], int, int)": "java.util.DesugarArrays",
+ "java.util.stream.Stream java.io.BufferedReader#lines()": "java.io.DesugarBufferedReader",
+ "java.util.stream.Stream java.util.Arrays#stream(java.lang.Object[])": "java.util.DesugarArrays",
+ "java.util.stream.Stream java.util.Arrays#stream(java.lang.Object[], int, int)": "java.util.DesugarArrays"
+ },
+ "wrapper_conversion": [
+ "java.util.function.IntUnaryOperator",
+ "java.util.function.BiFunction",
+ "java.util.function.IntConsumer",
+ "java.util.function.IntBinaryOperator",
+ "java.util.function.UnaryOperator",
+ "java.util.function.IntPredicate",
+ "java.util.function.DoubleConsumer",
+ "java.util.Spliterator$OfLong",
+ "java.util.stream.Collector",
+ "java.util.function.LongPredicate",
+ "java.util.function.ToLongFunction",
+ "java.util.function.LongToDoubleFunction",
+ "java.util.function.LongToIntFunction",
+ "java.util.PrimitiveIterator$OfInt",
+ "java.util.function.Predicate",
+ "java.util.Spliterator$OfPrimitive",
+ "java.util.function.DoubleToIntFunction",
+ "java.util.function.ObjDoubleConsumer",
+ "java.util.function.BinaryOperator",
+ "java.util.stream.DoubleStream",
+ "java.util.Spliterator$OfInt",
+ "java.util.stream.Stream",
+ "java.util.function.ObjLongConsumer",
+ "java.util.function.ToDoubleFunction",
+ "java.util.Spliterator",
+ "java.util.stream.IntStream",
+ "java.util.function.LongBinaryOperator",
+ "java.util.function.DoubleFunction",
+ "java.util.Spliterator$OfDouble",
+ "java.util.function.ObjIntConsumer",
+ "java.util.function.Function",
+ "java.util.function.Supplier",
+ "java.util.function.DoubleUnaryOperator",
+ "java.util.function.BiPredicate",
+ "java.util.PrimitiveIterator$OfDouble",
+ "java.util.function.DoubleBinaryOperator",
+ "java.util.PrimitiveIterator$OfLong",
+ "java.util.function.BiConsumer",
+ "java.util.function.IntFunction",
+ "java.util.function.IntToDoubleFunction",
+ "java.util.stream.LongStream",
+ "java.util.function.LongFunction",
+ "java.util.function.ToIntFunction",
+ "java.util.function.LongConsumer",
+ "java.util.function.Consumer",
+ "java.util.function.IntToLongFunction",
+ "java.util.function.DoubleToLongFunction",
+ "java.util.function.LongUnaryOperator",
+ "java.util.stream.BaseStream",
+ "java.util.function.DoublePredicate"
+ ],
"custom_conversion": {
+ "java.util.DoubleSummaryStatistics": "java.util.DoubleSummaryStatisticsConversions",
+ "java.util.IntSummaryStatistics": "java.util.IntSummaryStatisticsConversions",
+ "java.util.LongSummaryStatistics": "java.util.LongSummaryStatisticsConversions",
"java.util.Optional": "java.util.OptionalConversions",
"java.util.OptionalDouble": "java.util.OptionalConversions",
"java.util.OptionalInt": "java.util.OptionalConversions",
- "java.util.OptionalLong": "java.util.OptionalConversions",
- "java.util.LongSummaryStatistics": "java.util.LongSummaryStatisticsConversions",
- "java.util.IntSummaryStatistics": "java.util.IntSummaryStatisticsConversions",
- "java.util.DoubleSummaryStatistics": "java.util.DoubleSummaryStatisticsConversions"
+ "java.util.OptionalLong": "java.util.OptionalConversions"
}
},
{
"api_level_below_or_equal": 18,
"rewrite_prefix": {
"java.nio.charset.StandardCharsets": "j$.nio.charset.StandardCharsets"
+ }
+ }
+ ],
+ "program_flags": [
+ {
+ "api_level_below_or_equal": 30,
+ "retarget_method": {
+ "java.time.Instant java.util.Calendar#toInstant()": "java.util.DesugarCalendar",
+ "java.util.Date java.util.Date#from(java.time.Instant)": "java.util.DesugarDate",
+ "java.util.GregorianCalendar java.util.GregorianCalendar#from(java.time.ZonedDateTime)": "java.util.DesugarGregorianCalendar",
+ "java.util.TimeZone java.util.TimeZone#getTimeZone(java.lang.String)": "java.util.DesugarTimeZone",
+ "java.util.TimeZone java.util.TimeZone#getTimeZone(java.time.ZoneId)": "java.util.DesugarTimeZone"
+ }
+ },
+ {
+ "api_level_below_or_equal": 23,
+ "retarget_method": {
+ "int java.util.concurrent.atomic.AtomicInteger#accumulateAndGet(int, java.util.function.IntBinaryOperator)": "java.util.concurrent.atomic.DesugarAtomicInteger",
+ "int java.util.concurrent.atomic.AtomicInteger#getAndAccumulate(int, java.util.function.IntBinaryOperator)": "java.util.concurrent.atomic.DesugarAtomicInteger",
+ "int java.util.concurrent.atomic.AtomicInteger#getAndUpdate(java.util.function.IntUnaryOperator)": "java.util.concurrent.atomic.DesugarAtomicInteger",
+ "int java.util.concurrent.atomic.AtomicInteger#updateAndGet(java.util.function.IntUnaryOperator)": "java.util.concurrent.atomic.DesugarAtomicInteger",
+ "java.lang.Object java.util.concurrent.atomic.AtomicReference#accumulateAndGet(java.lang.Object, java.util.function.BinaryOperator)": "java.util.concurrent.atomic.DesugarAtomicReference",
+ "java.lang.Object java.util.concurrent.atomic.AtomicReference#getAndAccumulate(java.lang.Object, java.util.function.BinaryOperator)": "java.util.concurrent.atomic.DesugarAtomicReference",
+ "java.lang.Object java.util.concurrent.atomic.AtomicReference#getAndUpdate(java.util.function.UnaryOperator)": "java.util.concurrent.atomic.DesugarAtomicReference",
+ "java.lang.Object java.util.concurrent.atomic.AtomicReference#updateAndGet(java.util.function.UnaryOperator)": "java.util.concurrent.atomic.DesugarAtomicReference",
+ "java.util.Map java.util.Collections#synchronizedMap(java.util.Map)": "java.util.DesugarCollections",
+ "java.util.SortedMap java.util.Collections#synchronizedSortedMap(java.util.SortedMap)": "java.util.DesugarCollections",
+ "long java.util.concurrent.atomic.AtomicLong#accumulateAndGet(long, java.util.function.LongBinaryOperator)": "java.util.concurrent.atomic.DesugarAtomicLong",
+ "long java.util.concurrent.atomic.AtomicLong#getAndAccumulate(long, java.util.function.LongBinaryOperator)": "java.util.concurrent.atomic.DesugarAtomicLong",
+ "long java.util.concurrent.atomic.AtomicLong#getAndUpdate(java.util.function.LongUnaryOperator)": "java.util.concurrent.atomic.DesugarAtomicLong",
+ "long java.util.concurrent.atomic.AtomicLong#updateAndGet(java.util.function.LongUnaryOperator)": "java.util.concurrent.atomic.DesugarAtomicLong"
+ }
+ },
+ {
+ "api_level_below_or_equal": 18,
+ "retarget_method": {
+ "boolean java.lang.Character#isBmpCodePoint(int)": "j$.lang.DesugarCharacter"
+ }
+ }
+ ],
+ "library_flags": [
+ {
+ "api_level_below_or_equal": 10000,
+ "rewrite_prefix": {
+ "desugar.": "j$.desugar.",
+ "java.lang.Desugar": "j$.lang.Desugar",
+ "java.lang.ref.Cleaner": "j$.lang.ref.Cleaner",
+ "libcore.": "j$.libcore.",
+ "sun.security.action.": "j$.sun.security.action."
+ }
+ },
+ {
+ "api_level_below_or_equal": 30,
+ "rewrite_prefix": {
+ "java.io.DesugarFile": "j$.io.DesugarFile",
+ "java.nio.Desugar": "j$.nio.Desugar",
+ "java.nio.channels.AsynchronousChannel": "j$.nio.channels.AsynchronousChannel",
+ "java.nio.channels.AsynchronousFileChannel": "j$.nio.channels.AsynchronousFileChannel",
+ "java.nio.channels.CompletionHandler": "j$.nio.channels.CompletionHandler",
+ "java.nio.channels.Desugar": "j$.nio.channels.Desugar",
+ "java.nio.file.": "j$.nio.file.",
+ "jdk.internal.": "j$.jdk.internal.",
+ "sun.misc.Desugar": "j$.sun.misc.Desugar",
+ "sun.nio.cs.": "j$.sun.nio.cs.",
+ "sun.nio.fs.AbstractFileSystemProvider": "j$.sun.nio.fs.AbstractFileSystemProvider",
+ "sun.nio.fs.AbstractFileTypeDetector": "j$.sun.nio.fs.AbstractFileTypeDetector",
+ "sun.nio.fs.BasicFileAttributesHolder": "j$.sun.nio.fs.BasicFileAttributesHolder",
+ "sun.nio.fs.DynamicFileAttributeView": "j$.sun.nio.fs.DynamicFileAttributeView",
+ "sun.util.PreHashedMap": "j$.sun.util.PreHashedMap"
},
- "retarget_lib_member": {
- "java.lang.Character#isBmpCodePoint": "j$.lang.DesugarCharacter"
+ "rewrite_derived_prefix": {
+ "java.time.": {
+ "j$.time.": "java.time."
+ }
+ },
+ "retarget_method": {
+ "java.nio.file.Path java.io.File#toPath()": "java.io.DesugarFile"
+ },
+ "backport": {
+ "java.lang.DesugarDouble": "java.lang.Double",
+ "java.lang.DesugarInteger": "java.lang.Integer",
+ "java.lang.DesugarLong": "java.lang.Long",
+ "java.lang.DesugarMath": "java.lang.Math"
+ }
+ },
+ {
+ "api_level_below_or_equal": 29,
+ "rewrite_prefix": {
+ "java.util.concurrent.Flow": "j$.util.concurrent.Flow"
+ }
+ },
+ {
+ "api_level_below_or_equal": 25,
+ "retarget_method": {
+ "boolean java.util.Arrays#deepEquals0(java.lang.Object, java.lang.Object)": "java.util.DesugarArrays"
+ },
+ "amend_library_method": [
+ "private static boolean java.util.Arrays#deepEquals0(java.lang.Object, java.lang.Object)"
+ ]
+ },
+ {
+ "api_level_below_or_equal": 23,
+ "rewrite_prefix": {
+ "java.io.DesugarBufferedReader": "j$.io.DesugarBufferedReader",
+ "java.io.DesugarInputStream": "j$.io.DesugarInputStream",
+ "java.lang.FunctionalInterface": "j$.lang.FunctionalInterface",
+ "java.nio.channels.SeekableByteChannel": "j$.nio.channels.SeekableByteChannel",
+ "java.util.AbstractList": "j$.util.AbstractList",
+ "java.util.CollSer": "j$.util.CollSer",
+ "java.util.Comparators": "j$.util.Comparators",
+ "java.util.ImmutableCollections": "j$.util.ImmutableCollections",
+ "java.util.KeyValueHolder": "j$.util.KeyValueHolder",
+ "java.util.SortedSet$1": "j$.util.SortedSet$1",
+ "java.util.Tripwire": "j$.util.Tripwire",
+ "java.util.concurrent.Helpers": "j$.util.concurrent.Helpers"
+ },
+ "rewrite_derived_prefix": {
+ "java.util.DoubleSummaryStatistics": {
+ "j$.util.DoubleSummaryStatistics": "java.util.DoubleSummaryStatistics"
+ },
+ "java.util.IntSummaryStatistics": {
+ "j$.util.IntSummaryStatistics": "java.util.IntSummaryStatistics"
+ },
+ "java.util.LongSummaryStatistics": {
+ "j$.util.LongSummaryStatistics": "java.util.LongSummaryStatistics"
+ },
+ "java.util.Optional": {
+ "j$.util.Optional": "java.util.Optional"
+ }
+ }
+ },
+ {
+ "api_level_below_or_equal": 18,
+ "retarget_method": {
+ "boolean java.lang.Character#isBmpCodePoint(int)": "java.lang.DesugarCharacter"
}
}
],
@@ -332,4 +309,4 @@
"-keepattributes InnerClasses",
"-dontwarn sun.misc.Unsafe"
]
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java b/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
index 7ef1569..1ae2311 100644
--- a/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
+++ b/src/main/java/com/android/tools/r8/BackportedMethodListCommand.java
@@ -4,8 +4,9 @@
package com.android.tools.r8;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
@@ -41,7 +42,7 @@
private final boolean printVersion;
private final Reporter reporter;
private final int minApiLevel;
- private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
+ private final DesugaredLibrarySpecification desugaredLibrarySpecification;
private final AndroidApp app;
private final StringConsumer backportedMethodListConsumer;
private final DexItemFactory factory;
@@ -62,7 +63,7 @@
return minApiLevel;
}
- public LegacyDesugaredLibrarySpecification getDesugaredLibraryConfiguration() {
+ public DesugaredLibrarySpecification getDesugaredLibraryConfiguration() {
return desugaredLibrarySpecification;
}
@@ -88,7 +89,7 @@
private BackportedMethodListCommand(
Reporter reporter,
int minApiLevel,
- LegacyDesugaredLibrarySpecification desugaredLibrarySpecification,
+ DesugaredLibrarySpecification desugaredLibrarySpecification,
AndroidApp app,
StringConsumer backportedMethodListConsumer,
DexItemFactory factory) {
@@ -245,7 +246,7 @@
return this;
}
- LegacyDesugaredLibrarySpecification getDesugaredLibraryConfiguration(DexItemFactory factory) {
+ DesugaredLibrarySpecification getDesugaredLibraryConfiguration(DexItemFactory factory) {
if (desugaredLibrarySpecificationResources.isEmpty()) {
return LegacyDesugaredLibrarySpecification.empty();
}
@@ -254,9 +255,8 @@
}
StringResource desugaredLibrarySpecificationResource =
desugaredLibrarySpecificationResources.get(0);
- LegacyDesugaredLibrarySpecificationParser libraryParser =
- new LegacyDesugaredLibrarySpecificationParser(factory, null, false, getMinApiLevel());
- return libraryParser.parse(desugaredLibrarySpecificationResource);
+ return DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecification(
+ desugaredLibrarySpecificationResource, factory, null, false, getMinApiLevel());
}
/** Output file for the backported method list */
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
index 18b7c02..a474a31 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
@@ -7,8 +7,9 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.inspector.Inspector;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
@@ -573,7 +574,7 @@
return self();
}
- LegacyDesugaredLibrarySpecification getDesugaredLibraryConfiguration(
+ DesugaredLibrarySpecification getDesugaredLibraryConfiguration(
DexItemFactory factory, boolean libraryCompilation) {
if (desugaredLibrarySpecificationResources.isEmpty()) {
return LegacyDesugaredLibrarySpecification.empty();
@@ -583,10 +584,12 @@
}
StringResource desugaredLibrarySpecificationResource =
desugaredLibrarySpecificationResources.get(0);
- LegacyDesugaredLibrarySpecificationParser libraryParser =
- new LegacyDesugaredLibrarySpecificationParser(
- factory, getReporter(), libraryCompilation, getMinApiLevel());
- return libraryParser.parse(desugaredLibrarySpecificationResource);
+ return DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecification(
+ desugaredLibrarySpecificationResource,
+ factory,
+ getReporter(),
+ libraryCompilation,
+ getMinApiLevel());
}
boolean hasDesugaredLibraryConfiguration() {
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 10c5c5f..851b677 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -24,6 +24,7 @@
import com.android.tools.r8.inspector.internal.InspectorImpl;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.desugar.TypeRewriter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAmender;
import com.android.tools.r8.ir.optimize.AssertionsRewriter;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.jar.CfApplicationWriter;
@@ -195,6 +196,7 @@
assert forTesting(options, () -> !options.testing.testEnableTestAssertions);
AppView<AppInfo> appView = readApp(inputApp, options, executor, timing);
+ DesugaredLibraryAmender.run(appView);
SyntheticItems.collectSyntheticInputs(appView);
final CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
@@ -210,7 +212,7 @@
clazz -> {
ProgramMethod classInitializer = clazz.getProgramClassInitializer();
if (classInitializer != null) {
- analysis.processNewlyLiveMethod(classInitializer, clazz, null);
+ analysis.processNewlyLiveMethod(classInitializer, clazz, null, null);
}
},
executor);
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 0967f55..c8923f8 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger;
import com.android.tools.r8.inspector.Inspector;
import com.android.tools.r8.inspector.internal.InspectorImpl;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.ProguardConfigurationParser;
import com.android.tools.r8.shaking.ProguardConfigurationRule;
@@ -288,7 +288,7 @@
intermediate |= getProgramConsumer() instanceof DexFilePerClassFileConsumer;
DexItemFactory factory = new DexItemFactory();
- LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
+ DesugaredLibrarySpecification desugaredLibrarySpecification =
getDesugaredLibraryConfiguration(factory, false);
ImmutableList<ProguardConfigurationRule> mainDexKeepRules =
@@ -328,7 +328,7 @@
private final boolean intermediate;
private final DesugarGraphConsumer desugarGraphConsumer;
private final StringConsumer desugaredLibraryKeepRuleConsumer;
- private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
+ private final DesugaredLibrarySpecification desugaredLibrarySpecification;
private final String synthesizedClassPrefix;
private final boolean skipDump;
private final boolean enableMainDexListCheck;
@@ -390,7 +390,7 @@
BiPredicate<String, Long> dexClassChecksumFilter,
DesugarGraphConsumer desugarGraphConsumer,
StringConsumer desugaredLibraryKeepRuleConsumer,
- LegacyDesugaredLibrarySpecification desugaredLibrarySpecification,
+ DesugaredLibrarySpecification desugaredLibrarySpecification,
List<AssertionsConfiguration> assertionsConfiguration,
List<Consumer<Inspector>> outputInspections,
String synthesizedClassPrefix,
diff --git a/src/main/java/com/android/tools/r8/DumpOptions.java b/src/main/java/com/android/tools/r8/DumpOptions.java
index c7f3345..2726086 100644
--- a/src/main/java/com/android/tools/r8/DumpOptions.java
+++ b/src/main/java/com/android/tools/r8/DumpOptions.java
@@ -7,7 +7,7 @@
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.experimental.startup.StartupConfiguration;
import com.android.tools.r8.features.FeatureSplitConfiguration;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
import com.android.tools.r8.shaking.ProguardConfiguration;
import com.android.tools.r8.shaking.ProguardConfigurationRule;
import com.android.tools.r8.utils.InternalOptions.DesugarState;
@@ -50,7 +50,7 @@
private final Optional<Boolean> forceProguardCompatibility;
// Dump if present.
- private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
+ private final DesugaredLibrarySpecification desugaredLibrarySpecification;
private final FeatureSplitConfiguration featureSplitConfiguration;
private final ProguardConfiguration proguardConfiguration;
private final List<ProguardConfigurationRule> mainDexKeepRules;
@@ -62,7 +62,7 @@
Tool tool,
CompilationMode compilationMode,
int minAPI,
- LegacyDesugaredLibrarySpecification desugaredLibrarySpecification,
+ DesugaredLibrarySpecification desugaredLibrarySpecification,
boolean optimizeMultidexForLinearAlloc,
int threadCount,
DesugarState desugarState,
@@ -133,8 +133,7 @@
}
private boolean hasDesugaredLibraryConfiguration() {
- return desugaredLibrarySpecification != null
- && !desugaredLibrarySpecification.isEmptyConfiguration();
+ return desugaredLibrarySpecification != null && !desugaredLibrarySpecification.isEmpty();
}
public String getDesugaredLibraryJsonSource() {
@@ -186,7 +185,7 @@
private Optional<Boolean> minification = Optional.empty();
private Optional<Boolean> forceProguardCompatibility = Optional.empty();
// Dump if present.
- private LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
+ private DesugaredLibrarySpecification desugaredLibrarySpecification;
private FeatureSplitConfiguration featureSplitConfiguration;
private ProguardConfiguration proguardConfiguration;
private List<ProguardConfigurationRule> mainDexKeepRules;
@@ -209,7 +208,7 @@
}
public Builder setDesugaredLibraryConfiguration(
- LegacyDesugaredLibrarySpecification desugaredLibrarySpecification) {
+ DesugaredLibrarySpecification desugaredLibrarySpecification) {
this.desugaredLibrarySpecification = desugaredLibrarySpecification;
return this;
}
diff --git a/src/main/java/com/android/tools/r8/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
index 4c49b47..bc6cb77 100644
--- a/src/main/java/com/android/tools/r8/GenerateLintFiles.java
+++ b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
@@ -34,8 +34,9 @@
import com.android.tools.r8.graph.LazyLoadedDexApplication;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
import com.android.tools.r8.jar.CfApplicationWriter;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.origin.Origin;
@@ -73,7 +74,7 @@
private final Reporter reporter = new Reporter();
private final InternalOptions options = new InternalOptions(factory, reporter);
- private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
+ private final MachineDesugaredLibrarySpecification desugaredLibrarySpecification;
private final Path desugaredLibraryImplementation;
private final Path outputDirectory;
@@ -82,8 +83,12 @@
public GenerateLintFiles(
String desugarConfigurationPath, String desugarImplementationPath, String outputDirectory)
throws Exception {
- this.desugaredLibrarySpecification =
+ DesugaredLibrarySpecification specification =
readDesugaredLibraryConfiguration(desugarConfigurationPath);
+ Path androidJarPath = getAndroidJarPath(specification.getRequiredCompilationApiLevel());
+ this.desugaredLibrarySpecification =
+ specification.toMachineSpecification(options, androidJarPath);
+
this.desugaredLibraryImplementation = Paths.get(desugarImplementationPath);
this.outputDirectory = Paths.get(outputDirectory);
if (!Files.isDirectory(this.outputDirectory)) {
@@ -119,11 +124,14 @@
return Paths.get(jar);
}
- private LegacyDesugaredLibrarySpecification readDesugaredLibraryConfiguration(
+ private DesugaredLibrarySpecification readDesugaredLibraryConfiguration(
String desugarConfigurationPath) {
- return new LegacyDesugaredLibrarySpecificationParser(
- factory, reporter, false, AndroidApiLevel.B.getLevel())
- .parse(StringResource.fromFile(Paths.get(desugarConfigurationPath)));
+ return DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecification(
+ StringResource.fromFile(Paths.get(desugarConfigurationPath)),
+ factory,
+ reporter,
+ false,
+ AndroidApiLevel.B.getLevel());
}
private CfCode buildEmptyThrowingCfCode(DexMethod method) {
@@ -192,6 +200,7 @@
}
public static class SupportedMethods {
+
public final Set<DexClass> classesWithAllMethodsSupported;
public final Map<DexClass, List<DexEncodedMethod>> supportedMethods;
@@ -222,54 +231,34 @@
Set<DexClass> classesWithAllMethodsSupported = Sets.newIdentityHashSet();
Map<DexClass, List<DexEncodedMethod>> supportedMethods = new LinkedHashMap<>();
for (DexProgramClass clazz : dexApplication.classes()) {
- String className = clazz.toSourceString();
- // All the methods with the rewritten prefix are supported.
- for (String prefix : desugaredLibrarySpecification.getRewritePrefix().keySet()) {
- if (clazz.accessFlags.isPublic() && className.startsWith(prefix)) {
- DexProgramClass implementationClass =
- implementationApplication.programDefinitionFor(clazz.getType());
- if (implementationClass == null) {
- throw new Exception("Implementation class not found for " + clazz.toSourceString());
+ if (clazz.accessFlags.isPublic()
+ && desugaredLibrarySpecification.getRewriteType().containsKey(clazz.type)) {
+ DexProgramClass implementationClass =
+ implementationApplication.programDefinitionFor(clazz.getType());
+ if (implementationClass == null) {
+ throw new Exception("Implementation class not found for " + clazz.toSourceString());
+ }
+ boolean allMethodsAdded = true;
+ for (DexEncodedMethod method : clazz.methods()) {
+ if (!method.isPublic()) {
+ continue;
}
- boolean allMethodsAddad = true;
- for (DexEncodedMethod method : clazz.methods()) {
- if (!method.isPublic()) {
- continue;
- }
- ProgramMethod implementationMethod =
- implementationClass.lookupProgramMethod(method.getReference());
- // Don't include methods which are not implemented by the desugared library.
- if (supported.test(method) && implementationMethod != null) {
- supportedMethods.computeIfAbsent(clazz, k -> new ArrayList<>()).add(method);
- } else {
- allMethodsAddad = false;
- }
- }
- if (allMethodsAddad) {
- classesWithAllMethodsSupported.add(clazz);
+ ProgramMethod implementationMethod =
+ implementationClass.lookupProgramMethod(method.getReference());
+ // Don't include methods which are not implemented by the desugared library.
+ if (supported.test(method) && implementationMethod != null) {
+ supportedMethods.computeIfAbsent(clazz, k -> new ArrayList<>()).add(method);
+ } else {
+ allMethodsAdded = false;
}
}
- }
-
- // All retargeted methods are supported.
- for (DexEncodedMethod method : clazz.methods()) {
- if (desugaredLibrarySpecification
- .getRetargetCoreLibMember()
- .keySet()
- .contains(method.getReference().name)) {
- if (desugaredLibrarySpecification
- .getRetargetCoreLibMember()
- .get(method.getReference().name)
- .containsKey(clazz.type)) {
- if (supported.test(method)) {
- supportedMethods.computeIfAbsent(clazz, k -> new ArrayList<>()).add(method);
- }
- }
+ if (allMethodsAdded) {
+ classesWithAllMethodsSupported.add(clazz);
}
}
// All emulated interfaces static and default methods are supported.
- if (desugaredLibrarySpecification.getEmulateLibraryInterface().containsKey(clazz.type)) {
+ if (desugaredLibrarySpecification.getEmulatedInterfaces().containsKey(clazz.type)) {
assert clazz.isInterface();
for (DexEncodedMethod method : clazz.methods()) {
if (!method.isDefaultMethod() && !method.isStatic()) {
@@ -282,6 +271,21 @@
}
}
+ // All retargeted methods are supported.
+ desugaredLibrarySpecification.forEachRetargetMethod(
+ method -> {
+ DexClass clazz = dexApplication.contextIndependentDefinitionFor(method.getHolderType());
+ assert clazz != null;
+ DexEncodedMethod encodedMethod = clazz.lookupMethod(method);
+ if (encodedMethod == null) {
+ // Some methods are registered but present higher in the hierarchy, ignore them.
+ return;
+ }
+ if (supported.test(encodedMethod)) {
+ supportedMethods.computeIfAbsent(clazz, k -> new ArrayList<>()).add(encodedMethod);
+ }
+ });
+
return new SupportedMethods(classesWithAllMethodsSupported, supportedMethods);
}
@@ -400,6 +404,7 @@
}
private static class StringBuilderWithIndent {
+
String NL = System.lineSeparator();
StringBuilder builder = new StringBuilder();
String indent = "";
@@ -607,6 +612,7 @@
}
private static class HTMLBuilder extends StringBuilderWithIndent {
+
private String indent = "";
private void increaseIndent() {
@@ -648,6 +654,7 @@
}
public static class HTMLSourceBuilder extends SourceBuilder<HTMLSourceBuilder> {
+
private final Set<DexMethod> parallelMethods;
public HTMLSourceBuilder(DexClass clazz, boolean newClass, Set<DexMethod> parallelMethods) {
diff --git a/src/main/java/com/android/tools/r8/JarSizeCompare.java b/src/main/java/com/android/tools/r8/JarSizeCompare.java
index e520d1b..60a8e08 100644
--- a/src/main/java/com/android/tools/r8/JarSizeCompare.java
+++ b/src/main/java/com/android/tools/r8/JarSizeCompare.java
@@ -26,6 +26,7 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@@ -131,7 +132,7 @@
}
private Map<String, DexProgramClass> translateClassNames(
- DexApplication input, List<DexProgramClass> classes) {
+ DexApplication input, Collection<DexProgramClass> classes) {
Map<String, DexProgramClass> result = new HashMap<>();
ClassNameMapper classNameMapper = input.getProguardMap();
for (DexProgramClass programClass : classes) {
diff --git a/src/main/java/com/android/tools/r8/L8.java b/src/main/java/com/android/tools/r8/L8.java
index 7c0a805..0c8f9ea 100644
--- a/src/main/java/com/android/tools/r8/L8.java
+++ b/src/main/java/com/android/tools/r8/L8.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.graph.LazyLoadedDexApplication;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.desugar.TypeRewriter;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAmender;
import com.android.tools.r8.jar.CfApplicationWriter;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.naming.PrefixRewritingNamingLens;
@@ -134,6 +135,7 @@
options.enableLoadStoreOptimization = false;
AppView<AppInfo> appView = readApp(inputApp, options, executor, timing);
+ DesugaredLibraryAmender.run(appView);
if (!options.disableL8AnnotationRemoval) {
AnnotationRemover.clearAnnotations(appView);
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 6da92e2..8678a9d 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.horizontalclassmerging.HorizontalClassMerger;
import com.android.tools.r8.inspector.Inspector;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
@@ -42,7 +42,7 @@
private final D8Command d8Command;
private final R8Command r8Command;
- private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
+ private final DesugaredLibrarySpecification desugaredLibrarySpecification;
private final DexItemFactory factory;
boolean isShrinking() {
@@ -95,7 +95,7 @@
Reporter diagnosticsHandler,
boolean encodeChecksum,
BiPredicate<String, Long> dexClassChecksumFilter,
- LegacyDesugaredLibrarySpecification desugaredLibrarySpecification,
+ DesugaredLibrarySpecification desugaredLibrarySpecification,
List<AssertionsConfiguration> assertionsConfiguration,
List<Consumer<Inspector>> outputInspections,
int threadCount,
@@ -335,7 +335,7 @@
}
DexItemFactory factory = new DexItemFactory();
- LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
+ DesugaredLibrarySpecification desugaredLibrarySpecification =
getDesugaredLibraryConfiguration(factory, true);
R8Command r8Command = null;
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 8b93d23..ac01496 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -49,6 +49,7 @@
import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAmender;
import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
import com.android.tools.r8.ir.desugar.records.RecordDesugaring;
import com.android.tools.r8.ir.desugar.records.RecordFieldValuesRewriter;
@@ -310,6 +311,7 @@
if (!options.mainDexKeepRules.isEmpty()) {
MainDexListBuilder.checkForAssumedLibraryTypes(appView.appInfo());
}
+ DesugaredLibraryAmender.run(appView);
InterfaceMethodRewriter.checkForAssumedLibraryTypes(appView.appInfo(), options);
BackportedMethodRewriter.registerAssumedLibraryTypes(options);
if (options.enableEnumUnboxing) {
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 5bc9ddd..4e72575 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -15,7 +15,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.inspector.Inspector;
import com.android.tools.r8.inspector.internal.InspectorImpl;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
import com.android.tools.r8.naming.SourceFileRewriter;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
@@ -475,7 +475,7 @@
List<ProguardConfigurationRule> mainDexKeepRules =
ProguardConfigurationParser.parse(mainDexRules, factory, reporter);
- LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
+ DesugaredLibrarySpecification desugaredLibrarySpecification =
getDesugaredLibraryConfiguration(factory, false);
ProguardConfigurationParser parser =
@@ -666,7 +666,7 @@
private final GraphConsumer mainDexKeptGraphConsumer;
private final Consumer<List<ProguardConfigurationRule>> syntheticProguardRulesConsumer;
private final StringConsumer desugaredLibraryKeepRuleConsumer;
- private final LegacyDesugaredLibrarySpecification desugaredLibrarySpecification;
+ private final DesugaredLibrarySpecification desugaredLibrarySpecification;
private final FeatureSplitConfiguration featureSplitConfiguration;
private final String synthesizedClassPrefix;
private final boolean skipDump;
@@ -744,7 +744,7 @@
boolean encodeChecksum,
BiPredicate<String, Long> dexClassChecksumFilter,
StringConsumer desugaredLibraryKeepRuleConsumer,
- LegacyDesugaredLibrarySpecification desugaredLibrarySpecification,
+ DesugaredLibrarySpecification desugaredLibrarySpecification,
FeatureSplitConfiguration featureSplitConfiguration,
List<AssertionsConfiguration> assertionsConfiguration,
List<Consumer<Inspector>> outputInspections,
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index 5d26e0a..1eb78d1 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -383,7 +383,7 @@
return OriginalSourceFiles.unreachable();
}
// Clear all source files so as not to collect the original files.
- List<DexProgramClass> classes = appView.appInfo().classes();
+ Collection<DexProgramClass> classes = appView.appInfo().classes();
Map<DexType, DexString> originalSourceFiles = new HashMap<>(classes.size());
for (DexProgramClass clazz : classes) {
DexString originalSourceFile = clazz.getSourceFile();
diff --git a/src/main/java/com/android/tools/r8/graph/AccessFlags.java b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
index cdf0ad1..1e6fb22 100644
--- a/src/main/java/com/android/tools/r8/graph/AccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
@@ -82,6 +82,18 @@
return originalFlags;
}
+ public ClassAccessFlags asClassAccessFlags() {
+ return null;
+ }
+
+ public MethodAccessFlags asMethodAccessFlags() {
+ return null;
+ }
+
+ public FieldAccessFlags asFieldAccessFlags() {
+ return null;
+ }
+
@Override
public boolean equals(Object object) {
if (object instanceof AccessFlags) {
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index ef10e8d..1fac1e6 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -11,7 +11,7 @@
import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.utils.BooleanBox;
import com.android.tools.r8.utils.InternalOptions;
-import java.util.List;
+import java.util.Collection;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.function.Consumer;
@@ -122,12 +122,12 @@
return syntheticItems;
}
- public List<DexProgramClass> classes() {
+ public Collection<DexProgramClass> classes() {
assert checkIfObsolete();
return app.classes();
}
- public List<DexProgramClass> classesWithDeterministicOrder() {
+ public Collection<DexProgramClass> classesWithDeterministicOrder() {
assert checkIfObsolete();
return app.classesWithDeterministicOrder();
}
diff --git a/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java b/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java
index fd28cde..1d05d43 100644
--- a/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java
@@ -166,6 +166,11 @@
}
@Override
+ public DexMethod getNextMethodSignature(DexMethod method) {
+ return originalMethodSignatures.inverse().getOrDefault(method, method);
+ }
+
+ @Override
public boolean isContextFreeForMethods() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java b/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java
index 19f0fdf..45d4be7 100644
--- a/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java
@@ -107,6 +107,11 @@
return flags;
}
+ @Override
+ public ClassAccessFlags asClassAccessFlags() {
+ return this;
+ }
+
/**
* Checks whether the constraints from
* https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.1 are met.
diff --git a/src/main/java/com/android/tools/r8/graph/ClassResolutionResult.java b/src/main/java/com/android/tools/r8/graph/ClassResolutionResult.java
index 4e34aa3..4eca4e1 100644
--- a/src/main/java/com/android/tools/r8/graph/ClassResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/ClassResolutionResult.java
@@ -43,6 +43,12 @@
return this;
}
+ public Builder add(ProgramOrClasspathClass programOrClasspathClass) {
+ assert this.programOrClasspathClass == null;
+ this.programOrClasspathClass = programOrClasspathClass;
+ return this;
+ }
+
public ClassResolutionResult build() {
if (programOrClasspathClass == null && libraryClass == null) {
return noResult();
diff --git a/src/main/java/com/android/tools/r8/graph/Code.java b/src/main/java/com/android/tools/r8/graph/Code.java
index 7a06b3d..a260816 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -33,6 +33,10 @@
+ getClass().getCanonicalName());
}
+ public GraphLens getCodeLens(AppView<?> appView) {
+ return appView.codeLens();
+ }
+
public BytecodeMetadata<? extends CfOrDexInstruction> getMetadata() {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexApplication.java b/src/main/java/com/android/tools/r8/graph/DexApplication.java
index e08f2ed..feedd6c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DexApplication.java
@@ -94,9 +94,9 @@
// may process classes concurrently and fail-fast on the first error.
private static class ReorderBox<T> {
- private List<T> classes;
+ private Collection<T> classes;
- ReorderBox(List<T> classes) {
+ ReorderBox(Collection<T> classes) {
this.classes = classes;
}
@@ -109,20 +109,20 @@
return true;
}
- List<T> getClasses() {
+ Collection<T> getClasses() {
return classes;
}
}
- abstract List<DexProgramClass> programClasses();
+ abstract Collection<DexProgramClass> programClasses();
- public List<DexProgramClass> classes() {
+ public Collection<DexProgramClass> classes() {
ReorderBox<DexProgramClass> box = new ReorderBox<>(programClasses());
assert box.reorderClasses();
return box.getClasses();
}
- public List<DexProgramClass> classesWithDeterministicOrder() {
+ public Collection<DexProgramClass> classesWithDeterministicOrder() {
return classesWithDeterministicOrder(new ArrayList<>(programClasses()));
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index c326dc0..c33d18d 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -44,6 +44,7 @@
import com.android.tools.r8.graph.DexAnnotation.AnnotatedKind;
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.ir.code.ValueType;
@@ -85,7 +86,6 @@
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
-import java.util.function.IntPredicate;
import org.objectweb.asm.Opcodes;
public class DexEncodedMethod extends DexEncodedMember<DexEncodedMethod, DexMethod>
@@ -1470,21 +1470,31 @@
return this;
}
- public Builder removeParameterAnnotations(IntPredicate predicate) {
+ public Builder rewriteParameterAnnotations(
+ DexEncodedMethod method, ArgumentInfoCollection argumentInfoCollection) {
if (parameterAnnotations.isEmpty()) {
// Nothing to do.
return this;
}
+ if (!argumentInfoCollection.hasArgumentPermutation()
+ && !argumentInfoCollection.hasRemovedArguments()) {
+ // Nothing to do.
+ return this;
+ }
- List<DexAnnotationSet> newParameterAnnotations = new ArrayList<>();
+ List<DexAnnotationSet> newParameterAnnotations =
+ new ArrayList<>(parameterAnnotations.countNonMissing());
int newNumberOfMissingParameterAnnotations = 0;
- for (int oldIndex = 0; oldIndex < parameterAnnotations.size(); oldIndex++) {
- if (!predicate.test(oldIndex)) {
- if (parameterAnnotations.isMissing(oldIndex)) {
+ for (int parameterIndex = 0;
+ parameterIndex < method.getParameters().size();
+ parameterIndex++) {
+ int argumentIndex = parameterIndex + method.getFirstNonReceiverArgumentIndex();
+ if (!argumentInfoCollection.isArgumentRemoved(argumentIndex)) {
+ if (parameterAnnotations.isMissing(parameterIndex)) {
newNumberOfMissingParameterAnnotations++;
} else {
- newParameterAnnotations.add(parameterAnnotations.get(oldIndex));
+ newParameterAnnotations.add(parameterAnnotations.get(parameterIndex));
}
}
}
@@ -1493,6 +1503,23 @@
return setParameterAnnotations(ParameterAnnotationsList.empty());
}
+ if (argumentInfoCollection.hasArgumentPermutation()) {
+ List<DexAnnotationSet> newPermutedParameterAnnotations =
+ Arrays.asList(new DexAnnotationSet[method.getParameters().size()]);
+ for (int parameterIndex = newNumberOfMissingParameterAnnotations;
+ parameterIndex < method.getParameters().size();
+ parameterIndex++) {
+ int argumentIndex = parameterIndex + method.getFirstNonReceiverArgumentIndex();
+ int newArgumentIndex = argumentInfoCollection.getNewArgumentIndex(argumentIndex, 0);
+ int newParameterIndex = newArgumentIndex - method.getFirstNonReceiverArgumentIndex();
+ newPermutedParameterAnnotations.set(
+ newParameterIndex,
+ newParameterAnnotations.get(parameterIndex - newNumberOfMissingParameterAnnotations));
+ }
+ newParameterAnnotations = newPermutedParameterAnnotations;
+ newNumberOfMissingParameterAnnotations = 0;
+ }
+
return setParameterAnnotations(
ParameterAnnotationsList.create(
newParameterAnnotations.toArray(DexAnnotationSet.EMPTY_ARRAY),
diff --git a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
index 8e96fba..dd95a2d 100644
--- a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
@@ -10,17 +10,19 @@
import com.android.tools.r8.DataResourceProvider;
import com.android.tools.r8.graph.LazyLoadedDexApplication.AllClasses;
-import com.android.tools.r8.graph.classmerging.MergedClasses;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Timing;
+import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
public class DirectMappedDexApplication extends DexApplication {
@@ -29,63 +31,86 @@
private final Map<Code, DexEncodedMethod> codeOwners = new IdentityHashMap<>();
// Unmodifiable mapping of all types to their definitions.
- private final Map<DexType, DexClass> allClasses;
- // Collections of the three different types for iteration.
- private final ImmutableList<DexProgramClass> programClasses;
- private final ImmutableList<DexClasspathClass> classpathClasses;
- private final ImmutableList<DexLibraryClass> libraryClasses;
+ private final ImmutableMap<DexType, ProgramOrClasspathClass> programOrClasspathClasses;
+ private final ImmutableMap<DexType, DexLibraryClass> libraryClasses;
+
+ // Collections of different types for iteration.
+ private final ImmutableCollection<DexProgramClass> programClasses;
+ private final ImmutableCollection<DexClasspathClass> classpathClasses;
private DirectMappedDexApplication(
ClassNameMapper proguardMap,
DexApplicationReadFlags flags,
- Map<DexType, DexClass> allClasses,
- ImmutableList<DexProgramClass> programClasses,
- ImmutableList<DexClasspathClass> classpathClasses,
- ImmutableList<DexLibraryClass> libraryClasses,
+ ImmutableMap<DexType, ProgramOrClasspathClass> programOrClasspathClasses,
+ ImmutableMap<DexType, DexLibraryClass> libraryClasses,
+ ImmutableCollection<DexProgramClass> programClasses,
+ ImmutableCollection<DexClasspathClass> classpathClasses,
ImmutableList<DataResourceProvider> dataResourceProviders,
InternalOptions options,
DexString highestSortingString,
Timing timing) {
super(proguardMap, flags, dataResourceProviders, options, highestSortingString, timing);
- this.allClasses = Collections.unmodifiableMap(allClasses);
+ this.programOrClasspathClasses = programOrClasspathClasses;
+ this.libraryClasses = libraryClasses;
this.programClasses = programClasses;
this.classpathClasses = classpathClasses;
- this.libraryClasses = libraryClasses;
}
- public Collection<DexClass> allClasses() {
- return allClasses.values();
- }
-
- public List<DexClasspathClass> classpathClasses() {
+ public Collection<DexClasspathClass> classpathClasses() {
return classpathClasses;
}
@Override
- List<DexProgramClass> programClasses() {
+ Collection<DexProgramClass> programClasses() {
return programClasses;
}
- public List<DexLibraryClass> libraryClasses() {
- return libraryClasses;
+ public Collection<DexLibraryClass> libraryClasses() {
+ return libraryClasses.values();
}
@Override
public ClassResolutionResult contextIndependentDefinitionForWithResolutionResult(DexType type) {
- DexClass foundClass = definitionFor(type);
- return foundClass == null ? noResult() : foundClass;
+ assert type.isClassType() : "Cannot lookup definition for type: " + type;
+ DexLibraryClass libraryClass = libraryClasses.get(type);
+ ProgramOrClasspathClass programOrClasspathClass = programOrClasspathClasses.get(type);
+ if (libraryClass == null && programOrClasspathClass == null) {
+ return noResult();
+ } else if (libraryClass != null && programOrClasspathClass == null) {
+ return libraryClass;
+ } else if (libraryClass == null) {
+ return programOrClasspathClass.asDexClass();
+ } else {
+ return ClassResolutionResult.builder().add(libraryClass).add(programOrClasspathClass).build();
+ }
}
@Override
public DexClass definitionFor(DexType type) {
assert type.isClassType() : "Cannot lookup definition for type: " + type;
- return allClasses.get(type);
+ if (options.lookupLibraryBeforeProgram) {
+ DexLibraryClass libraryClass = libraryClasses.get(type);
+ if (libraryClass != null) {
+ return libraryClass;
+ }
+ ProgramOrClasspathClass programOrClasspathClass = programOrClasspathClasses.get(type);
+ return programOrClasspathClass != null ? programOrClasspathClass.asDexClass() : null;
+ } else {
+ ProgramOrClasspathClass programOrClasspathClass = programOrClasspathClasses.get(type);
+ if (programOrClasspathClass != null && programOrClasspathClass.isProgramClass()) {
+ return programOrClasspathClass.asDexClass();
+ }
+ DexLibraryClass libraryClass = libraryClasses.get(type);
+ return libraryClass != null
+ ? libraryClass
+ : (programOrClasspathClass == null ? null : programOrClasspathClass.asDexClass());
+ }
}
@Override
public DexProgramClass programDefinitionFor(DexType type) {
- // The direct mapped application has no duplicates so this coincides with definitionFor.
- return DexProgramClass.asProgramClassOrNull(definitionFor(type));
+ ProgramOrClasspathClass programOrClasspathClass = programOrClasspathClasses.get(type);
+ return programOrClasspathClass == null ? null : programOrClasspathClass.asProgramClass();
}
@Override
@@ -119,21 +144,8 @@
return true;
}
- public boolean verifyNothingToRewrite(AppView<?> appView, GraphLens lens) {
- assert allClasses.keySet().stream()
- .allMatch(
- type ->
- lens.lookupType(type) == type
- || MergedClasses.hasBeenMergedIntoDifferentType(
- appView.verticallyMergedClasses(), type)
- || MergedClasses.hasBeenMergedIntoDifferentType(
- appView.horizontallyMergedClasses(), type));
- assert verifyCodeObjectsOwners();
- return true;
- }
-
private boolean mappingIsValid(
- List<DexProgramClass> classesBeforeLensApplication, GraphLens lens) {
+ Collection<DexProgramClass> classesBeforeLensApplication, GraphLens lens) {
// The lens might either map to a different type that is already present in the application
// (e.g. relinking a type) or it might encode a type that was renamed, in which case the
// original type will point to a definition that was renamed.
@@ -188,19 +200,19 @@
public static class Builder extends DexApplication.Builder<Builder> {
- private ImmutableList<DexClasspathClass> classpathClasses;
- private ImmutableList<DexLibraryClass> libraryClasses;
+ private ImmutableCollection<DexClasspathClass> classpathClasses;
+ private Map<DexType, DexLibraryClass> libraryClasses;
private final List<DexClasspathClass> pendingClasspathClasses = new ArrayList<>();
+ private final Set<DexType> pendingClasspathRemovalIfPresent = Sets.newIdentityHashSet();
Builder(LazyLoadedDexApplication application) {
super(application);
// As a side-effect, this will force-load all classes.
AllClasses allClasses = application.loadAllClasses();
- classpathClasses = allClasses.getClasspathClasses();
+ classpathClasses = allClasses.getClasspathClasses().values();
libraryClasses = allClasses.getLibraryClasses();
- replaceProgramClasses(allClasses.getProgramClasses());
- replaceClasspathClasses(allClasses.getClasspathClasses());
+ replaceProgramClasses(allClasses.getProgramClasses().values());
}
private Builder(DirectMappedDexApplication application) {
@@ -222,32 +234,17 @@
@Override
public void addProgramClassPotentiallyOverridingNonProgramClass(DexProgramClass clazz) {
addProgramClass(clazz);
- if (containsType(clazz.type, libraryClasses)) {
- replaceLibraryClasses(withoutType(clazz.type, libraryClasses));
- return;
- }
- if (containsType(clazz.type, classpathClasses)) {
- replaceClasspathClasses(withoutType(clazz.type, classpathClasses));
+ pendingClasspathRemovalIfPresent.add(clazz.type);
+ if (libraryClasses.containsKey(clazz.type)) {
+ ensureMutableLibraryClassesMap();
+ libraryClasses.remove(clazz.type);
}
}
- private boolean containsType(DexType type, List<? extends DexClass> classes) {
- for (DexClass clazz : classes) {
- if (clazz.type == type) {
- return true;
- }
+ private void ensureMutableLibraryClassesMap() {
+ if (!(libraryClasses instanceof IdentityHashMap)) {
+ libraryClasses = new IdentityHashMap<>(libraryClasses);
}
- return false;
- }
-
- private <T extends DexClass> ImmutableList<T> withoutType(DexType type, List<T> classes) {
- ImmutableList.Builder<T> builder = ImmutableList.builder();
- for (T clazz : classes) {
- if (clazz.type != type) {
- builder.add(clazz);
- }
- }
- return builder.build();
}
@Override
@@ -260,11 +257,6 @@
return self();
}
- public Builder addClasspathClasses(Collection<DexClasspathClass> classes) {
- pendingClasspathClasses.addAll(classes);
- return self();
- }
-
private void commitPendingClasspathClasses() {
if (!pendingClasspathClasses.isEmpty()) {
classpathClasses =
@@ -276,11 +268,6 @@
}
}
- public List<DexClasspathClass> getClasspathClasses() {
- commitPendingClasspathClasses();
- return classpathClasses;
- }
-
public Builder replaceClasspathClasses(Collection<DexClasspathClass> newClasspathClasses) {
assert newClasspathClasses != null;
classpathClasses = ImmutableList.copyOf(newClasspathClasses);
@@ -289,13 +276,9 @@
}
public Builder replaceLibraryClasses(Collection<DexLibraryClass> libraryClasses) {
- this.libraryClasses = ImmutableList.copyOf(libraryClasses);
- return self();
- }
-
- public Builder addLibraryClasses(Collection<DexLibraryClass> classes) {
- libraryClasses =
- ImmutableList.<DexLibraryClass>builder().addAll(libraryClasses).addAll(classes).build();
+ ImmutableMap.Builder<DexType, DexLibraryClass> builder = ImmutableMap.builder();
+ libraryClasses.forEach(clazz -> builder.put(clazz.type, clazz));
+ this.libraryClasses = builder.build();
return self();
}
@@ -303,33 +286,56 @@
public DirectMappedDexApplication build() {
// Rebuild the map. This will fail if keys are not unique.
// TODO(zerny): Consider not rebuilding the map if no program classes are added.
- Map<DexType, DexClass> allClasses =
- new IdentityHashMap<>(
- getProgramClasses().size() + getClasspathClasses().size() + libraryClasses.size());
+ commitPendingClasspathClasses();
+ Map<DexType, ProgramOrClasspathClass> programAndClasspathClasses =
+ new IdentityHashMap<>(getProgramClasses().size() + classpathClasses.size());
// Note: writing classes in reverse priority order, so a duplicate will be correctly ordered.
- // There should never be duplicates and that is asserted in the addAll subroutine.
- addAll(allClasses, libraryClasses);
- addAll(allClasses, getClasspathClasses());
- addAll(allClasses, getProgramClasses());
+ // There should not be duplicates between program and classpath and that is asserted in the
+ // addAll subroutine.
+ ImmutableCollection<DexClasspathClass> newClasspathClasses = classpathClasses;
+ if (addAll(programAndClasspathClasses, classpathClasses)) {
+ ImmutableList.Builder<DexClasspathClass> builder = ImmutableList.builder();
+ for (DexClasspathClass classpathClass : classpathClasses) {
+ if (!pendingClasspathRemovalIfPresent.contains(classpathClass.getType())) {
+ builder.add(classpathClass);
+ }
+ }
+ newClasspathClasses = builder.build();
+ }
+ addAll(programAndClasspathClasses, getProgramClasses());
return new DirectMappedDexApplication(
proguardMap,
flags,
- allClasses,
+ ImmutableMap.copyOf(programAndClasspathClasses),
+ getLibraryClassesAsImmutableMap(),
ImmutableList.copyOf(getProgramClasses()),
- ImmutableList.copyOf(getClasspathClasses()),
- libraryClasses,
+ newClasspathClasses,
ImmutableList.copyOf(dataResourceProviders),
options,
highestSortingString,
timing);
}
- }
- private static <T extends DexClass> void addAll(
- Map<DexType, DexClass> allClasses, Iterable<T> toAdd) {
- for (DexClass clazz : toAdd) {
- DexClass old = allClasses.put(clazz.type, clazz);
- assert old == null : "Class " + old.type.toString() + " was already present.";
+ private <T extends ProgramOrClasspathClass> boolean addAll(
+ Map<DexType, ProgramOrClasspathClass> allClasses, Iterable<T> toAdd) {
+ boolean seenRemoved = false;
+ for (T clazz : toAdd) {
+ if (clazz.isProgramClass() || !pendingClasspathRemovalIfPresent.contains(clazz.getType())) {
+ ProgramOrClasspathClass old = allClasses.put(clazz.getType(), clazz);
+ assert old == null : "Class " + old.getType().toString() + " was already present.";
+ } else {
+ seenRemoved = true;
+ }
+ }
+ return seenRemoved;
+ }
+
+ private ImmutableMap<DexType, DexLibraryClass> getLibraryClassesAsImmutableMap() {
+ if (libraryClasses instanceof ImmutableMap) {
+ return (ImmutableMap<DexType, DexLibraryClass>) libraryClasses;
+ } else {
+ return ImmutableMap.copyOf(libraryClasses);
+ }
}
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessFlags.java b/src/main/java/com/android/tools/r8/graph/FieldAccessFlags.java
index 95b2a6f..cc2e10c 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessFlags.java
@@ -99,6 +99,11 @@
}
@Override
+ public FieldAccessFlags asFieldAccessFlags() {
+ return this;
+ }
+
+ @Override
public int getAsCfAccessFlags() {
return materialize();
}
@@ -138,6 +143,11 @@
super(FieldAccessFlags.fromSharedAccessFlags(0));
}
+ public Builder set(int flag) {
+ flags.set(flag);
+ return this;
+ }
+
@Override
public Builder self() {
return this;
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java
index 8fa722d..950e824 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java
@@ -26,6 +26,7 @@
import com.android.tools.r8.shaking.KeepMethodInfo;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
+import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -106,7 +107,7 @@
return new GenericSignatureCorrectnessHelper(appView, contextBuilder, Mode.VERIFY);
}
- public SignatureEvaluationResult run(List<DexProgramClass> programClasses) {
+ public SignatureEvaluationResult run(Collection<DexProgramClass> programClasses) {
if (appView.options().disableGenericSignatureValidation
|| !appView.options().parseSignatureAttribute()) {
return VALID;
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureEnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureEnqueuerAnalysis.java
index ccbb86f..2599a50 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignatureEnqueuerAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureEnqueuerAnalysis.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.graph.analysis.EnqueuerAnalysis;
+import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.Enqueuer.EnqueuerDefinitionSupplier;
import com.android.tools.r8.shaking.EnqueuerWorklist;
import com.google.common.collect.Sets;
@@ -42,7 +43,10 @@
@Override
public void processNewlyLiveMethod(
- ProgramMethod method, ProgramDefinition context, EnqueuerWorklist worklist) {
+ ProgramMethod method,
+ ProgramDefinition context,
+ Enqueuer enqueuer,
+ EnqueuerWorklist worklist) {
processSignature(method, context);
}
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLens.java b/src/main/java/com/android/tools/r8/graph/GraphLens.java
index 3041ccf..952c31d 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLens.java
@@ -543,6 +543,10 @@
return false;
}
+ public boolean isHorizontalClassMergerGraphLens() {
+ return false;
+ }
+
public abstract boolean isIdentityLens();
public boolean isMemberRebindingLens() {
@@ -911,6 +915,8 @@
public abstract DexMethod getPreviousMethodSignature(DexMethod method);
+ public abstract DexMethod getNextMethodSignature(DexMethod method);
+
@Override
public final boolean isIdentityLens() {
return false;
@@ -1122,6 +1128,11 @@
}
@Override
+ public DexMethod getNextMethodSignature(DexMethod method) {
+ return method;
+ }
+
+ @Override
public boolean isContextFreeForMethods() {
return getIdentityLens().isContextFreeForMethods();
}
diff --git a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
index 772227c..b781f0b 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
@@ -15,13 +15,13 @@
import com.android.tools.r8.utils.ProgramClassCollection;
import com.android.tools.r8.utils.Timing;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
-import java.util.Collections;
-import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
+import java.util.function.Function;
import java.util.stream.Collectors;
public class LazyLoadedDexApplication extends DexApplication {
@@ -119,92 +119,102 @@
static class AllClasses {
// Mapping of all types to their definitions.
- private final Map<DexType, DexClass> allClasses;
// Collections of the three different types for iteration.
- private final ImmutableList<DexProgramClass> programClasses;
- private final ImmutableList<DexClasspathClass> classpathClasses;
- private final ImmutableList<DexLibraryClass> libraryClasses;
+ private final ImmutableMap<DexType, DexProgramClass> programClasses;
+ private final ImmutableMap<DexType, DexClasspathClass> classpathClasses;
+ private final ImmutableMap<DexType, DexLibraryClass> libraryClasses;
AllClasses(
LibraryClassCollection libraryClassesLoader,
ClasspathClassCollection classpathClassesLoader,
ProgramClassCollection programClassesLoader,
InternalOptions options) {
- int expectedMaxSize = 0;
// Force-load library classes.
- Map<DexType, DexLibraryClass> allLibraryClasses = null;
+ ImmutableMap<DexType, DexLibraryClass> allLibraryClasses;
if (libraryClassesLoader != null) {
libraryClassesLoader.forceLoad(type -> true);
allLibraryClasses = libraryClassesLoader.getAllClassesInMap();
- expectedMaxSize += allLibraryClasses.size();
+ } else {
+ allLibraryClasses = ImmutableMap.of();
}
// Program classes should be fully loaded.
assert programClassesLoader != null;
assert programClassesLoader.isFullyLoaded();
programClassesLoader.forceLoad(type -> true);
- Map<DexType, DexProgramClass> allProgramClasses = programClassesLoader.getAllClassesInMap();
- expectedMaxSize += allProgramClasses.size();
+ ImmutableMap<DexType, DexProgramClass> allProgramClasses =
+ programClassesLoader.getAllClassesInMap();
// Force-load classpath classes.
- Map<DexType, DexClasspathClass> allClasspathClasses = null;
+ ImmutableMap<DexType, DexClasspathClass> allClasspathClasses;
if (classpathClassesLoader != null) {
classpathClassesLoader.forceLoad(type -> true);
allClasspathClasses = classpathClassesLoader.getAllClassesInMap();
- expectedMaxSize += allClasspathClasses.size();
+ } else {
+ allClasspathClasses = ImmutableMap.of();
}
// Collect loaded classes in the precedence order library classes, program classes and
// class path classes or program classes, classpath classes and library classes depending
// on the configured lookup order.
- Map<DexType, DexClass> prioritizedClasses = new IdentityHashMap<>(expectedMaxSize);
- if (options.lookupLibraryBeforeProgram) {
- libraryClasses = fillPrioritizedClasses(allLibraryClasses, prioritizedClasses, options);
- programClasses = fillPrioritizedClasses(allProgramClasses, prioritizedClasses, options);
- classpathClasses = fillPrioritizedClasses(allClasspathClasses, prioritizedClasses, options);
+ if (options.loadAllClassDefinitions) {
+ libraryClasses = allLibraryClasses;
+ programClasses = allProgramClasses;
+ classpathClasses = allClasspathClasses;
} else {
- programClasses = fillPrioritizedClasses(allProgramClasses, prioritizedClasses, options);
- classpathClasses = fillPrioritizedClasses(allClasspathClasses, prioritizedClasses, options);
- libraryClasses = fillPrioritizedClasses(allLibraryClasses, prioritizedClasses, options);
+ if (options.lookupLibraryBeforeProgram) {
+ libraryClasses = fillPrioritizedClasses(allLibraryClasses, type -> null, options);
+ programClasses = fillPrioritizedClasses(allProgramClasses, libraryClasses::get, options);
+ classpathClasses =
+ fillPrioritizedClasses(
+ allClasspathClasses,
+ type -> {
+ DexLibraryClass clazz = libraryClasses.get(type);
+ return clazz != null ? clazz : programClasses.get(type);
+ },
+ options);
+ } else {
+ programClasses = fillPrioritizedClasses(allProgramClasses, type -> null, options);
+ classpathClasses =
+ fillPrioritizedClasses(allClasspathClasses, programClasses::get, options);
+ libraryClasses =
+ fillPrioritizedClasses(
+ allLibraryClasses,
+ type -> {
+ DexProgramClass clazz = programClasses.get(type);
+ return clazz != null ? clazz : classpathClasses.get(type);
+ },
+ options);
+ }
}
-
- allClasses = Collections.unmodifiableMap(prioritizedClasses);
-
- assert prioritizedClasses.size()
- == libraryClasses.size() + classpathClasses.size() + programClasses.size();
}
- public Map<DexType, DexClass> getAllClasses() {
- return allClasses;
- }
-
- public ImmutableList<DexProgramClass> getProgramClasses() {
+ public ImmutableMap<DexType, DexProgramClass> getProgramClasses() {
return programClasses;
}
- public ImmutableList<DexClasspathClass> getClasspathClasses() {
+ public ImmutableMap<DexType, DexClasspathClass> getClasspathClasses() {
return classpathClasses;
}
- public ImmutableList<DexLibraryClass> getLibraryClasses() {
+ public ImmutableMap<DexType, DexLibraryClass> getLibraryClasses() {
return libraryClasses;
}
}
- private static <T extends DexClass> ImmutableList<T> fillPrioritizedClasses(
+ private static <T extends DexClass> ImmutableMap<DexType, T> fillPrioritizedClasses(
Map<DexType, T> classCollection,
- Map<DexType, DexClass> prioritizedClasses,
+ Function<DexType, DexClass> getExisting,
InternalOptions options) {
if (classCollection != null) {
Set<DexType> javaLibraryOverride = Sets.newIdentityHashSet();
- ImmutableList.Builder<T> builder = ImmutableList.builder();
+ ImmutableMap.Builder<DexType, T> builder = ImmutableMap.builder();
classCollection.forEach(
(type, clazz) -> {
- DexClass other = prioritizedClasses.get(type);
+ DexClass other = getExisting.apply(type);
if (other == null) {
- prioritizedClasses.put(type, clazz);
- builder.add(clazz);
+ builder.put(type, clazz);
} else if (type.getPackageName().startsWith("java.")
&& (clazz.isLibraryClass() || other.isLibraryClass())) {
javaLibraryOverride.add(type);
@@ -215,12 +225,15 @@
}
return builder.build();
} else {
- return ImmutableList.of();
+ return ImmutableMap.of();
}
}
private static void warnJavaLibraryOverride(
InternalOptions options, Set<DexType> javaLibraryOverride) {
+ if (options.ignoreJavaLibraryOverride) {
+ return;
+ }
String joined =
javaLibraryOverride.stream()
.sorted()
diff --git a/src/main/java/com/android/tools/r8/graph/MethodAccessFlags.java b/src/main/java/com/android/tools/r8/graph/MethodAccessFlags.java
index cd5e8de..a20ab1d 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodAccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodAccessFlags.java
@@ -119,6 +119,11 @@
return copy.materialize();
}
+ @Override
+ public MethodAccessFlags asMethodAccessFlags() {
+ return this;
+ }
+
public boolean isSynchronized() {
return isSet(Constants.ACC_SYNCHRONIZED);
}
@@ -249,6 +254,11 @@
super(MethodAccessFlags.fromSharedAccessFlags(0, false));
}
+ public Builder set(int flag) {
+ flags.set(flag);
+ return this;
+ }
+
public Builder setBridge() {
flags.setBridge();
return this;
diff --git a/src/main/java/com/android/tools/r8/graph/NestedGraphLens.java b/src/main/java/com/android/tools/r8/graph/NestedGraphLens.java
index 87e55e9..fe15a02 100644
--- a/src/main/java/com/android/tools/r8/graph/NestedGraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/NestedGraphLens.java
@@ -145,7 +145,7 @@
return originalMethod;
}
DexMethod renamedMethod = getPrevious().getRenamedMethodSignature(originalMethod, applied);
- return internalGetNextMethodSignature(renamedMethod);
+ return getNextMethodSignature(renamedMethod);
}
@Override
@@ -257,7 +257,8 @@
return newMethodSignatures.getRepresentativeKeyOrDefault(method, method);
}
- protected DexMethod internalGetNextMethodSignature(DexMethod method) {
+ @Override
+ public DexMethod getNextMethodSignature(DexMethod method) {
return newMethodSignatures.getRepresentativeValueOrDefault(method, method);
}
diff --git a/src/main/java/com/android/tools/r8/graph/SubtypingInfo.java b/src/main/java/com/android/tools/r8/graph/SubtypingInfo.java
index 2382abc..b61f288 100644
--- a/src/main/java/com/android/tools/r8/graph/SubtypingInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/SubtypingInfo.java
@@ -9,7 +9,6 @@
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import java.util.ArrayDeque;
-import java.util.Collection;
import java.util.Deque;
import java.util.HashSet;
import java.util.IdentityHashMap;
@@ -49,11 +48,15 @@
}
public static SubtypingInfo create(AppInfoWithClassHierarchy appInfo) {
- return create(appInfo.app().asDirect().allClasses(), appInfo);
+ DirectMappedDexApplication directApp = appInfo.app().asDirect();
+ return create(
+ Iterables.concat(
+ directApp.programClasses(), directApp.classpathClasses(), directApp.libraryClasses()),
+ appInfo);
}
public static SubtypingInfo create(
- Collection<? extends DexClass> classes, DexDefinitionSupplier definitions) {
+ Iterable<? extends DexClass> classes, DexDefinitionSupplier definitions) {
Map<DexType, TypeInfo> typeInfo = new ConcurrentHashMap<>();
Map<DexType, Set<DexType>> subtypeMap = new IdentityHashMap<>();
populateSubtypeMap(classes, subtypeMap, typeInfo, definitions);
@@ -117,7 +120,7 @@
}
private static void populateSubtypeMap(
- Collection<? extends DexClass> classes,
+ Iterable<? extends DexClass> classes,
Map<DexType, Set<DexType>> map,
Map<DexType, TypeInfo> typeInfo,
DexDefinitionSupplier definitionSupplier) {
diff --git a/src/main/java/com/android/tools/r8/graph/UseRegistry.java b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
index 09d477d..1ce97e6 100644
--- a/src/main/java/com/android/tools/r8/graph/UseRegistry.java
+++ b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
@@ -41,7 +41,8 @@
}
public GraphLens getCodeLens() {
- return appView.codeLens();
+ assert context.isMethod();
+ return getMethodContext().getDefinition().getCode().getCodeLens(appView);
}
public final T getContext() {
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
index 6e6088a..1321169 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.shaking.DefaultEnqueuerUseRegistry;
+import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.EnqueuerWorklist;
public class ApiModelAnalysis extends EnqueuerAnalysis {
@@ -36,7 +37,10 @@
@Override
public void processNewlyLiveMethod(
- ProgramMethod method, ProgramDefinition context, EnqueuerWorklist worklist) {
+ ProgramMethod method,
+ ProgramDefinition context,
+ Enqueuer enqueuer,
+ EnqueuerWorklist worklist) {
computeAndSetApiLevelForDefinition(method);
}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
index d110049..9f9d30a 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ClassInitializerAssertionEnablingAnalysis.java
@@ -25,6 +25,7 @@
import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
+import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.EnqueuerWorklist;
import com.android.tools.r8.utils.AssertionConfigurationWithDefault;
import com.google.common.collect.ImmutableList;
@@ -77,7 +78,10 @@
@Override
public void processNewlyLiveMethod(
- ProgramMethod method, ProgramDefinition context, EnqueuerWorklist worklist) {
+ ProgramMethod method,
+ ProgramDefinition context,
+ Enqueuer enqueuer,
+ EnqueuerWorklist worklist) {
DexEncodedMethod definition = method.getDefinition();
if (!definition.hasCode() || !definition.getCode().isCfCode()) {
return;
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
index eef04d0..8dc26d6 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
@@ -30,7 +30,10 @@
/** Called when a method is found to be live. */
public void processNewlyLiveMethod(
- ProgramMethod method, ProgramDefinition context, EnqueuerWorklist worklist) {}
+ ProgramMethod method,
+ ProgramDefinition context,
+ Enqueuer enqueuer,
+ EnqueuerWorklist worklist) {}
/** Called when a method's code has been processed by the registry. */
public void processTracedCode(
diff --git a/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfo.java b/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfo.java
index 26cf24f..d221385 100644
--- a/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfo.java
@@ -52,6 +52,10 @@
return null;
}
+ public boolean isRemovedReceiverInfo() {
+ return false;
+ }
+
public boolean isRewrittenTypeInfo() {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfoCollection.java b/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfoCollection.java
index 0a9fcbf..cbfa83d 100644
--- a/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/proto/ArgumentInfoCollection.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfoFixer;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.ConsumerUtils;
import com.android.tools.r8.utils.IntObjConsumer;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry;
import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap;
@@ -344,13 +343,6 @@
*/
public Consumer<DexEncodedMethod.Builder> createParameterAnnotationsRemover(
DexEncodedMethod method) {
- if (numberOfRemovedArguments() > 0 && !method.parameterAnnotationsList.isEmpty()) {
- return builder -> {
- int firstArgumentIndex = method.getFirstNonReceiverArgumentIndex();
- builder.removeParameterAnnotations(
- oldIndex -> getArgumentInfo(oldIndex + firstArgumentIndex).isRemovedArgumentInfo());
- };
- }
- return ConsumerUtils.emptyConsumer();
+ return builder -> builder.rewriteParameterAnnotations(method, this);
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/proto/RemovedArgumentInfo.java b/src/main/java/com/android/tools/r8/graph/proto/RemovedArgumentInfo.java
index 953cedd..79b3b6c 100644
--- a/src/main/java/com/android/tools/r8/graph/proto/RemovedArgumentInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/proto/RemovedArgumentInfo.java
@@ -13,39 +13,41 @@
public class RemovedArgumentInfo extends ArgumentInfo {
- public static class Builder {
+ abstract static class BuilderBase<B extends BuilderBase<B>> {
- private boolean checkNullOrZero;
- private SingleValue singleValue;
- private DexType type;
+ SingleValue singleValue;
+ DexType type;
- public Builder setCheckNullOrZero(boolean checkNullOrZero) {
- this.checkNullOrZero = checkNullOrZero;
- return this;
- }
-
- public Builder setSingleValue(SingleValue singleValue) {
+ public B setSingleValue(SingleValue singleValue) {
this.singleValue = singleValue;
- return this;
+ return self();
}
- public Builder setType(DexType type) {
+ public B setType(DexType type) {
this.type = type;
- return this;
+ return self();
}
+ abstract B self();
+ }
+
+ public static class Builder extends BuilderBase<Builder> {
+
public RemovedArgumentInfo build() {
- assert type != null;
- return new RemovedArgumentInfo(checkNullOrZero, singleValue, type);
+ return new RemovedArgumentInfo(singleValue, type);
+ }
+
+ @Override
+ Builder self() {
+ return this;
}
}
- private final boolean checkNullOrZero;
private final SingleValue singleValue;
private final DexType type;
- private RemovedArgumentInfo(boolean checkNullOrZero, SingleValue singleValue, DexType type) {
- this.checkNullOrZero = checkNullOrZero;
+ RemovedArgumentInfo(SingleValue singleValue, DexType type) {
+ assert type != null;
this.singleValue = singleValue;
this.type = type;
}
@@ -66,10 +68,6 @@
return type;
}
- public boolean isCheckNullOrZeroSet() {
- return checkNullOrZero;
- }
-
@Override
public boolean isRemovedArgumentInfo() {
return true;
@@ -93,7 +91,7 @@
hasSingleValue() ? singleValue.rewrittenWithLens(appView, graphLens, codeLens) : null;
DexType rewrittenType = graphLens.lookupType(type, codeLens);
if (rewrittenSingleValue != singleValue || rewrittenType != type) {
- return new RemovedArgumentInfo(checkNullOrZero, rewrittenSingleValue, rewrittenType);
+ return new RemovedArgumentInfo(rewrittenSingleValue, rewrittenType);
}
return this;
}
@@ -104,13 +102,11 @@
return false;
}
RemovedArgumentInfo other = (RemovedArgumentInfo) obj;
- return checkNullOrZero == other.checkNullOrZero
- && type == other.type
- && Objects.equals(singleValue, other.singleValue);
+ return type == other.type && Objects.equals(singleValue, other.singleValue);
}
@Override
public int hashCode() {
- return Objects.hash(checkNullOrZero, singleValue, type);
+ return Objects.hash(singleValue, type);
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/proto/RemovedReceiverInfo.java b/src/main/java/com/android/tools/r8/graph/proto/RemovedReceiverInfo.java
new file mode 100644
index 0000000..7bd6530
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/proto/RemovedReceiverInfo.java
@@ -0,0 +1,66 @@
+// 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.graph.proto;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.ir.analysis.value.SingleValue;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import java.util.Objects;
+
+public class RemovedReceiverInfo extends RemovedArgumentInfo {
+
+ RemovedReceiverInfo(SingleValue singleValue, DexType type) {
+ super(singleValue, type);
+ }
+
+ @Override
+ public boolean isRemovedReceiverInfo() {
+ return true;
+ }
+
+ @Override
+ public RemovedReceiverInfo rewrittenWithLens(
+ AppView<AppInfoWithLiveness> appView, GraphLens graphLens, GraphLens codeLens) {
+ SingleValue rewrittenSingleValue =
+ hasSingleValue() ? getSingleValue().rewrittenWithLens(appView, graphLens, codeLens) : null;
+ DexType rewrittenType = graphLens.lookupType(getType(), codeLens);
+ if (rewrittenSingleValue != getSingleValue() || rewrittenType != getType()) {
+ return new RemovedReceiverInfo(rewrittenSingleValue, rewrittenType);
+ }
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ RemovedReceiverInfo other = (RemovedReceiverInfo) obj;
+ return getType() == other.getType() && Objects.equals(getSingleValue(), other.getSingleValue());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getSingleValue(), getType());
+ }
+
+ public static class Builder extends BuilderBase<Builder> {
+
+ public static Builder create() {
+ return new Builder();
+ }
+
+ public RemovedReceiverInfo build() {
+ return new RemovedReceiverInfo(singleValue, type);
+ }
+
+ @Override
+ Builder self() {
+ return this;
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
index d7dc429..78a8743 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -41,6 +41,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Consumer;
/**
* The class merger is responsible for moving methods from the sources in {@link ClassMerger#group}
@@ -195,15 +196,22 @@
void mergeMethods(
SyntheticArgumentClass syntheticArgumentClass,
- SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder) {
- mergeVirtualMethods();
+ SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder,
+ Consumer<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfoConsumer) {
+ mergeVirtualMethods(virtuallyMergedMethodsKeepInfoConsumer);
mergeDirectMethods(syntheticArgumentClass, syntheticInitializerConverterBuilder);
classMethodsBuilder.setClassMethods(group.getTarget());
}
- void mergeVirtualMethods() {
+ void mergeVirtualMethods(
+ Consumer<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfoConsumer) {
virtualMethodMergers.forEach(
- merger -> merger.merge(classMethodsBuilder, lensBuilder, classIdentifiers));
+ merger ->
+ merger.merge(
+ classMethodsBuilder,
+ lensBuilder,
+ classIdentifiers,
+ virtuallyMergedMethodsKeepInfoConsumer));
group.forEachSource(clazz -> clazz.getMethodCollection().clearVirtualMethods());
}
@@ -318,13 +326,17 @@
public void mergeGroup(
PrunedItems.Builder prunedItemsBuilder,
SyntheticArgumentClass syntheticArgumentClass,
- SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder) {
+ SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder,
+ Consumer<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfoConsumer) {
fixAccessFlags();
fixNestMemberAttributes();
mergeAnnotations();
mergeInterfaces();
mergeFields(prunedItemsBuilder);
- mergeMethods(syntheticArgumentClass, syntheticInitializerConverterBuilder);
+ mergeMethods(
+ syntheticArgumentClass,
+ syntheticInitializerConverterBuilder,
+ virtuallyMergedMethodsKeepInfoConsumer);
group.getTarget().clearClassSignature();
group.getTarget().forEachProgramMember(ProgramMember::clearGenericSignature);
group.forEachSource(clazz -> prunedItemsBuilder.addRemovedClass(clazz.getType()));
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
index ad8d9df..dd7de45 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -4,17 +4,24 @@
package com.android.tools.r8.horizontalclassmerging;
+import static com.android.tools.r8.graph.DexClassAndMethod.asProgramMethodOrNull;
+
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DirectMappedDexApplication;
+import com.android.tools.r8.graph.GraphLens.MethodLookupResult;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.horizontalclassmerging.code.SyntheticInitializerConverter;
+import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.FieldAccessInfoCollectionModifier;
import com.android.tools.r8.shaking.KeepInfoCollection;
import com.android.tools.r8.shaking.RuntimeTypeCheckInfo;
import com.android.tools.r8.utils.InternalOptions.HorizontalClassMergerOptions;
+import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.TraversalContinuation;
import java.util.ArrayList;
@@ -23,6 +30,7 @@
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
+import java.util.function.Consumer;
public class HorizontalClassMerger {
@@ -103,9 +111,13 @@
: null;
SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder =
SyntheticInitializerConverter.builder(appView, codeProvider);
+ List<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfos = new ArrayList<>();
PrunedItems prunedItems =
applyClassMergers(
- classMergers, syntheticArgumentClass, syntheticInitializerConverterBuilder);
+ classMergers,
+ syntheticArgumentClass,
+ syntheticInitializerConverterBuilder,
+ virtuallyMergedMethodsKeepInfos::add);
SyntheticInitializerConverter syntheticInitializerConverter =
syntheticInitializerConverterBuilder.build();
@@ -136,12 +148,44 @@
// Record where the synthesized $r8$classId fields are read and written.
if (mode.isInitial()) {
createFieldAccessInfoCollectionModifier(groups).modify(appView.withLiveness());
+ transformIncompleteCode(groups, horizontalClassMergerGraphLens, executorService);
} else {
assert groups.stream().noneMatch(MergeGroup::hasClassIdField);
}
appView.pruneItems(
prunedItems.toBuilder().setPrunedApp(appView.app()).build(), executorService);
+
+ amendKeepInfo(horizontalClassMergerGraphLens, virtuallyMergedMethodsKeepInfos);
+ }
+
+ private void amendKeepInfo(
+ HorizontalClassMergerGraphLens horizontalClassMergerGraphLens,
+ List<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfos) {
+ appView
+ .getKeepInfo()
+ .mutate(
+ keepInfo -> {
+ for (VirtuallyMergedMethodsKeepInfo virtuallyMergedMethodsKeepInfo :
+ virtuallyMergedMethodsKeepInfos) {
+ DexMethod representative = virtuallyMergedMethodsKeepInfo.getRepresentative();
+ MethodLookupResult lookupResult =
+ horizontalClassMergerGraphLens.lookupMethod(
+ representative,
+ null,
+ Type.VIRTUAL,
+ horizontalClassMergerGraphLens.getPrevious());
+ ProgramMethod mergedMethod =
+ asProgramMethodOrNull(appView.definitionFor(lookupResult.getReference()));
+ if (mergedMethod != null) {
+ keepInfo.joinMethod(
+ mergedMethod,
+ info -> info.merge(virtuallyMergedMethodsKeepInfo.getKeepInfo()));
+ continue;
+ }
+ assert false;
+ }
+ });
}
private FieldAccessInfoCollectionModifier createFieldAccessInfoCollectionModifier(
@@ -164,6 +208,32 @@
return builder.build();
}
+ private void transformIncompleteCode(
+ Collection<MergeGroup> groups,
+ HorizontalClassMergerGraphLens horizontalClassMergerGraphLens,
+ ExecutorService executorService)
+ throws ExecutionException {
+ ThreadUtils.processItems(
+ groups,
+ group -> {
+ if (group.hasClassIdField()) {
+ DexProgramClass target = group.getTarget();
+ target.forEachProgramVirtualMethodMatching(
+ definition ->
+ definition.hasCode()
+ && definition.getCode() instanceof IncompleteVirtuallyMergedMethodCode,
+ method -> {
+ IncompleteVirtuallyMergedMethodCode code =
+ (IncompleteVirtuallyMergedMethodCode) method.getDefinition().getCode();
+ method
+ .getDefinition()
+ .setCode(code.toCfCode(method, horizontalClassMergerGraphLens), appView);
+ });
+ }
+ },
+ executorService);
+ }
+
private DirectMappedDexApplication getNewApplication(HorizontallyMergedClasses mergedClasses) {
// In the second round of class merging, we must forcefully remove the merged classes from the
// application, since we won't run tree shaking before writing the application.
@@ -217,11 +287,15 @@
private PrunedItems applyClassMergers(
Collection<ClassMerger> classMergers,
SyntheticArgumentClass syntheticArgumentClass,
- SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder) {
+ SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder,
+ Consumer<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfoConsumer) {
PrunedItems.Builder prunedItemsBuilder = PrunedItems.builder().setPrunedApp(appView.app());
for (ClassMerger merger : classMergers) {
merger.mergeGroup(
- prunedItemsBuilder, syntheticArgumentClass, syntheticInitializerConverterBuilder);
+ prunedItemsBuilder,
+ syntheticArgumentClass,
+ syntheticInitializerConverterBuilder,
+ virtuallyMergedMethodsKeepInfoConsumer);
}
return prunedItemsBuilder.build();
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerCfCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerCfCode.java
index 839b6d5..ce6f6be 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerCfCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerCfCode.java
@@ -5,7 +5,6 @@
package com.android.tools.r8.horizontalclassmerging;
import com.android.tools.r8.cf.code.CfInstruction;
-import com.android.tools.r8.cf.code.CfTryCatch;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexType;
import java.util.List;
@@ -17,13 +16,8 @@
public class HorizontalClassMergerCfCode extends CfCode {
HorizontalClassMergerCfCode(
- DexType originalHolder,
- int maxStack,
- int maxLocals,
- List<CfInstruction> instructions,
- List<CfTryCatch> tryCatchRanges,
- List<LocalVariableInfo> localVariables) {
- super(originalHolder, maxStack, maxLocals, instructions, tryCatchRanges, localVariables);
+ DexType originalHolder, int maxStack, int maxLocals, List<CfInstruction> instructions) {
+ super(originalHolder, maxStack, maxLocals, instructions);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
index 937a1fc..75743d6 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
@@ -45,6 +45,11 @@
}
@Override
+ public boolean isHorizontalClassMergerGraphLens() {
+ return true;
+ }
+
+ @Override
protected Iterable<DexType> internalGetOriginalTypes(DexType previous) {
return IterableUtils.prependSingleton(previous, mergedClasses.getSourcesFor(previous));
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
new file mode 100644
index 0000000..65aed84
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
@@ -0,0 +1,244 @@
+// 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.horizontalclassmerging;
+
+import com.android.tools.r8.cf.code.CfFrame;
+import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.cf.code.CfInstanceFieldRead;
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfLabel;
+import com.android.tools.r8.cf.code.CfLoad;
+import com.android.tools.r8.cf.code.CfReturn;
+import com.android.tools.r8.cf.code.CfReturnVoid;
+import com.android.tools.r8.cf.code.CfSwitch;
+import com.android.tools.r8.cf.code.CfSwitch.Kind;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.ClasspathMethod;
+import com.android.tools.r8.graph.Code;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.IterableUtils;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
+import it.unimi.dsi.fastutil.ints.IntBidirectionalIterator;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.List;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * A short-lived piece of code that will be converted into {@link CfCode} using the method {@link
+ * #toCfCode(ProgramMethod, HorizontalClassMergerGraphLens)}.
+ */
+public class IncompleteVirtuallyMergedMethodCode extends Code {
+
+ private final DexField classIdField;
+ private final Int2ReferenceSortedMap<DexMethod> mappedMethods;
+ private final DexMethod originalMethod;
+ private final DexMethod superMethod;
+
+ public IncompleteVirtuallyMergedMethodCode(
+ DexField classIdField,
+ Int2ReferenceSortedMap<DexMethod> mappedMethods,
+ DexMethod originalMethod,
+ DexMethod superMethod) {
+ this.mappedMethods = mappedMethods;
+ this.classIdField = classIdField;
+ this.superMethod = superMethod;
+ this.originalMethod = originalMethod;
+ }
+
+ @Override
+ public boolean isHorizontalClassMergingCode() {
+ return true;
+ }
+
+ /**
+ * Given a mapping from class ids to methods to invoke, this creates a piece of {@link CfCode} on
+ * the following form.
+ *
+ * <pre>
+ * public Bar m(Foo foo) {
+ * switch (this.classId) {
+ * case 0:
+ * return this.m1(foo);
+ * case 1:
+ * return this.m2(foo);
+ * ...
+ * default:
+ * return this.mN(foo); // or super.m(foo);
+ * }
+ * }
+ * </pre>
+ *
+ * <p>Note that the methods to invoke must be rewritten using {@param lens}, since the invoked
+ * methods may be changed as a result of the horizontal class merger's fixup (e.g., if the method
+ * signature refers to a horizontally merged type).
+ */
+ public CfCode toCfCode(ProgramMethod method, HorizontalClassMergerGraphLens lens) {
+ // We store each argument in a local.
+ int maxLocals = 1 + IterableUtils.sumInt(method.getParameters(), DexType::getRequiredRegisters);
+
+ // We load all arguments on the stack and then the receiver to fetch the class id.
+ int maxStack = maxLocals + 1;
+
+ // Create instructions.
+ List<CfInstruction> instructions = new ArrayList<>();
+
+ // Setup keys and labels for switch.
+ IntBidirectionalIterator classIdIterator = mappedMethods.keySet().iterator();
+ int[] keys = new int[mappedMethods.size() - BooleanUtils.intValue(superMethod == null)];
+ List<CfLabel> labels = new ArrayList<>();
+ for (int key = 0; key < keys.length; key++) {
+ keys[key] = classIdIterator.nextInt();
+ labels.add(new CfLabel());
+ }
+ CfLabel fallthroughLabel = new CfLabel();
+
+ // Add instructions.
+ instructions.add(new CfLoad(ValueType.OBJECT, 0));
+ int localIndex = 1;
+ for (DexType parameter : method.getParameters()) {
+ instructions.add(new CfLoad(ValueType.fromDexType(parameter), localIndex));
+ localIndex += parameter.getRequiredRegisters();
+ }
+ instructions.add(new CfLoad(ValueType.OBJECT, 0));
+ instructions.add(new CfInstanceFieldRead(classIdField));
+
+ // Emit switch.
+ instructions.add(new CfSwitch(Kind.LOOKUP, fallthroughLabel, keys, labels));
+ for (int key = 0; key < keys.length; key++) {
+ int classId = keys[key];
+ DexMethod target = lens.getNextMethodSignature(mappedMethods.get(classId));
+ instructions.add(labels.get(key));
+ instructions.add(createCfFrameForSwitchCase(method, maxLocals));
+ instructions.add(
+ new CfInvoke(Opcodes.INVOKESPECIAL, target, method.getHolder().isInterface()));
+ if (method.getReturnType().isVoidType()) {
+ instructions.add(new CfReturnVoid());
+ } else {
+ instructions.add(new CfReturn(ValueType.fromDexType(method.getReturnType())));
+ }
+ }
+
+ // Emit fallthrough.
+ instructions.add(fallthroughLabel);
+ instructions.add(createCfFrameForSwitchCase(method, maxLocals));
+
+ DexMethod fallthroughTarget =
+ lens.getNextMethodSignature(
+ superMethod != null ? superMethod : mappedMethods.get(mappedMethods.lastIntKey()));
+ instructions.add(
+ new CfInvoke(Opcodes.INVOKESPECIAL, fallthroughTarget, method.getHolder().isInterface()));
+
+ // Emit return.
+ if (method.getReturnType().isVoidType()) {
+ instructions.add(new CfReturnVoid());
+ } else {
+ instructions.add(new CfReturn(ValueType.fromDexType(method.getReturnType())));
+ }
+ return new CfCode(originalMethod.getHolderType(), maxStack, maxLocals, instructions) {
+
+ @Override
+ public GraphLens getCodeLens(AppView<?> appView) {
+ GraphLens graphLens =
+ appView
+ .graphLens()
+ .asNonIdentityLens()
+ .find(GraphLens::isHorizontalClassMergerGraphLens);
+ assert graphLens != null;
+ return graphLens;
+ }
+ };
+ }
+
+ private static CfFrame createCfFrameForSwitchCase(ProgramMethod representative, int localsSize) {
+ Deque<FrameType> stack =
+ new ArrayDeque<>(representative.getDefinition().getNumberOfArguments());
+ for (int argumentIndex = 0;
+ argumentIndex < representative.getDefinition().getNumberOfArguments();
+ argumentIndex++) {
+ stack.add(FrameType.initialized(representative.getArgumentType(argumentIndex)));
+ }
+ return new CfFrame(createLocalFrames(representative, localsSize), stack);
+ }
+
+ private static Int2ReferenceAVLTreeMap<FrameType> createLocalFrames(
+ ProgramMethod representative, int localsSize) {
+ Int2ReferenceAVLTreeMap<FrameType> locals = new Int2ReferenceAVLTreeMap<>();
+ for (int argumentIndex = 0, localIndex = 0;
+ argumentIndex < representative.getDefinition().getNumberOfArguments();
+ argumentIndex++) {
+ FrameType frameType = FrameType.initialized(representative.getArgumentType(argumentIndex));
+ locals.put(localIndex++, frameType);
+ if (frameType.isWide()) {
+ locals.put(localIndex++, frameType);
+ }
+ }
+ assert locals.size() == localsSize;
+ return locals;
+ }
+
+ // Implement Code.
+
+ @Override
+ public IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
+ throw new Unreachable();
+ }
+
+ @Override
+ protected boolean computeEquals(Object other) {
+ throw new Unreachable();
+ }
+
+ @Override
+ protected int computeHashCode() {
+ throw new Unreachable();
+ }
+
+ @Override
+ public int estimatedDexCodeSizeUpperBoundInBytes() {
+ throw new Unreachable();
+ }
+
+ @Override
+ public boolean isEmptyVoidMethod() {
+ throw new Unreachable();
+ }
+
+ @Override
+ public void registerCodeReferences(ProgramMethod method, UseRegistry registry) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public void registerCodeReferencesForDesugaring(ClasspathMethod method, UseRegistry registry) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public String toString() {
+ return "IncompleteVirtuallyMergedMethodCode";
+ }
+
+ @Override
+ public String toString(DexEncodedMethod method, ClassNameMapper naming) {
+ return toString();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerDescription.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerDescription.java
index 2affeaf..7aa753c 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerDescription.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerDescription.java
@@ -167,12 +167,7 @@
instructionBuilder.add(new CfReturnVoid());
return new HorizontalClassMergerCfCode(
- newMethodReference.getHolderType(),
- maxStack.get(),
- maxLocals,
- instructionBuilder.build(),
- ImmutableList.of(),
- ImmutableList.of());
+ newMethodReference.getHolderType(), maxStack.get(), maxLocals, instructionBuilder.build());
}
private static void addCfInstructionsForInstanceFieldAssignments(
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
index 4a3f2ff..0c36573 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
@@ -29,10 +29,10 @@
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
+import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.LinkedHashSet;
-import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@@ -124,7 +124,7 @@
* </ul>
*/
public HorizontalClassMergerGraphLens fixupTypeReferences() {
- List<DexProgramClass> classes = appView.appInfo().classesWithDeterministicOrder();
+ Collection<DexProgramClass> classes = appView.appInfo().classesWithDeterministicOrder();
Iterables.filter(classes, DexProgramClass::isInterface).forEach(this::fixupInterfaceClass);
classes.forEach(this::fixupAttributes);
classes.forEach(this::fixupProgramClassSuperTypes);
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPoint.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPoint.java
deleted file mode 100644
index 494e383..0000000
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPoint.java
+++ /dev/null
@@ -1,163 +0,0 @@
-// 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.horizontalclassmerging;
-
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.ir.code.Invoke.Type;
-import com.android.tools.r8.ir.code.Position;
-import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.code.ValueType;
-import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.ir.synthetic.SyntheticSourceCode;
-import com.android.tools.r8.utils.IntBox;
-import it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry;
-import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Assuming a method signature <code>
- * void method([args]);
- * </code>. This class generates code depending on which of the following cases it matches.
- *
- * <p>If the method does not override a method and is implemented by many (e.g. 2) classes:
- *
- * <pre>
- * void method([args]) {
- * switch (classId) {
- * case 0:
- * return method$1([args]);
- * default:
- * return method$2([args]);
- * }
- * }
- * </pre>
- *
- * <p>If the method overrides a method and is implemented by any number of classes:
- *
- * <pre>
- * void method([args]) {
- * switch (classId) {
- * case 0:
- * return method$1([args]);
- * // ... further cases ...
- * default:
- * return super.method$1([args]);
- * }
- * }
- * </pre>
- */
-public class VirtualMethodEntryPoint extends SyntheticSourceCode {
- private final Int2ReferenceSortedMap<DexMethod> mappedMethods;
- private final DexField classIdField;
- private final DexMethod superMethod;
-
- public VirtualMethodEntryPoint(
- Int2ReferenceSortedMap<DexMethod> mappedMethods,
- DexField classIdField,
- DexMethod superMethod,
- DexMethod newMethod,
- Position callerPosition,
- DexMethod originalMethod) {
- super(newMethod.holder, newMethod, callerPosition, originalMethod);
-
- assert classIdField != null;
-
- this.mappedMethods = mappedMethods;
- this.classIdField = classIdField;
- this.superMethod = superMethod;
- }
-
- void addInvokeDirect(DexMethod method) {
- add(
- builder -> {
- List<Value> arguments = new ArrayList<>(method.getArity() + 1);
- arguments.add(builder.getReceiverValue());
- if (builder.getArgumentValues() != null) {
- arguments.addAll(builder.getArgumentValues());
- }
- builder.addInvoke(Type.DIRECT, method, method.proto, arguments, false);
- });
- }
-
- void addInvokeSuper() {
- assert superMethod != null;
-
- add(
- builder -> {
- List<Value> arguments = new ArrayList<>(method.getArity() + 1);
- arguments.add(builder.getReceiverValue());
- if (builder.getArgumentValues() != null) {
- arguments.addAll(builder.getArgumentValues());
- }
- builder.addInvoke(Type.SUPER, superMethod, superMethod.proto, arguments, false);
- });
- }
-
- void handleReturn(int retRegister) {
- if (proto.returnType.isVoidType()) {
- add(IRBuilder::addReturn, endsBlock);
- } else {
- add(builder -> builder.addMoveResult(retRegister));
- add(builder -> builder.addReturn(retRegister), endsBlock);
- }
- }
-
- @Override
- protected void prepareInstructions() {
- int casesCount = mappedMethods.size();
-
- // If there is no super method, use one of the cases as a fallthrough case.
- if (superMethod == null) {
- casesCount--;
- }
-
- assert casesCount > 0;
-
- // Return value register if needed.
- int returnRegister =
- !proto.returnType.isVoidType() ? nextRegister(ValueType.fromDexType(proto.returnType)) : -1;
-
- int[] keys = new int[casesCount];
- int[] offsets = new int[casesCount];
- IntBox fallthrough = new IntBox();
-
- // Fetch the class id from the class id field.
- int idRegister = nextRegister(ValueType.INT);
- add(builder -> builder.addInstanceGet(idRegister, getReceiverRegister(), classIdField));
-
- int switchIndex = lastInstructionIndex();
- add(
- builder -> builder.addSwitch(idRegister, keys, fallthrough.get(), offsets),
- builder -> endsSwitch(builder, switchIndex, fallthrough.get(), offsets));
-
- int index = 0;
- for (Entry<DexMethod> entry : mappedMethods.int2ReferenceEntrySet()) {
- int classId = entry.getIntKey();
- DexMethod mappedMethod = entry.getValue();
-
- // If there is no super method, then use the last case as the default case.
- if (index >= casesCount) {
- fallthrough.set(nextInstructionIndex());
- } else {
- keys[index] = classId;
- offsets[index] = nextInstructionIndex();
- }
-
- addInvokeDirect(mappedMethod);
- handleReturn(returnRegister);
-
- index++;
- }
-
- // If the super class implements this method, then the fallthrough case should execute it.
- if (superMethod != null) {
- fallthrough.set(nextInstructionIndex());
- addInvokeSuper();
- handleReturn(returnRegister);
- }
- }
-}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
index b18a69c..67cc625 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
@@ -10,13 +10,10 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.horizontalclassmerging.code.VirtualMethodEntryPointSynthesizedCode;
-import com.android.tools.r8.ir.synthetic.AbstractSynthesizedCode;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.OptionalBool;
import com.android.tools.r8.utils.structural.Ordered;
@@ -26,6 +23,7 @@
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
public class VirtualMethodMerger {
@@ -57,14 +55,13 @@
/** Get the super method handle if this method overrides a parent method. */
private DexMethod superMethod(
- AppView<? extends AppInfoWithClassHierarchy> appView, DexProgramClass target) {
+ AppView<? extends AppInfoWithClassHierarchy> appView, MergeGroup group) {
DexMethod template = methods.iterator().next().getReference();
SingleResolutionResult resolutionResult =
appView
.appInfo()
- .resolveMethodOnClass(template, target.getSuperType())
+ .resolveMethodOnClass(template, group.getSuperType())
.asSingleResolution();
-
if (resolutionResult == null || resolutionResult.getResolvedMethod().isAbstract()) {
// If there is no super method or the method is abstract it should not be called.
return null;
@@ -74,7 +71,7 @@
return resolutionResult
.getResolvedMethod()
.getReference()
- .withHolder(target.getSuperType(), appView.dexItemFactory());
+ .withHolder(group.getSuperType(), appView.dexItemFactory());
}
return resolutionResult.getResolvedMethod().getReference();
}
@@ -82,8 +79,7 @@
public VirtualMethodMerger build(
AppView<? extends AppInfoWithClassHierarchy> appView, MergeGroup group) {
// If not all the classes are in the merge group, find the fallback super method to call.
- DexMethod superMethod =
- methods.size() < group.size() ? superMethod(appView, group.getTarget()) : null;
+ DexMethod superMethod = methods.size() < group.size() ? superMethod(appView, group) : null;
return new VirtualMethodMerger(appView, group, methods, superMethod);
}
}
@@ -229,7 +225,8 @@
public void merge(
ClassMethodsBuilder classMethodsBuilder,
HorizontalClassMergerGraphLens.Builder lensBuilder,
- Reference2IntMap<DexType> classIdentifiers) {
+ Reference2IntMap<DexType> classIdentifiers,
+ Consumer<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfoConsumer) {
assert !methods.isEmpty();
// Handle trivial merges.
@@ -252,7 +249,8 @@
}
DexMethod newMethod = moveMethod(classMethodsBuilder, method);
lensBuilder.recordNewMethodSignature(method.getReference(), newMethod);
- classIdToMethodMap.put(classIdentifiers.getInt(method.getHolderType()), newMethod);
+ classIdToMethodMap.put(
+ classIdentifiers.getInt(method.getHolderType()), method.getReference());
if (representative == null) {
representative = method;
}
@@ -271,14 +269,9 @@
classMethodsBuilder::isFresh);
DexEncodedMethod representativeMethod = representative.getDefinition();
DexMethod newMethodReference = getNewMethodReference();
- AbstractSynthesizedCode synthesizedCode =
- new VirtualMethodEntryPointSynthesizedCode(
- classIdToMethodMap,
- group.getClassIdField(),
- superMethod,
- newMethodReference,
- bridgeMethodReference,
- appView.dexItemFactory());
+ IncompleteVirtuallyMergedMethodCode synthesizedCode =
+ new IncompleteVirtuallyMergedMethodCode(
+ group.getClassIdField(), classIdToMethodMap, originalMethodReference, superMethod);
DexEncodedMethod newMethod =
DexEncodedMethod.syntheticBuilder()
.setMethod(newMethodReference)
@@ -293,13 +286,20 @@
}
// Map each old non-abstract method to the newly synthesized method in the graph lens.
+ VirtuallyMergedMethodsKeepInfo virtuallyMergedMethodsKeepInfo =
+ new VirtuallyMergedMethodsKeepInfo(representative.getReference());
for (ProgramMethod oldMethod : methods) {
lensBuilder.mapMethod(oldMethod.getReference(), newMethodReference);
+ virtuallyMergedMethodsKeepInfo.amendKeepInfo(appView.getKeepInfo(oldMethod));
}
// Add a mapping from a synthetic name to the synthetic merged method.
lensBuilder.recordNewMethodSignature(bridgeMethodReference, newMethodReference);
classMethodsBuilder.addVirtualMethod(newMethod);
+
+ if (!virtuallyMergedMethodsKeepInfo.getKeepInfo().isBottom()) {
+ virtuallyMergedMethodsKeepInfoConsumer.accept(virtuallyMergedMethodsKeepInfo);
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtuallyMergedMethodsKeepInfo.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtuallyMergedMethodsKeepInfo.java
new file mode 100644
index 0000000..b395d5d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtuallyMergedMethodsKeepInfo.java
@@ -0,0 +1,31 @@
+// 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.horizontalclassmerging;
+
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.shaking.KeepMethodInfo;
+import com.android.tools.r8.shaking.KeepMethodInfo.Joiner;
+
+public class VirtuallyMergedMethodsKeepInfo {
+
+ private final DexMethod representative;
+ private final KeepMethodInfo.Joiner keepInfo = KeepMethodInfo.newEmptyJoiner();
+
+ public VirtuallyMergedMethodsKeepInfo(DexMethod representative) {
+ this.representative = representative;
+ }
+
+ public void amendKeepInfo(KeepMethodInfo keepInfo) {
+ this.keepInfo.merge(keepInfo.joiner());
+ }
+
+ public DexMethod getRepresentative() {
+ return representative;
+ }
+
+ public Joiner getKeepInfo() {
+ return keepInfo;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/VirtualMethodEntryPointSynthesizedCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/VirtualMethodEntryPointSynthesizedCode.java
deleted file mode 100644
index 7cfd3dc..0000000
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/VirtualMethodEntryPointSynthesizedCode.java
+++ /dev/null
@@ -1,79 +0,0 @@
-// 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.horizontalclassmerging.code;
-
-import com.android.tools.r8.graph.DexClassAndMethod;
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.UseRegistry;
-import com.android.tools.r8.horizontalclassmerging.VirtualMethodEntryPoint;
-import com.android.tools.r8.ir.synthetic.SynthesizedCode;
-import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
-import java.util.function.Consumer;
-
-public class VirtualMethodEntryPointSynthesizedCode extends SynthesizedCode {
-
- private final DexItemFactory dexItemFactory;
- private final Int2ReferenceSortedMap<DexMethod> mappedMethods;
- private final DexMethod superMethod;
-
- public VirtualMethodEntryPointSynthesizedCode(
- Int2ReferenceSortedMap<DexMethod> mappedMethods,
- DexField classIdField,
- DexMethod superMethod,
- DexMethod method,
- DexMethod originalMethod,
- DexItemFactory factory) {
- super(
- (context, position) ->
- new VirtualMethodEntryPoint(
- mappedMethods,
- classIdField,
- computeSuperMethodTarget(superMethod, context, factory),
- method,
- position,
- originalMethod));
- this.dexItemFactory = factory;
- this.mappedMethods = mappedMethods;
- this.superMethod = superMethod;
- }
-
- private static DexMethod computeSuperMethodTarget(
- DexMethod superMethod, ProgramMethod method, DexItemFactory factory) {
- // We are only using superMethod as a bit but if this is changed to generate CfCode directly,
- // the superMethod needs to be computed by mapping through the lens.
- if (superMethod == null) {
- return null;
- }
- return method.getReference().withHolder(method.getHolder().superType, factory);
- }
-
- @Override
- public Consumer<UseRegistry> getRegistryCallback(DexClassAndMethod method) {
- return registry -> registerReachableDefinitions(method, registry);
- }
-
- private void registerReachableDefinitions(DexClassAndMethod method, UseRegistry registry) {
- assert registry.getTraversalContinuation().shouldContinue();
- for (DexMethod mappedMethod : mappedMethods.values()) {
- registry.registerInvokeDirect(mappedMethod);
- if (registry.getTraversalContinuation().shouldBreak()) {
- return;
- }
- }
- DexMethod superMethodTarget =
- computeSuperMethodTarget(superMethod, method.asProgramMethod(), dexItemFactory);
- if (superMethodTarget != null) {
- registry.registerInvokeSuper(superMethodTarget);
- }
- }
-
- @Override
- public boolean isHorizontalClassMergingCode() {
- return true;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
index 62b8e28..b3976c7 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
@@ -39,6 +39,7 @@
import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.EnqueuerWorklist;
import com.android.tools.r8.shaking.InstantiationReason;
+import com.android.tools.r8.shaking.KeepMethodInfo;
import com.android.tools.r8.shaking.KeepReason;
import com.android.tools.r8.utils.BitUtils;
import com.android.tools.r8.utils.OptionalBool;
@@ -133,8 +134,13 @@
*/
@Override
public void processNewlyLiveMethod(
- ProgramMethod method, ProgramDefinition context, EnqueuerWorklist worklist) {
+ ProgramMethod method,
+ ProgramDefinition context,
+ Enqueuer enqueuer,
+ EnqueuerWorklist worklist) {
if (references.isFindLiteExtensionByNumberMethod(method.getReference())) {
+ enqueuer.applyMinimumKeepInfoWhenLiveOrTargeted(
+ method, KeepMethodInfo.newEmptyJoiner().disallowParameterReordering());
findLiteExtensionByNumberMethods.add(method);
return;
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
index fa59829..fe2c785 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
@@ -17,6 +17,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
@@ -62,7 +63,7 @@
private void internalConvertClasses(
ClassConverterResult.Builder resultBuilder, ExecutorService executorService)
throws ExecutionException {
- List<DexProgramClass> classes = appView.appInfo().classes();
+ Collection<DexProgramClass> classes = appView.appInfo().classes();
CfClassSynthesizerDesugaringEventConsumer classSynthesizerEventConsumer =
new CfClassSynthesizerDesugaringEventConsumer();
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 29bee42..4d1cfc2 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -435,7 +435,7 @@
return new IRBuilder(
method,
appView,
- appView.codeLens(),
+ method.getDefinition().getCode().getCodeLens(appView),
source,
origin,
lookupPrototypeChanges(appView, method),
@@ -459,14 +459,6 @@
return appView.graphLens().lookupPrototypeChangesForMethodDefinition(method.getReference());
}
- public static RewrittenPrototypeDescription lookupPrototypeChangesForInlinee(
- AppView<?> appView, ProgramMethod method, MethodProcessor methodProcessor) {
- if (methodProcessor.shouldApplyCodeRewritings(method)) {
- return appView.graphLens().lookupPrototypeChangesForMethodDefinition(method.getReference());
- }
- return RewrittenPrototypeDescription.none();
- }
-
private IRBuilder(
ProgramMethod method,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index ba22a02..613ab36 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -969,7 +969,7 @@
private Deque<GraphLensInterval> getUnappliedLenses(ProgramMethod method) {
Deque<GraphLensInterval> unappliedLenses = new ArrayDeque<>(8);
- GraphLens codeLens = appView.codeLens();
+ GraphLens codeLens = method.getDefinition().getCode().getCodeLens(appView);
GraphLens currentLens = appView.graphLens();
DexMethod currentMethod = method.getReference();
while (currentLens != codeLens) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/callgraph/CallSiteInformation.java b/src/main/java/com/android/tools/r8/ir/conversion/callgraph/CallSiteInformation.java
index a46a6bc..125b53c 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/callgraph/CallSiteInformation.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/callgraph/CallSiteInformation.java
@@ -8,6 +8,8 @@
import com.android.tools.r8.graph.ImmediateProgramSubtypingInfo;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.KeepMethodInfo;
+import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.classhierarchy.MethodOverridesCollector;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.Sets;
@@ -57,14 +59,17 @@
private final Set<DexMethod> multiCallerInlineCandidates = Sets.newIdentityHashSet();
CallGraphBasedCallSiteInformation(AppView<AppInfoWithLiveness> appView, CallGraph graph) {
+ InternalOptions options = appView.options();
ProgramMethodSet pinned =
MethodOverridesCollector.findAllMethodsAndOverridesThatMatches(
appView,
ImmediateProgramSubtypingInfo.create(appView),
appView.appInfo().classes(),
- method ->
- appView.getKeepInfo(method).isPinned(appView.options())
- || appView.appInfo().isMethodTargetedByInvokeDynamic(method));
+ method -> {
+ KeepMethodInfo keepInfo = appView.getKeepInfo(method);
+ return !keepInfo.isClosedWorldReasoningAllowed(options)
+ || keepInfo.isPinned(options);
+ });
for (Node node : graph.getNodes()) {
ProgramMethod method = node.getProgramMethod();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index dd2bb76..68d48dc 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -179,6 +179,9 @@
if (options.getMinApiLevel().isLessThan(AndroidApiLevel.Sv2)) {
initializeAndroidSv2MethodProviders(factory);
}
+ if (options.getMinApiLevel().isLessThan(AndroidApiLevel.T)) {
+ initializeAndroidTMethodProviders(factory);
+ }
// The following providers are implemented at API level T. For backporting they require
// the java.util.Optional class to be present, either through library desugaring or natively.
@@ -1158,6 +1161,145 @@
}
}
+ private void initializeAndroidTMethodProviders(DexItemFactory factory) {
+ // java.lang.Integer.
+ {
+ // int Integer.parseInt(CharSequence s, int beginIndex, int endIndex, int radix)
+ DexType type = factory.boxedIntType;
+ DexString name = factory.createString("parseInt");
+ DexProto proto =
+ factory.createProto(
+ factory.intType,
+ factory.charSequenceType,
+ factory.intType,
+ factory.intType,
+ factory.intType);
+ DexMethod method = factory.createMethod(type, proto, name);
+ addProvider(
+ appView.options().canParseNumbersWithPlusPrefix()
+ ? new MethodGenerator(
+ method,
+ BackportedMethods::IntegerMethods_parseIntSubsequenceWithRadix,
+ "parseIntSubsequenceWithRadix")
+ : new MethodGenerator(
+ method,
+ BackportedMethods::IntegerMethods_parseIntSubsequenceWithRadixDalvik,
+ "parseIntSubsequenceWithRadix"));
+ }
+ {
+ // int Integer.parseUnsignedInt(CharSequence s, int beginIndex, int endIndex, int radix)
+ DexType type = factory.boxedIntType;
+ DexString name = factory.createString("parseUnsignedInt");
+ DexProto proto =
+ factory.createProto(
+ factory.intType,
+ factory.charSequenceType,
+ factory.intType,
+ factory.intType,
+ factory.intType);
+ DexMethod method = factory.createMethod(type, proto, name);
+ addProvider(
+ new MethodGenerator(
+ method,
+ BackportedMethods::IntegerMethods_parseUnsignedIntSubsequenceWithRadix,
+ "parseIntSubsequenceWithRadix"));
+ }
+
+ // java.lang.Long.
+ {
+ // long Long.parseLong(CharSequence s, int beginIndex, int endIndex, int radix)
+ DexType type = factory.boxedLongType;
+ DexString name = factory.createString("parseLong");
+ DexProto proto =
+ factory.createProto(
+ factory.longType,
+ factory.charSequenceType,
+ factory.intType,
+ factory.intType,
+ factory.intType);
+ DexMethod method = factory.createMethod(type, proto, name);
+ addProvider(
+ appView.options().canParseNumbersWithPlusPrefix()
+ ? new MethodGenerator(
+ method,
+ BackportedMethods::LongMethods_parseLongSubsequenceWithRadix,
+ "parseLongSubsequenceWithRadix")
+ : new MethodGenerator(
+ method,
+ BackportedMethods::LongMethods_parseLongSubsequenceWithRadixDalvik,
+ "parseLongSubsequenceWithRadix"));
+ }
+ {
+ // long Long.parseUnsignedLong(CharSequence s, int beginIndex, int endIndex, int radix)
+ DexType type = factory.boxedLongType;
+ DexString name = factory.createString("parseUnsignedLong");
+ DexProto proto =
+ factory.createProto(
+ factory.longType,
+ factory.charSequenceType,
+ factory.intType,
+ factory.intType,
+ factory.intType);
+ DexMethod method = factory.createMethod(type, proto, name);
+ addProvider(
+ new MethodGenerator(
+ method,
+ BackportedMethods::LongMethods_parseUnsignedLongSubsequenceWithRadix,
+ "parseUnsignedLongSubsequenceWithRadix"));
+ }
+ // java.lang.String.
+ {
+ // String String.repeat(int)
+ DexType type = factory.stringType;
+ DexString name = factory.createString("repeat");
+ DexProto proto = factory.createProto(factory.stringType, factory.intType);
+ DexMethod method = factory.createMethod(type, proto, name);
+ addProvider(
+ new StatifyingMethodGenerator(
+ method, BackportedMethods::StringMethods_repeat, "repeat", type));
+ }
+ {
+ // boolean String.isBlank()
+ DexType type = factory.stringType;
+ DexString name = factory.createString("isBlank");
+ DexProto proto = factory.createProto(factory.booleanType);
+ DexMethod method = factory.createMethod(type, proto, name);
+ addProvider(
+ new StatifyingMethodGenerator(
+ method, BackportedMethods::StringMethods_isBlank, "isBlank", type));
+ }
+ {
+ // String String.strip()
+ DexType type = factory.stringType;
+ DexString name = factory.createString("strip");
+ DexProto proto = factory.createProto(factory.stringType);
+ DexMethod method = factory.createMethod(type, proto, name);
+ addProvider(
+ new StatifyingMethodGenerator(
+ method, BackportedMethods::StringMethods_strip, "strip", type));
+ }
+ {
+ // String String.stripLeading()
+ DexType type = factory.stringType;
+ DexString name = factory.createString("stripLeading");
+ DexProto proto = factory.createProto(factory.stringType);
+ DexMethod method = factory.createMethod(type, proto, name);
+ addProvider(
+ new StatifyingMethodGenerator(
+ method, BackportedMethods::StringMethods_stripLeading, "stripLeading", type));
+ }
+ {
+ // String String.stripTrailing()
+ DexType type = factory.stringType;
+ DexString name = factory.createString("stripTrailing");
+ DexProto proto = factory.createProto(factory.stringType);
+ DexMethod method = factory.createMethod(type, proto, name);
+ addProvider(
+ new StatifyingMethodGenerator(
+ method, BackportedMethods::StringMethods_stripTrailing, "stripTrailing", type));
+ }
+ }
+
private void initializeAndroidOptionalTMethodProviders(DexItemFactory factory) {
DexType optionalType = factory.optionalType;
DexType[] optionalTypes =
@@ -1275,67 +1417,7 @@
}
private void initializeJava9MethodProviders(DexItemFactory factory) {
- // Integer
- DexType type = factory.boxedIntType;
- // int Integer.parseInt(CharSequence s, int beginIndex, int endIndex, int radix)
- DexString name = factory.createString("parseInt");
- DexProto proto =
- factory.createProto(
- factory.intType,
- factory.charSequenceType,
- factory.intType,
- factory.intType,
- factory.intType);
- DexMethod method = factory.createMethod(type, proto, name);
- addProvider(
- appView.options().canParseNumbersWithPlusPrefix()
- ? new MethodGenerator(
- method,
- BackportedMethods::IntegerMethods_parseIntSubsequenceWithRadix,
- "parseIntSubsequenceWithRadix")
- : new MethodGenerator(
- method,
- BackportedMethods::IntegerMethods_parseIntSubsequenceWithRadixDalvik,
- "parseIntSubsequenceWithRadix"));
-
- // Long
- type = factory.boxedLongType;
- // long Long.parseLong(CharSequence s, int beginIndex, int endIndex, int radix)
- name = factory.createString("parseLong");
- proto =
- factory.createProto(
- factory.longType,
- factory.charSequenceType,
- factory.intType,
- factory.intType,
- factory.intType);
- method = factory.createMethod(type, proto, name);
- addProvider(
- appView.options().canParseNumbersWithPlusPrefix()
- ? new MethodGenerator(
- method,
- BackportedMethods::LongMethods_parseLongSubsequenceWithRadix,
- "parseLongSubsequenceWithRadix")
- : new MethodGenerator(
- method,
- BackportedMethods::LongMethods_parseLongSubsequenceWithRadixDalvik,
- "parseLongSubsequenceWithRadix"));
-
- // long Long.parseUnsignedLong(CharSequence s, int beginIndex, int endIndex, int radix)
- name = factory.createString("parseUnsignedLong");
- proto =
- factory.createProto(
- factory.longType,
- factory.charSequenceType,
- factory.intType,
- factory.intType,
- factory.intType);
- method = factory.createMethod(type, proto, name);
- addProvider(
- new MethodGenerator(
- method,
- BackportedMethods::LongMethods_parseUnsignedLongSubsequenceWithRadix,
- "parseUnsignedLongSubsequenceWithRadix"));
+ // Nothing right now.
}
private void initializeJava10MethodProviders(DexItemFactory factory) {
@@ -1364,49 +1446,6 @@
method = factory.createMethod(type, proto, name);
addProvider(
new MethodGenerator(method, BackportedMethods::CharSequenceMethods_compare, "compare"));
-
- // String
- type = factory.stringType;
-
- // String String.repeat(int)
- name = factory.createString("repeat");
- proto = factory.createProto(factory.stringType, factory.intType);
- method = factory.createMethod(type, proto, name);
- addProvider(
- new StatifyingMethodGenerator(
- method, BackportedMethods::StringMethods_repeat, "repeat", type));
-
- // boolean String.isBlank()
- name = factory.createString("isBlank");
- proto = factory.createProto(factory.booleanType);
- method = factory.createMethod(type, proto, name);
- addProvider(
- new StatifyingMethodGenerator(
- method, BackportedMethods::StringMethods_isBlank, "isBlank", type));
-
- // String String.strip()
- name = factory.createString("strip");
- proto = factory.createProto(factory.stringType);
- method = factory.createMethod(type, proto, name);
- addProvider(
- new StatifyingMethodGenerator(
- method, BackportedMethods::StringMethods_strip, "strip", type));
-
- // String String.stripLeading()
- name = factory.createString("stripLeading");
- proto = factory.createProto(factory.stringType);
- method = factory.createMethod(type, proto, name);
- addProvider(
- new StatifyingMethodGenerator(
- method, BackportedMethods::StringMethods_stripLeading, "stripLeading", type));
-
- // String String.stripTrailing()
- name = factory.createString("stripTrailing");
- proto = factory.createProto(factory.stringType);
- method = factory.createMethod(type, proto, name);
- addProvider(
- new StatifyingMethodGenerator(
- method, BackportedMethods::StringMethods_stripTrailing, "stripTrailing", type));
}
private void initializeStreamMethodProviders(DexItemFactory factory) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
index ccd00a9..1b2332b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
@@ -2597,6 +2597,53 @@
ImmutableList.of());
}
+ public static CfCode IntegerMethods_parseUnsignedIntSubsequenceWithRadix(
+ InternalOptions options, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 3,
+ 4,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfLoad(ValueType.INT, 1),
+ new CfLoad(ValueType.INT, 2),
+ new CfInvoke(
+ 185,
+ options.itemFactory.createMethod(
+ options.itemFactory.charSequenceType,
+ options.itemFactory.createProto(
+ options.itemFactory.charSequenceType,
+ options.itemFactory.intType,
+ options.itemFactory.intType),
+ options.itemFactory.createString("subSequence")),
+ true),
+ new CfInvoke(
+ 185,
+ options.itemFactory.createMethod(
+ options.itemFactory.charSequenceType,
+ options.itemFactory.createProto(options.itemFactory.stringType),
+ options.itemFactory.createString("toString")),
+ true),
+ new CfLoad(ValueType.INT, 3),
+ new CfInvoke(
+ 184,
+ options.itemFactory.createMethod(
+ options.itemFactory.createType("Ljava/lang/Integer;"),
+ options.itemFactory.createProto(
+ options.itemFactory.intType,
+ options.itemFactory.stringType,
+ options.itemFactory.intType),
+ options.itemFactory.createString("parseUnsignedInt")),
+ false),
+ new CfReturn(ValueType.INT),
+ label1),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
public static CfCode IntegerMethods_parseUnsignedIntWithRadix(
InternalOptions options, DexMethod method) {
CfLabel label0 = new CfLabel();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAmender.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAmender.java
new file mode 100644
index 0000000..bd146e9
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAmender.java
@@ -0,0 +1,68 @@
+// 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;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.MethodAccessFlags;
+import java.util.Map;
+
+/**
+ * The LibraryAmender is responsible in amending the library so that desugared library can be
+ * applied. For example, it can insert missing methods which are not present in the library but are
+ * supported in desugared library.
+ */
+public class DesugaredLibraryAmender {
+
+ private final AppView<?> appView;
+
+ public static void run(AppView<?> appView) {
+ run(appView, appView.options().machineDesugaredLibrarySpecification.getAmendLibraryMethods());
+ }
+
+ public static void run(AppView<?> appView, Map<DexMethod, MethodAccessFlags> amendLibrary) {
+ if (amendLibrary.isEmpty()) {
+ return;
+ }
+ new DesugaredLibraryAmender(appView).run(amendLibrary);
+ }
+
+ private DesugaredLibraryAmender(AppView<?> appView) {
+ this.appView = appView;
+ }
+
+ private void run(Map<DexMethod, MethodAccessFlags> amendLibrary) {
+ amendLibrary.forEach(this::amendLibraryMethod);
+ }
+
+ private void amendLibraryMethod(DexMethod method, MethodAccessFlags methodAccessFlags) {
+ DexClass dexClass = appView.contextIndependentDefinitionFor(method.getHolderType());
+ if (dexClass == null || !dexClass.isLibraryClass()) {
+ // Consider just throwing an error.
+ appView
+ .options()
+ .reporter
+ .warning(
+ "Desugared library: Cannot amend library method "
+ + method
+ + " because the holder is not a library class"
+ + (dexClass == null ? "(null)." : "."));
+ return;
+ }
+ if (dexClass.lookupMethod(method) != null) {
+ return;
+ }
+ DexEncodedMethod encodedMethod =
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(method)
+ .setAccessFlags(methodAccessFlags)
+ .setCode(null)
+ .setApiLevelForDefinition(appView.computedMinApiLevel())
+ .build();
+ dexClass.getMethodCollection().addMethod(encodedMethod);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecification.java
new file mode 100644
index 0000000..f96e5cd
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecification.java
@@ -0,0 +1,58 @@
+// 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;
+
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.InternalOptions;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+
+public interface DesugaredLibrarySpecification {
+
+ default boolean isHuman() {
+ return false;
+ }
+
+ default boolean isLegacy() {
+ return false;
+ }
+
+ default LegacyDesugaredLibrarySpecification asLegacyDesugaredLibrarySpecification() {
+ return null;
+ }
+
+ default HumanDesugaredLibrarySpecification asHumanDesugaredLibrarySpecification() {
+ return null;
+ }
+
+ boolean isEmpty();
+
+ boolean isLibraryCompilation();
+
+ String getJsonSource();
+
+ String getSynthesizedLibraryClassesPackagePrefix();
+
+ List<String> getExtraKeepRules();
+
+ AndroidApiLevel getRequiredCompilationApiLevel();
+
+ MachineDesugaredLibrarySpecification toMachineSpecification(
+ InternalOptions options, AndroidApp app) throws IOException;
+
+ MachineDesugaredLibrarySpecification toMachineSpecification(
+ InternalOptions options, Path library, Path desugaredJDKLib) throws IOException;
+
+ default MachineDesugaredLibrarySpecification toMachineSpecification(
+ InternalOptions options, Path library) throws IOException {
+ assert !isLibraryCompilation();
+ return toMachineSpecification(options, library, null);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecificationParser.java
new file mode 100644
index 0000000..83ee3ec
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecificationParser.java
@@ -0,0 +1,94 @@
+// 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;
+
+import com.android.tools.r8.StringResource;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.ExceptionDiagnostic;
+import com.android.tools.r8.utils.Reporter;
+import com.android.tools.r8.utils.StringDiagnostic;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import java.util.function.Consumer;
+
+public class DesugaredLibrarySpecificationParser {
+
+ public static final String CONFIGURATION_FORMAT_VERSION_KEY = "configuration_format_version";
+ private static final int MIN_HUMAN_CONFIGURATION_FORMAT_VERSION = 100;
+
+ public static DesugaredLibrarySpecification parseDesugaredLibrarySpecification(
+ StringResource stringResource,
+ DexItemFactory dexItemFactory,
+ Reporter reporter,
+ boolean libraryCompilation,
+ int minAPILevel) {
+ Origin origin = stringResource.getOrigin();
+ assert origin != null;
+ String jsonConfigString;
+ JsonObject jsonConfig;
+ try {
+ jsonConfigString = stringResource.getString();
+ JsonParser parser = new JsonParser();
+ jsonConfig = parser.parse(jsonConfigString).getAsJsonObject();
+ } catch (Exception e) {
+ throw reporter.fatalError(new ExceptionDiagnostic(e, origin));
+ }
+
+ if (isHumanSpecification(jsonConfig, reporter, origin)) {
+ return new HumanDesugaredLibrarySpecificationParser(
+ dexItemFactory, reporter, libraryCompilation, minAPILevel)
+ .parse(origin, jsonConfigString, jsonConfig);
+ }
+ return new LegacyDesugaredLibrarySpecificationParser(
+ dexItemFactory, reporter, libraryCompilation, minAPILevel)
+ .parse(origin, jsonConfigString, jsonConfig);
+ }
+
+ public static DesugaredLibrarySpecification parseDesugaredLibrarySpecificationforTesting(
+ StringResource stringResource,
+ DexItemFactory dexItemFactory,
+ Reporter reporter,
+ boolean libraryCompilation,
+ int minAPILevel,
+ Consumer<TopLevelFlagsBuilder<?>> topLevelFlagsAmender) {
+ Origin origin = stringResource.getOrigin();
+ assert origin != null;
+ String jsonConfigString;
+ JsonObject jsonConfig;
+ try {
+ jsonConfigString = stringResource.getString();
+ JsonParser parser = new JsonParser();
+ jsonConfig = parser.parse(jsonConfigString).getAsJsonObject();
+ } catch (Exception e) {
+ throw reporter.fatalError(new ExceptionDiagnostic(e, origin));
+ }
+ if (isHumanSpecification(jsonConfig, reporter, origin)) {
+ return new HumanDesugaredLibrarySpecificationParser(
+ dexItemFactory, reporter, libraryCompilation, minAPILevel)
+ .parse(origin, jsonConfigString, jsonConfig, topLevelFlagsAmender);
+ }
+ return new LegacyDesugaredLibrarySpecificationParser(
+ dexItemFactory, reporter, libraryCompilation, minAPILevel)
+ .parse(origin, jsonConfigString, jsonConfig, topLevelFlagsAmender);
+ }
+
+ public static boolean isHumanSpecification(
+ JsonObject jsonConfig, Reporter reporter, Origin origin) {
+ if (!jsonConfig.has(CONFIGURATION_FORMAT_VERSION_KEY)) {
+ throw reporter.fatalError(
+ new StringDiagnostic(
+ "Invalid desugared library configuration. Expected required key '"
+ + CONFIGURATION_FORMAT_VERSION_KEY
+ + "'",
+ origin));
+ }
+
+ return jsonConfig.get(CONFIGURATION_FORMAT_VERSION_KEY).getAsInt()
+ >= MIN_HUMAN_CONFIGURATION_FORMAT_VERSION;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/TopLevelFlagsBuilder.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/TopLevelFlagsBuilder.java
new file mode 100644
index 0000000..e7c7bb5
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/TopLevelFlagsBuilder.java
@@ -0,0 +1,10 @@
+// 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;
+
+public interface TopLevelFlagsBuilder<T extends TopLevelFlagsBuilder<?>> {
+
+ T setSupportAllCallbacksFromLibrary(boolean supportAllCallbacksFromLibrary);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/AbstractMethodParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/AbstractMethodParser.java
new file mode 100644
index 0000000..d63efb6
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/AbstractMethodParser.java
@@ -0,0 +1,81 @@
+// 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.humanspecification;
+
+import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+
+/** Parse methods of the form: modifiers* returnType holder#name(arg0, ..., argN) */
+public abstract class AbstractMethodParser {
+
+ private static final String SEPARATORS = "\\s+|,\\s+|#|\\(|\\)";
+
+ private static final Map<String, Integer> modifiers =
+ ImmutableMap.<String, Integer>builder()
+ .put("public", Constants.ACC_PUBLIC)
+ .put("private", Constants.ACC_PRIVATE)
+ .put("protected", Constants.ACC_PROTECTED)
+ .put("final", Constants.ACC_FINAL)
+ .put("abstract", Constants.ACC_ABSTRACT)
+ .put("static", Constants.ACC_STATIC)
+ .build();
+
+ final DexItemFactory factory;
+
+ protected AbstractMethodParser(DexItemFactory factory) {
+ this.factory = factory;
+ }
+
+ // TODO(b/218755060): It would be nice to avoid the split regexp and use a nextToken()
+ // method instead, then add a TraversalContinuation.
+ public void parseMethod(String signature) {
+ String[] tokens = signature.split(SEPARATORS);
+ if (tokens.length < 3) {
+ throw new CompilationError("Desugared library: cannot parse method " + signature);
+ }
+ methodStart();
+ int first = parseModifiers(tokens);
+ returnType(stringTypeToDexType(tokens[first]));
+ holderType(stringTypeToDexType(tokens[first + 1]));
+ methodName(factory.createString(tokens[first + 1 + 1]));
+ for (int i = first + 3; i < tokens.length; i++) {
+ argType(stringTypeToDexType(tokens[i]));
+ }
+ methodEnd();
+ }
+
+ private DexType stringTypeToDexType(String stringType) {
+ return factory.createType(DescriptorUtils.javaTypeToDescriptor(stringType));
+ }
+
+ private int parseModifiers(String[] split) {
+ int index = 0;
+ while (modifiers.containsKey(split[index])) {
+ modifier(modifiers.get(split[index]));
+ index++;
+ }
+ return index;
+ }
+
+ protected abstract void methodStart();
+
+ protected abstract void methodEnd();
+
+ protected abstract void returnType(DexType type);
+
+ protected abstract void argType(DexType type);
+
+ protected abstract void modifier(int access);
+
+ protected abstract void holderType(DexType type);
+
+ protected abstract void methodName(DexString name);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java
index 1e871b3..157dcc6 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java
@@ -8,12 +8,19 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.HumanToMachineSpecificationConverter;
import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.InternalOptions;
+import java.io.IOException;
+import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Set;
-public class HumanDesugaredLibrarySpecification {
+public class HumanDesugaredLibrarySpecification implements DesugaredLibrarySpecification {
private final boolean libraryCompilation;
private final HumanTopLevelFlags topLevelFlags;
@@ -28,18 +35,36 @@
this.rewritingFlags = rewritingFlags;
}
+ @Override
+ public boolean isEmpty() {
+ return rewritingFlags.isEmpty();
+ }
+
+ @Override
+ public boolean isHuman() {
+ return true;
+ }
+
+ @Override
+ public HumanDesugaredLibrarySpecification asHumanDesugaredLibrarySpecification() {
+ return this;
+ }
+
public boolean supportAllCallbacksFromLibrary() {
return topLevelFlags.supportAllCallbacksFromLibrary();
}
+ @Override
public AndroidApiLevel getRequiredCompilationApiLevel() {
return topLevelFlags.getRequiredCompilationAPILevel();
}
+ @Override
public boolean isLibraryCompilation() {
return libraryCompilation;
}
+ @Override
public String getSynthesizedLibraryClassesPackagePrefix() {
return topLevelFlags.getSynthesizedLibraryClassesPackagePrefix();
}
@@ -65,12 +90,12 @@
}
public Map<DexType, DexType> getEmulateLibraryInterface() {
- return rewritingFlags.getEmulateLibraryInterface();
+ return rewritingFlags.getEmulatedInterfaces();
}
// If the method is retargeted, answers the retargeted method, else null.
public DexMethod retargetMethod(DexEncodedMethod method, AppView<?> appView) {
- Map<DexMethod, DexType> retargetCoreLibMember = rewritingFlags.getRetargetCoreLibMember();
+ Map<DexMethod, DexType> retargetCoreLibMember = rewritingFlags.getRetargetMethod();
DexType dexType = retargetCoreLibMember.get(method.getReference());
if (dexType != null) {
return appView
@@ -88,11 +113,11 @@
}
public Map<DexMethod, DexType> getRetargetCoreLibMember() {
- return rewritingFlags.getRetargetCoreLibMember();
+ return rewritingFlags.getRetargetMethod();
}
public Map<DexType, DexType> getBackportCoreLibraryMember() {
- return rewritingFlags.getBackportCoreLibraryMember();
+ return rewritingFlags.getLegacyBackport();
}
public Map<DexType, DexType> getCustomConversions() {
@@ -108,18 +133,38 @@
}
public Set<DexType> getDontRetargetLibMember() {
- return rewritingFlags.getDontRetargetLibMember();
+ return rewritingFlags.getDontRetarget();
}
+ @Override
public List<String> getExtraKeepRules() {
return topLevelFlags.getExtraKeepRules();
}
+ @Override
public String getJsonSource() {
return topLevelFlags.getJsonSource();
}
public boolean isEmptyConfiguration() {
- return false;
+ return rewritingFlags.isEmpty();
+ }
+
+ @Override
+ public MachineDesugaredLibrarySpecification toMachineSpecification(
+ InternalOptions options, AndroidApp app) throws IOException {
+ return new HumanToMachineSpecificationConverter()
+ .convert(
+ this,
+ isLibraryCompilation() ? app.getProgramResourceProviders() : null,
+ app.getLibraryResourceProviders(),
+ options);
+ }
+
+ @Override
+ public MachineDesugaredLibrarySpecification toMachineSpecification(
+ InternalOptions options, Path library, Path desugaredJDKLib) throws IOException {
+ return new HumanToMachineSpecificationConverter()
+ .convert(this, isLibraryCompilation() ? desugaredJDKLib : null, library, options);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
index e01def6..bb4bc68 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
@@ -4,10 +4,17 @@
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.DesugaredLibrarySpecificationParser.isHumanSpecification;
+
import com.android.tools.r8.StringResource;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.TopLevelFlagsBuilder;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.ExceptionDiagnostic;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
@@ -18,10 +25,13 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.function.Consumer;
public class HumanDesugaredLibrarySpecificationParser {
+ public static final int CURRENT_HUMAN_CONFIGURATION_FORMAT_VERSION = 100;
+
static final String IDENTIFIER_KEY = "identifier";
static final String REQUIRED_COMPILATION_API_LEVEL_KEY = "required_compilation_api_level";
static final String SYNTHESIZED_LIBRARY_CLASSES_PACKAGE_PREFIX_KEY =
@@ -35,15 +45,18 @@
static final String WRAPPER_CONVERSION_KEY = "wrapper_conversion";
static final String CUSTOM_CONVERSION_KEY = "custom_conversion";
static final String REWRITE_PREFIX_KEY = "rewrite_prefix";
- static final String RETARGET_LIB_MEMBER_KEY = "retarget_lib_member";
+ static final String RETARGET_METHOD_KEY = "retarget_method";
+ static final String REWRITE_DERIVED_PREFIX_KEY = "rewrite_derived_prefix";
static final String EMULATE_INTERFACE_KEY = "emulate_interface";
static final String DONT_REWRITE_KEY = "dont_rewrite";
- static final String DONT_RETARGET_LIB_MEMBER_KEY = "dont_retarget_lib_member";
+ static final String DONT_RETARGET_KEY = "dont_retarget";
static final String BACKPORT_KEY = "backport";
+ static final String AMEND_LIBRARY_METHOD_KEY = "amend_library_method";
static final String SHRINKER_CONFIG_KEY = "shrinker_config";
static final String SUPPORT_ALL_CALLBACKS_FROM_LIBRARY_KEY = "support_all_callbacks_from_library";
private final DexItemFactory dexItemFactory;
+ private final HumanMethodParser methodParser;
private final Reporter reporter;
private final boolean libraryCompilation;
private final int minAPILevel;
@@ -57,6 +70,7 @@
boolean libraryCompilation,
int minAPILevel) {
this.dexItemFactory = dexItemFactory;
+ this.methodParser = new HumanMethodParser(dexItemFactory);
this.reporter = reporter;
this.minAPILevel = minAPILevel;
this.libraryCompilation = libraryCompilation;
@@ -90,13 +104,26 @@
}
public HumanDesugaredLibrarySpecification parse(StringResource stringResource) {
- return parse(stringResource, builder -> {});
+ String jsonConfigString = parseJson(stringResource);
+ return parse(origin, jsonConfigString, jsonConfig, ignored -> {});
}
public HumanDesugaredLibrarySpecification parse(
- StringResource stringResource, Consumer<HumanTopLevelFlags.Builder> topLevelFlagAmender) {
- String jsonConfigString = parseJson(stringResource);
+ Origin origin, String jsonConfigString, JsonObject jsonConfig) {
+ return parse(origin, jsonConfigString, jsonConfig, ignored -> {});
+ }
+ public HumanDesugaredLibrarySpecification parse(
+ Origin origin,
+ String jsonConfigString,
+ JsonObject jsonConfig,
+ Consumer<TopLevelFlagsBuilder<?>> topLevelFlagAmender) {
+ if (!isHumanSpecification(jsonConfig, reporter, origin)) {
+ reporter.error(
+ "Attempt to parse a non desugared library human specification as a human specification.");
+ }
+ this.origin = origin;
+ this.jsonConfig = jsonConfig;
HumanTopLevelFlags topLevelFlags = parseTopLevelFlags(jsonConfigString, topLevelFlagAmender);
HumanRewritingFlags legacyRewritingFlags = parseRewritingFlags();
@@ -104,7 +131,7 @@
HumanDesugaredLibrarySpecification config =
new HumanDesugaredLibrarySpecification(
topLevelFlags, legacyRewritingFlags, libraryCompilation);
- origin = null;
+ this.origin = null;
return config;
}
@@ -127,8 +154,7 @@
}
private HumanRewritingFlags parseRewritingFlags() {
- HumanRewritingFlags.Builder builder =
- HumanRewritingFlags.builder(dexItemFactory, reporter, origin);
+ HumanRewritingFlags.Builder builder = HumanRewritingFlags.builder(reporter, origin);
JsonElement commonFlags = required(jsonConfig, COMMON_FLAGS_KEY);
JsonElement libraryFlags = required(jsonConfig, LIBRARY_FLAGS_KEY);
JsonElement programFlags = required(jsonConfig, PROGRAM_FLAGS_KEY);
@@ -140,11 +166,22 @@
}
HumanTopLevelFlags parseTopLevelFlags(
- String jsonConfigString, Consumer<HumanTopLevelFlags.Builder> topLevelFlagAmender) {
+ String jsonConfigString, Consumer<TopLevelFlagsBuilder<?>> topLevelFlagAmender) {
HumanTopLevelFlags.Builder builder = HumanTopLevelFlags.builder();
builder.setJsonSource(jsonConfigString);
+ JsonElement formatVersionElement = required(jsonConfig, CONFIGURATION_FORMAT_VERSION_KEY);
+ int formatVersion = formatVersionElement.getAsInt();
+ if (formatVersion != CURRENT_HUMAN_CONFIGURATION_FORMAT_VERSION) {
+ reporter.warning(
+ new StringDiagnostic(
+ "Human desugared library specification version mismatches the parser "
+ + "expected version. This is allowed and should happen only while extending "
+ + "the specifications.",
+ origin));
+ }
+
String identifier = required(jsonConfig, IDENTIFIER_KEY).getAsString();
builder.setDesugaredLibraryIdentifier(identifier);
builder.setSynthesizedLibraryClassesPackagePrefix(
@@ -191,46 +228,80 @@
builder.putRewritePrefix(rewritePrefix.getKey(), rewritePrefix.getValue().getAsString());
}
}
- if (jsonFlagSet.has(RETARGET_LIB_MEMBER_KEY)) {
+ if (jsonFlagSet.has(REWRITE_DERIVED_PREFIX_KEY)) {
+ for (Map.Entry<String, JsonElement> prefixToMatch :
+ jsonFlagSet.get(REWRITE_DERIVED_PREFIX_KEY).getAsJsonObject().entrySet()) {
+ for (Entry<String, JsonElement> rewriteRule :
+ prefixToMatch.getValue().getAsJsonObject().entrySet()) {
+ builder.putRewriteDerivedPrefix(
+ prefixToMatch.getKey(), rewriteRule.getKey(), rewriteRule.getValue().getAsString());
+ }
+ }
+ }
+ if (jsonFlagSet.has(RETARGET_METHOD_KEY)) {
for (Map.Entry<String, JsonElement> retarget :
- jsonFlagSet.get(RETARGET_LIB_MEMBER_KEY).getAsJsonObject().entrySet()) {
- builder.putRetargetCoreLibMember(retarget.getKey(), retarget.getValue().getAsString());
+ jsonFlagSet.get(RETARGET_METHOD_KEY).getAsJsonObject().entrySet()) {
+ builder.retargetMethod(
+ parseMethod(retarget.getKey()),
+ stringDescriptorToDexType(retarget.getValue().getAsString()));
}
}
if (jsonFlagSet.has(BACKPORT_KEY)) {
for (Map.Entry<String, JsonElement> backport :
jsonFlagSet.get(BACKPORT_KEY).getAsJsonObject().entrySet()) {
- builder.putBackportCoreLibraryMember(backport.getKey(), backport.getValue().getAsString());
+ builder.putLegacyBackport(
+ stringDescriptorToDexType(backport.getKey()),
+ stringDescriptorToDexType(backport.getValue().getAsString()));
}
}
if (jsonFlagSet.has(EMULATE_INTERFACE_KEY)) {
for (Map.Entry<String, JsonElement> itf :
jsonFlagSet.get(EMULATE_INTERFACE_KEY).getAsJsonObject().entrySet()) {
- builder.putEmulateLibraryInterface(itf.getKey(), itf.getValue().getAsString());
+ builder.putEmulatedInterface(
+ stringDescriptorToDexType(itf.getKey()),
+ stringDescriptorToDexType(itf.getValue().getAsString()));
}
}
if (jsonFlagSet.has(CUSTOM_CONVERSION_KEY)) {
for (Map.Entry<String, JsonElement> conversion :
jsonFlagSet.get(CUSTOM_CONVERSION_KEY).getAsJsonObject().entrySet()) {
- builder.putCustomConversion(conversion.getKey(), conversion.getValue().getAsString());
+ builder.putCustomConversion(
+ stringDescriptorToDexType(conversion.getKey()),
+ stringDescriptorToDexType(conversion.getValue().getAsString()));
}
}
if (jsonFlagSet.has(WRAPPER_CONVERSION_KEY)) {
for (JsonElement wrapper : jsonFlagSet.get(WRAPPER_CONVERSION_KEY).getAsJsonArray()) {
- builder.addWrapperConversion(wrapper.getAsString());
+ builder.addWrapperConversion(stringDescriptorToDexType(wrapper.getAsString()));
}
}
if (jsonFlagSet.has(DONT_REWRITE_KEY)) {
JsonArray dontRewrite = jsonFlagSet.get(DONT_REWRITE_KEY).getAsJsonArray();
for (JsonElement rewrite : dontRewrite) {
- builder.addDontRewriteInvocation(rewrite.getAsString());
+ builder.addDontRewriteInvocation(parseMethod(rewrite.getAsString()));
}
}
- if (jsonFlagSet.has(DONT_RETARGET_LIB_MEMBER_KEY)) {
- JsonArray dontRetarget = jsonFlagSet.get(DONT_RETARGET_LIB_MEMBER_KEY).getAsJsonArray();
+ if (jsonFlagSet.has(DONT_RETARGET_KEY)) {
+ JsonArray dontRetarget = jsonFlagSet.get(DONT_RETARGET_KEY).getAsJsonArray();
for (JsonElement rewrite : dontRetarget) {
- builder.addDontRetargetLibMember(rewrite.getAsString());
+ builder.addDontRetargetLibMember(stringDescriptorToDexType(rewrite.getAsString()));
}
}
+ if (jsonFlagSet.has(AMEND_LIBRARY_METHOD_KEY)) {
+ JsonArray amendLibraryMember = jsonFlagSet.get(AMEND_LIBRARY_METHOD_KEY).getAsJsonArray();
+ for (JsonElement amend : amendLibraryMember) {
+ methodParser.parseMethod(amend.getAsString());
+ builder.amendLibraryMethod(methodParser.getMethod(), methodParser.getFlags());
+ }
+ }
+ }
+
+ private DexMethod parseMethod(String signature) {
+ methodParser.parseMethod(signature);
+ return methodParser.getMethod();
+ }
+
+ private DexType stringDescriptorToDexType(String stringClass) {
+ return dexItemFactory.createType(DescriptorUtils.javaTypeToDescriptor(stringClass));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanMethodParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanMethodParser.java
new file mode 100644
index 0000000..b4bac60
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanMethodParser.java
@@ -0,0 +1,93 @@
+// 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.humanspecification;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.MethodAccessFlags;
+import java.util.ArrayList;
+import java.util.List;
+
+public class HumanMethodParser extends AbstractMethodParser {
+
+ // Values accumulated while parsing.
+ private MethodAccessFlags.Builder flagBuilder;
+ private DexType returnType;
+ private DexType holder;
+ private DexString methodName;
+ private List<DexType> argTypes;
+ // Resulting values.
+ private DexMethod method;
+ private MethodAccessFlags flags;
+
+ protected HumanMethodParser(DexItemFactory factory) {
+ super(factory);
+ }
+
+ private boolean parsingFinished() {
+ return method != null;
+ }
+
+ public DexMethod getMethod() {
+ assert parsingFinished();
+ return method;
+ }
+
+ public MethodAccessFlags getFlags() {
+ assert parsingFinished();
+ return flags;
+ }
+
+ @Override
+ protected void modifier(int access) {
+ assert !parsingFinished();
+ flagBuilder.set(access);
+ }
+
+ @Override
+ protected void holderType(DexType type) {
+ assert !parsingFinished();
+ holder = type;
+ }
+
+ @Override
+ protected void methodName(DexString name) {
+ assert !parsingFinished();
+ methodName = name;
+ }
+
+ @Override
+ protected void methodStart() {
+ flagBuilder = MethodAccessFlags.builder();
+ returnType = null;
+ holder = null;
+ methodName = null;
+ argTypes = new ArrayList<>();
+ method = null;
+ flags = null;
+ }
+
+ @Override
+ protected void methodEnd() {
+ DexProto proto = factory.createProto(returnType, argTypes);
+ method = factory.createMethod(holder, proto, methodName);
+ flags = flagBuilder.build();
+ }
+
+ @Override
+ protected void returnType(DexType type) {
+ assert !parsingFinished();
+ returnType = type;
+ }
+
+ @Override
+ protected void argType(DexType type) {
+ assert !parsingFinished();
+ argTypes.add(type);
+ }
+}
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 bf87cd8..ece6fe0 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
@@ -4,14 +4,10 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification;
-import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.DescriptorUtils;
-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.ImmutableMap;
@@ -27,31 +23,37 @@
public class HumanRewritingFlags {
private final Map<String, String> rewritePrefix;
- private final Map<DexType, DexType> emulateLibraryInterface;
- private final Map<DexMethod, DexType> retargetCoreLibMember;
- private final Map<DexType, DexType> backportCoreLibraryMember;
+ private final Map<String, Map<String, String>> rewriteDerivedPrefix;
+ private final Map<DexType, DexType> emulatedInterfaces;
+ private final Map<DexMethod, DexType> retargetMethod;
+ private final Map<DexType, DexType> legacyBackport;
private final Map<DexType, DexType> customConversions;
private final Set<DexMethod> dontRewriteInvocation;
- private final Set<DexType> dontRetargetLibMember;
+ private final Set<DexType> dontRetarget;
private final Set<DexType> wrapperConversions;
+ private final Map<DexMethod, MethodAccessFlags> amendLibraryMethod;
HumanRewritingFlags(
Map<String, String> rewritePrefix,
+ Map<String, Map<String, String>> rewriteDerivedPrefix,
Map<DexType, DexType> emulateLibraryInterface,
- Map<DexMethod, DexType> retargetCoreLibMember,
- Map<DexType, DexType> backportCoreLibraryMember,
- Map<DexType, DexType> customConversions,
+ Map<DexMethod, DexType> retargetMethod,
+ Map<DexType, DexType> legacyBackport,
+ Map<DexType, DexType> customConversion,
Set<DexMethod> dontRewriteInvocation,
- Set<DexType> dontRetargetLibMember,
- Set<DexType> wrapperConversions) {
+ Set<DexType> dontRetarget,
+ Set<DexType> wrapperConversion,
+ Map<DexMethod, MethodAccessFlags> amendLibraryMethod) {
this.rewritePrefix = rewritePrefix;
- this.emulateLibraryInterface = emulateLibraryInterface;
- this.retargetCoreLibMember = retargetCoreLibMember;
- this.backportCoreLibraryMember = backportCoreLibraryMember;
- this.customConversions = customConversions;
+ this.rewriteDerivedPrefix = rewriteDerivedPrefix;
+ this.emulatedInterfaces = emulateLibraryInterface;
+ this.retargetMethod = retargetMethod;
+ this.legacyBackport = legacyBackport;
+ this.customConversions = customConversion;
this.dontRewriteInvocation = dontRewriteInvocation;
- this.dontRetargetLibMember = dontRetargetLibMember;
- this.wrapperConversions = wrapperConversions;
+ this.dontRetarget = dontRetarget;
+ this.wrapperConversions = wrapperConversion;
+ this.amendLibraryMethod = amendLibraryMethod;
}
public static HumanRewritingFlags empty() {
@@ -61,51 +63,51 @@
ImmutableMap.of(),
ImmutableMap.of(),
ImmutableMap.of(),
+ ImmutableMap.of(),
ImmutableSet.of(),
ImmutableSet.of(),
- ImmutableSet.of());
+ ImmutableSet.of(),
+ ImmutableMap.of());
}
- public static HumanRewritingFlags withOnlyRewritePrefixForTesting(
- Map<String, String> prefix, InternalOptions options) {
- Builder builder = builder(options.dexItemFactory(), options.reporter, Origin.unknown());
- prefix.forEach(builder::putRewritePrefix);
- return builder.build();
+ public static Builder builder(Reporter reporter, Origin origin) {
+ return new Builder(reporter, origin);
}
- public static Builder builder(DexItemFactory dexItemFactory, Reporter reporter, Origin origin) {
- return new Builder(dexItemFactory, reporter, origin);
- }
-
- public Builder newBuilder(DexItemFactory dexItemFactory, Reporter reporter, Origin origin) {
+ public Builder newBuilder(Reporter reporter, Origin origin) {
return new Builder(
- dexItemFactory,
reporter,
origin,
rewritePrefix,
- emulateLibraryInterface,
- retargetCoreLibMember,
- backportCoreLibraryMember,
+ rewriteDerivedPrefix,
+ emulatedInterfaces,
+ retargetMethod,
+ legacyBackport,
customConversions,
dontRewriteInvocation,
- dontRetargetLibMember,
- wrapperConversions);
+ dontRetarget,
+ wrapperConversions,
+ amendLibraryMethod);
}
public Map<String, String> getRewritePrefix() {
return rewritePrefix;
}
- public Map<DexType, DexType> getEmulateLibraryInterface() {
- return emulateLibraryInterface;
+ public Map<String, Map<String, String>> getRewriteDerivedPrefix() {
+ return rewriteDerivedPrefix;
}
- public Map<DexMethod, DexType> getRetargetCoreLibMember() {
- return retargetCoreLibMember;
+ public Map<DexType, DexType> getEmulatedInterfaces() {
+ return emulatedInterfaces;
}
- public Map<DexType, DexType> getBackportCoreLibraryMember() {
- return backportCoreLibraryMember;
+ public Map<DexMethod, DexType> getRetargetMethod() {
+ return retargetMethod;
+ }
+
+ public Map<DexType, DexType> getLegacyBackport() {
+ return legacyBackport;
}
public Map<DexType, DexType> getCustomConversions() {
@@ -116,72 +118,85 @@
return dontRewriteInvocation;
}
- public Set<DexType> getDontRetargetLibMember() {
- return dontRetargetLibMember;
+ public Set<DexType> getDontRetarget() {
+ return dontRetarget;
}
public Set<DexType> getWrapperConversions() {
return wrapperConversions;
}
+ public Map<DexMethod, MethodAccessFlags> getAmendLibraryMethod() {
+ return amendLibraryMethod;
+ }
+
+ public boolean isEmpty() {
+ return rewritePrefix.isEmpty()
+ && rewriteDerivedPrefix.isEmpty()
+ && emulatedInterfaces.isEmpty()
+ && retargetMethod.isEmpty();
+ }
+
public static class Builder {
- private static final String SEPARATORS = "\\s+|,\\s+|#|\\(|\\)";
-
- private final DexItemFactory factory;
private final Reporter reporter;
private final Origin origin;
private final Map<String, String> rewritePrefix;
- private final Map<DexType, DexType> emulateLibraryInterface;
- private final Map<DexMethod, DexType> retargetCoreLibMember;
- private final Map<DexType, DexType> backportCoreLibraryMember;
+ private final Map<String, Map<String, String>> rewriteDerivedPrefix;
+ private final Map<DexType, DexType> emulatedInterfaces;
+ private final Map<DexMethod, DexType> retargetMethod;
+ private final Map<DexType, DexType> legacyBackport;
private final Map<DexType, DexType> customConversions;
private final Set<DexMethod> dontRewriteInvocation;
- private final Set<DexType> dontRetargetLibMember;
+ private final Set<DexType> dontRetarget;
private final Set<DexType> wrapperConversions;
+ private final Map<DexMethod, MethodAccessFlags> amendLibraryMethod;
- Builder(DexItemFactory factory, Reporter reporter, Origin origin) {
+ Builder(Reporter reporter, Origin origin) {
this(
- factory,
reporter,
origin,
new HashMap<>(),
+ new HashMap<>(),
new IdentityHashMap<>(),
new IdentityHashMap<>(),
new IdentityHashMap<>(),
new IdentityHashMap<>(),
Sets.newIdentityHashSet(),
Sets.newIdentityHashSet(),
- Sets.newIdentityHashSet());
+ Sets.newIdentityHashSet(),
+ new IdentityHashMap<>());
}
Builder(
- DexItemFactory factory,
Reporter reporter,
Origin origin,
Map<String, String> rewritePrefix,
+ Map<String, Map<String, String>> rewriteDerivedPrefix,
Map<DexType, DexType> emulateLibraryInterface,
Map<DexMethod, DexType> retargetCoreLibMember,
Map<DexType, DexType> backportCoreLibraryMember,
Map<DexType, DexType> customConversions,
Set<DexMethod> dontRewriteInvocation,
Set<DexType> dontRetargetLibMember,
- Set<DexType> wrapperConversions) {
- this.factory = factory;
+ Set<DexType> wrapperConversions,
+ Map<DexMethod, MethodAccessFlags> amendLibrary) {
this.reporter = reporter;
this.origin = origin;
this.rewritePrefix = new HashMap<>(rewritePrefix);
- this.emulateLibraryInterface = new IdentityHashMap<>(emulateLibraryInterface);
- this.retargetCoreLibMember = new IdentityHashMap<>(retargetCoreLibMember);
- this.backportCoreLibraryMember = new IdentityHashMap<>(backportCoreLibraryMember);
+ this.rewriteDerivedPrefix = new HashMap<>(rewriteDerivedPrefix);
+ this.emulatedInterfaces = new IdentityHashMap<>(emulateLibraryInterface);
+ this.retargetMethod = new IdentityHashMap<>(retargetCoreLibMember);
+ this.legacyBackport = new IdentityHashMap<>(backportCoreLibraryMember);
this.customConversions = new IdentityHashMap<>(customConversions);
this.dontRewriteInvocation = Sets.newIdentityHashSet();
this.dontRewriteInvocation.addAll(dontRewriteInvocation);
- this.dontRetargetLibMember = Sets.newIdentityHashSet();
- this.dontRetargetLibMember.addAll(dontRetargetLibMember);
+ this.dontRetarget = Sets.newIdentityHashSet();
+ this.dontRetarget.addAll(dontRetargetLibMember);
this.wrapperConversions = Sets.newIdentityHashSet();
this.wrapperConversions.addAll(wrapperConversions);
+ this.amendLibraryMethod = new IdentityHashMap<>(amendLibrary);
}
// Utility to set values.
@@ -209,30 +224,27 @@
return this;
}
- public Builder putEmulateLibraryInterface(
- String emulateLibraryItf, String rewrittenEmulateLibraryItf) {
- DexType interfaceType = stringClassToDexType(emulateLibraryItf);
- DexType rewrittenType = stringClassToDexType(rewrittenEmulateLibraryItf);
- putEmulateLibraryInterface(interfaceType, rewrittenType);
+ public Builder putRewriteDerivedPrefix(
+ String prefixToMatch, String prefixToRewrite, String rewrittenPrefix) {
+ Map<String, String> map =
+ rewriteDerivedPrefix.computeIfAbsent(prefixToMatch, k -> new HashMap<>());
+ put(
+ map,
+ prefixToRewrite,
+ rewrittenPrefix,
+ HumanDesugaredLibrarySpecificationParser.REWRITE_DERIVED_PREFIX_KEY);
return this;
}
- public Builder putEmulateLibraryInterface(DexType interfaceType, DexType rewrittenType) {
+ public Builder putEmulatedInterface(DexType interfaceType, DexType rewrittenType) {
put(
- emulateLibraryInterface,
+ emulatedInterfaces,
interfaceType,
rewrittenType,
HumanDesugaredLibrarySpecificationParser.EMULATE_INTERFACE_KEY);
return this;
}
- public Builder putCustomConversion(String type, String conversionHolder) {
- DexType dexType = stringClassToDexType(type);
- DexType conversionType = stringClassToDexType(conversionHolder);
- putCustomConversion(dexType, conversionType);
- return this;
- }
-
public Builder putCustomConversion(DexType dexType, DexType conversionType) {
put(
customConversions,
@@ -242,100 +254,57 @@
return this;
}
- public Builder addWrapperConversion(String type) {
- DexType dexType = stringClassToDexType(type);
- addWrapperConversion(dexType);
- return this;
- }
-
public Builder addWrapperConversion(DexType dexType) {
wrapperConversions.add(dexType);
return this;
}
- public Builder putRetargetCoreLibMember(String retarget, String rewrittenRetarget) {
- DexMethod key = parseMethod(retarget);
- DexType rewrittenType = stringClassToDexType(rewrittenRetarget);
- putRetargetCoreLibMember(key, rewrittenType);
- return this;
- }
-
- public Builder putRetargetCoreLibMember(DexMethod key, DexType rewrittenType) {
+ public Builder retargetMethod(DexMethod key, DexType rewrittenType) {
put(
- retargetCoreLibMember,
+ retargetMethod,
key,
rewrittenType,
- HumanDesugaredLibrarySpecificationParser.RETARGET_LIB_MEMBER_KEY);
+ HumanDesugaredLibrarySpecificationParser.RETARGET_METHOD_KEY);
return this;
}
- public Builder putBackportCoreLibraryMember(String backport, String rewrittenBackport) {
- DexType backportType = stringClassToDexType(backport);
- DexType rewrittenBackportType = stringClassToDexType(rewrittenBackport);
- putBackportCoreLibraryMember(backportType, rewrittenBackportType);
- return this;
- }
-
- public Builder putBackportCoreLibraryMember(
- DexType backportType, DexType rewrittenBackportType) {
+ public Builder putLegacyBackport(DexType backportType, DexType rewrittenBackportType) {
put(
- backportCoreLibraryMember,
+ legacyBackport,
backportType,
rewrittenBackportType,
HumanDesugaredLibrarySpecificationParser.BACKPORT_KEY);
return this;
}
- public Builder addDontRewriteInvocation(String dontRewriteInvocation) {
- DexMethod dontRewrite = parseMethod(dontRewriteInvocation);
- addDontRewriteInvocation(dontRewrite);
- return this;
- }
-
public Builder addDontRewriteInvocation(DexMethod dontRewrite) {
- this.dontRewriteInvocation.add(dontRewrite);
- return this;
- }
-
- public Builder addDontRetargetLibMember(String dontRetargetLibMember) {
- addDontRetargetLibMember(stringClassToDexType(dontRetargetLibMember));
+ dontRewriteInvocation.add(dontRewrite);
return this;
}
public Builder addDontRetargetLibMember(DexType dontRetargetLibMember) {
- this.dontRetargetLibMember.add(dontRetargetLibMember);
+ dontRetarget.add(dontRetargetLibMember);
return this;
}
- private DexMethod parseMethod(String signature) {
- String[] split = signature.split(SEPARATORS);
- assert split.length >= 3;
- DexType returnType = factory.createType(DescriptorUtils.javaTypeToDescriptor(split[0]));
- DexType holderType = factory.createType(DescriptorUtils.javaTypeToDescriptor(split[1]));
- DexString name = factory.createString(split[2]);
- DexType[] argTypes = new DexType[split.length - 3];
- for (int i = 3; i < split.length; i++) {
- argTypes[i - 3] = factory.createType(DescriptorUtils.javaTypeToDescriptor(split[i]));
- }
- DexProto proto = factory.createProto(returnType, argTypes);
- return factory.createMethod(holderType, proto, name);
- }
-
- private DexType stringClassToDexType(String stringClass) {
- return factory.createType(DescriptorUtils.javaTypeToDescriptor(stringClass));
+ public Builder amendLibraryMethod(DexMethod member, MethodAccessFlags flags) {
+ amendLibraryMethod.put(member, flags);
+ return this;
}
public HumanRewritingFlags build() {
validate();
return new HumanRewritingFlags(
ImmutableMap.copyOf(rewritePrefix),
- ImmutableMap.copyOf(emulateLibraryInterface),
- ImmutableMap.copyOf(retargetCoreLibMember),
- ImmutableMap.copyOf(backportCoreLibraryMember),
+ ImmutableMap.copyOf(rewriteDerivedPrefix),
+ ImmutableMap.copyOf(emulatedInterfaces),
+ ImmutableMap.copyOf(retargetMethod),
+ ImmutableMap.copyOf(legacyBackport),
ImmutableMap.copyOf(customConversions),
ImmutableSet.copyOf(dontRewriteInvocation),
- ImmutableSet.copyOf(dontRetargetLibMember),
- ImmutableSet.copyOf(wrapperConversions));
+ ImmutableSet.copyOf(dontRetarget),
+ ImmutableSet.copyOf(wrapperConversions),
+ ImmutableMap.copyOf(amendLibraryMethod));
}
private void validate() {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanTopLevelFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanTopLevelFlags.java
index 80a13b5..409cf74 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanTopLevelFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanTopLevelFlags.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.TopLevelFlagsBuilder;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.google.common.collect.ImmutableList;
import java.util.List;
@@ -77,7 +78,7 @@
return extraKeepRules;
}
- public static class Builder {
+ public static class Builder implements TopLevelFlagsBuilder<Builder> {
private AndroidApiLevel requiredCompilationAPILevel;
private String synthesizedLibraryClassesPackagePrefix;
@@ -108,6 +109,7 @@
return this;
}
+ @Override
public Builder setSupportAllCallbacksFromLibrary(boolean supportAllCallbacksFromLibrary) {
this.supportAllCallbacksFromLibrary = supportAllCallbacksFromLibrary;
return this;
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
index c79fad3..afc7dd6 100644
--- 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
@@ -5,8 +5,9 @@
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.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.Reporter;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
@@ -20,7 +21,6 @@
public static void deduplicateFlags(
MultiAPILevelHumanDesugaredLibrarySpecification specification,
- DexItemFactory factory,
Reporter reporter) {
IntArraySet apis = new IntArraySet();
@@ -29,13 +29,12 @@
apis.addAll(specification.getProgramFlags().keySet());
for (Integer api : apis) {
- deduplicateFlags(specification, factory, reporter, api);
+ deduplicateFlags(specification, reporter, api);
}
}
private static void deduplicateFlags(
MultiAPILevelHumanDesugaredLibrarySpecification specification,
- DexItemFactory factory,
Reporter reporter,
int api) {
@@ -53,21 +52,29 @@
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);
+ ? HumanRewritingFlags.builder(reporter, origin)
+ : commonFlags.get(api).newBuilder(reporter, origin);
+ HumanRewritingFlags.Builder libraryBuilder = HumanRewritingFlags.builder(reporter, origin);
+ HumanRewritingFlags.Builder programBuilder = HumanRewritingFlags.builder(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());
+ putNewFlags(api, commonFlags, commonBuilder);
+ putNewFlags(api, libraryFlags, libraryBuilder);
+ putNewFlags(api, programFlags, programBuilder);
+ }
+
+ private static void putNewFlags(
+ int api, Int2ObjectMap<HumanRewritingFlags> flags, HumanRewritingFlags.Builder builder) {
+ HumanRewritingFlags build = builder.build();
+ if (build.isEmpty()) {
+ flags.remove(api);
+ } else {
+ flags.put(api, build);
+ }
}
private static void deduplicateFlags(
@@ -76,22 +83,23 @@
HumanRewritingFlags.Builder commonBuilder,
HumanRewritingFlags.Builder builder) {
deduplicateRewritePrefix(flags, otherFlags, commonBuilder, builder);
+ deduplicateRewriteDifferentPrefix(flags, otherFlags, commonBuilder, builder);
deduplicateFlags(
- flags.getEmulateLibraryInterface(),
- otherFlags.getEmulateLibraryInterface(),
- commonBuilder::putEmulateLibraryInterface,
- builder::putEmulateLibraryInterface);
+ flags.getEmulatedInterfaces(),
+ otherFlags.getEmulatedInterfaces(),
+ commonBuilder::putEmulatedInterface,
+ builder::putEmulatedInterface);
deduplicateFlags(
- flags.getRetargetCoreLibMember(),
- otherFlags.getRetargetCoreLibMember(),
- commonBuilder::putRetargetCoreLibMember,
- builder::putRetargetCoreLibMember);
+ flags.getRetargetMethod(),
+ otherFlags.getRetargetMethod(),
+ commonBuilder::retargetMethod,
+ builder::retargetMethod);
deduplicateFlags(
- flags.getBackportCoreLibraryMember(),
- otherFlags.getBackportCoreLibraryMember(),
- commonBuilder::putBackportCoreLibraryMember,
- builder::putBackportCoreLibraryMember);
+ flags.getLegacyBackport(),
+ otherFlags.getLegacyBackport(),
+ commonBuilder::putLegacyBackport,
+ builder::putLegacyBackport);
deduplicateFlags(
flags.getCustomConversions(),
otherFlags.getCustomConversions(),
@@ -104,8 +112,8 @@
commonBuilder::addDontRewriteInvocation,
builder::addDontRewriteInvocation);
deduplicateFlags(
- flags.getDontRetargetLibMember(),
- otherFlags.getDontRetargetLibMember(),
+ flags.getDontRetarget(),
+ otherFlags.getDontRetarget(),
commonBuilder::addDontRetargetLibMember,
builder::addDontRetargetLibMember);
deduplicateFlags(
@@ -113,6 +121,53 @@
otherFlags.getWrapperConversions(),
commonBuilder::addWrapperConversion,
builder::addWrapperConversion);
+
+ deduplicateAmendLibraryMemberFlags(flags, otherFlags, commonBuilder, builder);
+ }
+
+ private static void deduplicateAmendLibraryMemberFlags(
+ HumanRewritingFlags flags,
+ HumanRewritingFlags otherFlags,
+ HumanRewritingFlags.Builder commonBuilder,
+ HumanRewritingFlags.Builder builder) {
+ Map<DexMethod, MethodAccessFlags> other = otherFlags.getAmendLibraryMethod();
+ flags
+ .getAmendLibraryMethod()
+ .forEach(
+ (k, v) -> {
+ if (other.get(k) == v) {
+ commonBuilder.amendLibraryMethod(k, v);
+ } else {
+ builder.amendLibraryMethod(k, v);
+ }
+ });
+ }
+
+ private static void deduplicateRewriteDifferentPrefix(
+ HumanRewritingFlags flags,
+ HumanRewritingFlags otherFlags,
+ HumanRewritingFlags.Builder commonBuilder,
+ HumanRewritingFlags.Builder builder) {
+ flags
+ .getRewriteDerivedPrefix()
+ .forEach(
+ (prefixToMatch, rewriteRules) -> {
+ if (!otherFlags.getRewriteDerivedPrefix().containsKey(prefixToMatch)) {
+ rewriteRules.forEach(
+ (k, v) -> builder.putRewriteDerivedPrefix(prefixToMatch, k, v));
+ } else {
+ Map<String, String> otherMap =
+ otherFlags.getRewriteDerivedPrefix().get(prefixToMatch);
+ rewriteRules.forEach(
+ (k, v) -> {
+ if (otherMap.containsKey(k) && otherMap.get(k).equals(v)) {
+ commonBuilder.putRewriteDerivedPrefix(prefixToMatch, k, v);
+ } else {
+ builder.putRewriteDerivedPrefix(prefixToMatch, k, v);
+ }
+ });
+ }
+ });
}
private static void deduplicateRewritePrefix(
@@ -124,7 +179,7 @@
.getRewritePrefix()
.forEach(
(k, v) -> {
- if (otherFlags.getRewritePrefix().get(k) != null
+ if (otherFlags.getRewritePrefix().containsKey(k)
&& otherFlags.getRewritePrefix().get(k).equals(v)) {
commonBuilder.putRewritePrefix(k, v);
} else {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.java
index fd76244..97749d6 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.java
@@ -4,8 +4,27 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification;
-import static com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecificationParser.*;
+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;
@@ -13,10 +32,12 @@
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;
@@ -36,12 +57,13 @@
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());
+ humanSpec.getTopLevelFlags().getSynthesizedLibraryClassesPackagePrefix().replace('/', '.'));
toJson.put(
SUPPORT_ALL_CALLBACKS_FROM_LIBRARY_KEY,
humanSpec.getTopLevelFlags().supportAllCallbacksFromLibrary());
@@ -60,39 +82,58 @@
private List<Object> rewritingFlagsToString(
Int2ObjectMap<HumanRewritingFlags> rewritingFlagsMap) {
ArrayList<Object> list = new ArrayList<>();
- rewritingFlagsMap.forEach(
- (apiBelowOrEqual, flags) -> {
- 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.getEmulateLibraryInterface().isEmpty()) {
- toJson.put(EMULATE_INTERFACE_KEY, mapToString(flags.getEmulateLibraryInterface()));
- }
- if (!flags.getDontRewriteInvocation().isEmpty()) {
- toJson.put(DONT_REWRITE_KEY, setToString(flags.getDontRewriteInvocation()));
- }
- if (!flags.getRetargetCoreLibMember().isEmpty()) {
- toJson.put(RETARGET_LIB_MEMBER_KEY, mapToString(flags.getRetargetCoreLibMember()));
- }
- if (!flags.getDontRetargetLibMember().isEmpty()) {
- toJson.put(DONT_RETARGET_LIB_MEMBER_KEY, setToString(flags.getDontRetargetLibMember()));
- }
- if (!flags.getBackportCoreLibraryMember().isEmpty()) {
- toJson.put(BACKPORT_KEY, mapToString(flags.getBackportCoreLibraryMember()));
- }
- if (!flags.getWrapperConversions().isEmpty()) {
- toJson.put(WRAPPER_CONVERSION_KEY, setToString(flags.getWrapperConversions()));
- }
- if (!flags.getCustomConversions().isEmpty()) {
- toJson.put(CUSTOM_CONVERSION_KEY, mapToString(flags.getCustomConversions()));
- }
- list.add(toJson);
- });
+ 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)));
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationParser.java
index 140609d..9f9fa81 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/MultiAPILevelHumanDesugaredLibrarySpecificationParser.java
@@ -43,10 +43,8 @@
int api_level_below_or_equal = required(flag, API_LEVEL_BELOW_OR_EQUAL_KEY).getAsInt();
HumanRewritingFlags.Builder builder =
flags.containsKey(api_level_below_or_equal)
- ? flags
- .get(api_level_below_or_equal)
- .newBuilder(dexItemFactory(), reporter(), getOrigin())
- : HumanRewritingFlags.builder(dexItemFactory(), reporter(), getOrigin());
+ ? flags.get(api_level_below_or_equal).newBuilder(reporter(), getOrigin())
+ : HumanRewritingFlags.builder(reporter(), getOrigin());
parseFlags(flag, builder);
flags.put(api_level_below_or_equal, builder.build());
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java
index 9ab05b9..71227cf 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java
@@ -9,37 +9,28 @@
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.DesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.LegacyToHumanSpecificationConverter;
import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Pair;
+import java.io.IOException;
+import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Set;
-public class LegacyDesugaredLibrarySpecification {
+public class LegacyDesugaredLibrarySpecification implements DesugaredLibrarySpecification {
private final boolean libraryCompilation;
private final LegacyTopLevelFlags topLevelFlags;
private final LegacyRewritingFlags rewritingFlags;
- public static LegacyDesugaredLibrarySpecification withOnlyRewritePrefixForTesting(
- Map<String, String> prefix, InternalOptions options) {
- return new LegacyDesugaredLibrarySpecification(
- LegacyTopLevelFlags.empty(),
- LegacyRewritingFlags.withOnlyRewritePrefixForTesting(prefix, options),
- true);
- }
-
public static LegacyDesugaredLibrarySpecification empty() {
return new LegacyDesugaredLibrarySpecification(
- LegacyTopLevelFlags.empty(), LegacyRewritingFlags.empty(), false) {
-
- @Override
- public boolean isEmptyConfiguration() {
- return true;
- }
- };
+ LegacyTopLevelFlags.empty(), LegacyRewritingFlags.empty(), false);
}
public LegacyDesugaredLibrarySpecification(
@@ -51,6 +42,21 @@
this.rewritingFlags = rewritingFlags;
}
+ @Override
+ public boolean isEmpty() {
+ return rewritingFlags.isEmpty();
+ }
+
+ @Override
+ public boolean isLegacy() {
+ return true;
+ }
+
+ @Override
+ public LegacyDesugaredLibrarySpecification asLegacyDesugaredLibrarySpecification() {
+ return this;
+ }
+
public LegacyTopLevelFlags getTopLevelFlags() {
return topLevelFlags;
}
@@ -63,29 +69,21 @@
return topLevelFlags.supportAllCallbacksFromLibrary();
}
+ @Override
public AndroidApiLevel getRequiredCompilationApiLevel() {
return topLevelFlags.getRequiredCompilationAPILevel();
}
+ @Override
public boolean isLibraryCompilation() {
return libraryCompilation;
}
+ @Override
public String getSynthesizedLibraryClassesPackagePrefix() {
return topLevelFlags.getSynthesizedLibraryClassesPackagePrefix();
}
- // TODO(b/183918843): We are currently computing a new name for the class by replacing the
- // initial package prefix by the synthesized library class package prefix, it would be better
- // to make the rewriting explicit in the desugared library json file.
- public String convertJavaNameToDesugaredLibrary(DexType type) {
- String prefix =
- DescriptorUtils.getJavaTypeFromBinaryName(getSynthesizedLibraryClassesPackagePrefix());
- String interfaceType = type.toString();
- int firstPackage = interfaceType.indexOf('.');
- return prefix + interfaceType.substring(firstPackage + 1);
- }
-
public String getIdentifier() {
return topLevelFlags.getIdentifier();
}
@@ -146,15 +144,29 @@
return rewritingFlags.getDontRetargetLibMember();
}
+ @Override
public List<String> getExtraKeepRules() {
return topLevelFlags.getExtraKeepRules();
}
+ @Override
public String getJsonSource() {
return topLevelFlags.getJsonSource();
}
- public boolean isEmptyConfiguration() {
- return false;
+ @Override
+ public MachineDesugaredLibrarySpecification toMachineSpecification(
+ InternalOptions options, AndroidApp app) throws IOException {
+ return new LegacyToHumanSpecificationConverter()
+ .convert(this, app.getLibraryResourceProviders(), options)
+ .toMachineSpecification(options, app);
+ }
+
+ @Override
+ public MachineDesugaredLibrarySpecification toMachineSpecification(
+ InternalOptions options, Path library, Path desugaredJDKLib) throws IOException {
+ return new LegacyToHumanSpecificationConverter()
+ .convert(this, library, options)
+ .toMachineSpecification(options, library, desugaredJDKLib);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java
index a3afcd9..5b6933d 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecificationParser.java
@@ -4,8 +4,12 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser.CONFIGURATION_FORMAT_VERSION_KEY;
+import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser.isHumanSpecification;
+
import com.android.tools.r8.StringResource;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.TopLevelFlagsBuilder;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.ExceptionDiagnostic;
@@ -26,7 +30,6 @@
public static final int MAX_SUPPORTED_VERSION = 4;
public static final SemanticVersion MIN_SUPPORTED_VERSION = new SemanticVersion(1, 0, 9);
- static final String CONFIGURATION_FORMAT_VERSION_KEY = "configuration_format_version";
static final String VERSION_KEY = "version";
static final String GROUP_ID_KEY = "group_id";
static final String ARTIFACT_ID_KEY = "artifact_id";
@@ -97,13 +100,26 @@
}
public LegacyDesugaredLibrarySpecification parse(StringResource stringResource) {
- return parse(stringResource, builder -> {});
+ String jsonConfigString = parseJson(stringResource);
+ return parse(origin, jsonConfigString, jsonConfig, ignored -> {});
}
public LegacyDesugaredLibrarySpecification parse(
- StringResource stringResource, Consumer<LegacyTopLevelFlags.Builder> topLevelFlagAmender) {
- String jsonConfigString = parseJson(stringResource);
+ Origin origin, String jsonConfigString, JsonObject jsonConfig) {
+ return parse(origin, jsonConfigString, jsonConfig, ignored -> {});
+ }
+ public LegacyDesugaredLibrarySpecification parse(
+ Origin origin,
+ String jsonConfigString,
+ JsonObject jsonConfig,
+ Consumer<TopLevelFlagsBuilder<?>> topLevelFlagAmender) {
+ if (isHumanSpecification(jsonConfig, reporter, origin)) {
+ reporter.error(
+ "Attempt to parse a desugared library human specification as a legacy specification.");
+ }
+ this.origin = origin;
+ this.jsonConfig = jsonConfig;
LegacyTopLevelFlags topLevelFlags = parseTopLevelFlags(jsonConfigString, topLevelFlagAmender);
LegacyRewritingFlags legacyRewritingFlags = parseRewritingFlags();
@@ -111,7 +127,7 @@
LegacyDesugaredLibrarySpecification config =
new LegacyDesugaredLibrarySpecification(
topLevelFlags, legacyRewritingFlags, libraryCompilation);
- origin = null;
+ this.origin = null;
return config;
}
@@ -147,7 +163,7 @@
}
LegacyTopLevelFlags parseTopLevelFlags(
- String jsonConfigString, Consumer<LegacyTopLevelFlags.Builder> topLevelFlagAmender) {
+ String jsonConfigString, Consumer<TopLevelFlagsBuilder<?>> topLevelFlagAmender) {
LegacyTopLevelFlags.Builder builder = LegacyTopLevelFlags.builder();
builder.setJsonSource(jsonConfigString);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyRewritingFlags.java
index 61a2eb8..9a38ff1a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyRewritingFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyRewritingFlags.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
@@ -69,13 +68,6 @@
ImmutableSet.of());
}
- public static LegacyRewritingFlags withOnlyRewritePrefixForTesting(
- Map<String, String> prefix, InternalOptions options) {
- Builder builder = builder(options.dexItemFactory(), options.reporter, Origin.unknown());
- prefix.forEach(builder::putRewritePrefix);
- return builder.build();
- }
-
public static Builder builder(DexItemFactory dexItemFactory, Reporter reporter, Origin origin) {
return new Builder(dexItemFactory, reporter, origin);
}
@@ -127,6 +119,12 @@
return wrapperConversions;
}
+ public boolean isEmpty() {
+ return rewritePrefix.isEmpty()
+ && emulateLibraryInterface.isEmpty()
+ && retargetCoreLibMember.isEmpty();
+ }
+
public static class Builder {
private final DexItemFactory factory;
@@ -172,14 +170,16 @@
this.factory = factory;
this.reporter = reporter;
this.origin = origin;
- this.rewritePrefix = rewritePrefix;
- this.emulateLibraryInterface = emulateLibraryInterface;
- this.retargetCoreLibMember = retargetCoreLibMember;
- this.backportCoreLibraryMember = backportCoreLibraryMember;
- this.customConversions = customConversions;
- this.dontRewriteInvocation = dontRewriteInvocation;
- this.dontRetargetLibMember = dontRetargetLibMember;
- this.wrapperConversions = wrapperConversions;
+ this.rewritePrefix = new HashMap<>(rewritePrefix);
+ this.emulateLibraryInterface = new IdentityHashMap<>(emulateLibraryInterface);
+ this.retargetCoreLibMember = new IdentityHashMap<>(retargetCoreLibMember);
+ this.backportCoreLibraryMember = new IdentityHashMap<>(backportCoreLibraryMember);
+ this.customConversions = new IdentityHashMap<>(customConversions);
+ this.dontRewriteInvocation = new ArrayList<>(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.
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyTopLevelFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyTopLevelFlags.java
index 8e0293b..59a3733 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyTopLevelFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyTopLevelFlags.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.TopLevelFlagsBuilder;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.google.common.collect.ImmutableList;
import java.util.List;
@@ -90,7 +91,7 @@
return extraKeepRules;
}
- public static class Builder {
+ public static class Builder implements TopLevelFlagsBuilder<Builder> {
private AndroidApiLevel requiredCompilationAPILevel;
private String synthesizedLibraryClassesPackagePrefix =
@@ -122,6 +123,7 @@
return this;
}
+ @Override
public Builder setSupportAllCallbacksFromLibrary(boolean supportAllCallbacksFromLibrary) {
this.supportAllCallbacksFromLibrary = supportAllCallbacksFromLibrary;
return this;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
index adc507f..d578eed 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.utils.AndroidApiLevel;
import java.util.List;
import java.util.Map;
@@ -98,8 +99,8 @@
return rewritingFlags.getEmulatedVirtualRetargetThroughEmulatedInterface();
}
- public void forEachRetargetHolder(Consumer<DexType> consumer) {
- rewritingFlags.forEachRetargetHolder(consumer);
+ public void forEachRetargetMethod(Consumer<DexMethod> consumer) {
+ rewritingFlags.forEachRetargetMethod(consumer);
}
public Map<DexType, EmulatedInterfaceDescriptor> getEmulatedInterfaces() {
@@ -135,6 +136,10 @@
return rewritingFlags.getCustomConversions();
}
+ public Map<DexMethod, MethodAccessFlags> getAmendLibraryMethods() {
+ return rewritingFlags.getAmendLibraryMethod();
+ }
+
public boolean hasRetargeting() {
return rewritingFlags.hasRetargeting();
}
@@ -166,4 +171,8 @@
}
return false;
}
+
+ public AndroidApiLevel getRequiredCompilationApiLevel() {
+ return topLevelFlags.getRequiredCompilationAPILevel();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
index f34634d..00a4747 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
@@ -6,6 +6,7 @@
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.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -33,7 +34,8 @@
Map<DexType, List<DexMethod>> wrappers,
Map<DexType, DexType> legacyBackport,
Set<DexType> dontRetarget,
- Map<DexType, CustomConversionDescriptor> customConversions) {
+ Map<DexType, CustomConversionDescriptor> customConversions,
+ Map<DexMethod, MethodAccessFlags> amendLibraryMethods) {
this.rewriteType = rewriteType;
this.rewriteDerivedTypeOnly = rewriteDerivedTypeOnly;
this.staticRetarget = staticRetarget;
@@ -46,6 +48,7 @@
this.legacyBackport = legacyBackport;
this.dontRetarget = dontRetarget;
this.customConversions = customConversions;
+ this.amendLibraryMethod = amendLibraryMethods;
}
// Rewrites all the references to the keys as well as synthetic types derived from any key.
@@ -79,6 +82,7 @@
private final Map<DexType, DexType> legacyBackport;
private final Set<DexType> dontRetarget;
private final Map<DexType, CustomConversionDescriptor> customConversions;
+ private final Map<DexMethod, MethodAccessFlags> amendLibraryMethod;
public Map<DexType, DexType> getRewriteType() {
return rewriteType;
@@ -104,10 +108,10 @@
return emulatedVirtualRetargetThroughEmulatedInterface;
}
- public void forEachRetargetHolder(Consumer<DexType> consumer) {
- staticRetarget.keySet().forEach(m -> consumer.accept(m.getHolderType()));
- nonEmulatedVirtualRetarget.keySet().forEach(m -> consumer.accept(m.getHolderType()));
- emulatedVirtualRetarget.keySet().forEach(m -> consumer.accept(m.getHolderType()));
+ public void forEachRetargetMethod(Consumer<DexMethod> consumer) {
+ staticRetarget.keySet().forEach(consumer);
+ nonEmulatedVirtualRetarget.keySet().forEach(consumer);
+ emulatedVirtualRetarget.keySet().forEach(consumer);
}
public Map<DexType, EmulatedInterfaceDescriptor> getEmulatedInterfaces() {
@@ -138,6 +142,10 @@
return customConversions;
}
+ public Map<DexMethod, MethodAccessFlags> getAmendLibraryMethod() {
+ return amendLibraryMethod;
+ }
+
public boolean hasRetargeting() {
return !staticRetarget.isEmpty()
|| !nonEmulatedVirtualRetarget.isEmpty()
@@ -182,6 +190,8 @@
private final ImmutableSet.Builder<DexType> dontRetarget = ImmutableSet.builder();
private final ImmutableMap.Builder<DexType, CustomConversionDescriptor> customConversions =
ImmutableMap.builder();
+ private final ImmutableMap.Builder<DexMethod, MethodAccessFlags> amendLibraryMethod =
+ ImmutableMap.builder();
public void rewriteType(DexType src, DexType target) {
assert src != null;
@@ -231,6 +241,10 @@
customConversions.put(src, descriptor);
}
+ public void amendLibraryMethod(DexMethod missingReference, MethodAccessFlags flags) {
+ amendLibraryMethod.put(missingReference, flags);
+ }
+
public DexType getRewrittenType(DexType type) {
return rewriteType.get(type);
}
@@ -247,7 +261,8 @@
wrappers.build(),
legacyBackport.build(),
dontRetarget.build(),
- customConversions.build());
+ customConversions.build(),
+ amendLibraryMethod.build());
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
index 73dd908..a4b984f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
@@ -140,13 +140,11 @@
AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
MethodResolutionResult resolutionResult =
appInfo.resolveMethod(invokedMethod, cfInvoke.isInterface());
- // We are required to use the invokedMethod if it does not resolve due to the rewriting of
- // private methods absent from the library.
- DexMethod singleTarget =
- resolutionResult.isSingleResolution()
- ? resolutionResult.getSingleTarget().getReference()
- : invokedMethod;
- assert singleTarget != null;
+ if (!resolutionResult.isSingleResolution()) {
+ return NO_REWRITING;
+ }
+ assert resolutionResult.getSingleTarget() != null;
+ DexMethod singleTarget = resolutionResult.getSingleTarget().getReference();
if (cfInvoke.isInvokeStatic()) {
DexMethod retarget = staticRetarget.get(singleTarget);
return retarget == null ? NO_REWRITING : ensureInvokeRetargetingResult(retarget);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineEmulatedInterfaceConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineEmulatedInterfaceConverter.java
index 4be8ef0..198fbc2 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineEmulatedInterfaceConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineEmulatedInterfaceConverter.java
@@ -43,7 +43,7 @@
AppInfoWithClassHierarchy appInfo,
MachineRewritingFlags.Builder builder,
BiConsumer<String, Set<? extends DexReference>> warnConsumer) {
- Map<DexType, DexType> emulateInterfaces = rewritingFlags.getEmulateLibraryInterface();
+ Map<DexType, DexType> emulateInterfaces = rewritingFlags.getEmulatedInterfaces();
Set<DexMethod> dontRewriteInvocation = rewritingFlags.getDontRewriteInvocation();
processEmulatedInterfaceHierarchy(appInfo, emulateInterfaces);
for (DexType itf : emulateInterfaces.keySet()) {
@@ -73,7 +73,7 @@
appInfo
.dexItemFactory()
.createMethod(
- rewritingFlags.getEmulateLibraryInterface().get(method.getHolderType()),
+ rewritingFlags.getEmulatedInterfaces().get(method.getHolderType()),
method.getProto(),
method.getName());
DerivedMethod interfaceMethod = new DerivedMethod(itfDexMethod);
@@ -93,7 +93,7 @@
List<DexType> subInterfaces = emulatedInterfaceHierarchy.get(method.getHolderType());
LinkedHashMap<DexType, DerivedMethod> extraDispatchCases = new LinkedHashMap<>();
// Retarget core lib emulated dispatch handled as part of emulated interface dispatch.
- Map<DexMethod, DexType> retargetCoreLibMember = rewritingFlags.getRetargetCoreLibMember();
+ Map<DexMethod, DexType> retargetCoreLibMember = rewritingFlags.getRetargetMethod();
for (DexMethod retarget : retargetCoreLibMember.keySet()) {
if (retarget.match(method)) {
DexClass inClass = appInfo.definitionFor(retarget.getHolderType());
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
index 5704f3d..55ac78c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
@@ -14,7 +14,6 @@
import com.android.tools.r8.utils.DescriptorUtils;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
-import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
@@ -25,49 +24,40 @@
private final MachineRewritingFlags.Builder builder;
private final String synthesizedPrefix;
private final Map<DexString, DexString> descriptorPrefix;
- private final Map<DexType, DexType> reverse = new IdentityHashMap<>();
+ private final Map<DexString, Map<DexString, DexString>> descriptorDifferentPrefix;
private final Set<DexString> usedPrefix = Sets.newIdentityHashSet();
public HumanToMachinePrefixConverter(
AppInfoWithClassHierarchy appInfo,
MachineRewritingFlags.Builder builder,
String synthesizedPrefix,
- Map<String, String> descriptorPrefix) {
+ HumanRewritingFlags rewritingFlags) {
this.appInfo = appInfo;
this.builder = builder;
this.synthesizedPrefix = synthesizedPrefix;
- this.descriptorPrefix = convertRewritePrefix(descriptorPrefix);
+ this.descriptorPrefix = convertRewritePrefix(rewritingFlags.getRewritePrefix());
+ this.descriptorDifferentPrefix =
+ convertRewriteDifferentPrefix(rewritingFlags.getRewriteDerivedPrefix());
}
public void convertPrefixFlags(
HumanRewritingFlags rewritingFlags, BiConsumer<String, Set<DexString>> warnConsumer) {
rewriteClasses();
- rewriteValues(rewritingFlags.getRetargetCoreLibMember());
+ rewriteValues(rewritingFlags.getRetargetMethod());
rewriteValues(rewritingFlags.getCustomConversions());
- rewriteEmulatedInterface(rewritingFlags.getEmulateLibraryInterface());
- rewriteRetargetKeys(rewritingFlags.getRetargetCoreLibMember());
- rewriteReverse();
+ rewriteEmulatedInterface(rewritingFlags.getEmulatedInterfaces());
+ rewriteRetargetKeys(rewritingFlags.getRetargetMethod());
warnIfUnusedPrefix(warnConsumer);
}
private void warnIfUnusedPrefix(BiConsumer<String, Set<DexString>> warnConsumer) {
Set<DexString> prefixes = Sets.newIdentityHashSet();
prefixes.addAll(descriptorPrefix.keySet());
+ prefixes.addAll(descriptorDifferentPrefix.keySet());
prefixes.removeAll(usedPrefix);
warnConsumer.accept("The following prefixes do not match any type: ", prefixes);
}
- // For custom conversions, this is responsible in rewriting backward.
- private void rewriteReverse() {
- reverse.forEach(
- (rewrittenType, type) -> {
- DexType chainType = rewrittenType(rewrittenType);
- if (chainType != null) {
- builder.rewriteType(rewrittenType, chainType);
- }
- });
- }
-
public DexType convertJavaNameToDesugaredLibrary(DexType type) {
String convertedPrefix = DescriptorUtils.getJavaTypeFromBinaryName(synthesizedPrefix);
String interfaceType = type.toString();
@@ -90,11 +80,6 @@
emulateLibraryInterface.forEach(builder::rewriteDerivedTypeOnly);
}
- private void rewriteType(DexType type, DexType rewrittenType) {
- builder.rewriteType(type, rewrittenType);
- reverse.put(rewrittenType, type);
- }
-
private void rewriteValues(
Map<?, DexType> flags) {
for (DexType type : flags.values()) {
@@ -104,46 +89,76 @@
private void rewriteClasses() {
for (DexClass clazz : appInfo.app().asDirect().libraryClasses()) {
- rewriteClass(clazz);
+ if (clazz.toString().contains("MonthDay")) {
+ clazz.toString();
+ }
+ registerType(clazz.type);
+ registerDifferentType(clazz.type);
}
for (DexClass clazz : appInfo.classes()) {
- rewriteClass(clazz);
- }
- }
-
- private void rewriteClass(DexClass clazz) {
- registerType(clazz.type);
- // We allow missing referenced types for the work-in-progress desugaring.
- if (clazz.superType != null) {
- registerType(clazz.superType);
- }
- clazz.interfaces.forEach(this::registerType);
- if (clazz.getInnerClasses() != null) {
- clazz.getInnerClasses().forEach(attr -> attr.forEachType(this::registerType));
+ registerType(clazz.type);
+ registerDifferentType(clazz.type);
}
}
private void registerType(DexType type) {
DexType rewrittenType = rewrittenType(type);
if (rewrittenType != null) {
- rewriteType(type, rewrittenType);
+ builder.rewriteType(type, rewrittenType);
}
}
- private DexType rewrittenType(DexType type) {
+ private void registerDifferentType(DexType type) {
+ DexString prefix = prefixMatching(type, descriptorDifferentPrefix.keySet());
+ if (prefix == null) {
+ return;
+ }
+ descriptorDifferentPrefix
+ .get(prefix)
+ .forEach(
+ (k, v) -> {
+ DexString typeDescriptor =
+ type.descriptor.withNewPrefix(prefix, k, appInfo.dexItemFactory());
+ DexString rewrittenTypeDescriptor =
+ type.descriptor.withNewPrefix(prefix, v, appInfo.dexItemFactory());
+ builder.rewriteType(
+ appInfo.dexItemFactory().createType(typeDescriptor),
+ appInfo.dexItemFactory().createType(rewrittenTypeDescriptor));
+ });
+ usedPrefix.add(prefix);
+ }
+
+ private DexString prefixMatching(DexType type, Set<DexString> prefixes) {
DexString prefixToMatch = type.descriptor.withoutArray(appInfo.dexItemFactory());
- for (DexString prefix : descriptorPrefix.keySet()) {
+ for (DexString prefix : prefixes) {
if (prefixToMatch.startsWith(prefix)) {
- DexString rewrittenTypeDescriptor =
- type.descriptor.withNewPrefix(
- prefix, descriptorPrefix.get(prefix), appInfo.dexItemFactory());
- usedPrefix.add(prefix);
- return appInfo.dexItemFactory().createType(rewrittenTypeDescriptor);
+ return prefix;
}
}
return null;
}
+ private DexType rewrittenType(DexType type) {
+ DexString prefix = prefixMatching(type, descriptorPrefix.keySet());
+ if (prefix == null) {
+ return null;
+ }
+ DexString rewrittenTypeDescriptor =
+ type.descriptor.withNewPrefix(
+ prefix, descriptorPrefix.get(prefix), appInfo.dexItemFactory());
+ usedPrefix.add(prefix);
+ return appInfo.dexItemFactory().createType(rewrittenTypeDescriptor);
+ }
+
+ private ImmutableMap<DexString, Map<DexString, DexString>> convertRewriteDifferentPrefix(
+ Map<String, Map<String, String>> rewriteDerivedPrefix) {
+ ImmutableMap.Builder<DexString, Map<DexString, DexString>> mapBuilder = ImmutableMap.builder();
+ for (String key : rewriteDerivedPrefix.keySet()) {
+ mapBuilder.put(toDescriptorPrefix(key), convertRewritePrefix(rewriteDerivedPrefix.get(key)));
+ }
+ return mapBuilder.build();
+ }
+
private ImmutableMap<DexString, DexString> convertRewritePrefix(
Map<String, String> rewritePrefix) {
ImmutableMap.Builder<DexString, DexString> mapBuilder = ImmutableMap.builder();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
index e153c70..6268125 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
@@ -41,7 +41,7 @@
MachineRewritingFlags.Builder builder,
BiConsumer<String, Set<? extends DexReference>> warnConsumer) {
rewritingFlags
- .getRetargetCoreLibMember()
+ .getRetargetMethod()
.forEach(
(method, type) ->
convertRetargetCoreLibMemberFlag(builder, rewritingFlags, method, type));
@@ -55,14 +55,8 @@
DexType type) {
DexClass holder = appInfo.definitionFor(method.holder);
DexEncodedMethod foundMethod = holder.lookupMethod(method);
- if (foundMethod == null && method.getName().toString().equals("deepEquals0")) {
- // TODO(b/184026720): Temporary work-around (the method is missing).
- DexMethod dest = method.withHolder(type, appInfo.dexItemFactory());
- builder.putStaticRetarget(method, dest);
- return;
- }
if (foundMethod == null) {
- missingMethods.add(foundMethod.getReference());
+ missingMethods.add(method);
return;
}
if (foundMethod.isStatic()) {
@@ -127,8 +121,7 @@
AppInfoWithClassHierarchy appInfo,
HumanRewritingFlags humanRewritingFlags) {
// Answers true if this method is already managed through emulated interface dispatch.
- Map<DexType, DexType> emulateLibraryInterface =
- humanRewritingFlags.getEmulateLibraryInterface();
+ Map<DexType, DexType> emulateLibraryInterface = humanRewritingFlags.getEmulatedInterfaces();
if (emulateLibraryInterface.isEmpty()) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
index c668858..51516d4 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
@@ -16,6 +16,8 @@
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAmender;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanTopLevelFlags;
@@ -27,6 +29,7 @@
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
+import com.google.common.collect.Sets;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
@@ -37,6 +40,7 @@
public class HumanToMachineSpecificationConverter {
private AppView<?> appView;
+ private final Set<DexType> missingCustomConversions = Sets.newIdentityHashSet();
public MachineDesugaredLibrarySpecification convert(
HumanDesugaredLibrarySpecification humanSpec,
@@ -77,7 +81,10 @@
throws IOException {
DexApplication app = readApp(inputApp, options);
appView = AppView.createForD8(AppInfo.createInitialAppInfo(app));
- LibraryValidator.validate(app, humanSpec.getTopLevelFlags().getRequiredCompilationAPILevel());
+ LibraryValidator.validate(
+ app,
+ humanSpec.isLibraryCompilation(),
+ humanSpec.getTopLevelFlags().getRequiredCompilationAPILevel());
MachineRewritingFlags machineRewritingFlags =
convertRewritingFlags(
humanSpec.getSynthesizedLibraryClassesPackagePrefix(), humanSpec.getRewritingFlags());
@@ -100,12 +107,13 @@
String synthesizedPrefix, HumanRewritingFlags rewritingFlags) {
AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
MachineRewritingFlags.Builder builder = MachineRewritingFlags.builder();
+ DesugaredLibraryAmender.run(appView, rewritingFlags.getAmendLibraryMethod());
+ rewritingFlags.getAmendLibraryMethod().forEach(builder::amendLibraryMethod);
new HumanToMachineRetargetConverter(appInfo)
.convertRetargetFlags(rewritingFlags, builder, this::warnMissingReferences);
new HumanToMachineEmulatedInterfaceConverter(appInfo)
.convertEmulatedInterfaces(rewritingFlags, appInfo, builder, this::warnMissingReferences);
- new HumanToMachinePrefixConverter(
- appInfo, builder, synthesizedPrefix, rewritingFlags.getRewritePrefix())
+ new HumanToMachinePrefixConverter(appInfo, builder, synthesizedPrefix, rewritingFlags)
.convertPrefixFlags(rewritingFlags, this::warnMissingDexString);
new HumanToMachineWrapperConverter(appInfo)
.convertWrappers(rewritingFlags, builder, this::warnMissingReferences);
@@ -114,8 +122,10 @@
.forEach(
(type, conversionType) ->
convertCustomConversion(appInfo, builder, type, conversionType));
- rewritingFlags.getDontRetargetLibMember().forEach(builder::addDontRetarget);
- rewritingFlags.getBackportCoreLibraryMember().forEach(builder::putLegacyBackport);
+ warnMissingReferences(
+ "Cannot register custom conversion due to missing type: ", missingCustomConversions);
+ rewritingFlags.getDontRetarget().forEach(builder::addDontRetarget);
+ rewritingFlags.getLegacyBackport().forEach(builder::putLegacyBackport);
return builder.build();
}
@@ -125,6 +135,10 @@
DexType type,
DexType conversionType) {
DexType rewrittenType = builder.getRewrittenType(type);
+ if (rewrittenType == null) {
+ missingCustomConversions.add(type);
+ return;
+ }
DexProto fromProto = appInfo.dexItemFactory().createProto(rewrittenType, type);
DexMethod fromMethod =
appInfo
@@ -141,7 +155,11 @@
private DexApplication readApp(AndroidApp inputApp, InternalOptions options) throws IOException {
ApplicationReader applicationReader = new ApplicationReader(inputApp, options, Timing.empty());
ExecutorService executorService = ThreadUtils.getExecutorService(options);
- return applicationReader.read(executorService).toDirect();
+ assert !options.ignoreJavaLibraryOverride;
+ options.ignoreJavaLibraryOverride = true;
+ DirectMappedDexApplication app = applicationReader.read(executorService).toDirect();
+ options.ignoreJavaLibraryOverride = false;
+ return app;
}
void warnMissingReferences(String message, Set<? extends DexReference> missingReferences) {
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 c4884a5..3a2c990 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
@@ -8,6 +8,7 @@
import com.android.tools.r8.StringConsumer;
import com.android.tools.r8.StringResource;
import com.android.tools.r8.dex.ApplicationReader;
+import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassAndMethod;
@@ -16,6 +17,7 @@
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanTopLevelFlags;
@@ -34,6 +36,7 @@
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
+import com.google.common.collect.ImmutableMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import java.io.IOException;
@@ -45,6 +48,7 @@
public class LegacyToHumanSpecificationConverter {
+ private static final String wrapperPrefix = "__wrapper__.";
private AndroidApiLevel legacyHackLevel = AndroidApiLevel.N_MR1;
public void convertAllAPILevels(
@@ -57,8 +61,6 @@
.parseMultiLevelConfiguration(inputSpecification);
MultiAPILevelHumanDesugaredLibrarySpecification humanSpec =
convertAllAPILevels(legacySpec, androidLib, options);
- MultiAPILevelHumanDesugaredLibrarySpecificationFlagDeduplicator.deduplicateFlags(
- humanSpec, options.dexItemFactory(), options.reporter);
MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.export(humanSpec, output);
}
@@ -70,7 +72,6 @@
Origin origin = legacySpec.getOrigin();
AndroidApp androidApp = AndroidApp.builder().addLibraryFile(androidLib).build();
DexApplication app = readApp(androidApp, options);
- LibraryValidator.validate(app, legacySpec.getTopLevelFlags().getRequiredCompilationAPILevel());
HumanTopLevelFlags humanTopLevelFlags = convertTopLevelFlags(legacySpec.getTopLevelFlags());
Int2ObjectArrayMap<HumanRewritingFlags> commonFlags =
convertRewritingFlagMap(legacySpec.getCommonFlags(), app, origin);
@@ -81,8 +82,12 @@
legacyLibraryFlagHacks(libraryFlags, app, origin);
- return new MultiAPILevelHumanDesugaredLibrarySpecification(
- origin, humanTopLevelFlags, commonFlags, libraryFlags, programFlags);
+ MultiAPILevelHumanDesugaredLibrarySpecification humanSpec =
+ new MultiAPILevelHumanDesugaredLibrarySpecification(
+ origin, humanTopLevelFlags, commonFlags, libraryFlags, programFlags);
+ MultiAPILevelHumanDesugaredLibrarySpecificationFlagDeduplicator.deduplicateFlags(
+ humanSpec, options.reporter);
+ return humanSpec;
}
public HumanDesugaredLibrarySpecification convert(
@@ -108,7 +113,10 @@
LegacyDesugaredLibrarySpecification legacySpec, AndroidApp inputApp, InternalOptions options)
throws IOException {
DexApplication app = readApp(inputApp, options);
- LibraryValidator.validate(app, legacySpec.getTopLevelFlags().getRequiredCompilationAPILevel());
+ LibraryValidator.validate(
+ app,
+ legacySpec.isLibraryCompilation(),
+ legacySpec.getTopLevelFlags().getRequiredCompilationAPILevel());
HumanTopLevelFlags humanTopLevelFlags = convertTopLevelFlags(legacySpec.getTopLevelFlags());
// The origin is not maintained in non multi-level specifications.
// It should not matter since the origin is used to report invalid specifications, and
@@ -120,7 +128,7 @@
if (options.getMinApiLevel().isLessThanOrEqualTo(legacyHackLevel)
&& legacySpec.isLibraryCompilation()) {
HumanRewritingFlags.Builder builder =
- humanRewritingFlags.newBuilder(app.dexItemFactory(), app.options.reporter, origin);
+ humanRewritingFlags.newBuilder(app.options.reporter, origin);
legacyLibraryFlagHacks(app.dexItemFactory(), builder);
humanRewritingFlags = builder.build();
}
@@ -132,8 +140,11 @@
Int2ObjectArrayMap<HumanRewritingFlags> libraryFlags, DexApplication app, Origin origin) {
int level = legacyHackLevel.getLevel();
HumanRewritingFlags humanRewritingFlags = libraryFlags.get(level);
+ if (humanRewritingFlags == null) {
+ return;
+ }
HumanRewritingFlags.Builder builder =
- humanRewritingFlags.newBuilder(app.dexItemFactory(), app.options.reporter, origin);
+ humanRewritingFlags.newBuilder(app.options.reporter, origin);
legacyLibraryFlagHacks(app.dexItemFactory(), builder);
libraryFlags.put(level, builder.build());
}
@@ -150,7 +161,12 @@
DexMethod source =
itemFactory.createMethod(itemFactory.createType(itemFactory.arraysDescriptor), proto, name);
DexType target = itemFactory.createType("Ljava/util/DesugarArrays;");
- builder.putRetargetCoreLibMember(source, target);
+ builder.retargetMethod(source, target);
+
+ builder.amendLibraryMethod(
+ source,
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PRIVATE | Constants.ACC_STATIC, false));
// TODO(b/181629049): This is only a workaround rewriting invokes of
// j.u.TimeZone.getTimeZone taking a java.time.ZoneId.
@@ -161,7 +177,7 @@
itemFactory.createType("Ljava/time/ZoneId;"));
source = itemFactory.createMethod(itemFactory.createType("Ljava/util/TimeZone;"), proto, name);
target = itemFactory.createType("Ljava/util/DesugarTimeZone;");
- builder.putRetargetCoreLibMember(source, target);
+ builder.retargetMethod(source, target);
}
private DexApplication readApp(AndroidApp inputApp, InternalOptions options) throws IOException {
@@ -179,12 +195,13 @@
private HumanRewritingFlags convertRewritingFlags(
LegacyRewritingFlags flags, DexApplication app, Origin origin) {
- HumanRewritingFlags.Builder builder =
- HumanRewritingFlags.builder(app.dexItemFactory(), app.options.reporter, origin);
+ HumanRewritingFlags.Builder builder = HumanRewritingFlags.builder(app.options.reporter, origin);
- flags.getRewritePrefix().forEach(builder::putRewritePrefix);
- flags.getEmulateLibraryInterface().forEach(builder::putEmulateLibraryInterface);
- flags.getBackportCoreLibraryMember().forEach(builder::putBackportCoreLibraryMember);
+ flags
+ .getRewritePrefix()
+ .forEach((prefix, rewritten) -> rewritePrefix(builder, prefix, rewritten));
+ flags.getEmulateLibraryInterface().forEach(builder::putEmulatedInterface);
+ flags.getBackportCoreLibraryMember().forEach(builder::putLegacyBackport);
flags.getCustomConversions().forEach(builder::putCustomConversion);
flags.getDontRetargetLibMember().forEach(builder::addDontRetargetLibMember);
flags.getWrapperConversions().forEach(builder::addWrapperConversion);
@@ -199,6 +216,28 @@
return builder.build();
}
+ private void rewritePrefix(HumanRewritingFlags.Builder builder, String prefix, String rewritten) {
+ // Legacy hacks: The human specification matches on class' types so we need different
+ // rewritings.
+ if (prefix.startsWith("j$")) {
+ assert rewritten.startsWith("java");
+ builder.putRewriteDerivedPrefix(rewritten, prefix, rewritten);
+ return;
+ }
+ if (prefix.equals(wrapperPrefix)) {
+ // We hard code here this applies to java.nio and java.io only.
+ ImmutableMap<String, String> map =
+ ImmutableMap.of("java.nio.", "j$.nio.", "java.io.", "j$.io.");
+ map.forEach(
+ (k, v) -> {
+ builder.putRewriteDerivedPrefix(k, wrapperPrefix + k, k);
+ builder.putRewriteDerivedPrefix(k, wrapperPrefix + v, v);
+ });
+ return;
+ }
+ builder.putRewritePrefix(prefix, rewritten);
+ }
+
private void convertDontRewriteInvocation(
HumanRewritingFlags.Builder builder, DexApplication app, Pair<DexType, DexString> pair) {
DexClass dexClass = app.definitionFor(pair.getFirst());
@@ -220,7 +259,7 @@
assert dexClass != null;
List<DexClassAndMethod> methodsWithName = findMethodsWithName(name, dexClass);
for (DexClassAndMethod dexClassAndMethod : methodsWithName) {
- builder.putRetargetCoreLibMember(dexClassAndMethod.getReference(), rewrittenType);
+ builder.retargetMethod(dexClassAndMethod.getReference(), rewrittenType);
}
});
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LibraryValidator.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LibraryValidator.java
index b415c354..ef19eb6 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LibraryValidator.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LibraryValidator.java
@@ -11,9 +11,16 @@
public class LibraryValidator {
- // Estimates if the library passed is at the expected minimum level, if it is not, raise
- // a warning.
- public static void validate(DexApplication app, AndroidApiLevel requiredCompilationAPILevel) {
+ /**
+ * In program compilation, The LibraryValidator estimates if the library passed is at the expected
+ * minimum level, if it is not, raises a warning.
+ */
+ public static void validate(
+ DexApplication app, boolean libraryCompilation, AndroidApiLevel requiredCompilationAPILevel) {
+ if (libraryCompilation) {
+ // In library compilation, the classes are passed as program classes and are always found.
+ return;
+ }
DexType levelType;
if (requiredCompilationAPILevel.isEqualTo(AndroidApiLevel.O)) {
levelType = app.dexItemFactory.createType("Ljava/time/LocalTime;");
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
index 3aec49b..06f2d76 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
@@ -420,7 +420,7 @@
}
@Override
- protected DexMethod internalGetNextMethodSignature(DexMethod method) {
+ public DexMethod getNextMethodSignature(DexMethod method) {
return newMethodSignatures.getRepresentativeValueOrDefault(
method, extraNewMethodSignatures.getRepresentativeValueOrDefault(method, method));
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ArgumentRemovalUtils.java b/src/main/java/com/android/tools/r8/ir/optimize/ArgumentRemovalUtils.java
deleted file mode 100644
index 8f9421d..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/ArgumentRemovalUtils.java
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2018, 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.optimize;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-
-public class ArgumentRemovalUtils {
-
- // Returns true if this method is pinned from the perspective of optimizations that attempt to
- // remove method arguments.
- public static boolean isPinned(DexEncodedMethod method, AppView<AppInfoWithLiveness> appView) {
- return appView.appInfo().isPinned(method.getReference())
- || appView.appInfo().isBootstrapMethod(method.getReference())
- || appView.appInfo().isFailedResolutionTarget(method.getReference())
- || appView.appInfo().isMethodTargetedByInvokeDynamic(method.getReference())
- || method.accessFlags.isNative();
- }
-}
diff --git a/src/main/java/com/android/tools/r8/optimize/FieldRebindingIdentityLens.java b/src/main/java/com/android/tools/r8/optimize/FieldRebindingIdentityLens.java
index 00867f4..a980c52 100644
--- a/src/main/java/com/android/tools/r8/optimize/FieldRebindingIdentityLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/FieldRebindingIdentityLens.java
@@ -100,6 +100,11 @@
}
@Override
+ public DexMethod getNextMethodSignature(DexMethod method) {
+ return method;
+ }
+
+ @Override
public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
DexMethod method, GraphLens codeLens) {
if (this == codeLens) {
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java
index b77fbd1..ebf61af 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java
@@ -123,6 +123,11 @@
}
@Override
+ public DexMethod getNextMethodSignature(DexMethod method) {
+ return method;
+ }
+
+ @Override
public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
DexMethod method, GraphLens codeLens) {
if (this == codeLens) {
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingLens.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingLens.java
index edba428..5065a75 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingLens.java
@@ -138,6 +138,11 @@
return method;
}
+ @Override
+ public DexMethod getNextMethodSignature(DexMethod method) {
+ return method;
+ }
+
public FieldRebindingIdentityLens toRewrittenFieldRebindingLens(
AppView<? extends AppInfoWithClassHierarchy> appView, GraphLens lens) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
index e72be3d..8dd8cb0 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorApplicationFixer.java
@@ -94,7 +94,7 @@
method -> {
DexMethod methodReferenceBeforeParameterRemoval = method.getReference();
DexMethod methodReferenceAfterParameterRemoval =
- graphLens.internalGetNextMethodSignature(methodReferenceBeforeParameterRemoval);
+ graphLens.getNextMethodSignature(methodReferenceBeforeParameterRemoval);
if (methodReferenceAfterParameterRemoval == methodReferenceBeforeParameterRemoval
&& !graphLens.hasPrototypeChanges(methodReferenceAfterParameterRemoval)) {
return method;
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java
index d67718a..958c85b 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorGraphLens.java
@@ -98,8 +98,8 @@
}
@Override
- public DexMethod internalGetNextMethodSignature(DexMethod method) {
- return super.internalGetNextMethodSignature(method);
+ public DexMethod getNextMethodSignature(DexMethod method) {
+ return super.getNextMethodSignature(method);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
index 6e6e88c..fdf81ab 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorMethodReprocessingEnqueuer.java
@@ -87,7 +87,7 @@
if (graphLens != null) {
DexMethod rewrittenMethodSignature =
- graphLens.internalGetNextMethodSignature(method.getReference());
+ graphLens.getNextMethodSignature(method.getReference());
if (graphLens.hasPrototypeChanges(rewrittenMethodSignature)) {
assert !appView.appInfo().isNeverReprocessMethod(method);
postMethodProcessorBuilder.add(method, currentGraphLens);
@@ -195,7 +195,7 @@
ProgramMethod resolvedMethod = resolutionResult.getResolvedProgramMethod();
DexMethod rewrittenMethodReference =
- graphLens.internalGetNextMethodSignature(resolvedMethod.getReference());
+ graphLens.getNextMethodSignature(resolvedMethod.getReference());
if (rewrittenMethodReference != resolvedMethod.getReference()
|| graphLens.hasPrototypeChanges(rewrittenMethodReference)) {
markAffected();
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
index c30afaf..24d6e46 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorProgramOptimizer.java
@@ -22,6 +22,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.graph.proto.RemovedArgumentInfo;
+import com.android.tools.r8.graph.proto.RemovedReceiverInfo;
import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.graph.proto.RewrittenTypeInfo;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
@@ -419,7 +420,6 @@
return appView.getKeepInfo(method).isParameterRemovalAllowed(options)
&& !method.getDefinition().isLibraryMethodOverride().isPossiblyTrue()
&& !appView.appInfo().isBootstrapMethod(method)
- && !appView.appInfo().isMethodTargetedByInvokeDynamic(method)
&& !interfaceDispatchOutsideProgram.contains(method);
}
@@ -1022,11 +1022,7 @@
&& ParameterRemovalUtils.canRemoveUnusedParametersFrom(appView, method)
&& ParameterRemovalUtils.canRemoveUnusedParameter(appView, method, 0)) {
parameterChangesBuilder.addArgumentInfo(
- 0,
- RemovedArgumentInfo.builder()
- .setCheckNullOrZero(true)
- .setType(method.getHolderType())
- .build());
+ 0, RemovedReceiverInfo.Builder.create().setType(method.getHolderType()).build());
}
CallSiteOptimizationInfo optimizationInfo = method.getOptimizationInfo().getArgumentInfos();
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorUnoptimizableMethods.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorUnoptimizableMethods.java
index c277bb7..28aa563 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorUnoptimizableMethods.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorUnoptimizableMethods.java
@@ -67,7 +67,6 @@
AppInfoWithLiveness appInfo = appView.appInfo();
InternalOptions options = appView.options();
return method.getDefinition().isLibraryMethodOverride().isPossiblyTrue()
- || appInfo.isMethodTargetedByInvokeDynamic(method)
|| !appInfo.getKeepInfo().getMethodInfo(method).isArgumentPropagationAllowed(options);
}
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/lenscoderewriter/NullCheckInserter.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/lenscoderewriter/NullCheckInserter.java
index e0341ae..07ffe61 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/lenscoderewriter/NullCheckInserter.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/lenscoderewriter/NullCheckInserter.java
@@ -76,8 +76,7 @@
ArgumentInfo receiverArgumentInfo =
lookup.getPrototypeChanges().getArgumentInfoCollection().getArgumentInfo(0);
- if (!receiverArgumentInfo.isRemovedArgumentInfo()
- || !receiverArgumentInfo.asRemovedArgumentInfo().isCheckNullOrZeroSet()) {
+ if (!receiverArgumentInfo.isRemovedReceiverInfo()) {
return;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/utils/ParameterRemovalUtils.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/utils/ParameterRemovalUtils.java
index 34d8967..cb44578 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/utils/ParameterRemovalUtils.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/utils/ParameterRemovalUtils.java
@@ -22,8 +22,7 @@
if (!appView.getKeepInfo(method).isUnusedArgumentOptimizationAllowed(options)) {
return false;
}
- return method.getDefinition().isLibraryMethodOverride().isFalse()
- && !appView.appInfoWithLiveness().isMethodTargetedByInvokeDynamic(method);
+ return method.getDefinition().isLibraryMethodOverride().isFalse();
}
public static boolean canRemoveUnusedParameter(
diff --git a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoistingLens.java b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoistingLens.java
index 9827d9a..d47ecd6 100644
--- a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoistingLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoistingLens.java
@@ -29,7 +29,7 @@
@Override
public DexMethod getRenamedMethodSignature(DexMethod originalMethod, GraphLens applied) {
DexMethod renamedMethod = getPrevious().getRenamedMethodSignature(originalMethod, applied);
- return bridgeToHoistedBridgeMap.getOrDefault(renamedMethod, renamedMethod);
+ return getNextMethodSignature(renamedMethod);
}
@Override
@@ -39,6 +39,11 @@
}
@Override
+ public DexMethod getNextMethodSignature(DexMethod method) {
+ return bridgeToHoistedBridgeMap.getOrDefault(method, method);
+ }
+
+ @Override
public DexType getOriginalType(DexType type) {
return getPrevious().getOriginalType(type);
}
diff --git a/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizer.java b/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizer.java
index 29ed273..b1237ed 100644
--- a/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizer.java
@@ -6,6 +6,7 @@
import static com.android.tools.r8.utils.MapUtils.ignoreKey;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
@@ -13,14 +14,20 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.IterableUtils;
+import com.android.tools.r8.utils.MapUtils;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.utils.WorkList;
import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
import com.android.tools.r8.utils.collections.DexMethodSignatureSet;
import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import java.util.Collections;
import java.util.HashMap;
@@ -59,21 +66,39 @@
LocalReservationState localReservationState = new LocalReservationState();
ProtoNormalizerGraphLens.Builder lensBuilder = ProtoNormalizerGraphLens.builder(appView);
for (DexProgramClass clazz : appView.appInfo().classesWithDeterministicOrder()) {
+ Map<DexMethodSignature, DexMethodSignature> newInstanceInitializerSignatures =
+ computeNewInstanceInitializerSignatures(
+ clazz, localReservationState, globalReservationState);
clazz
.getMethodCollection()
.replaceMethods(
method -> {
DexMethodSignature methodSignature = method.getSignature();
DexMethodSignature newMethodSignature =
- localReservationState.getNewMethodSignature(
- methodSignature, dexItemFactory, globalReservationState);
+ method.isInstanceInitializer()
+ ? newInstanceInitializerSignatures.get(methodSignature)
+ : localReservationState.getAndReserveNewMethodSignature(
+ methodSignature, dexItemFactory, globalReservationState);
if (methodSignature.equals(newMethodSignature)) {
return method;
}
DexMethod newMethodReference = newMethodSignature.withHolder(clazz, dexItemFactory);
- lensBuilder.recordNewMethodSignature(method, newMethodReference);
- // TODO(b/195112263): Fixup any optimization info and parameter annotations.
- return method.toTypeSubstitutedMethod(newMethodReference);
+ RewrittenPrototypeDescription prototypeChanges =
+ lensBuilder.recordNewMethodSignature(method, newMethodReference);
+ // TODO(b/195112263): Assert that the method does not have any optimization info.
+ // If/when enabling proto normalization after the final round of tree shaking, this
+ // should simply clear the optimization info, or replace it by a
+ // ThrowingMethodOptimizationInfo since we should never use the optimization info
+ // after this point.
+ return method.toTypeSubstitutedMethod(
+ newMethodReference,
+ builder -> {
+ if (!prototypeChanges.isEmpty()) {
+ builder
+ .apply(prototypeChanges.createParameterAnnotationsRemover(method))
+ .setGenericSignature(MethodTypeSignature.noSignature());
+ }
+ });
});
}
@@ -170,6 +195,90 @@
}
}
+ Map<DexMethodSignature, DexMethodSignature> computeNewInstanceInitializerSignatures(
+ DexProgramClass clazz,
+ LocalReservationState localReservationState,
+ GlobalReservationState globalReservationState) {
+ // Create a map from new method signatures to old method signatures. This produces a one-to-many
+ // mapping since multiple instance initializers may normalize to the same signature.
+ Map<DexMethodSignature, DexMethodSignatureSet> instanceInitializerCollisions =
+ computeInstanceInitializerCollisions(clazz, localReservationState, globalReservationState);
+
+ // Resolve each collision to ensure that the mapping is one-to-one.
+ resolveInstanceInitializerCollisions(instanceInitializerCollisions);
+
+ // Inverse the one-to-one map to produce a mapping from old method signatures to new method
+ // signatures.
+ return MapUtils.transform(
+ instanceInitializerCollisions,
+ HashMap::new,
+ (newMethodSignature, methodSignatures) -> Iterables.getFirst(methodSignatures, null),
+ (newMethodSignature, methodSignatures) -> newMethodSignature,
+ (newMethodSignature, methodSignature, otherMethodSignature) -> {
+ throw new Unreachable();
+ });
+ }
+
+ private Map<DexMethodSignature, DexMethodSignatureSet> computeInstanceInitializerCollisions(
+ DexProgramClass clazz,
+ LocalReservationState localReservationState,
+ GlobalReservationState globalReservationState) {
+ Map<DexMethodSignature, DexMethodSignatureSet> instanceInitializerCollisions = new HashMap<>();
+ clazz.forEachProgramInstanceInitializer(
+ method -> {
+ DexMethodSignature methodSignature = method.getMethodSignature();
+ DexMethodSignature newMethodSignature =
+ localReservationState.getNewMethodSignature(
+ methodSignature, dexItemFactory, globalReservationState);
+ instanceInitializerCollisions
+ .computeIfAbsent(newMethodSignature, ignoreKey(DexMethodSignatureSet::create))
+ .add(methodSignature);
+ });
+ return instanceInitializerCollisions;
+ }
+
+ private void resolveInstanceInitializerCollisions(
+ Map<DexMethodSignature, DexMethodSignatureSet> instanceInitializerCollisions) {
+ WorkList<DexMethodSignature> worklist = WorkList.newEqualityWorkList();
+ instanceInitializerCollisions.forEach(
+ (newMethodSignature, methodSignatures) -> {
+ if (methodSignatures.size() > 1) {
+ worklist.addIfNotSeen(newMethodSignature);
+ }
+ });
+
+ while (worklist.hasNext()) {
+ DexMethodSignature newMethodSignature = worklist.removeSeen();
+ DexMethodSignatureSet methodSignatures =
+ instanceInitializerCollisions.get(newMethodSignature);
+ assert methodSignatures.size() > 1;
+
+ // Resolve this conflict in a deterministic way.
+ DexMethodSignature survivor =
+ methodSignatures.contains(newMethodSignature)
+ ? newMethodSignature
+ : IterableUtils.min(methodSignatures, DexMethodSignature::compareTo);
+
+ // Disallow optimizations of all other methods than the `survivor`.
+ for (DexMethodSignature methodSignature : methodSignatures) {
+ if (!methodSignature.equals(survivor)) {
+ DexMethodSignatureSet originalMethodSignaturesForMethodSignature =
+ instanceInitializerCollisions.computeIfAbsent(
+ methodSignature, ignoreKey(DexMethodSignatureSet::create));
+ originalMethodSignaturesForMethodSignature.add(methodSignature);
+ if (originalMethodSignaturesForMethodSignature.size() > 1) {
+ worklist.addIfNotSeen(methodSignature);
+ }
+ }
+ }
+
+ // Remove all pinned methods from the set of original method signatures stored at
+ // instanceInitializerCollisions.get(newMethodSignature).
+ methodSignatures.clear();
+ methodSignatures.add(survivor);
+ }
+ }
+
private boolean isUnoptimizable(ProgramMethod method) {
// TODO(b/195112263): This is incomplete.
return appView.getKeepInfo(method).isPinned(options)
@@ -226,11 +335,27 @@
MutableBidirectionalOneToOneMap<DexMethodSignature, DexMethodSignature> newMethodSignatures =
new BidirectionalOneToOneHashMap<>();
- // TODO: avoid sorting multiple times.
DexMethodSignature getNewMethodSignature(
DexMethodSignature methodSignature,
DexItemFactory dexItemFactory,
GlobalReservationState globalReservationState) {
+ return internalGetAndReserveNewMethodSignature(
+ methodSignature, dexItemFactory, globalReservationState, false);
+ }
+
+ DexMethodSignature getAndReserveNewMethodSignature(
+ DexMethodSignature methodSignature,
+ DexItemFactory dexItemFactory,
+ GlobalReservationState globalReservationState) {
+ return internalGetAndReserveNewMethodSignature(
+ methodSignature, dexItemFactory, globalReservationState, true);
+ }
+
+ private DexMethodSignature internalGetAndReserveNewMethodSignature(
+ DexMethodSignature methodSignature,
+ DexItemFactory dexItemFactory,
+ GlobalReservationState globalReservationState,
+ boolean reserve) {
if (globalReservationState.isUnoptimizable(methodSignature)) {
assert !newMethodSignatures.containsKey(methodSignature);
return methodSignature;
@@ -254,7 +379,9 @@
newMethodSignature = newMethodSignature.withName(newMethodName);
} while (newMethodSignatures.containsValue(newMethodSignature));
}
- newMethodSignatures.put(methodSignature, newMethodSignature);
+ if (reserve) {
+ newMethodSignatures.put(methodSignature, newMethodSignature);
+ }
return newMethodSignature;
}
}
diff --git a/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizerGraphLens.java b/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizerGraphLens.java
index 89d95d6..bfeef49 100644
--- a/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizerGraphLens.java
@@ -62,20 +62,26 @@
@Override
public DexMethod getRenamedMethodSignature(DexMethod originalMethod, GraphLens applied) {
+ if (this == applied) {
+ return originalMethod;
+ }
return newMethodSignatures.getOrDefault(originalMethod, originalMethod);
}
@Override
public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(
DexMethod method, GraphLens codeLens) {
+ if (this == codeLens) {
+ return RewrittenPrototypeDescription.none();
+ }
DexMethod previousMethodSignature = getPreviousMethodSignature(method);
RewrittenPrototypeDescription previousPrototypeChanges =
getPrevious().lookupPrototypeChangesForMethodDefinition(previousMethodSignature);
if (previousMethodSignature == method) {
return previousPrototypeChanges;
}
- assert prototypeChanges.containsKey(method);
- return previousPrototypeChanges.combine(prototypeChanges.get(method));
+ return previousPrototypeChanges.combine(
+ prototypeChanges.getOrDefault(method, RewrittenPrototypeDescription.none()));
}
@Override
@@ -115,6 +121,11 @@
return newMethodSignatures.getRepresentativeKeyOrDefault(method, method);
}
+ @Override
+ public DexMethod getNextMethodSignature(DexMethod method) {
+ return newMethodSignatures.getOrDefault(method, method);
+ }
+
public static class Builder {
private final AppView<AppInfoWithLiveness> appView;
@@ -127,11 +138,17 @@
this.appView = appView;
}
- public Builder recordNewMethodSignature(DexEncodedMethod method, DexMethod newMethodSignature) {
+ public RewrittenPrototypeDescription recordNewMethodSignature(
+ DexEncodedMethod method, DexMethod newMethodSignature) {
assert method.getReference() != newMethodSignature;
- prototypeChanges.put(newMethodSignature, computePrototypeChanges(method, newMethodSignature));
newMethodSignatures.put(method.getReference(), newMethodSignature);
- return this;
+ if (!method.getParameters().equals(newMethodSignature.getParameters())) {
+ RewrittenPrototypeDescription prototypeChangesForMethod =
+ computePrototypeChanges(method, newMethodSignature);
+ prototypeChanges.put(newMethodSignature, prototypeChangesForMethod);
+ return prototypeChangesForMethod;
+ }
+ return RewrittenPrototypeDescription.none();
}
// TODO(b/195112263): Canonicalize the permutation maps.
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index 8216777..7464171 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -112,8 +112,6 @@
*/
private final Set<DexMethod> bootstrapMethods;
- /** Set of methods that are the immediate target of an invoke-dynamic. */
- private final Set<DexMethod> methodsTargetedByInvokeDynamic;
/** Set of virtual methods that are the immediate target of an invoke-direct. */
private final Set<DexMethod> virtualMethodsTargetedByInvokeDirect;
/**
@@ -210,7 +208,6 @@
Set<DexMethod> failedMethodResolutionTargets,
Set<DexField> failedFieldResolutionTargets,
Set<DexMethod> bootstrapMethods,
- Set<DexMethod> methodsTargetedByInvokeDynamic,
Set<DexMethod> virtualMethodsTargetedByInvokeDirect,
Set<DexMethod> liveMethods,
FieldAccessInfoCollectionImpl fieldAccessInfoCollection,
@@ -245,7 +242,6 @@
this.failedMethodResolutionTargets = failedMethodResolutionTargets;
this.failedFieldResolutionTargets = failedFieldResolutionTargets;
this.bootstrapMethods = bootstrapMethods;
- this.methodsTargetedByInvokeDynamic = methodsTargetedByInvokeDynamic;
this.virtualMethodsTargetedByInvokeDirect = virtualMethodsTargetedByInvokeDirect;
this.liveMethods = liveMethods;
this.fieldAccessInfoCollection = fieldAccessInfoCollection;
@@ -288,7 +284,6 @@
previous.failedMethodResolutionTargets,
previous.failedFieldResolutionTargets,
previous.bootstrapMethods,
- previous.methodsTargetedByInvokeDynamic,
previous.virtualMethodsTargetedByInvokeDirect,
previous.liveMethods,
previous.fieldAccessInfoCollection,
@@ -335,8 +330,6 @@
pruneFields(previous.failedFieldResolutionTargets, prunedItems, executorService, futures),
pruneMethods(previous.bootstrapMethods, prunedItems, executorService, futures),
pruneMethods(
- previous.methodsTargetedByInvokeDynamic, prunedItems, executorService, futures),
- pruneMethods(
previous.virtualMethodsTargetedByInvokeDirect, prunedItems, executorService, futures),
pruneMethods(previous.liveMethods, prunedItems, executorService, futures),
previous.fieldAccessInfoCollection,
@@ -541,7 +534,6 @@
failedMethodResolutionTargets,
failedFieldResolutionTargets,
bootstrapMethods,
- methodsTargetedByInvokeDynamic,
virtualMethodsTargetedByInvokeDirect,
liveMethods,
fieldAccessInfoCollection,
@@ -621,7 +613,6 @@
this.failedMethodResolutionTargets = previous.failedMethodResolutionTargets;
this.failedFieldResolutionTargets = previous.failedFieldResolutionTargets;
this.bootstrapMethods = previous.bootstrapMethods;
- this.methodsTargetedByInvokeDynamic = previous.methodsTargetedByInvokeDynamic;
this.virtualMethodsTargetedByInvokeDirect = previous.virtualMethodsTargetedByInvokeDirect;
this.liveMethods = previous.liveMethods;
this.fieldAccessInfoCollection = previous.fieldAccessInfoCollection;
@@ -745,14 +736,6 @@
return isBootstrapMethod(method.getReference());
}
- public boolean isMethodTargetedByInvokeDynamic(DexMethod method) {
- return methodsTargetedByInvokeDynamic.contains(method);
- }
-
- public boolean isMethodTargetedByInvokeDynamic(ProgramMethod method) {
- return isMethodTargetedByInvokeDynamic(method.getReference());
- }
-
public Set<DexMethod> getVirtualMethodsTargetedByInvokeDirect() {
return virtualMethodsTargetedByInvokeDirect;
}
@@ -1232,7 +1215,6 @@
lens.rewriteReferences(failedMethodResolutionTargets),
lens.rewriteReferences(failedFieldResolutionTargets),
lens.rewriteReferences(bootstrapMethods),
- lens.rewriteReferences(methodsTargetedByInvokeDynamic),
lens.rewriteReferences(virtualMethodsTargetedByInvokeDirect),
lens.rewriteReferences(liveMethods),
fieldAccessInfoCollection.rewrittenWithLens(definitionSupplier, lens),
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 8681f33..1125b65 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -57,7 +57,6 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexValue;
import com.android.tools.r8.graph.DirectMappedDexApplication;
-import com.android.tools.r8.graph.DirectMappedDexApplication.Builder;
import com.android.tools.r8.graph.EnclosingMethodAttribute;
import com.android.tools.r8.graph.FieldAccessInfoCollectionImpl;
import com.android.tools.r8.graph.FieldAccessInfoImpl;
@@ -356,10 +355,6 @@
*/
private final Set<DexMethod> bootstrapMethods = Sets.newIdentityHashSet();
/**
- * Set of direct methods that are the immediate target of an invoke-dynamic.
- */
- private final Set<DexMethod> methodsTargetedByInvokeDynamic = Sets.newIdentityHashSet();
- /**
* Set of virtual methods that are the immediate target of an invoke-direct.
*/
private final Set<DexMethod> virtualMethodsTargetedByInvokeDirect = Sets.newIdentityHashSet();
@@ -701,13 +696,17 @@
private void addLiveNonProgramType(
ClasspathOrLibraryClass clazz,
// TODO(b/216576191): Remove when tracking live library members.
- boolean visitMembers,
+ boolean markProgramSuperTypesAsLiveAndVisitMemberReferences,
BiConsumer<DexType, ClasspathOrLibraryDefinition> missingClassConsumer) {
WorkList<ClasspathOrLibraryClass> worklist =
WorkList.newIdentityWorkList(clazz, liveNonProgramTypes);
while (worklist.hasNext()) {
ClasspathOrLibraryClass definition = worklist.next();
- processNewLiveNonProgramType(definition, worklist, missingClassConsumer, visitMembers);
+ processNewLiveNonProgramType(
+ definition,
+ worklist,
+ missingClassConsumer,
+ markProgramSuperTypesAsLiveAndVisitMemberReferences);
}
}
@@ -715,13 +714,14 @@
ClasspathOrLibraryClass clazz,
WorkList<ClasspathOrLibraryClass> worklist,
BiConsumer<DexType, ClasspathOrLibraryDefinition> missingClassConsumer,
- boolean visitMembers) {
+ boolean markProgramSuperTypesAsLiveAndVisitMemberReferences) {
ensureMethodsContinueToWidenAccess(clazz);
- if (clazz.isLibraryClass()) {
- // Only libraries must not derive program. Classpath classes can, assuming correct keep rules.
- warnIfLibraryTypeInheritsFromProgramType(clazz.asLibraryClass());
- }
- if (visitMembers) {
+ if (markProgramSuperTypesAsLiveAndVisitMemberReferences) {
+ if (clazz.isLibraryClass()) {
+ // Only libraries must not derive program. Classpath classes can, assuming correct keep
+ // rules.
+ handleLibraryTypeInheritingFromProgramType(clazz.asLibraryClass());
+ }
clazz.forEachClassField(
field ->
addNonProgramClassToWorklist(
@@ -792,7 +792,7 @@
return asProgramClassOrNull(getClassOrNullFromReflectiveAccess(type, context));
}
- private void warnIfLibraryTypeInheritsFromProgramType(DexLibraryClass clazz) {
+ private void handleLibraryTypeInheritingFromProgramType(DexLibraryClass clazz) {
if (clazz.superType != null) {
ensureFromLibraryOrThrow(clazz.superType, clazz);
}
@@ -1026,7 +1026,7 @@
if (bootstrapArgument.isDexValueMethodHandle()) {
DexMethodHandle method = bootstrapArgument.asDexValueMethodHandle().getValue();
if (method.isMethodHandle()) {
- methodsTargetedByInvokeDynamic.add(method.asMethod());
+ disableClosedWorldReasoning(method.asMethod(), context);
}
}
}
@@ -1047,10 +1047,6 @@
assert implHandle != null;
DexMethod method = implHandle.asMethod();
- if (!methodsTargetedByInvokeDynamic.add(method)) {
- return;
- }
-
switch (implHandle.type) {
case INVOKE_STATIC:
traceInvokeStaticFromLambda(method, context);
@@ -1070,6 +1066,18 @@
default:
throw new Unreachable();
}
+
+ disableClosedWorldReasoning(method, context);
+ }
+
+ private void disableClosedWorldReasoning(DexMethod reference, ProgramMethod context) {
+ SingleResolutionResult resolutionResult =
+ resolveMethod(reference, context, KeepReason.methodHandleReferencedIn(context));
+ if (resolutionResult != null && resolutionResult.getResolvedHolder().isProgramClass()) {
+ applyMinimumKeepInfoWhenLiveOrTargeted(
+ resolutionResult.getResolvedProgramMethod(),
+ KeepMethodInfo.newEmptyJoiner().disallowClosedWorldReasoning());
+ }
}
void traceCheckCast(DexType type, ProgramMethod currentMethod, boolean ignoreCompatRules) {
@@ -3420,9 +3428,8 @@
}
}
- private void applyMinimumKeepInfoWhenLiveOrTargeted(
- ProgramMethod method,
- KeepMethodInfo.Joiner minimumKeepInfo) {
+ public void applyMinimumKeepInfoWhenLiveOrTargeted(
+ ProgramMethod method, KeepMethodInfo.Joiner minimumKeepInfo) {
applyMinimumKeepInfoWhenLiveOrTargeted(method, minimumKeepInfo, EnqueuerEvent.unconditional());
}
@@ -3801,10 +3808,14 @@
// Add just referenced non-program types. We can't replace the program classes at this point as
// they are needed in tree pruning.
- Builder appBuilder = appInfo.app().asDirect().builder();
- appBuilder.replaceLibraryClasses(libraryClasses);
- appBuilder.replaceClasspathClasses(classpathClasses);
- DirectMappedDexApplication app = appBuilder.build();
+ DirectMappedDexApplication app =
+ appInfo
+ .app()
+ .asDirect()
+ .builder()
+ .replaceLibraryClasses(libraryClasses)
+ .replaceClasspathClasses(classpathClasses)
+ .build();
// Verify the references on the pruned application after type synthesis.
assert verifyReferences(app);
@@ -3832,7 +3843,6 @@
failedMethodResolutionTargets,
failedFieldResolutionTargets,
bootstrapMethods,
- methodsTargetedByInvokeDynamic,
virtualMethodsTargetedByInvokeDirect,
toDescriptorSet(liveMethods.getItems()),
// Filter out library fields and pinned fields, because these are read by default.
@@ -4347,7 +4357,7 @@
}
// Notify analyses.
- analyses.forEach(analysis -> analysis.processNewlyLiveMethod(method, context, workList));
+ analyses.forEach(analysis -> analysis.processNewlyLiveMethod(method, context, this, workList));
}
private void markMethodAsTargeted(ProgramMethod method, KeepReason reason) {
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java b/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
index cd46a71..0173fb2 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepMethodInfo.java
@@ -25,6 +25,7 @@
}
private final boolean allowClassInlining;
+ private final boolean allowClosedWorldReasoning;
private final boolean allowConstantArgumentOptimization;
private final boolean allowInlining;
private final boolean allowMethodStaticizing;
@@ -37,6 +38,7 @@
private KeepMethodInfo(Builder builder) {
super(builder);
this.allowClassInlining = builder.isClassInliningAllowed();
+ this.allowClosedWorldReasoning = builder.isClosedWorldReasoningAllowed();
this.allowConstantArgumentOptimization = builder.isConstantArgumentOptimizationAllowed();
this.allowInlining = builder.isInliningAllowed();
this.allowMethodStaticizing = builder.isMethodStaticizingAllowed();
@@ -59,7 +61,8 @@
}
public boolean isParameterRemovalAllowed(GlobalKeepInfoConfiguration configuration) {
- return isOptimizationAllowed(configuration)
+ return isClosedWorldReasoningAllowed(configuration)
+ && isOptimizationAllowed(configuration)
&& isShrinkingAllowed(configuration)
&& !isCheckDiscardedEnabled(configuration);
}
@@ -72,6 +75,14 @@
return allowClassInlining;
}
+ public boolean isClosedWorldReasoningAllowed(GlobalKeepInfoConfiguration configuration) {
+ return isOptimizationAllowed(configuration) && internalIsClosedWorldReasoningAllowed();
+ }
+
+ boolean internalIsClosedWorldReasoningAllowed() {
+ return allowClosedWorldReasoning;
+ }
+
public boolean isConstantArgumentOptimizationAllowed(GlobalKeepInfoConfiguration configuration) {
return isOptimizationAllowed(configuration) && internalIsConstantArgumentOptimizationAllowed();
}
@@ -89,7 +100,8 @@
}
public boolean isMethodStaticizingAllowed(GlobalKeepInfoConfiguration configuration) {
- return isOptimizationAllowed(configuration)
+ return isClosedWorldReasoningAllowed(configuration)
+ && isOptimizationAllowed(configuration)
&& isShrinkingAllowed(configuration)
&& configuration.isMethodStaticizingEnabled()
&& internalIsMethodStaticizingAllowed();
@@ -100,7 +112,8 @@
}
public boolean isParameterReorderingAllowed(GlobalKeepInfoConfiguration configuration) {
- return isOptimizationAllowed(configuration)
+ return isClosedWorldReasoningAllowed(configuration)
+ && isOptimizationAllowed(configuration)
&& isShrinkingAllowed(configuration)
&& internalIsParameterReorderingAllowed();
}
@@ -110,7 +123,8 @@
}
public boolean isParameterTypeStrengtheningAllowed(GlobalKeepInfoConfiguration configuration) {
- return isOptimizationAllowed(configuration)
+ return isClosedWorldReasoningAllowed(configuration)
+ && isOptimizationAllowed(configuration)
&& isShrinkingAllowed(configuration)
&& internalIsParameterTypeStrengtheningAllowed();
}
@@ -120,7 +134,8 @@
}
public boolean isReturnTypeStrengtheningAllowed(GlobalKeepInfoConfiguration configuration) {
- return isOptimizationAllowed(configuration)
+ return isClosedWorldReasoningAllowed(configuration)
+ && isOptimizationAllowed(configuration)
&& isShrinkingAllowed(configuration)
&& internalIsReturnTypeStrengtheningAllowed();
}
@@ -130,7 +145,8 @@
}
public boolean isUnusedArgumentOptimizationAllowed(GlobalKeepInfoConfiguration configuration) {
- return isOptimizationAllowed(configuration)
+ return isClosedWorldReasoningAllowed(configuration)
+ && isOptimizationAllowed(configuration)
&& isShrinkingAllowed(configuration)
&& internalIsUnusedArgumentOptimizationAllowed();
}
@@ -140,7 +156,8 @@
}
public boolean isUnusedReturnValueOptimizationAllowed(GlobalKeepInfoConfiguration configuration) {
- return isOptimizationAllowed(configuration)
+ return isClosedWorldReasoningAllowed(configuration)
+ && isOptimizationAllowed(configuration)
&& isShrinkingAllowed(configuration)
&& internalIsUnusedReturnValueOptimizationAllowed();
}
@@ -167,6 +184,7 @@
public static class Builder extends KeepInfo.Builder<Builder, KeepMethodInfo> {
private boolean allowClassInlining;
+ private boolean allowClosedWorldReasoning;
private boolean allowConstantArgumentOptimization;
private boolean allowInlining;
private boolean allowMethodStaticizing;
@@ -183,6 +201,7 @@
private Builder(KeepMethodInfo original) {
super(original);
allowClassInlining = original.internalIsClassInliningAllowed();
+ allowClosedWorldReasoning = original.internalIsClosedWorldReasoningAllowed();
allowConstantArgumentOptimization = original.internalIsConstantArgumentOptimizationAllowed();
allowInlining = original.internalIsInliningAllowed();
allowMethodStaticizing = original.internalIsMethodStaticizingAllowed();
@@ -213,6 +232,25 @@
return setAllowClassInlining(false);
}
+ // Closed world reasoning.
+
+ public boolean isClosedWorldReasoningAllowed() {
+ return allowClosedWorldReasoning;
+ }
+
+ public Builder setAllowClosedWorldReasoning(boolean allowClosedWorldReasoning) {
+ this.allowClosedWorldReasoning = allowClosedWorldReasoning;
+ return self();
+ }
+
+ public Builder allowClosedWorldReasoning() {
+ return setAllowClosedWorldReasoning(true);
+ }
+
+ public Builder disallowClosedWorldReasoning() {
+ return setAllowClosedWorldReasoning(false);
+ }
+
// Constant argument optimization.
public boolean isConstantArgumentOptimizationAllowed() {
@@ -390,6 +428,7 @@
boolean internalIsEqualTo(KeepMethodInfo other) {
return super.internalIsEqualTo(other)
&& isClassInliningAllowed() == other.internalIsClassInliningAllowed()
+ && isClosedWorldReasoningAllowed() == other.internalIsClosedWorldReasoningAllowed()
&& isConstantArgumentOptimizationAllowed()
== other.internalIsConstantArgumentOptimizationAllowed()
&& isInliningAllowed() == other.internalIsInliningAllowed()
@@ -413,6 +452,7 @@
public Builder makeTop() {
return super.makeTop()
.disallowClassInlining()
+ .disallowClosedWorldReasoning()
.disallowConstantArgumentOptimization()
.disallowInlining()
.disallowMethodStaticizing()
@@ -427,6 +467,7 @@
public Builder makeBottom() {
return super.makeBottom()
.allowClassInlining()
+ .allowClosedWorldReasoning()
.allowConstantArgumentOptimization()
.allowInlining()
.allowMethodStaticizing()
@@ -449,6 +490,11 @@
return self();
}
+ public Joiner disallowClosedWorldReasoning() {
+ builder.disallowClosedWorldReasoning();
+ return self();
+ }
+
public Joiner disallowConstantArgumentOptimization() {
builder.disallowConstantArgumentOptimization();
return self();
@@ -500,6 +546,8 @@
return super.merge(joiner)
.applyIf(!joiner.builder.isClassInliningAllowed(), Joiner::disallowClassInlining)
.applyIf(
+ !joiner.builder.isClosedWorldReasoningAllowed(), Joiner::disallowClosedWorldReasoning)
+ .applyIf(
!joiner.builder.isConstantArgumentOptimizationAllowed(),
Joiner::disallowConstantArgumentOptimization)
.applyIf(!joiner.builder.isInliningAllowed(), Joiner::disallowInlining)
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index db5dcdc..f3391c8 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -89,7 +89,7 @@
.replaceProgramClasses(getNewProgramClasses(application.classesWithDeterministicOrder()));
}
- private List<DexProgramClass> getNewProgramClasses(List<DexProgramClass> classes) {
+ private List<DexProgramClass> getNewProgramClasses(Collection<DexProgramClass> classes) {
AppInfoWithLiveness appInfo = appView.appInfo();
InternalOptions options = appView.options();
List<DexProgramClass> newClasses = new ArrayList<>();
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 0ad5ad4..91f926c 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -2006,6 +2006,11 @@
}
@Override
+ public DexMethod getNextMethodSignature(DexMethod method) {
+ throw new Unreachable();
+ }
+
+ @Override
public MethodLookupResult lookupMethod(
DexMethod method, DexMethod context, Type type, GraphLens codeLens) {
// First look up the method using the existing graph lens (for example, the type will have
diff --git a/src/main/java/com/android/tools/r8/utils/ClassMap.java b/src/main/java/com/android/tools/r8/utils/ClassMap.java
index 23d71ee..506a990 100644
--- a/src/main/java/com/android/tools/r8/utils/ClassMap.java
+++ b/src/main/java/com/android/tools/r8/utils/ClassMap.java
@@ -147,7 +147,7 @@
return loadedClasses;
}
- public Map<DexType, T> getAllClassesInMap() {
+ public ImmutableMap<DexType, T> getAllClassesInMap() {
if (classProvider.get() != null) {
throw new Unreachable("Getting all classes from not fully loaded collection.");
}
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 066ca9f..3fec28a 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -54,11 +54,8 @@
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.desugar.TypeRewriter;
import com.android.tools.r8.ir.desugar.TypeRewriter.MachineDesugarPrefixRewritingMapper;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.HumanToMachineSpecificationConverter;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.LegacyToHumanSpecificationConverter;
import com.android.tools.r8.ir.desugar.nest.Nest;
import com.android.tools.r8.ir.optimize.Inliner;
import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
@@ -352,6 +349,8 @@
public boolean invalidDebugInfoStrict =
System.getProperty("com.android.tools.r8.strictdebuginfo") != null;
+ public boolean ignoreJavaLibraryOverride = false;
+
// When dexsplitting we ignore main dex classes missing in the application. These will be
// fused together by play store when shipped for pre-L devices.
public boolean ignoreMainDexMissingClasses = false;
@@ -563,6 +562,8 @@
// public boolean lookupLibraryBeforeProgram =
// System.getProperty("com.android.tools.r8.lookupProgramBeforeLibrary") == null;
+ public boolean loadAllClassDefinitions = false;
+
// Whether or not to check for valid multi-dex builds.
//
// For min-api levels that did not support native multi-dex the user should provide a main dex
@@ -889,38 +890,25 @@
public StringConsumer configurationConsumer = null;
public void setDesugaredLibrarySpecification(
- LegacyDesugaredLibrarySpecification specification, AndroidApp app) {
- if (specification.isEmptyConfiguration()) {
+ DesugaredLibrarySpecification specification, AndroidApp app) {
+ if (specification.isEmpty()) {
return;
}
try {
- HumanDesugaredLibrarySpecification human =
- new LegacyToHumanSpecificationConverter()
- .convert(specification, app.getLibraryResourceProviders(), this);
- machineDesugaredLibrarySpecification =
- new HumanToMachineSpecificationConverter()
- .convert(
- human,
- specification.isLibraryCompilation() ? app.getProgramResourceProviders() : null,
- app.getLibraryResourceProviders(),
- this);
+ machineDesugaredLibrarySpecification = specification.toMachineSpecification(this, app);
} catch (IOException e) {
reporter.error(new ExceptionDiagnostic(e, Origin.unknown()));
}
}
public void setDesugaredLibrarySpecificationForTesting(
- LegacyDesugaredLibrarySpecification specification, Path desugaredJDKLib, Path library)
+ DesugaredLibrarySpecification specification, Path desugaredJDKLib, Path library)
throws IOException {
- HumanDesugaredLibrarySpecification human =
- new LegacyToHumanSpecificationConverter().convert(specification, library, this);
+ if (specification.isEmpty()) {
+ return;
+ }
machineDesugaredLibrarySpecification =
- new HumanToMachineSpecificationConverter()
- .convert(
- human,
- specification.isLibraryCompilation() ? desugaredJDKLib : null,
- library,
- this);
+ specification.toMachineSpecification(this, library, desugaredJDKLib);
}
// Contains flags describing library desugaring.
diff --git a/src/main/java/com/android/tools/r8/utils/MapUtils.java b/src/main/java/com/android/tools/r8/utils/MapUtils.java
index a29af0b..2f55680 100644
--- a/src/main/java/com/android/tools/r8/utils/MapUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/MapUtils.java
@@ -9,6 +9,7 @@
import it.unimi.dsi.fastutil.ints.Int2ReferenceMaps;
import java.util.IdentityHashMap;
import java.util.Map;
+import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.function.IntFunction;
@@ -63,14 +64,28 @@
Function<K1, K2> keyMapping,
Function<V1, V2> valueMapping,
TriFunction<K2, V2, V2, V2> valueMerger) {
+ return transform(
+ map,
+ factory,
+ (key, value) -> keyMapping.apply(key),
+ (key, value) -> valueMapping.apply(value),
+ valueMerger);
+ }
+
+ public static <K1, V1, K2, V2> Map<K2, V2> transform(
+ Map<K1, V1> map,
+ IntFunction<Map<K2, V2>> factory,
+ BiFunction<K1, V1, K2> keyMapping,
+ BiFunction<K1, V1, V2> valueMapping,
+ TriFunction<K2, V2, V2, V2> valueMerger) {
Map<K2, V2> result = factory.apply(map.size());
map.forEach(
(key, value) -> {
- K2 newKey = keyMapping.apply(key);
+ K2 newKey = keyMapping.apply(key, value);
if (newKey == null) {
return;
}
- V2 newValue = valueMapping.apply(value);
+ V2 newValue = valueMapping.apply(key, value);
V2 existingValue = result.put(newKey, newValue);
if (existingValue != null) {
result.put(newKey, valueMerger.apply(newKey, existingValue, newValue));
diff --git a/src/test/examplesJava9/backport/IntegerBackportJava9Main.java b/src/test/examplesJava9/backport/IntegerBackportJava9Main.java
index 8188fe1..acf18d2 100644
--- a/src/test/examplesJava9/backport/IntegerBackportJava9Main.java
+++ b/src/test/examplesJava9/backport/IntegerBackportJava9Main.java
@@ -4,8 +4,6 @@
package backport;
-import java.math.BigInteger;
-
public final class IntegerBackportJava9Main {
private static final int[] interestingValues = {
Integer.MIN_VALUE,
@@ -23,6 +21,7 @@
public static void main(String[] args) {
testParseIntegerSubsequenceWithRadix();
+ testParseUnsignedIntegerSubsequenceWithRadix();
}
private static void testParseIntegerSubsequenceWithRadix() {
@@ -71,22 +70,87 @@
} catch (NumberFormatException expected) {
}
- BigInteger overflow = new BigInteger("18446744073709551616");
+ long overflow = 73709551616L;
for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
for (String prefix : new String[] {"", "x", "xxx"}) {
for (String postfix : new String[] {"", "x", "xxx"}) {
- String overflowString = prefix + overflow.toString(radix) + postfix;
+ String overflowString = prefix + Long.toString(overflow, radix) + postfix;
int start = prefix.length();
int end = overflowString.length() - postfix.length();
try {
- throw new AssertionError(Long.parseLong(overflowString, start, end, radix));
+ throw new AssertionError(Integer.parseInt(overflowString, start, end, radix));
} catch (NumberFormatException expected) {
}
- String underflowString = prefix + '-' + overflow.toString(radix) + postfix;
+ String underflowString = prefix + '-' + Long.toString(overflow, radix) + postfix;
start = prefix.length();
end = underflowString.length() - postfix.length();
try {
- throw new AssertionError(Long.parseLong(underflowString, start, end, radix));
+ throw new AssertionError(Integer.parseInt(underflowString, start, end, radix));
+ } catch (NumberFormatException expected) {
+ }
+ }
+ }
+ }
+ }
+
+ private static void testParseUnsignedIntegerSubsequenceWithRadix() {
+ for (int value : interestingValues) {
+ for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
+ for (String prefix : new String[] {"", "x", "xxx"}) {
+ for (String postfix : new String[] {"", "x", "xxx"}) {
+ String unsignedIntergerString = Long.toString(Integer.toUnsignedLong(value), radix);
+ String valueString = prefix + unsignedIntergerString + postfix;
+ int start = prefix.length();
+ int end = valueString.length() - postfix.length();
+ assertEquals(
+ valueString, value, Integer.parseUnsignedInt(valueString, start, end, radix));
+ if (value > 0) {
+ valueString = prefix + '+' + unsignedIntergerString + postfix;
+ end++;
+ assertEquals(
+ valueString, value, Integer.parseUnsignedInt(valueString, start, end, radix));
+ }
+ }
+ }
+ }
+ }
+
+ try {
+ throw new AssertionError(Integer.parseUnsignedInt("0", 0, 1, Character.MIN_RADIX - 1));
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ throw new AssertionError(Integer.parseUnsignedInt("0", 0, 1, Character.MAX_RADIX + 1));
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ throw new AssertionError(Integer.parseUnsignedInt("", 0, 0, 16));
+ } catch (NumberFormatException expected) {
+ }
+ try {
+ throw new AssertionError(Integer.parseUnsignedInt("-", 0, 1, 16));
+ } catch (NumberFormatException expected) {
+ }
+ try {
+ throw new AssertionError(Integer.parseUnsignedInt("+", 0, 1, 16));
+ } catch (NumberFormatException expected) {
+ }
+
+ try {
+ throw new AssertionError(Integer.parseUnsignedInt("+a", 0, 2, 10));
+ } catch (NumberFormatException expected) {
+ }
+
+ long overflow = 73709551616L;
+ for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
+ for (String prefix : new String[] {"", "x", "xxx"}) {
+ for (String postfix : new String[] {"", "x", "xxx"}) {
+ String overflowString = prefix + Long.toString(overflow, radix) + postfix;
+ int start = prefix.length();
+ int end = overflowString.length() - postfix.length();
+ try {
+ throw new AssertionError(Integer.parseUnsignedInt(overflowString, start, end, radix));
} catch (NumberFormatException expected) {
}
}
diff --git a/src/test/java/com/android/tools/r8/MarkersTest.java b/src/test/java/com/android/tools/r8/MarkersTest.java
index d883360..a38cf08 100644
--- a/src/test/java/com/android/tools/r8/MarkersTest.java
+++ b/src/test/java/com/android/tools/r8/MarkersTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.origin.Origin;
@@ -27,6 +28,7 @@
import com.android.tools.r8.utils.FileUtils;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
+import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.nio.file.Path;
import java.util.Collection;
@@ -36,7 +38,7 @@
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
-public class MarkersTest extends TestBase {
+public class MarkersTest extends DesugaredLibraryTestBase {
@Parameterized.Parameters(
name = "{0}, compilationMode {1}, shrinkDesugaredLibrary {2}, noCfMarkerForDesugaredCode {3}")
@@ -84,18 +86,20 @@
}
L8.run(builder.build());
Collection<Marker> markers = ExtractMarker.extractMarkerFromDexFile(output);
- String version =
+ JsonObject jsonObject =
new JsonParser()
.parse(FileUtils.readTextFile(ToolHelper.getDesugarLibJsonForTesting(), Charsets.UTF_8))
- .getAsJsonObject()
- .get("version")
- .getAsString();
+ .getAsJsonObject();
+ String identifier =
+ jsonObject.has("version")
+ ? "com.tools.android:desugar_jdk_libs:" + jsonObject.get("version").getAsString()
+ : jsonObject.get("identifier").getAsString();
Matcher<Marker> l8Matcher =
allOf(
markerTool(Tool.L8),
markerCompilationMode(compilationMode),
- markerDesugaredLibraryIdentifier("com.tools.android:desugar_jdk_libs:" + version),
+ markerDesugaredLibraryIdentifier(identifier),
markerHasChecksums(false));
Matcher<Marker> r8Matcher =
allOf(
diff --git a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
index 028b4b7..e6cd425 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
@@ -297,17 +297,22 @@
.put(
DexVm.Version.V9_0_0,
ImmutableList.of(
- // TODO(120402963): Triage.
+ // TODO(b/120402963): Triage.
"invokecustom", "invokecustom2"))
.put(
DexVm.Version.V10_0_0,
ImmutableList.of(
- // TODO(120402963): Triage.
+ // TODO(b/120402963): Triage.
"invokecustom", "invokecustom2"))
.put(
DexVm.Version.V12_0_0,
ImmutableList.of(
- // TODO(120402963): Triage.
+ // TODO(b/120402963): Triage.
+ "invokecustom", "invokecustom2"))
+ .put(
+ Version.V13_MASTER,
+ ImmutableList.of(
+ // TODO(b/120402963): Triage.
"invokecustom", "invokecustom2"))
.put(DexVm.Version.DEFAULT, ImmutableList.of());
failsOn = builder.build();
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java b/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
index 2cb5556..d0db2c9 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/ApiLevelBackportsTest.java
@@ -6,7 +6,6 @@
import static org.hamcrest.core.StringContains.containsString;
-import com.android.tools.r8.D8TestRunResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -50,24 +49,31 @@
.compile()
.assertNoMessages()
.run(parameters.getRuntime(), TestMathMultiplyExactLongInt.class)
- .assertSuccessWithOutputLines("4");
+ .applyIf(
+ runtimeHasParseIntWithFourArgs(),
+ r -> r.assertSuccessWithOutputLines("4"),
+ r ->
+ r.assertFailureWithErrorThatMatches(
+ containsString(
+ "java.lang.NoSuchMethodError: No static method"
+ + " parseInt(Ljava/lang/CharSequence;III)I")));
}
@Test
public void backportOfPresentMethodOnLatest() throws Exception {
- D8TestRunResult result =
- testForD8()
- .addProgramClassFileData(transformTestListOf())
- .setMinApi(AndroidApiLevel.LATEST)
- .compile()
- .assertNoMessages()
- .run(parameters.getRuntime(), TestListOf.class);
- if (runtimeHasListOf()) {
- result.assertSuccessWithOutputLines("0");
- } else {
- result.assertFailureWithErrorThatMatches(
- containsString("java.lang.NoSuchMethodError: No static method of()Ljava/util/List;"));
- }
+ testForD8()
+ .addProgramClassFileData(transformTestListOf())
+ .setMinApi(AndroidApiLevel.LATEST)
+ .compile()
+ .assertNoMessages()
+ .run(parameters.getRuntime(), TestListOf.class)
+ .applyIf(
+ runtimeHasListOf(),
+ r -> r.assertSuccessWithOutputLines("0"),
+ r ->
+ r.assertFailureWithErrorThatMatches(
+ containsString(
+ "java.lang.NoSuchMethodError: No static method of()Ljava/util/List;")));
}
@Test
@@ -79,7 +85,14 @@
.assertOnlyWarnings()
.assertWarningMessageThatMatches(containsString("is not supported by this compiler"))
.run(parameters.getRuntime(), TestMathMultiplyExactLongInt.class)
- .assertSuccessWithOutputLines("4");
+ .applyIf(
+ runtimeHasParseIntWithFourArgs(),
+ r -> r.assertSuccessWithOutputLines("4"),
+ r ->
+ r.assertFailureWithErrorThatMatches(
+ containsString(
+ "java.lang.NoSuchMethodError: No static method"
+ + " parseInt(Ljava/lang/CharSequence;III)I")));
}
@Test
@@ -109,6 +122,14 @@
.isGreaterThanOrEqualTo(AndroidApiLevel.R);
}
+ boolean runtimeHasParseIntWithFourArgs() {
+ return parameters
+ .getRuntime()
+ .asDex()
+ .getMinApiLevel()
+ .isGreaterThanOrEqualTo(AndroidApiLevel.T);
+ }
+
byte[] transformTestListOf() throws Exception {
return transformer(TestListOf.class)
.transformMethodInsnInMethod(
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/IntegerBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/IntegerBackportJava9Test.java
index a2e1120..f8c5a53 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/IntegerBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/IntegerBackportJava9Test.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.runner.RunWith;
@@ -30,8 +31,11 @@
Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
public IntegerBackportJava9Test(TestParameters parameters) {
- super(parameters, Short.class, TEST_JAR, "backport.IntegerBackportJava9Main");
- // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
- // an actual API level, migrate these tests to IntegerBackportTest.
+ super(parameters, Integer.class, TEST_JAR, "backport.IntegerBackportJava9Main");
+ // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+ // Java 11 move these tests to IntegerBackportTest (out of examplesJava9).
+
+ registerTarget(AndroidApiLevel.O, 1);
+ registerTarget(AndroidApiLevel.T, 20);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/LongBackportJava9Test.java b/src/test/java/com/android/tools/r8/desugar/backports/LongBackportJava9Test.java
index 4bd90c8..487f80f 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/LongBackportJava9Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/LongBackportJava9Test.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.runner.RunWith;
@@ -30,8 +31,12 @@
Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR).resolve("backport" + JAR_EXTENSION);
public LongBackportJava9Test(TestParameters parameters) {
- super(parameters, Short.class, TEST_JAR, "backport.LongBackportJava9Main");
- // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
- // an actual API level, migrate these tests to LongBackportTest.
+ super(parameters, Long.class, TEST_JAR, "backport.LongBackportJava9Main");
+ // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+ // Java 11 move these tests to LongBackportTest (out of examplesJava9).
+
+ ignoreInvokes("toString");
+
+ registerTarget(AndroidApiLevel.T, 17);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/StringBackportJava11Test.java b/src/test/java/com/android/tools/r8/desugar/backports/StringBackportJava11Test.java
index b7f4b6d..6290238 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/StringBackportJava11Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/StringBackportJava11Test.java
@@ -4,17 +4,18 @@
package com.android.tools.r8.desugar.backports;
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
-
@RunWith(Parameterized.class)
public final class StringBackportJava11Test extends AbstractBackportTest {
@Parameters(name = "{0}")
@@ -31,7 +32,9 @@
public StringBackportJava11Test(TestParameters parameters) {
super(parameters, String.class, TEST_JAR, "backport.StringBackportJava11Main");
- // Note: None of the methods in this test exist in the latest android.jar. If/when they ship in
- // an actual API level, migrate these tests to CharacterBackportTest.
+ // Note: The methods in this test exist in android.jar from Android T. When R8 builds targeting
+ // Java 11 move these tests to StringBackportTest (out of examplesJava11).
+
+ registerTarget(AndroidApiLevel.T, 49);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
index b5e5c03..6d3a0d3 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
@@ -10,8 +10,8 @@
import com.android.tools.r8.StringResource;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -60,16 +60,16 @@
: "Caught j$.io.UncheckedIOException");
}
- LegacyDesugaredLibrarySpecification configurationAlternative3(
+ DesugaredLibrarySpecification configurationAlternative3(
InternalOptions options, boolean libraryCompilation, TestParameters parameters) {
// Parse the current configuration and amend the configuration for BufferedReader.lines. The
// configuration is the same for both program and library.
- return new LegacyDesugaredLibrarySpecificationParser(
- options.dexItemFactory(),
- options.reporter,
- libraryCompilation,
- parameters.getApiLevel().getLevel())
- .parse(StringResource.fromFile(ToolHelper.getDesugarLibJsonForTestingAlternative3()));
+ return DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecification(
+ StringResource.fromFile(ToolHelper.getDesugarLibJsonForTestingAlternative3()),
+ options.dexItemFactory(),
+ options.reporter,
+ libraryCompilation,
+ parameters.getApiLevel().getLevel());
}
private void configurationForProgramCompilation(InternalOptions options) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java
index e27dda9..4d87dbf 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryCHMOnlyContentTest.java
@@ -8,8 +8,8 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.nio.file.Path;
@@ -67,13 +67,13 @@
assert inspector.clazz("j$.util.concurrent.ConcurrentHashMap").isPresent();
}
- LegacyDesugaredLibrarySpecification chmOnlyConfiguration(
+ DesugaredLibrarySpecification chmOnlyConfiguration(
InternalOptions options, boolean libraryCompilation, TestParameters parameters) {
- return new LegacyDesugaredLibrarySpecificationParser(
- options.dexItemFactory(),
- options.reporter,
- libraryCompilation,
- parameters.getApiLevel().getLevel())
- .parse(StringResource.fromFile(ToolHelper.getCHMOnlyDesugarLibJsonForTesting()));
+ return DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecification(
+ StringResource.fromFile(ToolHelper.getCHMOnlyDesugarLibJsonForTesting()),
+ options.dexItemFactory(),
+ options.reporter,
+ libraryCompilation,
+ parameters.getApiLevel().getLevel());
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
index f4786f7..2684b3b 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
@@ -5,16 +5,15 @@
package com.android.tools.r8.desugar.desugaredlibrary;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertTrue;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.fail;
+import com.android.tools.r8.D8TestBuilder;
import com.android.tools.r8.L8Command;
-import com.android.tools.r8.L8TestBuilder;
+import com.android.tools.r8.LibraryDesugaringTestConfiguration;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.StringResource;
import com.android.tools.r8.TestDiagnosticMessages;
@@ -29,7 +28,6 @@
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import java.nio.file.Path;
import java.util.ArrayList;
-import java.util.Collections;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -50,22 +48,22 @@
}
@Test
- public void testInvalidLibrary() throws Exception {
+ public void testInvalidLibrary() {
Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
- L8TestBuilder l8TestBuilder =
- testForL8(parameters.getApiLevel())
- .addProgramFiles(Collections.singleton(ToolHelper.getDesugarJDKLibs()))
+ D8TestBuilder testBuilder =
+ testForD8()
+ .setMinApi(parameters.getApiLevel())
+ .addProgramClasses(GuineaPig.class)
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.L))
- .setDesugarJDKLibsConfiguration(ToolHelper.DESUGAR_LIB_CONVERSIONS);
+ .enableCoreLibraryDesugaring(
+ LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()));
try {
- l8TestBuilder.compile();
- fail();
- } catch (AssertionError ae) {
- // Expected since the library is invalid.
+ testBuilder.compile();
+ } catch (Throwable t) {
+ // Expected since we are compiling with an invalid set-up.
}
- TestDiagnosticMessages diagnosticMessages = l8TestBuilder.getDiagnosticMessages();
+ TestDiagnosticMessages diagnosticMessages = testBuilder.getState().getDiagnosticsMessages();
diagnosticMessages.assertOnlyWarnings();
- assertEquals(diagnosticMessages.getWarnings().size(), 1);
assertTrue(
diagnosticMessages
.getWarnings()
@@ -121,21 +119,7 @@
ToolHelper.runL8(l8Builder.build(), options -> {});
CodeInspector codeInspector = new CodeInspector(desugaredLib);
assertCorrect(codeInspector);
- assertOneWarning(diagnosticsHandler);
- }
-
- private void assertOneWarning(TestDiagnosticMessagesImpl diagnosticsHandler) {
- assertEquals(
- (isJDK11DesugaredLibrary() && parameters.getApiLevel().isLessThan(AndroidApiLevel.O))
- ? 2
- : 1,
- diagnosticsHandler.getWarnings().size());
- String msg = diagnosticsHandler.getWarnings().get(0).getDiagnosticMessage();
- assertTrue(
- msg.contains(
- "The following library types, prefixed by java., are present both as library and non"
- + " library classes"));
- assertTrue(diagnosticsHandler.getErrors().isEmpty());
+ diagnosticsHandler.assertNoMessages();
}
private void assertCorrect(CodeInspector inspector) {
@@ -166,4 +150,8 @@
}
}
+ static class GuineaPig {
+
+ public static void main(String[] args) {}
+ }
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryMismatchTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryMismatchTest.java
index 1409ec7..d80d01d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryMismatchTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryMismatchTest.java
@@ -65,14 +65,18 @@
.enableCoreLibraryDesugaring(LibraryDesugaringTestConfiguration.forApiLevel(apiLevel))
.compileWithExpectedDiagnostics(
diagnostics -> {
- diagnostics.assertNoInfos();
- diagnostics.assertAllWarningsMatch(
- diagnosticMessage(
- containsString(
- "The compilation is slowed down due to a mix of class file and dex"
- + " file inputs in the context of desugared library.")));
- diagnostics.assertErrorsMatch(
- diagnosticType(DesugaredLibraryMismatchDiagnostic.class));
+ if (requiresAnyCoreLibDesugaring(apiLevel)) {
+ diagnostics.assertNoInfos();
+ diagnostics.assertAllWarningsMatch(
+ diagnosticMessage(
+ containsString(
+ "The compilation is slowed down due to a mix of class file and dex"
+ + " file inputs in the context of desugared library.")));
+ diagnostics.assertErrorsMatch(
+ diagnosticType(DesugaredLibraryMismatchDiagnostic.class));
+ } else {
+ diagnostics.assertNoMessages();
+ }
});
} catch (CompilationFailedException e) {
@@ -146,9 +150,13 @@
.setMinApi(apiLevel)
.compileWithExpectedDiagnostics(
diagnostics -> {
- diagnostics.assertOnlyErrors();
- diagnostics.assertErrorsMatch(
- diagnosticType(DesugaredLibraryMismatchDiagnostic.class));
+ if (requiresAnyCoreLibDesugaring(apiLevel)) {
+ diagnostics.assertOnlyErrors();
+ diagnostics.assertErrorsMatch(
+ diagnosticType(DesugaredLibraryMismatchDiagnostic.class));
+ } else {
+ diagnostics.assertNoMessages();
+ }
});
} catch (CompilationFailedException e) {
}
@@ -181,9 +189,13 @@
.setMinApi(apiLevel)
.compileWithExpectedDiagnostics(
diagnostics -> {
- diagnostics.assertOnlyErrors();
- diagnostics.assertErrorsMatch(
- diagnosticType(DesugaredLibraryMismatchDiagnostic.class));
+ if (requiresAnyCoreLibDesugaring(apiLevel)) {
+ diagnostics.assertOnlyErrors();
+ diagnostics.assertErrorsMatch(
+ diagnosticType(DesugaredLibraryMismatchDiagnostic.class));
+ } else {
+ diagnostics.assertNoMessages();
+ }
});
} catch (CompilationFailedException e) {
}
@@ -211,7 +223,10 @@
+ "\"version\":\"1.0.9\","
+ "\"synthesized_library_classes_package_prefix\":\"my_prefix\","
+ "\"required_compilation_api_level\":\"30\","
- + "\"common_flags\":[],"
+ + "\"common_flags\":[{"
+ + " \"api_level_below_or_equal\": 9999,"
+ + " \"rewrite_prefix\": {\"j$.time.\": \"java.time.\"}"
+ + " }],"
+ "\"library_flags\":[],"
+ "\"program_flags\":[]"
+ "}",
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
index eb25adf..56f687c 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
@@ -24,8 +24,8 @@
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
import com.android.tools.r8.tracereferences.TraceReferences;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.FileUtils;
@@ -68,7 +68,7 @@
}
public void setDesugaredLibrarySpecificationForTesting(
- InternalOptions options, LegacyDesugaredLibrarySpecification specification) {
+ InternalOptions options, DesugaredLibrarySpecification specification) {
try {
options.setDesugaredLibrarySpecificationForTesting(
specification,
@@ -117,10 +117,14 @@
}
protected boolean requiresAnyCoreLibDesugaring(TestParameters parameters) {
- return parameters.getApiLevel().getLevel()
+ return requiresAnyCoreLibDesugaring(parameters.getApiLevel());
+ }
+
+ protected boolean requiresAnyCoreLibDesugaring(AndroidApiLevel apiLevel) {
+ return apiLevel.getLevel()
<= (isJDK11DesugaredLibrary()
? AndroidApiLevel.LATEST.getLevel()
- : AndroidApiLevel.N.getLevel());
+ : AndroidApiLevel.N_MR1.getLevel());
}
protected L8TestBuilder testForL8(AndroidApiLevel apiLevel) {
@@ -245,19 +249,18 @@
return desugaredLib;
}
- protected LegacyDesugaredLibrarySpecification configurationWithSupportAllCallbacksFromLibrary(
+ protected DesugaredLibrarySpecification configurationWithSupportAllCallbacksFromLibrary(
InternalOptions options,
boolean libraryCompilation,
TestParameters parameters,
boolean supportAllCallbacksFromLibrary) {
- return new LegacyDesugaredLibrarySpecificationParser(
- options.dexItemFactory(),
- options.reporter,
- libraryCompilation,
- parameters.getApiLevel().getLevel())
- .parse(
- StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()),
- builder -> builder.setSupportAllCallbacksFromLibrary(supportAllCallbacksFromLibrary));
+ return DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecificationforTesting(
+ StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()),
+ options.dexItemFactory(),
+ options.reporter,
+ libraryCompilation,
+ parameters.getApiLevel().getLevel(),
+ builder -> builder.setSupportAllCallbacksFromLibrary(supportAllCallbacksFromLibrary));
}
private Map<AndroidApiLevel, Path> desugaredLibraryClassFileCache = new HashMap<>();
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java
index 47b01f1..0c61a06 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryWarningTest.java
@@ -4,9 +4,6 @@
package com.android.tools.r8.desugar.desugaredlibrary;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.L8Command;
import com.android.tools.r8.OutputMode;
@@ -15,7 +12,6 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import java.nio.file.Path;
import java.util.Arrays;
@@ -69,19 +65,6 @@
Arrays.asList(FUNCTION_KEEP.split(System.lineSeparator())), Origin.unknown());
}
ToolHelper.runL8(l8Builder.build(), options -> {});
- assertEquals(
- (isJDK11DesugaredLibrary() && parameters.getApiLevel().isLessThan(AndroidApiLevel.O))
- ? 2
- : 1,
- diagnosticsHandler.getWarnings().size());
- diagnosticsHandler.assertNoErrors();
- assertTrue(
- diagnosticsHandler
- .getWarnings()
- .get(0)
- .getDiagnosticMessage()
- .contains(
- "The following library types, prefixed by java., are present both as library and"
- + " non library classes:"));
+ diagnosticsHandler.assertNoMessages();
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
index 21dc2f9..86d87d5 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
@@ -10,20 +10,22 @@
import com.android.tools.r8.GenerateLintFiles;
import com.android.tools.r8.StringResource;
-import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.references.TypeReference;
import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.WorkList;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -46,7 +48,7 @@
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
-public class ExtractWrapperTypesTest extends TestBase {
+public class ExtractWrapperTypesTest extends DesugaredLibraryTestBase {
// Filter on types that do not need to be considered for wrapping.
private static boolean doesNotNeedWrapper(String type, Set<String> customConversions) {
@@ -128,11 +130,22 @@
CodeInspector desugaredApiJar = getDesugaredApiJar();
Set<ClassReference> preDesugarTypes = getPreDesugarTypes();
- LegacyDesugaredLibrarySpecification spec = getDesugaredLibraryConfiguration();
+ DexItemFactory factory = new DexItemFactory();
+ DesugaredLibrarySpecification spec =
+ DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecification(
+ StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()),
+ factory,
+ null,
+ false,
+ minApi.getLevel());
+ MachineDesugaredLibrarySpecification specification =
+ spec.toMachineSpecification(new InternalOptions(factory, new Reporter()), getLibraryFile());
Set<String> wrappersInSpec =
- spec.getWrapperConversions().stream().map(DexType::toString).collect(Collectors.toSet());
+ specification.getWrappers().keySet().stream()
+ .map(DexType::toString)
+ .collect(Collectors.toSet());
Set<String> customConversionsInSpec =
- spec.getCustomConversions().keySet().stream()
+ specification.getCustomConversions().keySet().stream()
.map(DexType::toString)
.collect(Collectors.toSet());
assertEquals(
@@ -191,13 +204,6 @@
return missingWrappers;
}
- private LegacyDesugaredLibrarySpecification getDesugaredLibraryConfiguration() {
- LegacyDesugaredLibrarySpecificationParser parser =
- new LegacyDesugaredLibrarySpecificationParser(
- new DexItemFactory(), null, true, minApi.getLevel());
- return parser.parse(StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
- }
-
private Map<ClassReference, Set<MethodReference>> getDirectlyReferencedWrapperTypes(
CodeInspector desugaredApiJar,
Set<ClassReference> preDesugarTypes,
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryConfigurationParsingTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LegacyDesugaredLibraryConfigurationParsingTest.java
similarity index 96%
rename from src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryConfigurationParsingTest.java
rename to src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LegacyDesugaredLibraryConfigurationParsingTest.java
index efc5ce8..83316eb 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryConfigurationParsingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LegacyDesugaredLibraryConfigurationParsingTest.java
@@ -1,4 +1,4 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// 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.desugar.desugaredlibrary;
@@ -12,7 +12,6 @@
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.StringResource;
-import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestDiagnosticMessages;
import com.android.tools.r8.TestDiagnosticMessagesImpl;
import com.android.tools.r8.TestParameters;
@@ -38,19 +37,20 @@
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;
+import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
-public class DesugaredLibraryConfigurationParsingTest extends TestBase {
+public class LegacyDesugaredLibraryConfigurationParsingTest extends DesugaredLibraryTestBase {
@Parameterized.Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withNoneRuntime().build();
}
- public DesugaredLibraryConfigurationParsingTest(TestParameters parameters) {
+ public LegacyDesugaredLibraryConfigurationParsingTest(TestParameters parameters) {
parameters.assertNoneRuntime();
}
@@ -87,6 +87,7 @@
}
private LegacyDesugaredLibrarySpecificationParser parser(DiagnosticsHandler handler) {
+ Assume.assumeFalse(isJDK11DesugaredLibrary());
return new LegacyDesugaredLibrarySpecificationParser(
factory, new Reporter(handler), libraryCompilation, minApi.getLevel());
}
@@ -179,7 +180,7 @@
@Test
public void testUnsupportedAbove() {
LinkedHashMap<String, Object> data = template();
- data.put("configuration_format_version", 100000);
+ data.put("configuration_format_version", 99);
runFailing(
toJson(data),
diagnostics ->
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
index d296ec9..cd54e5d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
@@ -14,8 +14,8 @@
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -125,10 +125,13 @@
directory.toString()
});
InternalOptions options = new InternalOptions(new DexItemFactory(), new Reporter());
- LegacyDesugaredLibrarySpecification desugaredLibrarySpecification =
- new LegacyDesugaredLibrarySpecificationParser(
- options.itemFactory, options.reporter, false, AndroidApiLevel.B.getLevel())
- .parse(StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
+ DesugaredLibrarySpecification desugaredLibrarySpecification =
+ DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecification(
+ StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()),
+ options.itemFactory,
+ options.reporter,
+ false,
+ AndroidApiLevel.B.getLevel());
for (AndroidApiLevel apiLevel : AndroidApiLevel.values()) {
if (apiLevel.isGreaterThan(AndroidApiLevel.Sv2)) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
index ed772cb..c21b7ea 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
@@ -15,8 +15,8 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -84,18 +84,17 @@
Ordered.max(parameters.getApiLevel(), getRequiredCompilationAPILevel()));
}
- LegacyDesugaredLibrarySpecification desugaredLibrarySpecification(
+ DesugaredLibrarySpecification desugaredLibrarySpecification(
InternalOptions options, boolean libraryCompilation, TestParameters parameters) {
- return new LegacyDesugaredLibrarySpecificationParser(
- options.dexItemFactory(),
- options.reporter,
- libraryCompilation,
- parameters.getApiLevel().getLevel())
- .parse(
- StringResource.fromFile(
- libraryDesugarJavaUtilObjects
- ? ToolHelper.getDesugarLibJsonForTestingAlternative3()
- : ToolHelper.getDesugarLibJsonForTesting()));
+ return DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecification(
+ StringResource.fromFile(
+ libraryDesugarJavaUtilObjects
+ ? ToolHelper.getDesugarLibJsonForTestingAlternative3()
+ : ToolHelper.getDesugarLibJsonForTesting()),
+ options.dexItemFactory(),
+ options.reporter,
+ libraryCompilation,
+ parameters.getApiLevel().getLevel());
}
private void configurationForProgramCompilation(InternalOptions options) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
index 4d861a0..125b4ec 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
@@ -8,10 +8,10 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.StringResource;
-import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
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;
@@ -31,9 +31,7 @@
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
-public class ConvertExportReadTest extends TestBase {
-
- private final TestParameters parameters;
+public class ConvertExportReadTest extends DesugaredLibraryTestBase {
@Parameterized.Parameters(name = "{0}")
public static TestParametersCollection data() {
@@ -41,7 +39,7 @@
}
public ConvertExportReadTest(TestParameters parameters) {
- this.parameters = parameters;
+ assert parameters.isNoneRuntime();
}
@Test
@@ -98,25 +96,27 @@
HumanRewritingFlags humanRewritingFlags1, HumanRewritingFlags humanRewritingFlags2) {
assertEquals(humanRewritingFlags1.getRewritePrefix(), humanRewritingFlags2.getRewritePrefix());
assertEquals(
- humanRewritingFlags1.getBackportCoreLibraryMember(),
- humanRewritingFlags2.getBackportCoreLibraryMember());
+ humanRewritingFlags1.getRewriteDerivedPrefix(),
+ humanRewritingFlags2.getRewriteDerivedPrefix());
+
+ assertEquals(
+ humanRewritingFlags1.getLegacyBackport(), humanRewritingFlags2.getLegacyBackport());
assertEquals(
humanRewritingFlags1.getCustomConversions(), humanRewritingFlags2.getCustomConversions());
assertEquals(
- humanRewritingFlags1.getEmulateLibraryInterface(),
- humanRewritingFlags2.getEmulateLibraryInterface());
+ humanRewritingFlags1.getEmulatedInterfaces(), humanRewritingFlags2.getEmulatedInterfaces());
assertEquals(
- humanRewritingFlags1.getRetargetCoreLibMember(),
- humanRewritingFlags2.getRetargetCoreLibMember());
+ humanRewritingFlags1.getRetargetMethod(), humanRewritingFlags2.getRetargetMethod());
- assertEquals(
- humanRewritingFlags1.getDontRetargetLibMember(),
- humanRewritingFlags2.getDontRetargetLibMember());
+ assertEquals(humanRewritingFlags1.getDontRetarget(), humanRewritingFlags2.getDontRetarget());
assertEquals(
humanRewritingFlags1.getDontRewriteInvocation(),
humanRewritingFlags2.getDontRewriteInvocation());
assertEquals(
humanRewritingFlags1.getWrapperConversions(), humanRewritingFlags2.getWrapperConversions());
+
+ assertEquals(
+ humanRewritingFlags1.getAmendLibraryMethod(), humanRewritingFlags2.getAmendLibraryMethod());
}
private void assertTopLevelFlagsEquals(
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceMethodDesugaringTests.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceMethodDesugaringTests.java
index cbe8874..5b700d5 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceMethodDesugaringTests.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InterfaceMethodDesugaringTests.java
@@ -138,7 +138,7 @@
}
@Test(expected = CompilationFailedException.class)
- @IgnoreForRangeOfVmVersions(from = Version.V7_0_0, to = Version.V12_0_0) // No desugaring
+ @IgnoreForRangeOfVmVersions(from = Version.V7_0_0, to = Version.V13_MASTER) // No desugaring
public void testInvokeDefault1() throws Exception {
ensureSameOutput(
TestMainDefault1.class.getCanonicalName(),
diff --git a/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignaturePartialTypeArgumentApplierTest.java b/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignaturePartialTypeArgumentApplierTest.java
index da89df6..4b04321 100644
--- a/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignaturePartialTypeArgumentApplierTest.java
+++ b/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignaturePartialTypeArgumentApplierTest.java
@@ -33,6 +33,7 @@
import java.util.Map;
import java.util.Set;
import java.util.function.BiPredicate;
+import java.util.function.Function;
import java.util.function.Predicate;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -121,7 +122,7 @@
MapUtils.transform(
substitutions,
HashMap::new,
- s -> s,
+ Function.identity(),
ClassTypeSignature::new,
(key, val1, val2) -> {
throw new Unreachable("No keys should be merged");
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/backports/IntegerMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/backports/IntegerMethods.java
index bc84108..b7ddc31 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/backports/IntegerMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/backports/IntegerMethods.java
@@ -73,4 +73,9 @@
}
return Integer.parseInt(s.subSequence(beginIndex, endIndex).toString(), radix);
}
+
+ public static int parseUnsignedIntSubsequenceWithRadix(
+ CharSequence s, int beginIndex, int endIndex, int radix) throws NumberFormatException {
+ return Integer.parseUnsignedInt(s.subSequence(beginIndex, endIndex).toString(), radix);
+ }
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInnerClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInnerClassTest.java
index 5cc9de6..aa3a51d 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInnerClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInnerClassTest.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.ClassFileConsumer;
import com.android.tools.r8.DexIndexedConsumer.ArchiveConsumer;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion;
import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.ProgramConsumer;
import com.android.tools.r8.TestParameters;
@@ -41,6 +42,20 @@
private final TestParameters parameters;
+ private String getExpected() {
+ return replaceInitNameInExpectedBasedOnKotlinVersion(EXPECTED);
+ }
+
+ private String getExpectedOuterRenamed() {
+ return replaceInitNameInExpectedBasedOnKotlinVersion(EXPECTED_OUTER_RENAMED);
+ }
+
+ private String replaceInitNameInExpectedBasedOnKotlinVersion(String expected) {
+ return kotlinParameters.isNewerThanOrEqualTo(KotlinCompilerVersion.KOTLIN_DEV)
+ ? expected.replace("<init>", "`<init>`")
+ : expected;
+ }
+
@Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
@@ -64,7 +79,7 @@
testForRuntime(parameters)
.addProgramFiles(kotlinc.getKotlinStdlibJar(), kotlinc.getKotlinReflectJar(), libJar)
.run(parameters.getRuntime(), PKG_NESTED_REFLECT + ".MainKt")
- .assertSuccessWithOutput(EXPECTED);
+ .assertSuccessWithOutput(getExpected());
}
@Test
@@ -83,8 +98,7 @@
.compile()
.inspect(inspector -> inspectPruned(inspector, true))
.writeToZip();
-
- runD8(mainJar, EXPECTED_OUTER_RENAMED);
+ runD8(mainJar, getExpectedOuterRenamed());
}
@Test
@@ -105,8 +119,7 @@
.compile()
.inspect(inspector -> inspectPruned(inspector, false))
.writeToZip();
-
- runD8(mainJar, EXPECTED);
+ runD8(mainJar, getExpected());
}
private void runD8(Path jar, String expected) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/kotlin/stringplus/StringPlusTest.java b/src/test/java/com/android/tools/r8/kotlin/stringplus/StringPlusTest.java
new file mode 100644
index 0000000..170595a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/stringplus/StringPlusTest.java
@@ -0,0 +1,113 @@
+// 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.kotlin.stringplus;
+
+import static com.android.tools.r8.ToolHelper.getFilesInTestFolderRelativeToClass;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.KotlinCompilerTool;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion;
+import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeMatchers;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class StringPlusTest extends KotlinTestBase {
+
+ private static final String MAIN = "com.android.tools.r8.kotlin.sealed.kt.StringPlusKt";
+ private static final String[] EXPECTED =
+ new String[] {
+ "Hello World!",
+ "Hello World!",
+ "StringConcat(Hello World!)",
+ "StringBuilder[Hello World!]",
+ "abc"
+ };
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}, {1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+ }
+
+ public StringPlusTest(TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
+ this.parameters = parameters;
+ }
+
+ private static final KotlinCompileMemoizer compilationResults =
+ getCompileMemoizer(getKotlinSources()).configure(KotlinCompilerTool::includeRuntime);
+
+ private static Collection<Path> getKotlinSources() {
+ try {
+ return getFilesInTestFolderRelativeToClass(StringPlusTest.class, "kt", ".kt");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Test
+ public void testRuntime() throws ExecutionException, CompilationFailedException, IOException {
+ testForRuntime(parameters)
+ .addProgramFiles(compilationResults.getForConfiguration(kotlinc, targetVersion))
+ .run(parameters.getRuntime(), MAIN)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ @Test
+ public void testR8() throws ExecutionException, CompilationFailedException, IOException {
+ testForR8(parameters.getBackend())
+ .addProgramFiles(compilationResults.getForConfiguration(kotlinc, targetVersion))
+ .addProgramFiles(kotlinc.getKotlinAnnotationJar())
+ .setMinApi(parameters.getApiLevel())
+ .allowAccessModification()
+ .allowDiagnosticWarningMessages()
+ .addKeepMainRule(MAIN)
+ .addKeepRules("-keep class " + MAIN + "{ void keepFor*(...); }")
+ .noMinification()
+ .compile()
+ .inspect(
+ inspector -> {
+ if (parameters.isCfRuntime()) {
+ return;
+ }
+ ClassSubject clazz = inspector.clazz(MAIN);
+ assertThat(clazz, isPresent());
+ MethodSubject methodSubject = clazz.mainMethod();
+ assertThat(methodSubject, isPresent());
+ if (kotlinParameters.isNewerThanOrEqualTo(KotlinCompilerVersion.KOTLINC_1_5_0)
+ && kotlinParameters.isOlderThan(KotlinCompilerVersion.KOTLIN_DEV)) {
+ // TODO(b/190489514): We should be able to optimize constant stringPlus calls.
+ assertThat(methodSubject, CodeMatchers.invokesMethodWithName("stringPlus"));
+ }
+ // TODO(b/219455761): StringBuilderOptimizer fails to remove constant input.
+ assertThat(
+ methodSubject,
+ CodeMatchers.invokesMethodWithHolderAndName(
+ typeName(StringBuilder.class), "append"));
+ })
+ .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
+ .run(parameters.getRuntime(), MAIN)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/stringplus/kt/StringPlus.kt b/src/test/java/com/android/tools/r8/kotlin/stringplus/kt/StringPlus.kt
new file mode 100644
index 0000000..4213f76
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/stringplus/kt/StringPlus.kt
@@ -0,0 +1,33 @@
+// 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.kotlin.sealed.kt
+
+fun string1() : String {
+ return "Hello "
+}
+
+fun string2() : String {
+ return "World!"
+}
+
+fun main() {
+ println(string1() + string2())
+ println(string1().plus(string2()))
+ println("StringConcat(" + string1() + string2() + ")")
+ println(StringBuilder().append("StringBuilder[").append(string1()).append(string2()).append("]"))
+ var foo = "a";
+ foo = foo + "b";
+ println(foo + "c")
+}
+
+fun keepForNoMemberRebinding() {
+ println((if (System.currentTimeMillis() > 0) "foo" else "bar")
+ + (if (System.currentTimeMillis() > 0) "baz" else "qux"))
+}
+
+fun keepForNoDoubleInlining() {
+ println((if (System.currentTimeMillis() > 0) "ini" else "mini")
+ + (if (System.currentTimeMillis() > 0) "miny" else "moe"))
+}
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithInstanceInitializerCollisionTest.java b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithInstanceInitializerCollisionTest.java
new file mode 100644
index 0000000..66a4cdc
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithInstanceInitializerCollisionTest.java
@@ -0,0 +1,107 @@
+// 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.optimize.proto;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NoHorizontalClassMerging;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.android.tools.r8.utils.codeinspector.TypeSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ProtoNormalizationWithInstanceInitializerCollisionTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addOptionsModification(
+ options -> options.testing.enableExperimentalProtoNormalization = true)
+ .enableNoHorizontalClassMergingAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ ClassSubject mainClassSubject = inspector.clazz(Main.class);
+ assertThat(mainClassSubject, isPresent());
+
+ ClassSubject aClassSubject = inspector.clazz(A.class);
+ assertThat(aClassSubject, isPresent());
+
+ ClassSubject bClassSubject = inspector.clazz(B.class);
+ assertThat(bClassSubject, isPresent());
+
+ TypeSubject aTypeSubject = aClassSubject.asTypeSubject();
+ TypeSubject bTypeSubject = bClassSubject.asTypeSubject();
+
+ // Main.<init>(A, B) is unchanged.
+ MethodSubject initMethodSubject =
+ mainClassSubject.initFromTypes(aTypeSubject, bTypeSubject);
+ assertThat(initMethodSubject, isPresent());
+
+ // Main.<init>(B, A) is unchanged.
+ MethodSubject otherInitMethodSubject =
+ mainClassSubject.initFromTypes(bTypeSubject, aTypeSubject);
+ assertThat(otherInitMethodSubject, isPresent());
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A", "B", "A", "B");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ new Main(new A(), new B());
+ new Main(new B(), new A());
+ }
+
+ Main(A a, B b) {
+ System.out.println(a);
+ System.out.println(b);
+ }
+
+ Main(B b, A a) {
+ System.out.println(a);
+ System.out.println(b);
+ }
+ }
+
+ @NoHorizontalClassMerging
+ static class A {
+
+ @Override
+ public String toString() {
+ return "A";
+ }
+ }
+
+ @NoHorizontalClassMerging
+ static class B {
+
+ @Override
+ public String toString() {
+ return "B";
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithParameterAnnotationsTest.java b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithParameterAnnotationsTest.java
new file mode 100644
index 0000000..a9b9af9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithParameterAnnotationsTest.java
@@ -0,0 +1,153 @@
+// 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.optimize.proto;
+
+import static com.android.tools.r8.utils.codeinspector.AnnotationMatchers.hasParameterAnnotationTypes;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.MethodMatchers.hasParameters;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoHorizontalClassMerging;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.android.tools.r8.utils.codeinspector.TypeSubject;
+import com.google.common.collect.ImmutableList;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ProtoNormalizationWithParameterAnnotationsTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8Compat(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addKeepClassAndMembersRules(Foo.class, Bar.class)
+ .addKeepRuntimeVisibleAnnotations()
+ .addOptionsModification(
+ options -> options.testing.enableExperimentalProtoNormalization = true)
+ .enableInliningAnnotations()
+ .enableNoHorizontalClassMergingAnnotations()
+ // TODO(b/173398086): uniqueMethodWithName() does not work with proto changes.
+ .noMinification()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ ClassSubject mainClassSubject = inspector.clazz(Main.class);
+ assertThat(mainClassSubject, isPresent());
+
+ TypeSubject aTypeSubject = inspector.clazz(A.class).asTypeSubject();
+ TypeSubject bTypeSubject = inspector.clazz(B.class).asTypeSubject();
+ TypeSubject fooTypeSubject = inspector.clazz(Foo.class).asTypeSubject();
+ TypeSubject barTypeSubject = inspector.clazz(Bar.class).asTypeSubject();
+
+ // Main.bar() has parameter annotations [@Bar, @Foo].
+ MethodSubject barMethodSubject = mainClassSubject.uniqueMethodWithName("bar");
+ assertThat(barMethodSubject, isPresent());
+ assertThat(barMethodSubject, hasParameters(aTypeSubject, bTypeSubject));
+ assertThat(
+ barMethodSubject,
+ hasParameterAnnotationTypes(
+ ImmutableList.of(barTypeSubject), ImmutableList.of(fooTypeSubject)));
+
+ // Main.baz() has parameter annotations [, @Foo].
+ MethodSubject bazMethodSubject = mainClassSubject.uniqueMethodWithName("baz");
+ assertThat(bazMethodSubject, isPresent());
+ assertThat(bazMethodSubject, hasParameters(aTypeSubject, bTypeSubject));
+ assertThat(
+ bazMethodSubject,
+ hasParameterAnnotationTypes(
+ ImmutableList.of(), ImmutableList.of(fooTypeSubject)));
+
+ // Main.qux() has parameter annotations [@Foo, ].
+ MethodSubject quxMethodSubject = mainClassSubject.uniqueMethodWithName("qux");
+ assertThat(quxMethodSubject, isPresent());
+ assertThat(quxMethodSubject, hasParameters(aTypeSubject, bTypeSubject));
+ assertThat(
+ quxMethodSubject,
+ hasParameterAnnotationTypes(
+ ImmutableList.of(fooTypeSubject), ImmutableList.of()));
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A", "B", "A", "B", "A", "B", "A", "B");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ foo(new A(), new B());
+ bar(new B(), new A());
+ baz(new B(), new A());
+ qux(new B(), new A());
+ }
+
+ @NeverInline
+ static void foo(A a, B b) {
+ System.out.println(a);
+ System.out.println(b);
+ }
+
+ @NeverInline
+ static void bar(@Foo B b, @Bar A a) {
+ System.out.println(a);
+ System.out.println(b);
+ }
+
+ @NeverInline
+ static void baz(@Foo B b, A a) {
+ System.out.println(a);
+ System.out.println(b);
+ }
+
+ @NeverInline
+ static void qux(B b, @Foo A a) {
+ System.out.println(a);
+ System.out.println(b);
+ }
+ }
+
+ @NoHorizontalClassMerging
+ static class A {
+
+ @Override
+ public String toString() {
+ return "A";
+ }
+ }
+
+ @NoHorizontalClassMerging
+ static class B {
+
+ @Override
+ public String toString() {
+ return "B";
+ }
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface Foo {}
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface Bar {}
+}
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithoutSharingTest.java b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithoutSharingTest.java
index 0088b3b..d9190df 100644
--- a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithoutSharingTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithoutSharingTest.java
@@ -41,8 +41,6 @@
options -> options.testing.enableExperimentalProtoNormalization = true)
.enableInliningAnnotations()
.enableNoHorizontalClassMergingAnnotations()
- // TODO(b/173398086): uniqueMethodWithName() does not work with proto changes.
- .noMinification()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(
diff --git a/src/test/java/com/android/tools/r8/shaking/negatedrules/NegatedMethodArgumentTest.java b/src/test/java/com/android/tools/r8/shaking/negatedrules/NegatedMethodArgumentTest.java
new file mode 100644
index 0000000..b4d6576
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/negatedrules/NegatedMethodArgumentTest.java
@@ -0,0 +1,131 @@
+// 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.shaking.negatedrules;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.ProguardVersion;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class NegatedMethodArgumentTest extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ private static final String EXPECTED_OUTPUT = StringUtils.lines("Hello, world!");
+
+ @Test
+ public void testR8NegatedPrimitive() throws Exception {
+ assertThrows(
+ CompilationFailedException.class,
+ () ->
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .addKeepRules("-keep class * { void setX(!%); }")
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT));
+ }
+
+ @Test
+ public void testR8NegatedClass() throws Exception {
+ assertThrows(
+ CompilationFailedException.class,
+ () ->
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .addKeepRules("-keep class * { void setX(!**Producer); }")
+ .compile());
+ }
+
+ private void classPresentWithOnlyInstanceInitializer(ClassSubject subject) {
+ assertThat(subject, isPresent());
+ assertTrue(subject.allMethods().stream().allMatch(FoundMethodSubject::isInstanceInitializer));
+ }
+
+ @Test
+ public void testProguardNegatedPrimitive() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
+ testForProguard(ProguardVersion.V7_0_0)
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
+ .addKeepRules("-keep class * { void setX(!%); }")
+ .addKeepRules("-dontwarn **.NegatedMethodArgumentTest")
+ .noMinification()
+ .run(parameters.getRuntime(), TestClass.class)
+ .inspect(
+ inspector -> {
+ classPresentWithOnlyInstanceInitializer(inspector.clazz(A.class));
+ classPresentWithOnlyInstanceInitializer(inspector.clazz(B.class));
+ })
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ @Test
+ public void testProguardNegatedClass() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
+ testForProguard(ProguardVersion.V7_0_0)
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
+ .addKeepRules("-keep class * { void setX(!**.*P1); }")
+ .addKeepRules("-dontwarn **.NegatedMethodArgumentTest")
+ .noMinification()
+ .run(parameters.getRuntime(), TestClass.class)
+ .inspect(
+ inspector -> {
+ classPresentWithOnlyInstanceInitializer(inspector.clazz(A.class));
+ classPresentWithOnlyInstanceInitializer(inspector.clazz(B.class));
+ })
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ static class P1 {}
+
+ static class P2 {}
+
+ static class A {
+
+ public void setX(int x) {}
+
+ public void setX(P1 x) {}
+ }
+
+ static class B {
+
+ public void setX(int x) {}
+
+ public void setX(P2 x) {}
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ System.out.println("Hello, world!");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
index 7f35d90..61c6fb5 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
@@ -115,7 +115,7 @@
}
@Override
- public List<AnnotationSubject> annotations() {
+ public List<FoundAnnotationSubject> annotations() {
throw new Unreachable("Cannot determine if an absent class has annotations");
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentFieldSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentFieldSubject.java
index 8d91f3c..6eeab19 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentFieldSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentFieldSubject.java
@@ -60,7 +60,7 @@
}
@Override
- public List<AnnotationSubject> annotations() {
+ public List<FoundAnnotationSubject> annotations() {
throw new Unreachable("Cannot determine if an absent field has annotations");
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
index 9be6468..a4fb7b4 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
@@ -87,6 +87,16 @@
}
@Override
+ public List<List<FoundAnnotationSubject>> getParameterAnnotations() {
+ throw new Unreachable("Cannot get the parameter annotations for an absent method");
+ }
+
+ @Override
+ public List<FoundAnnotationSubject> getParameterAnnotations(int index) {
+ throw new Unreachable("Cannot get the parameter annotations for an absent method");
+ }
+
+ @Override
public ProgramMethod getProgramMethod() {
return null;
}
@@ -127,7 +137,7 @@
}
@Override
- public List<AnnotationSubject> annotations() {
+ public List<FoundAnnotationSubject> annotations() {
throw new Unreachable("Cannot determine if an absent method has annotations");
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AnnotationMatchers.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AnnotationMatchers.java
new file mode 100644
index 0000000..8965f41
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AnnotationMatchers.java
@@ -0,0 +1,103 @@
+// 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.utils.codeinspector;
+
+import com.android.tools.r8.utils.StringUtils;
+import java.util.Arrays;
+import java.util.List;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
+public class AnnotationMatchers {
+
+ public static Matcher<MethodSubject> hasParameterAnnotationTypes(
+ List<TypeSubject>... typeSubjects) {
+ return hasParameterAnnotationTypes(Arrays.asList(typeSubjects));
+ }
+
+ public static Matcher<MethodSubject> hasParameterAnnotationTypes(
+ List<List<TypeSubject>> typeSubjects) {
+ return new TypeSafeMatcher<MethodSubject>() {
+
+ @Override
+ protected boolean matchesSafely(MethodSubject subject) {
+ List<List<FoundAnnotationSubject>> parameterAnnotations = subject.getParameterAnnotations();
+ if (parameterAnnotations.size() != typeSubjects.size()) {
+ return false;
+ }
+ for (int parameterIndex = 0;
+ parameterIndex < parameterAnnotations.size();
+ parameterIndex++) {
+ List<FoundAnnotationSubject> parameterAnnotationsForParameter =
+ parameterAnnotations.get(parameterIndex);
+ List<TypeSubject> typeSubjectsForParameter = typeSubjects.get(parameterIndex);
+ if (!hasAnnotationTypes(typeSubjectsForParameter)
+ .matches(parameterAnnotationsForParameter)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(
+ "has parameter annotation types ["
+ + StringUtils.join(
+ "; ",
+ typeSubjects,
+ typeSubjectsForParameter ->
+ StringUtils.join(", ", typeSubjectsForParameter, TypeSubject::getTypeName))
+ + "]");
+ }
+
+ @Override
+ public void describeMismatchSafely(MethodSubject subject, Description description) {
+ description.appendText("method did not");
+ }
+ };
+ }
+
+ public static Matcher<List<FoundAnnotationSubject>> hasAnnotationTypes(
+ TypeSubject... typeSubjects) {
+ return hasAnnotationTypes(Arrays.asList(typeSubjects));
+ }
+
+ public static Matcher<List<FoundAnnotationSubject>> hasAnnotationTypes(
+ List<TypeSubject> typeSubjects) {
+ return new TypeSafeMatcher<List<FoundAnnotationSubject>>() {
+
+ @Override
+ protected boolean matchesSafely(List<FoundAnnotationSubject> subjects) {
+ if (subjects.size() != typeSubjects.size()) {
+ return false;
+ }
+ for (int i = 0; i < subjects.size(); i++) {
+ FoundAnnotationSubject subject = subjects.get(i);
+ TypeSubject typeSubject = typeSubjects.get(i);
+ if (!subject.getType().equals(typeSubject)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText(
+ "has annotation types ["
+ + StringUtils.join(", ", typeSubjects, TypeSubject::getTypeName)
+ + "]");
+ }
+
+ @Override
+ public void describeMismatchSafely(
+ List<FoundAnnotationSubject> subjects, Description description) {
+ description.appendText("annotations did not");
+ }
+ };
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassOrMemberSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassOrMemberSubject.java
index 754b470..2c38d35 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassOrMemberSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassOrMemberSubject.java
@@ -10,7 +10,7 @@
public abstract class ClassOrMemberSubject extends Subject {
- public abstract List<AnnotationSubject> annotations();
+ public abstract List<FoundAnnotationSubject> annotations();
public abstract AnnotationSubject annotation(String name);
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
index 30b3fb0..d604156 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
@@ -26,6 +26,7 @@
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
import kotlinx.metadata.jvm.KotlinClassMetadata;
import org.junit.rules.TemporaryFolder;
@@ -128,6 +129,14 @@
return init(Arrays.asList(parameters));
}
+ public MethodSubject initFromTypes(List<TypeSubject> parameters) {
+ return init(parameters.stream().map(TypeSubject::getTypeName).collect(Collectors.toList()));
+ }
+
+ public MethodSubject initFromTypes(TypeSubject... parameters) {
+ return initFromTypes(Arrays.asList(parameters));
+ }
+
public MethodSubject method(MethodSignature signature) {
return method(signature.type, signature.name, ImmutableList.copyOf(signature.parameters));
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundAnnotationSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundAnnotationSubject.java
index d06b289..e73c25a 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundAnnotationSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundAnnotationSubject.java
@@ -14,13 +14,22 @@
public class FoundAnnotationSubject extends AnnotationSubject {
private final DexAnnotation annotation;
+ private final CodeInspector codeInspector;
- FoundAnnotationSubject(DexAnnotation annotation) {
+ FoundAnnotationSubject(DexAnnotation annotation, CodeInspector codeInspector) {
this.annotation = annotation;
+ this.codeInspector = codeInspector;
}
- public static List<AnnotationSubject> listFromDex(DexAnnotationSet annotations) {
- return ListUtils.map(annotations.annotations, FoundAnnotationSubject::new);
+ public static List<FoundAnnotationSubject> listFromDex(
+ DexAnnotationSet annotations, CodeInspector codeInspector) {
+ return ListUtils.map(
+ annotations.annotations,
+ annotation -> new FoundAnnotationSubject(annotation, codeInspector));
+ }
+
+ public TypeSubject getType() {
+ return new TypeSubject(codeInspector, annotation.getAnnotationType());
}
@Override
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
index cdc420e..fbf91d6 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
@@ -359,8 +359,8 @@
}
@Override
- public List<AnnotationSubject> annotations() {
- return FoundAnnotationSubject.listFromDex(dexClass.annotations());
+ public List<FoundAnnotationSubject> annotations() {
+ return FoundAnnotationSubject.listFromDex(dexClass.annotations(), codeInspector);
}
@Override
@@ -372,7 +372,7 @@
DexAnnotation annotation = codeInspector.findAnnotation(name, dexClass.annotations());
return annotation == null
? new AbsentAnnotationSubject()
- : new FoundAnnotationSubject(annotation);
+ : new FoundAnnotationSubject(annotation, codeInspector);
}
@Override
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java
index 2ea0107..c2daded 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundFieldSubject.java
@@ -114,7 +114,7 @@
}
@Override
- public List<AnnotationSubject> annotations() {
+ public List<FoundAnnotationSubject> annotations() {
throw new Unimplemented();
}
@@ -123,7 +123,7 @@
DexAnnotation annotation = codeInspector.findAnnotation(name, dexField.annotations());
return annotation == null
? new AbsentAnnotationSubject()
- : new FoundAnnotationSubject(annotation);
+ : new FoundAnnotationSubject(annotation, codeInspector);
}
@Override
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
index b99b090..b33f4a3 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
@@ -42,6 +42,7 @@
import com.google.common.collect.ImmutableList;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
@@ -136,6 +137,24 @@
}
@Override
+ public List<FoundAnnotationSubject> getParameterAnnotations(int index) {
+ return FoundAnnotationSubject.listFromDex(
+ getMethod().getParameterAnnotation(index), codeInspector);
+ }
+
+ @Override
+ public List<List<FoundAnnotationSubject>> getParameterAnnotations() {
+ List<List<FoundAnnotationSubject>> parameterAnnotations =
+ new ArrayList<>(getMethod().getParameters().size());
+ for (int parameterIndex = 0;
+ parameterIndex < getMethod().getParameters().size();
+ parameterIndex++) {
+ parameterAnnotations.add(getParameterAnnotations(parameterIndex));
+ }
+ return parameterAnnotations;
+ }
+
+ @Override
public ProgramMethod getProgramMethod() {
return new ProgramMethod(clazz.getDexProgramClass(), getMethod());
}
@@ -343,8 +362,8 @@
}
@Override
- public List<AnnotationSubject> annotations() {
- return FoundAnnotationSubject.listFromDex(dexMethod.annotations());
+ public List<FoundAnnotationSubject> annotations() {
+ return FoundAnnotationSubject.listFromDex(dexMethod.annotations(), codeInspector);
}
@Override
@@ -352,7 +371,7 @@
DexAnnotation annotation = codeInspector.findAnnotation(name, dexMethod.annotations());
return annotation == null
? new AbsentAnnotationSubject()
- : new FoundAnnotationSubject(annotation);
+ : new FoundAnnotationSubject(annotation, codeInspector);
}
@Override
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
index 3b7fe05..dda3e35 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
@@ -56,6 +56,10 @@
public abstract List<TypeSubject> getParameters();
+ public abstract List<List<FoundAnnotationSubject>> getParameterAnnotations();
+
+ public abstract List<FoundAnnotationSubject> getParameterAnnotations(int index);
+
public abstract ProgramMethod getProgramMethod();
public Iterator<InstructionSubject> iterateInstructions() {
diff --git a/third_party/google/google-java-format/1.14.0.tar.gz.sha1 b/third_party/google/google-java-format/1.14.0.tar.gz.sha1
new file mode 100644
index 0000000..4989c27
--- /dev/null
+++ b/third_party/google/google-java-format/1.14.0.tar.gz.sha1
@@ -0,0 +1 @@
+b26f4b8c825401d198d54d5e230779fe7fc3c132
\ No newline at end of file
diff --git a/tools/download_kotlin_dev.py b/tools/download_kotlin_dev.py
index c6c127e..6360cd2 100755
--- a/tools/download_kotlin_dev.py
+++ b/tools/download_kotlin_dev.py
@@ -3,22 +3,28 @@
# 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.
-from HTMLParser import HTMLParser
+import utils
+if utils.is_python3():
+ from html.parser import HTMLParser
+ import urllib.request
+ url_request = urllib.request
+else:
+ from HTMLParser import HTMLParser
+ import urllib
+ url_request = urllib
import os
import sys
-import urllib
-import utils
JETBRAINS_KOTLIN_MAVEN_URL = "https://maven.pkg.jetbrains.space/kotlin/p/" \
"kotlin/bootstrap/org/jetbrains/kotlin/"
KOTLIN_RELEASE_URL = JETBRAINS_KOTLIN_MAVEN_URL + "kotlin-compiler/"
def download_newest():
- response = urllib.urlopen(KOTLIN_RELEASE_URL)
+ response = url_request.urlopen(KOTLIN_RELEASE_URL)
if response.getcode() != 200:
raise Exception('Url: %s \n returned %s'
% (KOTLIN_RELEASE_URL, response.getcode()))
- content = response.read()
+ content = str(response.read())
release_candidates = []
class HTMLContentParser(HTMLParser):
@@ -70,7 +76,7 @@
def download_and_save(url, path, name):
print('Downloading: ' + url)
- urllib.urlretrieve(url, os.path.join(path, name))
+ url_request.urlretrieve(url, os.path.join(path, name))
if __name__ == '__main__':
diff --git a/tools/fmt-diff.py b/tools/fmt-diff.py
index fc08c80..cda33f9 100755
--- a/tools/fmt-diff.py
+++ b/tools/fmt-diff.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# 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.
@@ -13,8 +13,10 @@
GOOGLE_JAVA_FORMAT_DIFF = os.path.join(
utils.THIRD_PARTY,
+ 'google',
'google-java-format',
- 'google-java-format-google-java-format-1.7',
+ '1.14.0',
+ 'google-java-format-1.14.0',
'scripts',
'google-java-format-diff.py')
diff --git a/tools/test.py b/tools/test.py
index e822efe..56f30e7 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -15,13 +15,17 @@
import shutil
import subprocess
import sys
-import thread
import time
import uuid
import gradle
import utils
+if utils.is_python3():
+ import threading
+else:
+ import thread
+
ALL_ART_VMS = [
"default",
"13.0.0",
@@ -365,7 +369,7 @@
if args is None:
return 1
if len(args) == 0:
- print "No failing tests"
+ print("No failing tests")
return 0
# Test filtering. Must always follow the 'test' task.
for testFilter in args:
@@ -392,7 +396,14 @@
print_stacks_timeout = (print_stacks_timeout
if print_stacks_timeout != -1
else TIMEOUT_HANDLER_PERIOD)
- thread.start_new_thread(timeout_handler, (timestamp_file, print_stacks_timeout,))
+ if utils.is_python3():
+ threading.Thread(
+ target=timeout_handler,
+ args=(timestamp_file, print_stacks_timeout),
+ daemon=True).start()
+ else:
+ thread.start_new_thread(
+ timeout_handler, (timestamp_file, print_stacks_timeout,))
rotate_test_reports()
if options.only_jctf:
@@ -403,7 +414,7 @@
# Now run tests on selected runtime(s).
if options.runtimes:
if options.dex_vm != 'default':
- print 'Unexpected runtimes and dex_vm argument: ' + options.dex_vm
+ print('Unexpected runtimes and dex_vm argument: ' + options.dex_vm)
sys.exit(1)
if options.runtimes == 'empty':
# Set runtimes with no content will configure no runtimes.
@@ -417,9 +428,9 @@
for prefix in prefixes:
matches = [ rt for rt in VALID_RUNTIMES if rt.startswith(prefix) ]
if len(matches) == 0:
- print "Invalid runtime prefix '%s'." % prefix
- print "Must be just 'all', 'empty'," \
- " or a prefix of %s" % ', '.join(VALID_RUNTIMES)
+ print("Invalid runtime prefix '%s'." % prefix)
+ print("Must be just 'all', 'empty'," \
+ " or a prefix of %s" % ', '.join(VALID_RUNTIMES))
sys.exit(1)
runtimes.extend(matches)
gradle_args.append('-Pruntimes=%s' % ':'.join(runtimes))
@@ -499,7 +510,7 @@
last_timestamp = new_timestamp
def report_dir_path(index):
- if index is 0:
+ if index == 0:
return REPORTS_PATH
return '%s%d' % (REPORTS_PATH, index)
@@ -521,7 +532,7 @@
def compute_failed_tests(args):
if len(args) > 1:
- print "Running with --failed can take an optional path to a report index (or report number)."
+ print("Running with --failed can take an optional path to a report index (or report number).")
return None
report = report_index_path(0)
# If the default report does not exist, fall back to the previous report as it may be a failed
@@ -539,9 +550,9 @@
# if integer parsing failed assume it is a report file path.
report = args[0]
if not os.path.exists(report):
- print "Can't re-run failing, no report at:", report
+ print("Can't re-run failing, no report at:", report)
return None
- print "Reading failed tests in", report
+ print("Reading failed tests in", report)
failing = set()
inFailedSection = False
for line in file(report):