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):