Merge commit '1e3bc961f4a60a7f5150e0f42e50aa2b6e70d7ff' into dev-release
diff --git a/.gitignore b/.gitignore index 59981e8..d6d767e 100644 --- a/.gitignore +++ b/.gitignore
@@ -126,6 +126,8 @@ third_party/kotlin/kotlin-compiler-1.6.0 third_party/kotlin/kotlin-compiler-1.7.0.tar.gz third_party/kotlin/kotlin-compiler-1.7.0 +third_party/kotlin/kotlin-compiler-1.8.0.tar.gz +third_party/kotlin/kotlin-compiler-1.8.0 third_party/kotlin/kotlin-compiler-dev.tar.gz third_party/kotlin/kotlin-compiler-dev third_party/kotlinx-coroutines-1.3.6.tar.gz
diff --git a/build.gradle b/build.gradle index f5838d6..6429c57 100644 --- a/build.gradle +++ b/build.gradle
@@ -388,6 +388,7 @@ "kotlin/kotlin-compiler-1.5.0", "kotlin/kotlin-compiler-1.6.0", "kotlin/kotlin-compiler-1.7.0", + "kotlin/kotlin-compiler-1.8.0", "kotlinx-coroutines-1.3.6", "multidex", "openjdk/openjdk-rt-1.8",
diff --git a/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json b/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json deleted file mode 100644 index 6c0dd3d..0000000 --- a/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json +++ /dev/null
@@ -1,40 +0,0 @@ -{ - "identifier": "com.tools.android:chm_only_desugar_jdk_libs:1.0.13", - "configuration_format_version": 100, - "required_compilation_api_level": 26, - "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", - "sun.misc.Desugar": "j$.sun.misc.Desugar" - }, - "rewrite_derived_prefix": { - "sun.misc.DesugarUnsafe": { - "jdk.internal.misc.Unsafe": "j$.sun.misc.DesugarUnsafe" - } - } - } - ], - "shrinker_config": [ - "-keepclassmembers class j$.** extends java.io.Serializable { void <init>(); private static final java.io.ObjectStreamField[] serialPersistentFields; static final long serialVersionUID; java.lang.Object readResolve(); java.lang.Object writeReplace(); private void readObject(java.io.ObjectInputStream); private void writeObject(java.io.ObjectOutputStream); private void readObjectNoData(); }", - "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$TreeBin { int lockState; }", - "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { int sizeCtl; int transferIndex; long baseCount; int cellsBusy; }", - "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$CounterCell { long value; }", - "-keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); }", - "-keeppackagenames j$", - "-dontwarn sun.misc.Unsafe" - ] -} \ No newline at end of file
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs.json b/src/library_desugar/jdk11/desugar_jdk_libs.json index d6649f7..1132b9a 100644 --- a/src/library_desugar/jdk11/desugar_jdk_libs.json +++ b/src/library_desugar/jdk11/desugar_jdk_libs.json
@@ -7,6 +7,31 @@ "common_flags": [ { "api_level_below_or_equal": 10000, + "api_level_greater_or_equal": 26, + "rewrite_prefix": { + "java.time.DesugarLocalDate": "j$.time.DesugarLocalDate" + }, + "retarget_static_field": { + "java.time.LocalDate java.time.LocalDate#EPOCH": "java.time.LocalDate java.time.DesugarLocalDate#EPOCH" + }, + "retarget_method": { + "java.util.stream.Stream java.time.LocalDate#datesUntil(java.time.LocalDate)": "java.time.DesugarLocalDate", + "java.util.stream.Stream java.time.LocalDate#datesUntil(java.time.LocalDate, java.time.Period)": "java.time.DesugarLocalDate", + "java.time.LocalDate java.time.LocalDate#ofInstant(java.time.Instant, java.time.ZoneId)": "java.time.DesugarLocalDate", + "long java.time.LocalDate#toEpochSecond(java.time.LocalTime, java.time.ZoneOffset)": "java.time.DesugarLocalDate" + }, + "amend_library_field": [ + "public static java.time.LocalDate java.time.LocalDate#EPOCH" + ], + "amend_library_method": [ + "public java.util.stream.Stream java.time.LocalDate#datesUntil(java.time.LocalDate)", + "public java.util.stream.Stream java.time.LocalDate#datesUntil(java.time.LocalDate, java.time.Period)", + "public static java.time.LocalDate java.time.LocalDate#ofInstant(java.time.Instant, java.time.ZoneId)", + "public long java.time.LocalDate#toEpochSecond(java.time.LocalTime, java.time.ZoneOffset)" + ] + }, + { + "api_level_below_or_equal": 10000, "api_level_greater_or_equal": 24, "rewrite_prefix": { "java.util.stream.DesugarDoubleStream": "j$.util.stream.DesugarDoubleStream",
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_minimal.json b/src/library_desugar/jdk11/desugar_jdk_libs_minimal.json index eb7db99..a958c8b 100644 --- a/src/library_desugar/jdk11/desugar_jdk_libs_minimal.json +++ b/src/library_desugar/jdk11/desugar_jdk_libs_minimal.json
@@ -13,9 +13,12 @@ }, { "api_level_below_or_equal": 23, + "rewrite_prefix": { + "java.util.concurrent.ConcurrentHashMap": "j$.util.concurrent.ConcurrentHashMap", + "java.util.concurrent.ThreadLocalRandom": "j$.util.concurrent.ThreadLocalRandom" + }, "maintain_prefix": [ - "java.util.function.", - "java.util.Optional" + "java.util.function." ] } ], @@ -26,10 +29,25 @@ "rewrite_prefix": { "java.util.concurrent.Helpers": "j$.util.concurrent.Helpers" } + }, + { + "api_level_below_or_equal": 23, + "rewrite_prefix": { + "sun.misc.Desugar": "j$.sun.misc.Desugar" + }, + "rewrite_derived_prefix": { + "sun.misc.DesugarUnsafe": { + "jdk.internal.misc.Unsafe": "j$.sun.misc.DesugarUnsafe" + } + } } ], "shrinker_config": [ "-keepclassmembers class j$.** extends java.io.Serializable { void <init>(); private static final java.io.ObjectStreamField[] serialPersistentFields; static final long serialVersionUID; java.lang.Object readResolve(); java.lang.Object writeReplace(); private void readObject(java.io.ObjectInputStream); private void writeObject(java.io.ObjectOutputStream); private void readObjectNoData(); }", + "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$TreeBin { int lockState; }", + "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { int sizeCtl; int transferIndex; long baseCount; int cellsBusy; }", + "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$CounterCell { long value; }", + "-keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); }", "-keepclassmembers class j$.util.concurrent.ConcurrentLinkedQueue { j$.util.concurrent.ConcurrentLinkedQueue$Node head; j$.util.concurrent.ConcurrentLinkedQueue$Node tail; }", "-keep,allowshrinking class j$.util.concurrent.ConcurrentLinkedQueue$Node", "-keepclassmembers class j$.util.concurrent.ConcurrentLinkedQueue$Node { j$.util.concurrent.ConcurrentLinkedQueue$Node next; java.lang.Object item; }", @@ -37,6 +55,7 @@ "-keeppackagenames j$.**", "-keepattributes Signature", "-keepattributes EnclosingMethod", - "-keepattributes InnerClasses" + "-keepattributes InnerClasses", + "-dontwarn sun.misc.Unsafe" ] }
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_nio.json b/src/library_desugar/jdk11/desugar_jdk_libs_nio.json index 98054a7..cd20a37 100644 --- a/src/library_desugar/jdk11/desugar_jdk_libs_nio.json +++ b/src/library_desugar/jdk11/desugar_jdk_libs_nio.json
@@ -14,6 +14,31 @@ }, { "api_level_below_or_equal": 10000, + "api_level_greater_or_equal": 26, + "rewrite_prefix": { + "java.time.DesugarLocalDate": "j$.time.DesugarLocalDate" + }, + "retarget_static_field": { + "java.time.LocalDate java.time.LocalDate#EPOCH": "java.time.LocalDate java.time.DesugarLocalDate#EPOCH" + }, + "retarget_method": { + "java.util.stream.Stream java.time.LocalDate#datesUntil(java.time.LocalDate)": "java.time.DesugarLocalDate", + "java.util.stream.Stream java.time.LocalDate#datesUntil(java.time.LocalDate, java.time.Period)": "java.time.DesugarLocalDate", + "java.time.LocalDate java.time.LocalDate#ofInstant(java.time.Instant, java.time.ZoneId)": "java.time.DesugarLocalDate", + "long java.time.LocalDate#toEpochSecond(java.time.LocalTime, java.time.ZoneOffset)": "java.time.DesugarLocalDate" + }, + "amend_library_field": [ + "public static java.time.LocalDate java.time.LocalDate#EPOCH" + ], + "amend_library_method": [ + "public java.util.stream.Stream java.time.LocalDate#datesUntil(java.time.LocalDate)", + "public java.util.stream.Stream java.time.LocalDate#datesUntil(java.time.LocalDate, java.time.Period)", + "public static java.time.LocalDate java.time.LocalDate#ofInstant(java.time.Instant, java.time.ZoneId)", + "public long java.time.LocalDate#toEpochSecond(java.time.LocalTime, java.time.ZoneOffset)" + ] + }, + { + "api_level_below_or_equal": 10000, "api_level_greater_or_equal": 24, "rewrite_prefix": { "java.util.stream.DesugarDoubleStream": "j$.util.stream.DesugarDoubleStream",
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_nio_alternative_3.json b/src/library_desugar/jdk11/desugar_jdk_libs_nio_alternative_3.json deleted file mode 100644 index 3c503e9..0000000 --- a/src/library_desugar/jdk11/desugar_jdk_libs_nio_alternative_3.json +++ /dev/null
@@ -1,333 +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": 32, - "rewrite_prefix": { - "java.net.URLDecoder": "j$.net.URLDecoder", - "java.net.URLEncoder": "j$.net.URLEncoder", - "java.io.DesugarInputStream": "j$.io.DesugarInputStream" - }, - "retarget_method_with_emulated_dispatch": { - "long java.io.InputStream#transferTo(java.io.OutputStream)": "java.io.DesugarInputStream" - }, - "amend_library_method": [ - "public long java.io.InputStream#transferTo(java.io.OutputStream)" - ] - }, - { - "api_level_below_or_equal": 30, - "rewrite_prefix": { - "java.time.": "j$.time.", - "java.util.Desugar": "j$.util.Desugar" - }, - "retarget_method": { - "java.util.TimeZone java.util.TimeZone#getTimeZone(java.time.ZoneId)": "java.util.DesugarTimeZone" - }, - "retarget_method_with_emulated_dispatch": { - "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" - }, - "wrapper_conversion": [ - "java.time.Clock" - ], - "custom_conversion": { - "java.time.Duration": "java.time.TimeConversions", - "java.time.Instant": "java.time.TimeConversions", - "java.time.LocalDate": "java.time.TimeConversions", - "java.time.LocalTime": "java.time.TimeConversions", - "java.time.MonthDay": "java.time.TimeConversions", - "java.time.Period": "java.time.TimeConversions", - "java.time.ZoneId": "java.time.TimeConversions", - "java.time.ZonedDateTime": "java.time.TimeConversions" - } - }, - { - "api_level_below_or_equal": 29, - "rewrite_prefix": { - "java.util.concurrent.Flow": "j$.util.concurrent.Flow" - } - }, - { - "api_level_below_or_equal": 23, - "rewrite_prefix": { - "java.io.DesugarBufferedReader": "j$.io.DesugarBufferedReader", - "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.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.function.": "j$.util.function.", - "java.util.stream.": "j$.util.stream." - }, - "maintain_prefix": [ - "java.io.UncheckedIOException" - ], - "emulate_interface": { - "java.lang.Iterable": "j$.lang.Iterable", - "java.util.Collection": "j$.util.Collection", - "java.util.Comparator": "j$.util.Comparator", - "java.util.Iterator": "j$.util.Iterator", - "java.util.List": "j$.util.List", - "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$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" - }, - "retarget_method_with_emulated_dispatch": { - "java.util.stream.Stream java.io.BufferedReader#lines()": "java.io.DesugarBufferedReader", - "java.util.Spliterator java.util.LinkedHashSet#spliterator()": "java.util.DesugarLinkedHashSet" - }, - "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.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", - "java.util.Spliterator" - ], - "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" - } - }, - { - "api_level_below_or_equal": 18, - "rewrite_prefix": { - "java.lang.DesugarCharacter": "j$.lang.DesugarCharacter", - "java.nio.charset.StandardCharsets": "j$.nio.charset.StandardCharsets" - }, - "retarget_method": { - "boolean java.lang.Character#isBmpCodePoint(int)": "java.lang.DesugarCharacter" - } - } - ], - "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" - } - }, - { - "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": 19, - "dont_retarget": [ - "android.support.multidex.MultiDexExtractor$ExtractedDex" - ] - } - ], - "library_flags": [ - { - "api_level_below_or_equal": 32, - "rewrite_prefix": { - "desugar.": "j$.desugar.", - "libcore.": "j$.libcore.", - "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_derived_prefix": { - "java.time.": { - "j$.time.": "java.time." - } - } - }, - { - "api_level_below_or_equal": 25, - "rewrite_prefix": { - "java.io.DesugarFile": "j$.io.DesugarFile", - "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", - "wrapper." : "j$.wrapper." - }, - "rewrite_derived_prefix": { - "java.io.": { - "__wrapper__.j$.io.": "j$.io.", - "__wrapper__.java.io.": "java.io." - }, - "java.nio.": { - "__wrapper__.j$.nio.": "j$.nio.", - "__wrapper__.java.nio.": "java.nio." - } - }, - "retarget_method": { - "boolean java.util.Arrays#deepEquals0(java.lang.Object, java.lang.Object)": "java.util.DesugarArrays" - }, - "retarget_method_with_emulated_dispatch": { - "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" - }, - "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.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" - } - } - } - ], - "shrinker_config": [ - "-keepclassmembers class j$.** extends java.io.Serializable { void <init>(); private static final java.io.ObjectStreamField[] serialPersistentFields; static final long serialVersionUID; java.lang.Object readResolve(); java.lang.Object writeReplace(); private void readObject(java.io.ObjectInputStream); private void writeObject(java.io.ObjectOutputStream); private void readObjectNoData(); }", - "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$TreeBin { int lockState; }", - "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { int sizeCtl; int transferIndex; long baseCount; int cellsBusy; }", - "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$CounterCell { long value; }", - "-keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); public static final !synthetic <fields>; }", - "-keeppackagenames j$.**", - "-keepclassmembers class j$.util.IntSummaryStatistics { long count; long sum; int min; int max; }", - "-keepclassmembers class j$.util.LongSummaryStatistics { long count; long sum; long min; long max; }", - "-keepclassmembers class j$.util.DoubleSummaryStatistics { long count; double sum; double min; double max; }", - "-keepattributes Signature", - "-keepattributes EnclosingMethod", - "-keepattributes InnerClasses", - "-dontwarn sun.misc.Unsafe", - "-dontwarn wrapper.**" - ] -} \ No newline at end of file
diff --git a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java index 4337302..586e8e5 100644 --- a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java +++ b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
@@ -94,6 +94,9 @@ .isSyntheticOfKind(clazz.getType(), kinds -> kinds.API_MODEL_OUTLINE)) { return; } + // We cannot reliably create a stub that will have the same throwing behavior for all VMs. + // Only create stubs for exceptions to allow them being present in catch handlers and super + // types of existing program classes. See b/258270051 and b/259076765 for more information. clazz .allImmediateSupertypes() .forEach(superType -> findReferencedLibraryClasses(superType, clazz)); @@ -141,7 +144,19 @@ DexLibraryClass libraryClass, ThrowExceptionCode throwExceptionCode) { DexItemFactory factory = appView.dexItemFactory(); - if (!appView.options().apiModelingOptions().stubbingEnabledFor(appView, libraryClass)) { + // Do not stub the anything starting with java (including the object type). + if (libraryClass.getType() == appView.dexItemFactory().objectType + || libraryClass + .getType() + .getDescriptor() + .startsWith(appView.dexItemFactory().javaDescriptorPrefix)) { + return; + } + // Check if desugared library will bridge the type. + if (appView + .options() + .machineDesugaredLibrarySpecification + .isSupported(libraryClass.getType())) { return; } Set<ProgramDefinition> contexts = referencingContexts.get(libraryClass);
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java index 82e4b48..38bf4ee 100644 --- a/src/main/java/com/android/tools/r8/graph/CfCode.java +++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -392,8 +392,7 @@ return false; } // If tree shaking, only keep annotations on kept methods. - if (appView.appInfo().hasLiveness() - && !appView.appInfo().withLiveness().isPinned(method.getReference())) { + if (appView.appInfo().hasLiveness() && !appView.appInfo().withLiveness().isPinned(method)) { return false; } return true; @@ -774,7 +773,7 @@ // The enqueuer might build IR to trace reflective behaviour. At that point liveness is not // known, so be conservative with collection parameter name information. if (appView.appInfo().hasLiveness() - && !appView.appInfo().withLiveness().isPinned(encodedMethod.getReference())) { + && !appView.appInfo().withLiveness().isPinned(encodedMethod)) { return DexEncodedMethod.NO_PARAMETER_INFO; }
diff --git a/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java b/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java index 4062f96..7d6b3a2 100644 --- a/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java +++ b/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java
@@ -101,10 +101,10 @@ public boolean isEnclosingPinned(AppView<AppInfoWithLiveness> appView) { if (enclosingMethod != null) { - return appView.appInfo().isPinned(enclosingMethod); + return appView.appInfo().isPinnedWithDefinitionLookup(enclosingMethod); } if (enclosingClass != null) { - return appView.appInfo().isPinned(enclosingClass); + return appView.appInfo().isPinnedWithDefinitionLookup(enclosingClass); } return false; }
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java index 0d19daa..d849002 100644 --- a/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java +++ b/src/main/java/com/android/tools/r8/graph/analysis/InitializedClassesInInstanceMethodsAnalysis.java
@@ -35,7 +35,7 @@ // If `subject` is kept, then it is instantiated by reflection, which means that the analysis // has not seen all allocation sites. In that case, we conservatively return false. AppInfoWithClassHierarchy appInfo = appView.appInfo(); - if (appInfo.hasLiveness() && appInfo.withLiveness().isPinned(subject.type)) { + if (appInfo.hasLiveness() && appInfo.withLiveness().isPinned(subject)) { return false; }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java index 94577c8..1673079 100644 --- a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
@@ -18,6 +18,7 @@ import com.android.tools.r8.horizontalclassmerging.policies.LimitInterfaceGroups; import com.android.tools.r8.horizontalclassmerging.policies.MinimizeInstanceFieldCasts; import com.android.tools.r8.horizontalclassmerging.policies.NoAnnotationClasses; +import com.android.tools.r8.horizontalclassmerging.policies.NoApiOutlineWithNonApiOutline; import com.android.tools.r8.horizontalclassmerging.policies.NoCheckDiscard; import com.android.tools.r8.horizontalclassmerging.policies.NoClassAnnotationCollisions; import com.android.tools.r8.horizontalclassmerging.policies.NoClassInitializerCycles; @@ -265,6 +266,7 @@ new SameNestHost(appView), new SameParentClass(), new SyntheticItemsPolicy(appView, mode), + new NoApiOutlineWithNonApiOutline(appView), new SamePackageForApiOutline(appView, mode), new NoDifferentApiReferenceLevel(appView), new LimitClassGroups(appView));
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoApiOutlineWithNonApiOutline.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoApiOutlineWithNonApiOutline.java new file mode 100644 index 0000000..3176cb7 --- /dev/null +++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoApiOutlineWithNonApiOutline.java
@@ -0,0 +1,41 @@ +// Copyright (c) 2023, 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.policies; + +import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexProgramClass; +import com.android.tools.r8.horizontalclassmerging.MultiClassSameReferencePolicy; +import com.android.tools.r8.horizontalclassmerging.policies.NoApiOutlineWithNonApiOutline.SyntheticKindForMerging; + +public class NoApiOutlineWithNonApiOutline + extends MultiClassSameReferencePolicy<SyntheticKindForMerging> { + + public enum SyntheticKindForMerging { + API_MODEL, + NOT_API_MODEL + } + + private final AppView<?> appView; + + public NoApiOutlineWithNonApiOutline(AppView<?> appView) { + this.appView = appView; + } + + @Override + public String getName() { + return "NoApiOutlineWithNonApiOutline"; + } + + @Override + public SyntheticKindForMerging getMergeKey(DexProgramClass clazz) { + if (appView + .getSyntheticItems() + .isSyntheticOfKind(clazz.getType(), kinds -> kinds.API_MODEL_OUTLINE)) { + return SyntheticKindForMerging.API_MODEL; + } else { + return SyntheticKindForMerging.NOT_API_MODEL; + } + } +}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java index 9af0407..33ab115 100644 --- a/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java +++ b/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java
@@ -275,7 +275,8 @@ return root.isDefinedByInstructionSatisfying(Instruction::isConstClass) && !appView .getKeepInfo() - .isPinned(root.getDefinition().asConstClass().getType(), appView, options); + .isPinnedWithDefinitionLookup( + root.getDefinition().asConstClass().getType(), options, appView); } private boolean addLogicalBinopValueToValueGraph(
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 60c67a1..7396bf6 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
@@ -166,12 +166,14 @@ appView.dexItemFactory().createMethod(newHolder, method.proto, method.name); provider = rewritableMethods.getProvider(backportedMethod); } - if (provider != null && appView.options().disableBackportsWithErrorDiagnostics) { - appView - .reporter() - .error( - new BackportDiagnostic( - provider.method, context.getOrigin(), MethodPosition.create(context))); + if (provider != null && appView.options().disableBackports) { + if (appView.options().disableBackportsWithErrorDiagnostics) { + appView + .reporter() + .error( + new BackportDiagnostic( + provider.method, context.getOrigin(), MethodPosition.create(context))); + } return null; } return provider;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java index 810812a..8f1ddeb 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java
@@ -6,6 +6,7 @@ import com.android.tools.r8.cf.code.CfInstruction; import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext; +import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.DexItemFactory; import com.android.tools.r8.graph.ProgramMethod; import java.util.Collection; @@ -33,7 +34,7 @@ * Given an instruction, returns the list of instructions that the instruction should be desugared * to. If no desugaring is needed, {@code null} should be returned (for efficiency). */ - Collection<CfInstruction> desugarInstruction( + default Collection<CfInstruction> desugarInstruction( CfInstruction instruction, FreshLocalProvider freshLocalProvider, LocalStackAllocator localStackAllocator, @@ -41,14 +42,25 @@ ProgramMethod context, MethodProcessingContext methodProcessingContext, CfInstructionDesugaringCollection desugaringCollection, - DexItemFactory dexItemFactory); + DexItemFactory dexItemFactory) { + return compute(instruction, context) + .desugarInstruction( + freshLocalProvider, + localStackAllocator, + eventConsumer, + context, + methodProcessingContext, + dexItemFactory); + } /** * Returns true if the given instruction needs desugaring. * * <p>This should return true if-and-only-if {@link #desugarInstruction} returns non-null. */ - boolean needsDesugaring(CfInstruction instruction, ProgramMethod context); + default boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) { + return compute(instruction, context).needsDesugaring(); + } /** * Returns true if and only if needsDesugaring() answering true implies a desugaring is needed. @@ -59,4 +71,8 @@ default boolean hasPreciseNeedsDesugaring() { return true; } + + default DesugarDescription compute(CfInstruction instruction, ProgramMethod context) { + throw new Unreachable(); + } }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java index 99eef8c..292d844 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
@@ -14,7 +14,6 @@ import com.android.tools.r8.cf.code.CfInstanceOf; import com.android.tools.r8.cf.code.CfInstruction; import com.android.tools.r8.cf.code.CfInvoke; -import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext; import com.android.tools.r8.contexts.CompilationContext.UniqueContext; import com.android.tools.r8.graph.AppView; import com.android.tools.r8.graph.DexClass; @@ -31,10 +30,7 @@ import com.android.tools.r8.graph.MethodAccessFlags; import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.ir.desugar.CfInstructionDesugaring; -import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection; -import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer; -import com.android.tools.r8.ir.desugar.FreshLocalProvider; -import com.android.tools.r8.ir.desugar.LocalStackAllocator; +import com.android.tools.r8.ir.desugar.DesugarDescription; import com.android.tools.r8.ir.synthetic.CheckCastSourceCode; import com.android.tools.r8.ir.synthetic.ConstClassSourceCode; import com.android.tools.r8.ir.synthetic.FieldAccessorBuilder; @@ -69,33 +65,28 @@ } @Override - public Collection<CfInstruction> desugarInstruction( - CfInstruction instruction, - FreshLocalProvider freshLocalProvider, - LocalStackAllocator localStackAllocator, - CfInstructionDesugaringEventConsumer eventConsumer, - ProgramMethod context, - MethodProcessingContext methodProcessingContext, - CfInstructionDesugaringCollection desugaringCollection, - DexItemFactory dexItemFactory) { + public DesugarDescription compute(CfInstruction instruction, ProgramMethod context) { ComputedApiLevel computedApiLevel = getComputedApiLevelInstructionOnHolderWithMinApi(instruction, context); - if (computedApiLevel.isGreaterThan(appView.computedMinApiLevel())) { - return desugarLibraryCall( - methodProcessingContext.createUniqueContext(), - instruction, - computedApiLevel, - dexItemFactory, - eventConsumer, - context); + if (appView.computedMinApiLevel().isGreaterThanOrEqualTo(computedApiLevel)) { + return DesugarDescription.nothing(); } - return null; - } - - @Override - public boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) { - return getComputedApiLevelInstructionOnHolderWithMinApi(instruction, context) - .isGreaterThan(appView.computedMinApiLevel()); + return DesugarDescription.builder() + .setDesugarRewrite( + (freshLocalProvider, + localStackAllocator, + eventConsumer, + context1, + methodProcessingContext, + dexItemFactory) -> + desugarLibraryCall( + methodProcessingContext.createUniqueContext(), + instruction, + computedApiLevel, + dexItemFactory, + eventConsumer, + context)) + .build(); } private ComputedApiLevel getComputedApiLevelInstructionOnHolderWithMinApi(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/GenerateLintFiles.java index e93c6c6..752964b 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/GenerateLintFiles.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/lint/GenerateLintFiles.java
@@ -36,6 +36,7 @@ import com.android.tools.r8.graph.MethodAccessFlags; import com.android.tools.r8.graph.MethodCollection.MethodCollectionFactory; import com.android.tools.r8.graph.ProgramMethod; +import com.android.tools.r8.ir.desugar.BackportedMethodRewriter; 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; @@ -253,6 +254,11 @@ DirectMappedDexApplication implementationApplication = new ApplicationReader(implementation, options, Timing.empty()).read().toDirect(); + options.setDesugaredLibrarySpecification(desugaredLibrarySpecification); + List<DexMethod> backports = + BackportedMethodRewriter.generateListOfBackportedMethods( + implementation, options, ThreadUtils.getExecutorService(1)); + // Collect all the methods that the library desugar configuration adds support for. Set<DexClass> classesWithAllMethodsSupported = Sets.newIdentityHashSet(); Map<DexClass, List<DexEncodedMethod>> supportedMethods = new LinkedHashMap<>(); @@ -271,7 +277,8 @@ ProgramMethod implementationMethod = implementationClass.lookupProgramMethod(method.getReference()); // Don't include methods which are not implemented by the desugared library. - if (supported.test(method) && implementationMethod != null) { + if (supported.test(method) + && (implementationMethod != null || backports.contains(method.getReference()))) { supportedMethods.computeIfAbsent(clazz, k -> new ArrayList<>()).add(method); } else { allMethodsAdded = false; @@ -404,7 +411,7 @@ private void run() throws Exception { // Run over all the API levels that the desugared library can be compiled with. - for (int apiLevel = AndroidApiLevel.Sv2.getLevel(); + for (int apiLevel = AndroidApiLevel.T.getLevel(); apiLevel >= desugaredLibrarySpecification.getRequiredCompilationApiLevel().getLevel(); apiLevel--) { System.out.println("Generating lint files for compile API " + apiLevel);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java index ef1b959..66ef64e 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
@@ -332,7 +332,7 @@ } if (appView.enableWholeProgramOptimizations() - && appView.withLiveness().appInfo().isMinificationAllowed(holder)) { + && appView.withLiveness().appInfo().isMinificationAllowed(clazz)) { if (invokedMethod == dexItemFactory.classMethods.getName) { return new DexItemBasedValueString(holder, ClassNameComputationInfo.getInstance(NAME)); }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java index 753b6ce..12030bf 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java
@@ -113,7 +113,7 @@ ConstClass constClass = argument.getConstInstruction().asConstClass(); // Check that the service is not kept. - if (appView.appInfo().isPinned(constClass.getValue())) { + if (appView.appInfo().isPinnedWithDefinitionLookup(constClass.getValue())) { continue; }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java index c02b953..ed89e93 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -235,7 +235,7 @@ IRCode code, OptimizationFeedback feedback, InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos) { - assert !appView.appInfo().isPinned(method.getReference()); + assert !appView.appInfo().isPinned(method); if (!method.isInstanceInitializer()) { return;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java index 1d0e301..09c8163 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
@@ -350,7 +350,7 @@ } boolean mayBeRenamed = appView.enableWholeProgramOptimizations() - && appView.withLiveness().appInfo().isMinificationAllowed(holder.type); + && appView.withLiveness().appInfo().isMinificationAllowed(holder); // b/120138731: Filter out escaping uses. In such case, the result of this optimization will // be stored somewhere, which can lead to a regression if the corresponding class is in a deep // package hierarchy. For local cases, it is likely a one-time computation, but make sure the
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java b/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java index d2ec4d6..4d3075c 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java
@@ -119,8 +119,8 @@ // Verify that the methods are not pinned. They shouldn't be, since we've computed an abstract // return value for both. - assert !appView.appInfo().isPinned(method.getReference()); - assert !appView.appInfo().isPinned(parentMethod.getReference()); + assert !appView.appInfo().isPinned(method); + assert !appView.appInfo().isPinned(parentMethod); if (appView .appInfo()
diff --git a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java index acc9161..cc88ca9 100644 --- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java +++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -640,6 +640,15 @@ Code code = method.getDefinition().getCode(); assert code.isCfWritableCode(); assert code.estimatedDexCodeSizeUpperBoundInBytes() > 0; + if (!code.isCfWritableCode()) { + // This should never happen (see assertion above), but desugaring bugs may lead the + // CfApplicationWriter to try to write invalid code and we need the better error message. + throw new Unreachable( + "The CfApplicationWriter cannot write non cf writable code " + + code.getClass().getCanonicalName() + + " for method " + + method.getReference().toSourceString()); + } code.asCfWritableCode() .writeCf(method, classFileVersion, appView, namingLens, rewriter, visitor); }
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java index 415995e..c06aea8 100644 --- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java +++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
@@ -110,7 +110,7 @@ if (oldMeta == null || kotlinInfo == getNoKotlinInfo() || (appView.appInfo().hasLiveness() - && !appView.withLiveness().appInfo().isPinned(clazz.type))) { + && !appView.withLiveness().appInfo().isPinned(clazz))) { // Remove @Metadata in DexAnnotation when there is no kotlin info and the type is not // missing. if (oldMeta != null) {
diff --git a/src/main/java/com/android/tools/r8/naming/Minifier.java b/src/main/java/com/android/tools/r8/naming/Minifier.java index 00c0d9f..52fee79 100644 --- a/src/main/java/com/android/tools/r8/naming/Minifier.java +++ b/src/main/java/com/android/tools/r8/naming/Minifier.java
@@ -312,7 +312,7 @@ if (!allowMemberRenaming(holder) || holder.accessFlags.isAnnotation() || method.accessFlags.isConstructor() - || !appView.appInfo().isMinificationAllowed(method.getReference())) { + || !appView.appInfo().isMinificationAllowed(method)) { return method.getReference().name; } if (desugaredLibraryRenaming @@ -327,8 +327,7 @@ @Override public DexString getReservedName(DexEncodedField field, DexClass holder) { - if (holder.isLibraryClass() - || !appView.appInfo().isMinificationAllowed(field.getReference())) { + if (holder.isLibraryClass() || !appView.appInfo().isMinificationAllowed(field)) { return field.getReference().name; } return null;
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java index 6637177..3c128fb 100644 --- a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java +++ b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
@@ -408,7 +408,7 @@ return mappings.get(type); } if (clazz.isProgramClass()) { - if (appView.appInfo().isMinificationAllowed(type)) { + if (appView.appInfo().isMinificationAllowed(clazz.asProgramClass())) { return mappings.get(type); } // TODO(b/136694827): Report a warning here if in the mapping since the user may find this @@ -454,7 +454,7 @@ nextName = reservedName; } else { assert !mappedNames.containsKey(reference); - assert appView.appInfo().isMinificationAllowed(reference); + assert appView.appInfo().isMinificationAllowed(method); nextName = super.next(method, internalState, isAvailable); } assert nextName == reference.name || !method.isInitializer(); @@ -477,7 +477,7 @@ return reservedName; } assert !mappedNames.containsKey(reference); - assert appView.appInfo().isMinificationAllowed(reference); + assert appView.appInfo().isMinificationAllowed(field); return super.next(field, internalState, isAvailable); }
diff --git a/src/main/java/com/android/tools/r8/optimize/AccessModifier.java b/src/main/java/com/android/tools/r8/optimize/AccessModifier.java index c1ee380..b2d577c 100644 --- a/src/main/java/com/android/tools/r8/optimize/AccessModifier.java +++ b/src/main/java/com/android/tools/r8/optimize/AccessModifier.java
@@ -223,7 +223,7 @@ boolean wasSeen = methodPoolCollection.markIfNotSeen(method.getHolder(), method.getReference()); if (wasSeen) { // We can't do anything further because even renaming is not allowed due to the keep rule. - if (!appView.appInfo().isMinificationAllowed(method.getReference())) { + if (!appView.appInfo().isMinificationAllowed(method)) { return false; } // TODO(b/111118390): Renaming will enable more private instance methods to be publicized.
diff --git a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java index e6df4a0..b6236d8 100644 --- a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java +++ b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
@@ -154,7 +154,7 @@ // If the method is defined on the parent class, we cannot hoist the bridge. // TODO(b/153147967): If the declared method is abstract, we could replace it by the bridge. // Add a test. - if (clazz.lookupMethod(method) != null) { + if (clazz.lookupProgramMethod(method) != null) { return; } @@ -278,8 +278,8 @@ representative.getReference()); // Remove all of the bridges in the eligible subclasses. + assert !appView.appInfo().isPinnedWithDefinitionLookup(method); for (DexProgramClass subclass : eligibleSubclasses) { - assert !appView.appInfo().isPinned(method); DexEncodedMethod removed = subclass.removeMethod(method); assert removed != null; }
diff --git a/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java b/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java index e0c7f83..edfa788 100644 --- a/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java +++ b/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java
@@ -6,13 +6,14 @@ 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.DexProgramClass; import com.android.tools.r8.graph.DexType; +import com.android.tools.r8.graph.ProgramMethod; import com.android.tools.r8.graph.SubtypingInfo; import com.android.tools.r8.logging.Log; import com.android.tools.r8.shaking.ScopedDexMethodSet.AddMethodIfMoreVisibleResult; -import com.android.tools.r8.utils.IterableUtils; -import com.android.tools.r8.utils.ListUtils; -import java.util.List; +import java.util.HashSet; +import java.util.Set; /** * Removes abstract methods if they only shadow methods of the same signature in a superclass. @@ -43,39 +44,38 @@ DexClass holder = appView.definitionFor(type); scope = scope.newNestedScope(); if (holder != null && holder.isProgramClass()) { - DexEncodedMethod[] newVirtualMethods = - processMethods(IterableUtils.ensureUnmodifiableList(holder.virtualMethods())); - if (newVirtualMethods != null) { - holder.setVirtualMethods(newVirtualMethods); - } + processMethods(holder.asProgramClass()); } // TODO(b/154881041): Does this need the full subtype hierarchy of referenced types!? subtypingInfo.forAllImmediateExtendsSubtypes(type, this::processClass); scope = scope.getParent(); } - private DexEncodedMethod[] processMethods(List<DexEncodedMethod> virtualMethods) { - if (virtualMethods == null) { - return null; + private void processMethods(DexProgramClass clazz) { + Set<DexEncodedMethod> toRemove = null; + for (ProgramMethod method : clazz.virtualProgramMethods()) { + if (!isNonAbstractPinnedOrWideningVisibility(method)) { + if (toRemove == null) { + toRemove = new HashSet<>(); + } + toRemove.add(method.getDefinition()); + } } - // Removal of abstract methods is rare, ListUtils.filterOrElse does no copying if nothing is - // filtered out. - List<DexEncodedMethod> filteredMethods = - ListUtils.filterOrElse(virtualMethods, this::isNonAbstractPinnedOrWideningVisibility); - return filteredMethods == virtualMethods - ? null - : filteredMethods.toArray(DexEncodedMethod.EMPTY_ARRAY); + if (toRemove != null) { + clazz.getMethodCollection().removeMethods(toRemove); + } } - private boolean isNonAbstractPinnedOrWideningVisibility(DexEncodedMethod method) { - if (!method.accessFlags.isAbstract()) { + private boolean isNonAbstractPinnedOrWideningVisibility(ProgramMethod method) { + if (!method.getAccessFlags().isAbstract()) { return true; } // Check if the method widens visibility. Adding to the scope mutates it. - if (scope.addMethodIfMoreVisible(method) != AddMethodIfMoreVisibleResult.NOT_ADDED) { + if (scope.addMethodIfMoreVisible(method.getDefinition()) + != AddMethodIfMoreVisibleResult.NOT_ADDED) { return true; } - if (appView.appInfo().isPinned(method.getReference())) { + if (appView.appInfo().isPinned(method)) { return true; } // We will filter the method out since it is not pinned.
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 387186f..cb80e54 100644 --- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java +++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -918,7 +918,7 @@ assert info.isRead() || info.isWritten(); return true; } - assert getKeepInfo().getFieldInfo(reference, this).isShrinkingAllowed(options()); + assert getKeepInfo().getFieldInfo(field, this).isShrinkingAllowed(options()); return false; } @@ -929,7 +929,7 @@ if (info != null && info.isRead()) { return true; } - if (isPinned(field)) { + if (isPinned(encodedField)) { return true; } // For library classes we don't know whether a field is read. @@ -938,8 +938,7 @@ public boolean isFieldWritten(DexEncodedField encodedField) { assert checkIfObsolete(); - return isFieldWrittenByFieldPutInstruction(encodedField) - || isPinned(encodedField.getReference()); + return isFieldWrittenByFieldPutInstruction(encodedField) || isPinned(encodedField); } public boolean isFieldWrittenByFieldPutInstruction(DexEncodedField encodedField) { @@ -957,7 +956,7 @@ public boolean isFieldOnlyWrittenInMethod(DexEncodedField field, DexEncodedMethod method) { assert checkIfObsolete(); assert isFieldWritten(field) : "Expected field `" + field.toSourceString() + "` to be written"; - if (isPinned(field.getReference())) { + if (isPinned(field)) { return false; } return isFieldOnlyWrittenInMethodIgnoringPinning(field, method); @@ -980,7 +979,7 @@ public boolean isInstanceFieldWrittenOnlyInInstanceInitializers(DexEncodedField field) { assert checkIfObsolete(); assert isFieldWritten(field) : "Expected field `" + field.toSourceString() + "` to be written"; - if (isPinned(field.getReference())) { + if (isPinned(field)) { return false; } FieldAccessInfo fieldAccessInfo = getFieldAccessInfoCollection().get(field.getReference()); @@ -1027,7 +1026,7 @@ if (neverPropagateValue.contains(field)) { return false; } - if (isPinned(field) && !field.getType().isAlwaysNull(appView)) { + if (isPinnedWithDefinitionLookup(field) && !field.getType().isAlwaysNull(appView)) { return false; } return true; @@ -1039,7 +1038,9 @@ return false; } if (!method.getReturnType().isAlwaysNull(appView) - && !getKeepInfo().getMethodInfo(method, this).isOptimizationAllowed(options())) { + && !getKeepInfo() + .getMethodInfoWithDefinitionLookup(method, this) + .isOptimizationAllowed(options())) { return false; } return true; @@ -1071,18 +1072,29 @@ return !isPinned(clazz) && !neverClassInline.contains(clazz.getType()); } - public boolean isMinificationAllowed(DexReference reference) { + public boolean isMinificationAllowed(DexProgramClass clazz) { return options().isMinificationEnabled() - && keepInfo.getInfo(reference, this).isMinificationAllowed(options()); + && keepInfo.getInfo(clazz).isMinificationAllowed(options()); + } + + public boolean isMinificationAllowed(ProgramDefinition definition) { + return options().isMinificationEnabled() + && keepInfo.getInfo(definition).isMinificationAllowed(options()); + } + + public boolean isMinificationAllowed(DexDefinition definition) { + return options().isMinificationEnabled() + && keepInfo.getInfo(definition, this).isMinificationAllowed(options()); + } + + public boolean isMinificationAllowed(DexType reference) { + return options().isMinificationEnabled() + && keepInfo.getClassInfo(reference, this).isMinificationAllowed(options()); } public boolean isAccessModificationAllowed(ProgramDefinition definition) { - return isAccessModificationAllowed(definition.getReference()); - } - - public boolean isAccessModificationAllowed(DexReference reference) { assert options().getProguardConfiguration().isAccessModificationAllowed(); - return keepInfo.getInfo(reference, this).isAccessModificationAllowed(options()); + return keepInfo.getInfo(definition).isAccessModificationAllowed(options()); } public boolean isRepackagingAllowed(DexProgramClass clazz, AppView<?> appView) { @@ -1099,27 +1111,30 @@ return applyMappingSeedMapper == null || !applyMappingSeedMapper.hasMapping(clazz.type); } - public boolean isPinned(DexReference reference) { + public boolean isPinnedWithDefinitionLookup(DexReference reference) { assert checkIfObsolete(); - return keepInfo.isPinned(reference, this, options()); + return keepInfo.isPinnedWithDefinitionLookup(reference, options(), this); } public boolean isPinned(DexDefinition definition) { - assert definition != null; - return isPinned(definition.getReference()); + return keepInfo.isPinned(definition, options(), this); } - public boolean isPinned(DexClassAndMember<?, ?> member) { - assert member != null; - return isPinned(member.getReference()); + public boolean isPinned(DexProgramClass clazz) { + return keepInfo.isPinned(clazz, options()); + } + + public boolean isPinned(ProgramDefinition definition) { + assert definition != null; + return keepInfo.isPinned(definition, options()); } public boolean hasPinnedInstanceInitializer(DexType type) { assert type.isClassType(); DexProgramClass clazz = asProgramClassOrNull(definitionFor(type)); if (clazz != null) { - for (DexEncodedMethod method : clazz.directMethods()) { - if (method.isInstanceInitializer() && isPinned(method.getReference())) { + for (ProgramMethod method : clazz.directProgramMethods()) { + if (method.getDefinition().isInstanceInitializer() && isPinned(method)) { return true; } } @@ -1495,11 +1510,11 @@ } private boolean isInstantiatedOrPinned(DexProgramClass clazz) { - return isInstantiatedDirectly(clazz) || isPinned(clazz.type) || isInstantiatedInterface(clazz); + return isInstantiatedDirectly(clazz) || isPinned(clazz) || isInstantiatedInterface(clazz); } public boolean isPinnedNotProgramOrLibraryOverride(DexDefinition definition) { - if (isPinned(definition.getReference())) { + if (isPinned(definition)) { return true; } if (definition.isDexEncodedMethod()) {
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 59b7ae3..610cfa9 100644 --- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java +++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -2918,8 +2918,7 @@ instantiation.apply(subTypeConsumer, lambdaConsumer); }, definition -> - keepInfo.isPinned( - definition.getReference(), appInfo, options)); + keepInfo.isPinned(definition, options, appInfo)); lookupResult.forEach( target -> markVirtualDispatchTargetAsLive( @@ -3422,7 +3421,7 @@ (type, subTypeConsumer, lambdaConsumer) -> objectAllocationInfoCollection.forEachInstantiatedSubType( type, subTypeConsumer, lambdaConsumer, appInfo), - definition -> keepInfo.isPinned(definition.getReference(), appInfo, options)) + definition -> keepInfo.isPinned(definition, options, appInfo)) .forEach( target -> markVirtualDispatchTargetAsLive( @@ -4328,7 +4327,7 @@ (methodReference, companionReference) -> { ProgramMethod companion = appView.definitionFor(companionReference).asProgramMethod(); KeepMethodInfo.Joiner minimumKeepInfoForCompanion = - keepInfo.getMethodInfo(methodReference, appInfo).joiner(); + keepInfo.getMethodInfoWithDefinitionLookup(methodReference, appInfo).joiner(); KeepMethodInfo.Joiner extraMinimumKeepInfoForCompanion = dependentMinimumKeepInfo .getUnconditionalMinimumKeepInfoOrDefault(MinimumKeepInfoCollection.empty())
diff --git a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java index 8596642..f56779b 100644 --- a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java +++ b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
@@ -118,9 +118,13 @@ // `sourceType` is still available until the second round of tree shaking. This // way we can still retrieve the access flags of `sourceType`. DexProgramClass sourceClass = - asProgramClassOrNull(appView.definitionFor(sourceType)); + asProgramClassOrNull( + appView.appInfo().definitionForWithoutExistenceAssert(sourceType)); if (sourceClass == null) { - assert false; + // TODO(b/266049507): The evaluation of -if rules in the final round of tree + // shaking and during -whyareyoukeeping should be the same. Currently the pruning + // of classes changes behavior. + assert enqueuer.getMode().isWhyAreYouKeeping(); continue; } if (appView.options().testing.measureProguardIfRuleEvaluations) {
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java index c78e39a..f13a407 100644 --- a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java +++ b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
@@ -9,6 +9,8 @@ import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.AppInfoWithClassHierarchy; import com.android.tools.r8.graph.AppView; +import com.android.tools.r8.graph.DexClass; +import com.android.tools.r8.graph.DexDefinition; import com.android.tools.r8.graph.DexDefinitionSupplier; import com.android.tools.r8.graph.DexEncodedField; import com.android.tools.r8.graph.DexEncodedMember; @@ -92,9 +94,14 @@ return getMethodInfo(member.asDexEncodedMethod(), holder); } + public final KeepClassInfo getClassInfo(DexClass clazz) { + return clazz != null && clazz.isProgramClass() + ? getClassInfo(clazz.asProgramClass()) + : keepInfoForNonProgramClass(); + } + public final KeepClassInfo getClassInfo(DexType type, DexDefinitionSupplier definitions) { - DexProgramClass clazz = asProgramClassOrNull(definitions.definitionFor(type)); - return clazz == null ? keepInfoForNonProgramClass() : getClassInfo(clazz); + return getClassInfo(definitions.contextIndependentDefinitionFor(type)); } public final KeepMemberInfo<?, ?> getMemberInfo(ProgramMember<?, ?> member) { @@ -105,8 +112,21 @@ return getMethodInfo(method.getDefinition(), method.getHolder()); } - public final KeepMethodInfo getMethodInfo(DexMethod method, DexDefinitionSupplier definitions) { - DexProgramClass holder = asProgramClassOrNull(definitions.definitionFor(method.holder)); + public final KeepMethodInfo getMethodInfo( + DexEncodedMethod method, DexDefinitionSupplier definitions) { + DexProgramClass holder = + asProgramClassOrNull(definitions.contextIndependentDefinitionFor(method.getHolderType())); + if (holder == null) { + return keepInfoForNonProgramMethod(); + } + assert method == holder.lookupMethod(method.getReference()); + return getMethodInfo(method, holder); + } + + public final KeepMethodInfo getMethodInfoWithDefinitionLookup( + DexMethod method, DexDefinitionSupplier definitions) { + DexProgramClass holder = + asProgramClassOrNull(definitions.contextIndependentDefinitionFor(method.holder)); if (holder == null) { return keepInfoForNonProgramMethod(); } @@ -118,7 +138,19 @@ return getFieldInfo(field.getDefinition(), field.getHolder()); } - public final KeepFieldInfo getFieldInfo(DexField field, DexDefinitionSupplier definitions) { + public final KeepFieldInfo getFieldInfo( + DexEncodedField field, DexDefinitionSupplier definitions) { + DexProgramClass holder = + asProgramClassOrNull(definitions.contextIndependentDefinitionFor(field.getHolderType())); + if (holder == null) { + return keepInfoForNonProgramField(); + } + assert holder.lookupField(field.getReference()) == field; + return getFieldInfo(field, holder); + } + + private KeepFieldInfo getFieldInfoWithDefinitionLookup( + DexField field, DexDefinitionSupplier definitions) { DexProgramClass holder = asProgramClassOrNull(definitions.definitionFor(field.holder)); if (holder == null) { return keepInfoForNonProgramField(); @@ -127,15 +159,29 @@ return definition == null ? KeepFieldInfo.bottom() : getFieldInfo(definition, holder); } - public final KeepInfo<?, ?> getInfo(DexReference reference, DexDefinitionSupplier definitions) { + private KeepInfo<?, ?> getInfoWithDefinitionLookup( + DexReference reference, DexDefinitionSupplier definitions) { if (reference.isDexType()) { return getClassInfo(reference.asDexType(), definitions); } if (reference.isDexMethod()) { - return getMethodInfo(reference.asDexMethod(), definitions); + return getMethodInfoWithDefinitionLookup(reference.asDexMethod(), definitions); } if (reference.isDexField()) { - return getFieldInfo(reference.asDexField(), definitions); + return getFieldInfoWithDefinitionLookup(reference.asDexField(), definitions); + } + throw new Unreachable(); + } + + public final KeepInfo<?, ?> getInfo(DexDefinition definition, DexDefinitionSupplier definitions) { + if (definition.isDexClass()) { + return getClassInfo(definition.asDexClass()); + } + if (definition.isDexEncodedMethod()) { + return getMethodInfo(definition.asDexEncodedMethod(), definitions); + } + if (definition.isDexEncodedField()) { + return getFieldInfo(definition.asDexEncodedField(), definitions); } throw new Unreachable(); } @@ -158,37 +204,28 @@ } public final boolean isPinned( + ProgramDefinition definition, GlobalKeepInfoConfiguration configuration) { + return getInfo(definition).isPinned(configuration); + } + + public final boolean isPinned( + DexDefinition definition, + GlobalKeepInfoConfiguration configuration, + DexDefinitionSupplier definitions) { + return getInfo(definition, definitions).isPinned(configuration); + } + + public final boolean isPinnedWithDefinitionLookup( DexReference reference, - DexDefinitionSupplier definitions, - GlobalKeepInfoConfiguration configuration) { - return getInfo(reference, definitions).isPinned(configuration); - } - - public final boolean isPinned( - DexType type, DexDefinitionSupplier definitions, GlobalKeepInfoConfiguration configuration) { - return getClassInfo(type, definitions).isPinned(configuration); - } - - public final boolean isPinned( - DexMethod method, - DexDefinitionSupplier definitions, - GlobalKeepInfoConfiguration configuration) { - return getMethodInfo(method, definitions).isPinned(configuration); - } - - public final boolean isPinned( - DexField field, - DexDefinitionSupplier definitions, - GlobalKeepInfoConfiguration configuration) { - return getFieldInfo(field, definitions).isPinned(configuration); + GlobalKeepInfoConfiguration configuration, + DexDefinitionSupplier definitions) { + return getInfoWithDefinitionLookup(reference, definitions).isPinned(configuration); } public final boolean isMinificationAllowed( - DexReference reference, - DexDefinitionSupplier definitions, - GlobalKeepInfoConfiguration configuration) { + ProgramDefinition definition, GlobalKeepInfoConfiguration configuration) { return configuration.isMinificationEnabled() - && getInfo(reference, definitions).isMinificationAllowed(configuration); + && getInfo(definition).isMinificationAllowed(configuration); } public abstract boolean verifyPinnedTypesAreLive(Set<DexType> liveTypes, InternalOptions options);
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java index a728063..5717ccf 100644 --- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java +++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -1965,6 +1965,9 @@ if (graphLens.isIdentityLens()) { return this; } + // TODO(b/164019179): If rules can now reference dead items. These should be pruned or + // rewritten + ifRules.forEach(ProguardIfRule::canReferenceDeadTypes); return new RootSet( getDependentMinimumKeepInfo().rewrittenWithLens(graphLens), reasonAsked, @@ -2083,12 +2086,14 @@ (reference, minimumKeepInfo) -> { if (reference.isDexType()) { DexType type = reference.asDexType(); - assert !appInfo.hasLiveness() || appInfo.withLiveness().isPinned(type) + assert !appInfo.hasLiveness() + || appInfo.withLiveness().isPinnedWithDefinitionLookup(type) : "Expected reference `" + type.toSourceString() + "` to be pinned"; requiredMembersPerType.computeIfAbsent(type, key -> Sets.newIdentityHashSet()); } else { DexMember<?, ?> member = reference.asDexMember(); - assert !appInfo.hasLiveness() || appInfo.withLiveness().isPinned(member) + assert !appInfo.hasLiveness() + || appInfo.withLiveness().isPinnedWithDefinitionLookup(member) : "Expected reference `" + member.toSourceString() + "` to be pinned"; requiredMembersPerType .computeIfAbsent(member.holder, key -> Sets.newIdentityHashSet())
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 32878da..4819d4d 100644 --- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java +++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -359,7 +359,7 @@ private void markTypeAsPinned(DexType type, AbortReason reason) { DexType baseType = type.toBaseType(appView.dexItemFactory()); - if (!baseType.isClassType() || appInfo.isPinned(baseType)) { + if (!baseType.isClassType() || appInfo.isPinnedWithDefinitionLookup(baseType)) { // We check for the case where the type is pinned according to appInfo.isPinned, // so we only need to add it here if it is not the case. return; @@ -380,14 +380,13 @@ if (allocationInfo.isInstantiatedDirectly(sourceClass) || allocationInfo.isInterfaceWithUnknownSubtypeHierarchy(sourceClass) || allocationInfo.isImmediateInterfaceOfInstantiatedLambda(sourceClass) - || appInfo.isPinned(sourceClass.type) + || appInfo.isPinned(sourceClass) || pinnedTypes.contains(sourceClass.type) || appInfo.isNoVerticalClassMergingOfType(sourceClass.type)) { return false; } assert Streams.stream(Iterables.concat(sourceClass.fields(), sourceClass.methods())) - .map(DexEncodedMember::getReference) .noneMatch(appInfo::isPinned); if (!FeatureSplitBoundaryOptimizationUtils.isSafeForVerticalClassMerging( @@ -395,7 +394,7 @@ return false; } if (appView.appServices().allServiceTypes().contains(sourceClass.type) - && appInfo.isPinned(targetClass.type)) { + && appInfo.isPinned(targetClass)) { if (Log.ENABLED) { AbortReason.SERVICE_LOADER.printLogMessageForClass(sourceClass); }
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 f49f0d4..b95ac53 100644 --- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java +++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -278,7 +278,8 @@ assert !addAndroidPlatformBuildToMarker; if (isAndroidPlatformBuild || minApiLevel.isPlatform()) { apiModelingOptions().disableApiModeling(); - disableBackportsWithErrorDiagnostics = true; + // TODO(b/232073181): This should also enable throwing errors on triggered backports. + disableBackports = true; addAndroidPlatformBuildToMarker = isAndroidPlatformBuild; } } @@ -618,7 +619,9 @@ // Flag to turn on/off partial VarHandle desugaring. public boolean enableVarHandleDesugaring = false; // Flag to turn off backport methods (and report errors if triggered). - public boolean disableBackportsWithErrorDiagnostics = false; + public boolean disableBackports = false; + public boolean disableBackportsWithErrorDiagnostics = + System.getProperty("com.android.tools.r8.throwErrorOnBackport") != null; // Flag to turn on/off reduction of nest to improve class merging optimizations. public boolean enableNestReduction = true; // Defines interface method rewriter behavior. @@ -1809,9 +1812,6 @@ System.getProperty("com.android.tools.r8.disableApiModeling") == null; public boolean reportUnknownApiReferences = System.getProperty("com.android.tools.r8.reportUnknownApiReferences") != null; - // TODO(b/259076765): Remove when resolved. - public boolean stubNonThrowableClasses = - System.getProperty("com.android.tools.r8.stubNonThrowableClasses") != null; // TODO(b/232823652): Enable when we can compute the offset correctly. public boolean useMemoryMappedByteBuffer = false; @@ -1878,28 +1878,6 @@ enableStubbingOfClasses = false; } - public boolean stubbingEnabledFor(AppView<?> appView, DexLibraryClass libraryClass) { - if (libraryClass.getType() == appView.dexItemFactory().objectType - || libraryClass - .getType() - .getDescriptor() - .startsWith(appView.dexItemFactory().javaDescriptorPrefix)) { - return false; - } - // Check if desugared library will bridge the type. - if (appView - .options() - .machineDesugaredLibrarySpecification - .isSupported(libraryClass.getType())) { - return false; - } - // We cannot reliably create a stub that will have the same throwing behavior for all VMs. We - // only create stubs for exceptions to allow them being present in catch handlers. See - // b/258270051 for more information. Note that throwables in the java namespace are not - // stubbed (bailout above). - return isThrowable(appView, libraryClass) || stubNonThrowableClasses; - } - private boolean isThrowable(AppView<?> appView, DexLibraryClass libraryClass) { DexClass current = libraryClass; while (current.getSuperType() != null) {
diff --git a/src/main/java/com/android/tools/r8/utils/positions/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/positions/LineNumberOptimizer.java index c1e6850..11f01d2 100644 --- a/src/main/java/com/android/tools/r8/utils/positions/LineNumberOptimizer.java +++ b/src/main/java/com/android/tools/r8/utils/positions/LineNumberOptimizer.java
@@ -170,7 +170,7 @@ } allSeenAreInstanceInitializers = false; // If the method is pinned, we cannot minify it. - if (!keepInfo.isMinificationAllowed(method.getReference(), appView, appView.options())) { + if (!keepInfo.isMinificationAllowed(method, appView.options())) { continue; } // With desugared library, call-backs names are reserved here.
diff --git a/src/test/examplesJava11/collectiontoarray/Main.java b/src/test/examplesJava11/collectiontoarray/Main.java index 91bbd8b..3a4cc01 100644 --- a/src/test/examplesJava11/collectiontoarray/Main.java +++ b/src/test/examplesJava11/collectiontoarray/Main.java
@@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.function.IntFunction; public class Main { public static void main(String[] args) { @@ -16,5 +17,20 @@ // This default method was added in Android T. String[] toArray = list.toArray(String[]::new); System.out.println(Arrays.toString(toArray)); + + List<String> myList = new MyList<>(); + myList.add("one"); + myList.add("two"); + // This default method was added in Android T. + String[] toArray2 = myList.toArray(String[]::new); + System.out.println(Arrays.toString(toArray2)); + } + + @SuppressWarnings("all") + public static class MyList<T> extends ArrayList<T> { + public <T> T[] toArray(IntFunction<T[]> generator) { + System.out.println("Override"); + return super.toArray(generator); + } } }
diff --git a/src/test/examplesJava9/time/LocalDateMain.java b/src/test/examplesJava9/time/LocalDateMain.java new file mode 100644 index 0000000..79077bb --- /dev/null +++ b/src/test/examplesJava9/time/LocalDateMain.java
@@ -0,0 +1,25 @@ +// Copyright (c) 2023, 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 time; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.Period; +import java.time.ZoneId; +import java.time.ZoneOffset; + +public class LocalDateMain { + + public static void main(String[] args) { + System.out.println(LocalDate.EPOCH); + System.out.println(LocalDate.ofInstant(Instant.EPOCH, ZoneId.ofOffset("UTC", ZoneOffset.UTC))); + System.out.println(LocalDate.EPOCH.toEpochSecond(LocalTime.NOON, ZoneOffset.UTC)); + System.out.println(LocalDate.EPOCH.datesUntil(LocalDate.EPOCH).count()); + System.out.println(LocalDate.EPOCH.datesUntil(LocalDate.EPOCH, Period.of(1, 1, 1)).count()); + System.out.println( + LocalDate.EPOCH.datesUntil(LocalDate.ofEpochDay(7), Period.of(0, 0, 1)).count()); + } +}
diff --git a/src/test/java/com/android/tools/r8/KotlinCompilerTool.java b/src/test/java/com/android/tools/r8/KotlinCompilerTool.java index 737e8bd..36f3b07 100644 --- a/src/test/java/com/android/tools/r8/KotlinCompilerTool.java +++ b/src/test/java/com/android/tools/r8/KotlinCompilerTool.java
@@ -64,10 +64,11 @@ KOTLINC_1_5_0("kotlin-compiler-1.5.0"), KOTLINC_1_6_0("kotlin-compiler-1.6.0"), KOTLINC_1_7_0("kotlin-compiler-1.7.0"), + KOTLINC_1_8_0("kotlin-compiler-1.8.0"), KOTLIN_DEV("kotlin-compiler-dev"); - public static final KotlinCompilerVersion MIN_SUPPORTED_VERSION = KOTLINC_1_5_0; - public static final KotlinCompilerVersion MAX_SUPPORTED_VERSION = KOTLINC_1_7_0; + public static final KotlinCompilerVersion MIN_SUPPORTED_VERSION = KOTLINC_1_6_0; + public static final KotlinCompilerVersion MAX_SUPPORTED_VERSION = KOTLINC_1_8_0; private final String folder;
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java index 5d32ca1..322b30f 100644 --- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockInheritedClassTest.java
@@ -6,8 +6,7 @@ import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass; import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer; -import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; -import static org.hamcrest.MatcherAssert.assertThat; +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat; import static org.junit.Assume.assumeTrue; import com.android.tools.r8.CompilationMode; @@ -98,7 +97,7 @@ } private void inspect(CodeInspector inspector) { - assertThat(inspector.clazz(LibraryClass.class), isAbsent()); + verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(mockLevel); } private void checkOutput(SingleTestRunResult<?> runResult) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java index a45f683..5d4fc8f 100644 --- a/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java +++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelMockSuperChainClassTest.java
@@ -6,8 +6,7 @@ import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass; import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForDefaultInstanceInitializer; -import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent; -import static org.hamcrest.MatcherAssert.assertThat; +import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat; import static org.junit.Assume.assumeTrue; import com.android.tools.r8.CompilationMode; @@ -122,9 +121,9 @@ } private void inspect(CodeInspector inspector) { - assertThat(inspector.clazz(LibraryClass.class), isAbsent()); - assertThat(inspector.clazz(LibraryInterface.class), isAbsent()); - assertThat(inspector.clazz(OtherLibraryClass.class), isAbsent()); + verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(lowerMockApiLevel); + verifyThat(inspector, parameters, LibraryInterface.class).stubbedUntil(lowerMockApiLevel); + verifyThat(inspector, parameters, OtherLibraryClass.class).stubbedUntil(mockApiLevel); } private void checkOutput(SingleTestRunResult<?> runResult) {
diff --git a/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java b/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java index abe31f8..2376a81 100644 --- a/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java +++ b/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java
@@ -10,6 +10,7 @@ import com.android.tools.r8.CompilationMode; import com.android.tools.r8.DiagnosticsMatcher; import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler; +import com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion; import com.android.tools.r8.KotlinTestParameters; import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; @@ -50,7 +51,7 @@ .setMinApi(parameters.getApiLevel()) .compileWithExpectedDiagnostics( diagnostics -> { - if (kotlinTestParameters.isKotlinDev() + if (kotlinTestParameters.isNewerThanOrEqualTo(KotlinCompilerVersion.KOTLINC_1_8_0) && parameters.isDexRuntime() && parameters.getApiLevel().isLessThan(AndroidApiLevel.N)) { diagnostics.assertWarningsCount(2); @@ -75,7 +76,8 @@ .setMode(CompilationMode.DEBUG) .setMinApi(parameters.getApiLevel()) .applyIf( - parameters.isCfRuntime() && kotlinTestParameters.isKotlinDev(), + parameters.isCfRuntime() + && kotlinTestParameters.isNewerThanOrEqualTo(KotlinCompilerVersion.KOTLINC_1_8_0), TestShrinkerBuilder::addDontWarnJavaLangInvokeLambdaMetadataFactory) .compile() .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."));
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/BackportPlatformTest.java b/src/test/java/com/android/tools/r8/desugar/backports/BackportPlatformTest.java index 94fb0ce..bd8016c 100644 --- a/src/test/java/com/android/tools/r8/desugar/backports/BackportPlatformTest.java +++ b/src/test/java/com/android/tools/r8/desugar/backports/BackportPlatformTest.java
@@ -68,6 +68,7 @@ public void testPlatformR8() throws Exception { testForR8(parameters.getBackend()) .apply(b -> b.getBuilder().setAndroidPlatformBuild(true)) + .addOptionsModification(o -> o.disableBackportsWithErrorDiagnostics = true) .addProgramClasses(CLASSES) .addKeepMainRule(TestClass.class) .addKeepClassAndMembersRules(MiniAssert.class) @@ -79,6 +80,7 @@ public void testPlatformD8() throws Exception { testForD8(parameters.getBackend()) .apply(b -> b.getBuilder().setAndroidPlatformBuild(true)) + .addOptionsModification(o -> o.disableBackportsWithErrorDiagnostics = true) .addProgramClasses(CLASSES) .setMinApi(parameters.getApiLevel()) .compileWithExpectedDiagnostics(this::checkDiagnostics);
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 24969a0..b915afe 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
@@ -6,7 +6,6 @@ import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG; import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8SHRINK; -import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_CHM_ONLY; import com.android.tools.r8.TestParameters; import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification; @@ -29,7 +28,7 @@ public static List<Object[]> data() { return buildParameters( getTestParameters().withNoneRuntime().build(), - ImmutableList.of(JDK11_CHM_ONLY), + ImmutableList.of(LibraryDesugaringSpecification.JDK11_MINIMAL), ImmutableList.of(D8_L8DEBUG, D8_L8SHRINK)); }
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 2c99723..fb817c5 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
@@ -29,10 +29,13 @@ import com.android.tools.r8.graph.DexMethod; import com.android.tools.r8.graph.DirectMappedDexApplication; import com.android.tools.r8.graph.MethodResolutionResult; +import com.android.tools.r8.ir.desugar.BackportedMethodRewriter; import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy; import com.android.tools.r8.utils.AndroidApiLevel; import com.android.tools.r8.utils.AndroidApp; +import com.android.tools.r8.utils.InternalOptions; import com.android.tools.r8.utils.Pair; +import com.android.tools.r8.utils.ThreadUtils; import com.android.tools.r8.utils.Timing; import com.android.tools.r8.utils.codeinspector.CodeInspector; import com.android.tools.r8.utils.codeinspector.FoundClassSubject; @@ -123,10 +126,9 @@ AndroidApp.builder() .addLibraryFiles(libraryDesugaringSpecification.getLibraryFiles()) .build(); + InternalOptions options = inspector.getApplication().options; DirectMappedDexApplication libHolder = - new ApplicationReader(build, inspector.getApplication().options, Timing.empty()) - .read() - .toDirect(); + new ApplicationReader(build, options, Timing.empty()).read().toDirect(); DirectMappedDexApplication finalApp = inspector .getApplication() @@ -139,6 +141,9 @@ AppInfo.createInitialAppInfo( finalApp, GlobalSyntheticsStrategy.forNonSynthesizing())) .appInfoForDesugaring(); + List<DexMethod> backports = + BackportedMethodRewriter.generateListOfBackportedMethods( + build, options, ThreadUtils.getExecutorService(1)); Map<DexMethod, Object> failures = new IdentityHashMap<>(); for (FoundClassSubject clazz : inspector.allClasses()) { for (FoundMethodSubject method : clazz.allMethods()) { @@ -154,6 +159,8 @@ failures.remove(dexMethod); } else if (ALLOWED_MISSING_METHOD.contains(dexMethod.toString())) { failures.remove(dexMethod); + } else if (backports.contains(dexMethod)) { + failures.remove(dexMethod); } } assertTrue(failures.isEmpty());
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 17ed737..b357b2c 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
@@ -4,8 +4,9 @@ package com.android.tools.r8.desugar.desugaredlibrary; +import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_MINIMAL; import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8; -import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11; +import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8AndAll3Jdk11; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -41,7 +42,7 @@ @Parameters(name = "{0}, spec: {1}") public static List<Object[]> data() { - return buildParameters(getTestParameters().withNoneRuntime().build(), getJdk8Jdk11()); + return buildParameters(getTestParameters().withNoneRuntime().build(), getJdk8AndAll3Jdk11()); } public LintFilesTest( @@ -63,6 +64,18 @@ // Just do some light probing in the generated lint files. lintContents = FileUtils.readAllLines(lintFile); + // All methods supported on CHM. + assertEquals( + libraryDesugaringSpecification != JDK8, + supportsAllMethodsOf("java/util/concurrent/ConcurrentHashMap")); + + // All methods supported on BiFunction with maintain prefix. + assertTrue(supportsAllMethodsOf("java/util/function/BiFunction")); + + if (libraryDesugaringSpecification == JDK11_MINIMAL) { + return; + } + // All methods supported on Optional*. assertTrue(supportsAllMethodsOf("java/util/Optional")); assertTrue(supportsAllMethodsOf("java/util/OptionalInt")); @@ -97,10 +110,6 @@ supportsMethodButNotAllMethodsInClass( "java/util/stream/IntStream#allMatch(Ljava/util/function/IntPredicate;)Z")); - assertEquals( - libraryDesugaringSpecification != JDK8, - supportsAllMethodsOf("java/util/concurrent/ConcurrentHashMap")); - // Checks specific methods are supported or not in JDK8, all is supported in JDK11. if (libraryDesugaringSpecification == JDK8) { // Supported methods on ConcurrentHashMap. @@ -174,7 +183,7 @@ AndroidApiLevel.B.getLevel()); for (AndroidApiLevel apiLevel : AndroidApiLevel.values()) { - if (apiLevel.isGreaterThan(AndroidApiLevel.Sv2)) { + if (apiLevel.isGreaterThan(AndroidApiLevel.T)) { continue; } Path compileApiLevelDirectory = directory.resolve("compile_api_level_" + apiLevel.getLevel()); @@ -202,5 +211,16 @@ } } } + + Path directory2 = temp.newFolder().toPath(); + GenerateLintFiles.main( + new String[] { + "--generate-api-docs", + libraryDesugaringSpecification.getSpecification().toString(), + jdkLibJar.toString(), + directory2.toString() + }); + List<String> html = Files.readAllLines(directory2.resolve("apis.html")); + assertTrue(html.contains(" <td><code>java.util.function</code></td>")); } }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/CollectionToArrayTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/CollectionToArrayTest.java index d3d901a..6f1b750 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/CollectionToArrayTest.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/CollectionToArrayTest.java
@@ -4,7 +4,7 @@ package com.android.tools.r8.desugar.desugaredlibrary.jdk11; -import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS; +import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.SPECIFICATIONS_WITH_CF2CF; import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11; import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_PATH; @@ -32,7 +32,8 @@ private static final Path INPUT_JAR = Paths.get(ToolHelper.EXAMPLES_JAVA11_JAR_DIR + "collectiontoarray.jar"); - private static final String EXPECTED_OUTPUT = StringUtils.lines("[one, two]"); + private static final String EXPECTED_OUTPUT = + StringUtils.lines("[one, two]", "Override", "[one, two]"); private static final String MAIN_CLASS = "collectiontoarray.Main"; @Parameters(name = "{0}, spec: {1}, {2}") @@ -40,7 +41,7 @@ return buildParameters( getTestParameters().withDexRuntimes().withAllApiLevels().build(), ImmutableList.of(JDK11, JDK11_PATH), - DEFAULT_SPECIFICATIONS); + SPECIFICATIONS_WITH_CF2CF); } public CollectionToArrayTest(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesMoveCopyTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesMoveCopyTest.java index 59564e6..9656a73 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesMoveCopyTest.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/FilesMoveCopyTest.java
@@ -51,7 +51,7 @@ @RunWith(Parameterized.class) public class FilesMoveCopyTest extends DesugaredLibraryTestBase { - private static final String EXPECTED_RESULT_FORMAT = + private static final String EXPECTED_RESULT = StringUtils.lines( "Testing COPY_TO_OUTPUT_STREAM EXISTING NONE", "COPY_TO_OUTPUT_STREAM_NONE", @@ -66,7 +66,7 @@ "Testing COPY EXISTING NONE", "Failure: class java.nio.file.FileAlreadyExistsException :: dest", "Testing COPY_FROM_INPUT_STREAM EXISTING NONE", - "%s", + "Failure: class java.nio.file.FileAlreadyExistsException :: dest", "Testing MOVE NEW ATOMIC_MOVE", "MOVE_ATOMIC_MOVE", "Testing COPY NEW ATOMIC_MOVE", @@ -108,7 +108,8 @@ // Skip Android 4.4.4 due to missing libjavacrypto. getTestParameters() .withCfRuntime(CfVm.JDK11) - .withDexRuntimesStartingFromIncluding(Version.V8_1_0) + .withDexRuntime(Version.V4_0_4) + .withDexRuntimesStartingFromIncluding(Version.V5_1_1) .withAllApiLevels() .build(), ImmutableList.of(JDK11_PATH), @@ -124,19 +125,6 @@ this.compilationSpecification = compilationSpecification; } - private String getExpectedResult() { - // TODO(b/260208125): Fix invalid behavior. - // When copying from the input stream into an existing file and no options, - // the desugared version succeeds by deleting the file while the regular version fails - // with FileAlreadyExistsException exception. - String result = - (parameters.isDexRuntime() - && !libraryDesugaringSpecification.usesPlatformFileSystem(parameters)) - ? "COPY_FROM_INPUT_STREAM_NONE" - : "Failure: class java.nio.file.FileAlreadyExistsException :: dest"; - return String.format(EXPECTED_RESULT_FORMAT, result); - } - @Test public void test() throws Throwable { if (parameters.isCfRuntime()) { @@ -146,7 +134,7 @@ testForJvm() .addInnerClasses(getClass()) .run(parameters.getRuntime(), TestClass.class) - .assertSuccessWithOutput(getExpectedResult()); + .assertSuccessWithOutput(EXPECTED_RESULT); return; } testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification) @@ -155,7 +143,7 @@ .compile() .withArt6Plus64BitsLib() .run(parameters.getRuntime(), TestClass.class) - .assertSuccessWithOutput(getExpectedResult()); + .assertSuccessWithOutput(EXPECTED_RESULT); } public static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/NewLocalDateTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/NewLocalDateTest.java new file mode 100644 index 0000000..d942e79 --- /dev/null +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/NewLocalDateTest.java
@@ -0,0 +1,63 @@ +// Copyright (c) 2023, 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.jdk11; + +import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS; +import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11; +import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_PATH; + +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.ToolHelper; +import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase; +import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification; +import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification; +import com.android.tools.r8.utils.StringUtils; +import com.google.common.collect.ImmutableList; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +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 NewLocalDateTest extends DesugaredLibraryTestBase { + + private final TestParameters parameters; + private final LibraryDesugaringSpecification libraryDesugaringSpecification; + private final CompilationSpecification compilationSpecification; + + private static final Path INPUT_JAR = Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR + "time.jar"); + private static final String EXPECTED_OUTPUT = + StringUtils.lines("1970-01-01", "1970-01-01", "43200", "0", "0", "7"); + private static final String MAIN_CLASS = "time.LocalDateMain"; + + @Parameters(name = "{0}, spec: {1}, {2}") + public static List<Object[]> data() { + return buildParameters( + getTestParameters().withDexRuntimes().withAllApiLevels().build(), + ImmutableList.of(JDK11, JDK11_PATH), + DEFAULT_SPECIFICATIONS); + } + + public NewLocalDateTest( + TestParameters parameters, + LibraryDesugaringSpecification libraryDesugaringSpecification, + CompilationSpecification compilationSpecification) { + this.parameters = parameters; + this.libraryDesugaringSpecification = libraryDesugaringSpecification; + this.compilationSpecification = compilationSpecification; + } + + @Test + public void test() throws Throwable { + testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification) + .addProgramFiles(INPUT_JAR) + .addKeepMainRule(MAIN_CLASS) + .run(parameters.getRuntime(), MAIN_CLASS) + .assertSuccessWithOutput(EXPECTED_OUTPUT); + } +}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestBuilder.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestBuilder.java index 6ef6b8b..4144aaa 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestBuilder.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestBuilder.java
@@ -324,10 +324,15 @@ return this; } + public DesugaredLibraryTestBuilder<T> apply(Consumer<DesugaredLibraryTestBuilder<T>> consumer) { + consumer.accept(this); + return this; + } + public DesugaredLibraryTestBuilder<T> applyIf( boolean apply, Consumer<DesugaredLibraryTestBuilder<T>> consumer) { if (apply) { - consumer.accept(this); + return apply(consumer); } return this; }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java index 42ade2a..7f89255 100644 --- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java +++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
@@ -144,22 +144,6 @@ LATEST); // Legacy specifications. - public static LibraryDesugaringSpecification JDK11_PATH_ALTERNATIVE_3 = - new LibraryDesugaringSpecification( - "JDK11_PATH_ALTERNATIVE_3", - tempLibraryJDK11Undesugar, - "jdk11/desugar_jdk_libs_nio_alternative_3.json", - AndroidApiLevel.R, - JDK11_PATH_DESCRIPTOR, - LATEST); - public static LibraryDesugaringSpecification JDK11_CHM_ONLY = - new LibraryDesugaringSpecification( - "JDK11_CHM_ONLY", - tempLibraryJDK11Undesugar, - "jdk11/chm_only_desugar_jdk_libs.json", - AndroidApiLevel.R, - EMPTY_DESCRIPTOR_24, - LATEST); public static LibraryDesugaringSpecification JDK11_LEGACY = new LibraryDesugaringSpecification( "JDK11_LEGACY", @@ -286,6 +270,10 @@ return ImmutableList.of(JDK8, JDK11); } + public static List<LibraryDesugaringSpecification> getJdk8AndAll3Jdk11() { + return ImmutableList.of(JDK8, JDK11, JDK11_MINIMAL, JDK11_PATH); + } + public DexApplication getAppForTesting(InternalOptions options, boolean libraryCompilation) throws IOException { AndroidApp.Builder builder = AndroidApp.builder();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceRemovalPackageBoundaryTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceRemovalPackageBoundaryTest.java index 2ea0223..df6a58c 100644 --- a/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceRemovalPackageBoundaryTest.java +++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceRemovalPackageBoundaryTest.java
@@ -47,7 +47,6 @@ .enableNeverClassInliningAnnotations() .enableNoVerticalClassMergingAnnotations() .setMinApi(parameters.getApiLevel()) - .addDontObfuscate() .compile() .inspect( inspector -> {
diff --git a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java index 214b507..0095c21 100644 --- a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java
@@ -5,6 +5,7 @@ import static org.hamcrest.CoreMatchers.equalTo; +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; @@ -41,7 +42,9 @@ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.LATEST)) .addKeepRules(rules) .applyIf( - notShrinking && kotlinParameters.isKotlinDev() && parameters.isCfRuntime(), + notShrinking + && kotlinParameters.isNewerThanOrEqualTo(KotlinCompilerVersion.KOTLINC_1_8_0) + && parameters.isCfRuntime(), TestShrinkerBuilder::addDontWarnJavaLangInvokeLambdaMetadataFactory) .addKeepAttributes(ProguardKeepAttributes.SIGNATURE) .addKeepAttributes(ProguardKeepAttributes.INNER_CLASSES)
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java index 87dc848..7b07978 100644 --- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
@@ -5,7 +5,7 @@ package com.android.tools.r8.kotlin.metadata; import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_4_20; -import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_7_0; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_8_0; import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.MatcherAssert.assertThat; @@ -130,7 +130,7 @@ .setOutputPath(temp.newFolder().toPath()) .compileRaw(); Assert.assertEquals(1, compileResult.exitCode); - if (kotlinParameters.isNewerThan(KOTLINC_1_7_0)) { + if (kotlinParameters.isNewerThan(KOTLINC_1_8_0)) { assertThat( compileResult.stderr, containsString("the feature \"references to synthetic java properties\""));
diff --git a/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java b/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java index 6078cef..ab2f10d 100644 --- a/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java +++ b/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java
@@ -5,6 +5,7 @@ package com.android.tools.r8.kotlin.reflection; import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_3_72; +import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_8_0; import static org.junit.Assume.assumeTrue; import com.android.tools.r8.DexIndexedConsumer.ArchiveConsumer; @@ -100,7 +101,7 @@ .allowDiagnosticMessages() .allowUnusedDontWarnKotlinReflectJvmInternal(kotlinc.isNot(KOTLINC_1_3_72)) .applyIf( - parameters.isCfRuntime() && kotlinParameters.isKotlinDev(), + parameters.isCfRuntime() && kotlinParameters.isNewerThanOrEqualTo(KOTLINC_1_8_0), TestShrinkerBuilder::addDontWarnJavaLangInvokeLambdaMetadataFactory) .compile() .assertNoErrorMessages()
diff --git a/src/test/java/com/android/tools/r8/profile/art/ArtProfileCollisionAfterClassMergingRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/ArtProfileCollisionAfterClassMergingRewritingTest.java index 598101f..922cae7 100644 --- a/src/test/java/com/android/tools/r8/profile/art/ArtProfileCollisionAfterClassMergingRewritingTest.java +++ b/src/test/java/com/android/tools/r8/profile/art/ArtProfileCollisionAfterClassMergingRewritingTest.java
@@ -7,22 +7,24 @@ import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import com.android.tools.r8.NeverInline; import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; -import com.android.tools.r8.origin.Origin; +import com.android.tools.r8.profile.art.model.ExternalArtProfile; +import com.android.tools.r8.profile.art.model.ExternalArtProfileClassRule; +import com.android.tools.r8.profile.art.model.ExternalArtProfileMethodRule; +import com.android.tools.r8.profile.art.utils.ArtProfileTestingUtils; 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.utils.AndroidApiLevel; +import com.android.tools.r8.utils.Box; import com.android.tools.r8.utils.MethodReferenceUtils; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.CodeInspector; import com.android.tools.r8.utils.codeinspector.MethodSubject; -import com.google.common.collect.Lists; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -54,23 +56,36 @@ @Test public void test() throws Exception { - MyArtProfileProvider artProfileProvider = new MyArtProfileProvider(); - ArtProfileConsumerForTesting residualArtProfileConsumer = new ArtProfileConsumerForTesting(); + Box<ExternalArtProfile> residualArtProfile = new Box<>(); testForR8(Backend.DEX) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addArtProfileForRewriting(artProfileProvider, residualArtProfileConsumer) .addHorizontallyMergedClassesInspector( inspector -> inspector.assertMergedInto(Foo.class, Bar.class).assertNoOtherClassesMerged()) + .apply( + testBuilder -> + ArtProfileTestingUtils.addArtProfileForRewriting( + getArtProfile(), residualArtProfile::set, testBuilder)) .enableInliningAnnotations() .setMinApi(AndroidApiLevel.LATEST) .compile() - .inspect(inspector -> inspect(inspector, residualArtProfileConsumer)); + .inspect(inspector -> inspect(inspector, residualArtProfile.get())); } - private void inspect( - CodeInspector inspector, ArtProfileConsumerForTesting residualArtProfileConsumer) { + public ExternalArtProfile getArtProfile() { + return ExternalArtProfile.builder() + .addRules( + ExternalArtProfileClassRule.builder().setClassReference(mainClassReference).build(), + ExternalArtProfileMethodRule.builder().setMethodReference(mainMethodReference).build(), + ExternalArtProfileClassRule.builder().setClassReference(fooClassReference).build(), + ExternalArtProfileMethodRule.builder().setMethodReference(helloMethodReference).build(), + ExternalArtProfileClassRule.builder().setClassReference(barClassReference).build(), + ExternalArtProfileMethodRule.builder().setMethodReference(worldMethodReference).build()) + .build(); + } + + public ExternalArtProfile getExpectedResidualArtProfile(CodeInspector inspector) { ClassSubject barClassSubject = inspector.clazz(Bar.class); assertThat(barClassSubject, isPresentAndRenamed()); @@ -80,45 +95,24 @@ MethodSubject worldMethodSubject = barClassSubject.uniqueMethodWithOriginalName("world"); assertThat(worldMethodSubject, isPresentAndRenamed()); - assertTrue(residualArtProfileConsumer.finished); - assertEquals( - Lists.newArrayList( - mainClassReference, - mainMethodReference, - barClassSubject.getFinalReference(), - helloMethodSubject.getFinalReference(), - worldMethodSubject.getFinalReference()), - residualArtProfileConsumer.references); - assertEquals( - Lists.newArrayList( - ArtProfileClassRuleInfoImpl.empty(), - ArtProfileMethodRuleInfoImpl.empty(), - ArtProfileClassRuleInfoImpl.empty(), - ArtProfileMethodRuleInfoImpl.empty(), - ArtProfileMethodRuleInfoImpl.empty()), - residualArtProfileConsumer.infos); + return ExternalArtProfile.builder() + .addRules( + ExternalArtProfileClassRule.builder().setClassReference(mainClassReference).build(), + ExternalArtProfileMethodRule.builder().setMethodReference(mainMethodReference).build(), + ExternalArtProfileClassRule.builder() + .setClassReference(barClassSubject.getFinalReference()) + .build(), + ExternalArtProfileMethodRule.builder() + .setMethodReference(helloMethodSubject.getFinalReference()) + .build(), + ExternalArtProfileMethodRule.builder() + .setMethodReference(worldMethodSubject.getFinalReference()) + .build()) + .build(); } - static class MyArtProfileProvider implements ArtProfileProvider { - - @Override - public void getArtProfile(ArtProfileBuilder profileBuilder) { - profileBuilder - .addClassRule(classRuleBuilder -> classRuleBuilder.setClassReference(mainClassReference)) - .addMethodRule( - methodRuleBuilder -> methodRuleBuilder.setMethodReference(mainMethodReference)) - .addClassRule(classRuleBuilder -> classRuleBuilder.setClassReference(fooClassReference)) - .addMethodRule( - methodRuleBuilder -> methodRuleBuilder.setMethodReference(helloMethodReference)) - .addClassRule(classRuleBuilder -> classRuleBuilder.setClassReference(barClassReference)) - .addMethodRule( - methodRuleBuilder -> methodRuleBuilder.setMethodReference(worldMethodReference)); - } - - @Override - public Origin getOrigin() { - return Origin.unknown(); - } + private void inspect(CodeInspector inspector, ExternalArtProfile residualArtProfile) { + assertEquals(getExpectedResidualArtProfile(inspector), residualArtProfile); } static class Main {
diff --git a/src/test/java/com/android/tools/r8/profile/art/ArtProfileConsumerForTesting.java b/src/test/java/com/android/tools/r8/profile/art/ArtProfileConsumerForTesting.java deleted file mode 100644 index 2a0a041..0000000 --- a/src/test/java/com/android/tools/r8/profile/art/ArtProfileConsumerForTesting.java +++ /dev/null
@@ -1,43 +0,0 @@ -// 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.profile.art; - -import com.android.tools.r8.DiagnosticsHandler; -import com.android.tools.r8.references.ClassReference; -import com.android.tools.r8.references.MethodReference; -import java.util.ArrayList; -import java.util.List; - -public class ArtProfileConsumerForTesting implements ArtProfileConsumer { - - boolean finished; - List<Object> references = new ArrayList<>(); - List<Object> infos = new ArrayList<>(); - - @Override - public ArtProfileRuleConsumer getRuleConsumer() { - return new ArtProfileRuleConsumer() { - - @Override - public void acceptClassRule( - ClassReference classReference, ArtProfileClassRuleInfo classRuleInfo) { - references.add(classReference); - infos.add(classRuleInfo); - } - - @Override - public void acceptMethodRule( - MethodReference methodReference, ArtProfileMethodRuleInfo methodRuleInfo) { - references.add(methodReference); - infos.add(methodRuleInfo); - } - }; - } - - @Override - public void finished(DiagnosticsHandler handler) { - finished = true; - } -}
diff --git a/src/test/java/com/android/tools/r8/profile/art/ArtProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/ArtProfileRewritingTest.java index ff9003a..c5fb462 100644 --- a/src/test/java/com/android/tools/r8/profile/art/ArtProfileRewritingTest.java +++ b/src/test/java/com/android/tools/r8/profile/art/ArtProfileRewritingTest.java
@@ -7,22 +7,24 @@ import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import com.android.tools.r8.NeverInline; import com.android.tools.r8.TestBase; import com.android.tools.r8.TestParameters; import com.android.tools.r8.TestParametersCollection; -import com.android.tools.r8.origin.Origin; +import com.android.tools.r8.profile.art.model.ExternalArtProfile; +import com.android.tools.r8.profile.art.model.ExternalArtProfileClassRule; +import com.android.tools.r8.profile.art.model.ExternalArtProfileMethodRule; +import com.android.tools.r8.profile.art.utils.ArtProfileTestingUtils; 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.utils.AndroidApiLevel; +import com.android.tools.r8.utils.Box; import com.android.tools.r8.utils.MethodReferenceUtils; import com.android.tools.r8.utils.codeinspector.ClassSubject; import com.android.tools.r8.utils.codeinspector.CodeInspector; import com.android.tools.r8.utils.codeinspector.MethodSubject; -import com.google.common.collect.Lists; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -51,70 +53,64 @@ @Test public void test() throws Exception { - ArtProfileProviderForTesting artProfileProvider = new ArtProfileProviderForTesting(); - ArtProfileConsumerForTesting residualArtProfileConsumer = new ArtProfileConsumerForTesting(); + Box<ExternalArtProfile> residualArtProfile = new Box<>(); testForR8(Backend.DEX) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addArtProfileForRewriting(artProfileProvider, residualArtProfileConsumer) + .apply( + testBuilder -> + ArtProfileTestingUtils.addArtProfileForRewriting( + getArtProfile(), residualArtProfile::set, testBuilder)) .enableInliningAnnotations() .setMinApi(AndroidApiLevel.LATEST) .compile() - .inspect(inspector -> inspect(inspector, residualArtProfileConsumer)); + .inspect(inspector -> inspect(inspector, residualArtProfile.get())); } - private void inspect( - CodeInspector inspector, ArtProfileConsumerForTesting residualArtProfileConsumer) { + private ExternalArtProfile getArtProfile() { + return ExternalArtProfile.builder() + .addRules( + ExternalArtProfileClassRule.builder().setClassReference(mainClassReference).build(), + ExternalArtProfileMethodRule.builder() + .setMethodReference(mainMethodReference) + .setMethodRuleInfo(ArtProfileMethodRuleInfoImpl.builder().setIsStartup().build()) + .build(), + ExternalArtProfileClassRule.builder().setClassReference(greeterClassReference).build(), + ExternalArtProfileMethodRule.builder() + .setMethodReference(greetMethodReference) + .setMethodRuleInfo( + ArtProfileMethodRuleInfoImpl.builder().setIsHot().setIsPostStartup().build()) + .build()) + .build(); + } + + private ExternalArtProfile getExpectedResidualArtProfile(CodeInspector inspector) { ClassSubject greeterClassSubject = inspector.clazz(Greeter.class); assertThat(greeterClassSubject, isPresentAndRenamed()); MethodSubject greetMethodSubject = greeterClassSubject.uniqueMethodWithOriginalName("greet"); assertThat(greetMethodSubject, isPresentAndRenamed()); - assertTrue(residualArtProfileConsumer.finished); - assertEquals( - Lists.newArrayList( - mainClassReference, - mainMethodReference, - greeterClassSubject.getFinalReference(), - greetMethodSubject.getFinalReference()), - residualArtProfileConsumer.references); - assertEquals( - Lists.newArrayList( - ArtProfileClassRuleInfoImpl.empty(), - ArtProfileMethodRuleInfoImpl.builder().setIsStartup().build(), - ArtProfileClassRuleInfoImpl.empty(), - ArtProfileMethodRuleInfoImpl.builder().setIsHot().setIsPostStartup().build()), - residualArtProfileConsumer.infos); + return ExternalArtProfile.builder() + .addRules( + ExternalArtProfileClassRule.builder().setClassReference(mainClassReference).build(), + ExternalArtProfileMethodRule.builder() + .setMethodReference(mainMethodReference) + .setMethodRuleInfo(ArtProfileMethodRuleInfoImpl.builder().setIsStartup().build()) + .build(), + ExternalArtProfileClassRule.builder() + .setClassReference(greeterClassSubject.getFinalReference()) + .build(), + ExternalArtProfileMethodRule.builder() + .setMethodReference(greetMethodSubject.getFinalReference()) + .setMethodRuleInfo( + ArtProfileMethodRuleInfoImpl.builder().setIsHot().setIsPostStartup().build()) + .build()) + .build(); } - static class ArtProfileProviderForTesting implements ArtProfileProvider { - - @Override - public void getArtProfile(ArtProfileBuilder profileBuilder) { - profileBuilder - .addClassRule(classRuleBuilder -> classRuleBuilder.setClassReference(mainClassReference)) - .addMethodRule( - methodRuleBuilder -> - methodRuleBuilder - .setMethodReference(mainMethodReference) - .setMethodRuleInfo( - methodRuleInfoBuilder -> methodRuleInfoBuilder.setIsStartup(true))) - .addClassRule( - classRuleBuilder -> classRuleBuilder.setClassReference(greeterClassReference)) - .addMethodRule( - methodRuleBuilder -> - methodRuleBuilder - .setMethodReference(greetMethodReference) - .setMethodRuleInfo( - methodRuleInfoBuilder -> - methodRuleInfoBuilder.setIsHot(true).setIsPostStartup(true))); - } - - @Override - public Origin getOrigin() { - return Origin.unknown(); - } + private void inspect(CodeInspector inspector, ExternalArtProfile residualArtProfile) { + assertEquals(getExpectedResidualArtProfile(inspector), residualArtProfile); } static class Main {
diff --git a/src/test/java/com/android/tools/r8/profile/art/DesugaredLibraryArtProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/DesugaredLibraryArtProfileRewritingTest.java index f93737b..52e0beb 100644 --- a/src/test/java/com/android/tools/r8/profile/art/DesugaredLibraryArtProfileRewritingTest.java +++ b/src/test/java/com/android/tools/r8/profile/art/DesugaredLibraryArtProfileRewritingTest.java
@@ -16,13 +16,16 @@ import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase; import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification; import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification; -import com.android.tools.r8.origin.Origin; +import com.android.tools.r8.profile.art.model.ExternalArtProfile; +import com.android.tools.r8.profile.art.model.ExternalArtProfileMethodRule; +import com.android.tools.r8.profile.art.utils.ArtProfileTestingUtils; import com.android.tools.r8.references.MethodReference; import com.android.tools.r8.references.Reference; +import com.android.tools.r8.utils.Box; import com.android.tools.r8.utils.codeinspector.ClassSubject; +import com.android.tools.r8.utils.codeinspector.CodeInspector; import com.android.tools.r8.utils.codeinspector.MethodSubject; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -56,64 +59,65 @@ @Test public void test() throws Throwable { Assume.assumeTrue(libraryDesugaringSpecification.hasEmulatedInterfaceDesugaring(parameters)); - ArtProfileProviderForTesting artProfileProvider = new ArtProfileProviderForTesting(); - ArtProfileConsumerForTesting residualArtProfileConsumer = new ArtProfileConsumerForTesting(); + Box<ExternalArtProfile> residualArtProfile = new Box<>(); testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification) .addInnerClasses(getClass()) .addKeepMainRule(Main.class) - .addL8ArtProfileForRewriting(artProfileProvider, residualArtProfileConsumer) + .apply( + testBuilder -> + ArtProfileTestingUtils.addArtProfileForRewriting( + getArtProfile(), residualArtProfile::set, testBuilder)) .compile() - .inspectL8( - inspector -> { - ClassSubject consumerClassSubject = - inspector.clazz( - libraryDesugaringSpecification.functionPrefix(parameters) - + ".util.function.Consumer"); - assertThat(consumerClassSubject, isPresent()); - - ClassSubject streamClassSubject = inspector.clazz("j$.util.stream.Stream"); - assertThat(streamClassSubject, isPresentAndNotRenamed()); - - MethodSubject forEachMethodSubject = - streamClassSubject.uniqueMethodWithOriginalName("forEach"); - assertThat( - forEachMethodSubject, - isPresentAndRenamed( - compilationSpecification.isL8Shrink() - && libraryDesugaringSpecification - == LibraryDesugaringSpecification.JDK8)); - assertEquals( - consumerClassSubject.asTypeSubject(), forEachMethodSubject.getParameter(0)); - - assertEquals( - Lists.newArrayList(forEachMethodSubject.getFinalReference()), - residualArtProfileConsumer.references); - }) + .inspectL8(inspector -> inspect(inspector, residualArtProfile.get())) .run(parameters.getRuntime(), Main.class) .assertSuccessWithOutputLines("0"); } - class ArtProfileProviderForTesting implements ArtProfileProvider { + private ExternalArtProfile getArtProfile() { + MethodReference forEachMethodReference = + Reference.method( + Reference.classFromTypeName("j$.util.stream.Stream"), + "forEach", + ImmutableList.of( + Reference.classFromTypeName( + libraryDesugaringSpecification.functionPrefix(parameters) + + ".util.function.Consumer")), + null); + return ExternalArtProfile.builder() + .addRule( + ExternalArtProfileMethodRule.builder() + .setMethodReference(forEachMethodReference) + .build()) + .build(); + } - @Override - public void getArtProfile(ArtProfileBuilder profileBuilder) { - MethodReference forEachMethodReference = - Reference.method( - Reference.classFromTypeName("j$.util.stream.Stream"), - "forEach", - ImmutableList.of( - Reference.classFromTypeName( - libraryDesugaringSpecification.functionPrefix(parameters) - + ".util.function.Consumer")), - null); - profileBuilder.addMethodRule( - methodRuleBuilder -> methodRuleBuilder.setMethodReference(forEachMethodReference)); - } + private ExternalArtProfile getExpectedResidualArtProfile(MethodSubject forEachMethodSubject) { + return ExternalArtProfile.builder() + .addRule( + ExternalArtProfileMethodRule.builder() + .setMethodReference(forEachMethodSubject.getFinalReference()) + .build()) + .build(); + } - @Override - public Origin getOrigin() { - return Origin.unknown(); - } + private void inspect(CodeInspector inspector, ExternalArtProfile residualArtProfile) { + ClassSubject consumerClassSubject = + inspector.clazz( + libraryDesugaringSpecification.functionPrefix(parameters) + ".util.function.Consumer"); + assertThat(consumerClassSubject, isPresent()); + + ClassSubject streamClassSubject = inspector.clazz("j$.util.stream.Stream"); + assertThat(streamClassSubject, isPresentAndNotRenamed()); + + MethodSubject forEachMethodSubject = streamClassSubject.uniqueMethodWithOriginalName("forEach"); + assertThat( + forEachMethodSubject, + isPresentAndRenamed( + compilationSpecification.isL8Shrink() + && libraryDesugaringSpecification == LibraryDesugaringSpecification.JDK8)); + assertEquals(consumerClassSubject.asTypeSubject(), forEachMethodSubject.getParameter(0)); + + assertEquals(getExpectedResidualArtProfile(forEachMethodSubject), residualArtProfile); } static class Main {
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/SyntheticLambdaClassProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/SyntheticLambdaClassProfileRewritingTest.java new file mode 100644 index 0000000..3e9ef1c --- /dev/null +++ b/src/test/java/com/android/tools/r8/profile/art/completeness/SyntheticLambdaClassProfileRewritingTest.java
@@ -0,0 +1,97 @@ +// Copyright (c) 2023, 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.profile.art.completeness; + +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static com.android.tools.r8.utils.codeinspector.Matchers.onlyIf; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.TestParametersCollection; +import com.android.tools.r8.profile.art.model.ExternalArtProfile; +import com.android.tools.r8.profile.art.model.ExternalArtProfileMethodRule; +import com.android.tools.r8.profile.art.utils.ArtProfileTestingUtils; +import com.android.tools.r8.synthesis.SyntheticItemsTestUtils; +import com.android.tools.r8.utils.MethodReferenceUtils; +import com.android.tools.r8.utils.codeinspector.CodeInspector; +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 SyntheticLambdaClassProfileRewritingTest 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) + .apply( + testBuilder -> + ArtProfileTestingUtils.addArtProfileForRewriting( + getArtProfile(), this::inspectResidualArtProfile, testBuilder)) + .noHorizontalClassMergingOfSynthetics() + .setMinApi(parameters.getApiLevel()) + .compile() + .inspect(this::inspect) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("Hello, world!"); + } + + private ExternalArtProfile getArtProfile() { + return ExternalArtProfile.builder() + .addRule( + ExternalArtProfileMethodRule.builder() + .setMethodReference(MethodReferenceUtils.mainMethod(Main.class)) + .build()) + .build(); + } + + private void inspect(CodeInspector inspector) { + // Verify that two lambdas were synthesized when compiling to dex. + assertThat( + inspector.clazz(SyntheticItemsTestUtils.syntheticLambdaClass(Main.class, 0)), + onlyIf(parameters.isDexRuntime(), isPresent())); + assertThat( + inspector.clazz(SyntheticItemsTestUtils.syntheticLambdaClass(Main.class, 1)), + onlyIf(parameters.isDexRuntime(), isPresent())); + } + + private void inspectResidualArtProfile(ExternalArtProfile residualArtProfile) { + if (parameters.isCfRuntime()) { + assertEquals(getArtProfile(), residualArtProfile); + } else { + assert parameters.isDexRuntime(); + // TODO(b/265729283): Since Main.main() is in the art profile, so should the two synthetic + // lambdas be. + assertEquals(getArtProfile(), residualArtProfile); + } + } + + static class Main { + + public static void main(String[] args) { + Runnable lambda = + System.currentTimeMillis() > 0 + ? () -> System.out.println("Hello, world!") + : () -> { + throw new RuntimeException(); + }; + lambda.run(); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfile.java b/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfile.java new file mode 100644 index 0000000..0082727 --- /dev/null +++ b/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfile.java
@@ -0,0 +1,75 @@ +// Copyright (c) 2023, 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.profile.art.model; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; + +/** + * Represents an ART baseline profile (for testing). + * + * <p>This is similar to {@link com.android.tools.r8.profile.art.ArtProfile}, but unlike ArtProfile, + * this ExternalArtProfile is backed by {@link com.android.tools.r8.references.Reference}, and not + * {@link com.android.tools.r8.graph.DexItem}, so that no {@link + * com.android.tools.r8.graph.DexItemFactory} is needed to create an ExternalArtProfile. + */ +public class ExternalArtProfile { + + private final List<ExternalArtProfileRule> rules; + + ExternalArtProfile(List<ExternalArtProfileRule> rules) { + this.rules = rules; + } + + public static Builder builder() { + return new Builder(); + } + + public void forEach( + Consumer<ExternalArtProfileClassRule> classRuleConsumer, + Consumer<ExternalArtProfileMethodRule> methodRuleConsumer) { + for (ExternalArtProfileRule rule : rules) { + rule.accept(classRuleConsumer, methodRuleConsumer); + } + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + ExternalArtProfile profile = (ExternalArtProfile) obj; + return rules.equals(profile.rules); + } + + @Override + public int hashCode() { + return rules.hashCode(); + } + + public static class Builder { + + private final List<ExternalArtProfileRule> rules = new ArrayList<>(); + + public Builder addRule(ExternalArtProfileRule rule) { + rules.add(rule); + return this; + } + + public Builder addRules(ExternalArtProfileRule... rules) { + Collections.addAll(this.rules, rules); + return this; + } + + public ExternalArtProfile build() { + return new ExternalArtProfile(rules); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfileClassRule.java b/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfileClassRule.java new file mode 100644 index 0000000..84cc34b --- /dev/null +++ b/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfileClassRule.java
@@ -0,0 +1,68 @@ +// Copyright (c) 2023, 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.profile.art.model; + +import com.android.tools.r8.references.ClassReference; +import java.util.function.Consumer; + +/** + * Represents a class rule from an ART baseline profile, backed by {@link ClassReference}. Class + * rules currently contain no other information than the class reference. + */ +public class ExternalArtProfileClassRule extends ExternalArtProfileRule { + + private final ClassReference classReference; + + ExternalArtProfileClassRule(ClassReference classReference) { + assert classReference != null; + this.classReference = classReference; + } + + public static Builder builder() { + return new Builder(); + } + + @Override + public void accept( + Consumer<ExternalArtProfileClassRule> classRuleConsumer, + Consumer<ExternalArtProfileMethodRule> methodRuleConsumer) { + classRuleConsumer.accept(this); + } + + public ClassReference getClassReference() { + return classReference; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + ExternalArtProfileClassRule methodRule = (ExternalArtProfileClassRule) obj; + return classReference.equals(methodRule.classReference); + } + + @Override + public int hashCode() { + return classReference.hashCode(); + } + + public static class Builder { + + private ClassReference classReference; + + public Builder setClassReference(ClassReference classReference) { + this.classReference = classReference; + return this; + } + + public ExternalArtProfileClassRule build() { + return new ExternalArtProfileClassRule(classReference); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfileMethodRule.java b/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfileMethodRule.java new file mode 100644 index 0000000..86894b9 --- /dev/null +++ b/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfileMethodRule.java
@@ -0,0 +1,82 @@ +// Copyright (c) 2023, 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.profile.art.model; + +import com.android.tools.r8.profile.art.ArtProfileMethodRuleInfo; +import com.android.tools.r8.profile.art.ArtProfileMethodRuleInfoImpl; +import com.android.tools.r8.references.MethodReference; +import java.util.function.Consumer; + +/** Represents a method rule from an ART baseline profile, backed by {@link MethodReference}. */ +public class ExternalArtProfileMethodRule extends ExternalArtProfileRule { + + private final MethodReference methodReference; + private final ArtProfileMethodRuleInfo methodRuleInfo; + + ExternalArtProfileMethodRule( + MethodReference methodReference, ArtProfileMethodRuleInfo methodRuleInfo) { + assert methodReference != null; + assert methodRuleInfo != null; + this.methodReference = methodReference; + this.methodRuleInfo = methodRuleInfo; + } + + public static Builder builder() { + return new Builder(); + } + + @Override + public void accept( + Consumer<ExternalArtProfileClassRule> classRuleConsumer, + Consumer<ExternalArtProfileMethodRule> methodRuleConsumer) { + methodRuleConsumer.accept(this); + } + + public MethodReference getMethodReference() { + return methodReference; + } + + public ArtProfileMethodRuleInfo getMethodRuleInfo() { + return methodRuleInfo; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + ExternalArtProfileMethodRule methodRule = (ExternalArtProfileMethodRule) obj; + return methodReference.equals(methodRule.methodReference) + && methodRuleInfo.equals(methodRule.methodRuleInfo); + } + + @Override + public int hashCode() { + return methodReference.hashCode(); + } + + public static class Builder { + + private MethodReference methodReference; + private ArtProfileMethodRuleInfo methodRuleInfo = ArtProfileMethodRuleInfoImpl.empty(); + + public Builder setMethodReference(MethodReference methodReference) { + this.methodReference = methodReference; + return this; + } + + public Builder setMethodRuleInfo(ArtProfileMethodRuleInfo methodRuleInfo) { + this.methodRuleInfo = methodRuleInfo; + return this; + } + + public ExternalArtProfileMethodRule build() { + return new ExternalArtProfileMethodRule(methodReference, methodRuleInfo); + } + } +}
diff --git a/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfileRule.java b/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfileRule.java new file mode 100644 index 0000000..bd3c99e --- /dev/null +++ b/src/test/java/com/android/tools/r8/profile/art/model/ExternalArtProfileRule.java
@@ -0,0 +1,14 @@ +// Copyright (c) 2023, 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.profile.art.model; + +import java.util.function.Consumer; + +public abstract class ExternalArtProfileRule { + + public abstract void accept( + Consumer<ExternalArtProfileClassRule> classRuleConsumer, + Consumer<ExternalArtProfileMethodRule> methodRuleConsumer); +}
diff --git a/src/test/java/com/android/tools/r8/profile/art/utils/ArtProfileTestingUtils.java b/src/test/java/com/android/tools/r8/profile/art/utils/ArtProfileTestingUtils.java new file mode 100644 index 0000000..7443e49 --- /dev/null +++ b/src/test/java/com/android/tools/r8/profile/art/utils/ArtProfileTestingUtils.java
@@ -0,0 +1,116 @@ +// Copyright (c) 2023, 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.profile.art.utils; + +import com.android.tools.r8.DiagnosticsHandler; +import com.android.tools.r8.R8TestBuilder; +import com.android.tools.r8.desugar.desugaredlibrary.test.DesugaredLibraryTestBuilder; +import com.android.tools.r8.origin.Origin; +import com.android.tools.r8.profile.art.ArtProfileBuilder; +import com.android.tools.r8.profile.art.ArtProfileClassRuleInfo; +import com.android.tools.r8.profile.art.ArtProfileConsumer; +import com.android.tools.r8.profile.art.ArtProfileMethodRuleInfo; +import com.android.tools.r8.profile.art.ArtProfileProvider; +import com.android.tools.r8.profile.art.ArtProfileRuleConsumer; +import com.android.tools.r8.profile.art.model.ExternalArtProfile; +import com.android.tools.r8.profile.art.model.ExternalArtProfileClassRule; +import com.android.tools.r8.profile.art.model.ExternalArtProfileMethodRule; +import com.android.tools.r8.references.ClassReference; +import com.android.tools.r8.references.MethodReference; +import java.util.function.Consumer; + +public class ArtProfileTestingUtils { + + /** + * Adds the given {@param artProfile} as an ART profile for rewriting. The residual ART profile + * will be forwarded to the given test inspector, {@param residualArtProfileInspector}. + */ + public static void addArtProfileForRewriting( + ExternalArtProfile artProfile, + Consumer<ExternalArtProfile> residualArtProfileInspector, + R8TestBuilder<?> testBuilder) { + testBuilder.addArtProfileForRewriting( + createArtProfileProvider(artProfile), + createResidualArtProfileConsumer(residualArtProfileInspector)); + } + + public static void addArtProfileForRewriting( + ExternalArtProfile artProfile, + Consumer<ExternalArtProfile> residualArtProfileInspector, + DesugaredLibraryTestBuilder<?> testBuilder) { + testBuilder.addL8ArtProfileForRewriting( + createArtProfileProvider(artProfile), + createResidualArtProfileConsumer(residualArtProfileInspector)); + } + + // Creates an ArtProfileProvider for passing the given ART profile to a D8/L8/R8 compilation. + private static ArtProfileProvider createArtProfileProvider(ExternalArtProfile artProfile) { + return new ArtProfileProvider() { + + @Override + public void getArtProfile(ArtProfileBuilder profileBuilder) { + artProfile.forEach( + classRule -> + profileBuilder.addClassRule( + classRuleBuilder -> + classRuleBuilder.setClassReference(classRule.getClassReference())), + methodRule -> + profileBuilder.addMethodRule( + methodRuleBuilder -> + methodRuleBuilder + .setMethodReference(methodRule.getMethodReference()) + .setMethodRuleInfo( + methodRuleInfoBuilder -> + methodRuleInfoBuilder + .setIsHot(methodRule.getMethodRuleInfo().isHot()) + .setIsStartup(methodRule.getMethodRuleInfo().isStartup()) + .setIsPostStartup( + methodRule.getMethodRuleInfo().isPostStartup())))); + } + + @Override + public Origin getOrigin() { + return Origin.unknown(); + } + }; + } + + // Creates an ArtProfileConsumer for accepting the residual ART profile from the compilation. + private static ArtProfileConsumer createResidualArtProfileConsumer( + Consumer<ExternalArtProfile> residualArtProfileInspector) { + return new ArtProfileConsumer() { + + final ExternalArtProfile.Builder residualArtProfileBuilder = ExternalArtProfile.builder(); + + @Override + public ArtProfileRuleConsumer getRuleConsumer() { + return new ArtProfileRuleConsumer() { + + @Override + public void acceptClassRule( + ClassReference classReference, ArtProfileClassRuleInfo classRuleInfo) { + residualArtProfileBuilder.addRule( + ExternalArtProfileClassRule.builder().setClassReference(classReference).build()); + } + + @Override + public void acceptMethodRule( + MethodReference methodReference, ArtProfileMethodRuleInfo methodRuleInfo) { + residualArtProfileBuilder.addRule( + ExternalArtProfileMethodRule.builder() + .setMethodReference(methodReference) + .setMethodRuleInfo(methodRuleInfo) + .build()); + } + }; + } + + @Override + public void finished(DiagnosticsHandler handler) { + residualArtProfileInspector.accept(residualArtProfileBuilder.build()); + } + }; + } +}
diff --git a/src/test/java/com/android/tools/r8/regress/b191296688/Regress191296688.java b/src/test/java/com/android/tools/r8/regress/b191296688/Regress191296688.java index 9dc3d7f..0fc1c4e 100644 --- a/src/test/java/com/android/tools/r8/regress/b191296688/Regress191296688.java +++ b/src/test/java/com/android/tools/r8/regress/b191296688/Regress191296688.java
@@ -30,8 +30,9 @@ return buildParameters( getTestParameters().withDexRuntimes().withAllApiLevels().build(), getKotlinTestParameters() - .withCompiler(KotlinCompilerVersion.KOTLINC_1_5_0) + .withCompilersStartingFromIncluding(KotlinCompilerVersion.KOTLINC_1_5_0) .withTargetVersion(KotlinTargetVersion.JAVA_8) + .withOldCompilersStartingFrom(KotlinCompilerVersion.KOTLINC_1_5_0) .build()); }
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/CheckDiscardedFailuresWithIfRulesAndVerticalClassMergingTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/CheckDiscardedFailuresWithIfRulesAndVerticalClassMergingTest.java new file mode 100644 index 0000000..2541213 --- /dev/null +++ b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/CheckDiscardedFailuresWithIfRulesAndVerticalClassMergingTest.java
@@ -0,0 +1,115 @@ +// Copyright (c) 2023, 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.ifrule.verticalclassmerging; + +import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType; +import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; +import static com.android.tools.r8.utils.codeinspector.Matchers.notIf; +import static org.hamcrest.MatcherAssert.assertThat; + +import com.android.tools.r8.NoVerticalClassMerging; +import com.android.tools.r8.R8TestBuilder; +import com.android.tools.r8.TestBase; +import com.android.tools.r8.TestParameters; +import com.android.tools.r8.errors.CheckDiscardDiagnostic; +import com.android.tools.r8.utils.BooleanUtils; +import com.android.tools.r8.utils.codeinspector.AssertUtils; +import java.util.List; +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 CheckDiscardedFailuresWithIfRulesAndVerticalClassMergingTest extends TestBase { + + @Parameter(0) + public boolean enableCheckDiscard; + + @Parameter(1) + public boolean enableVerticalClassMerging; + + @Parameter(2) + public TestParameters parameters; + + @Parameters(name = "{2}, check discard: {0}, vertical class merging: {1}") + public static List<Object[]> data() { + return buildParameters( + BooleanUtils.values(), + BooleanUtils.values(), + getTestParameters().withAllRuntimesAndApiLevels().build()); + } + + @Test + public void test() throws Exception { + AssertUtils.assertFailsCompilationIf( + enableCheckDiscard, + () -> + testForR8(parameters.getBackend()) + .addInnerClasses(getClass()) + .addKeepMainRule(Main.class) + .addKeepRules( + "-if class " + A.class.getTypeName(), "-keep class " + C.class.getTypeName()) + .addNoVerticalClassMergingAnnotations() + .addVerticallyMergedClassesInspector( + inspector -> { + if (enableVerticalClassMerging) { + inspector.assertMergedIntoSubtype(A.class); + } else { + inspector.assertNoClassesMerged(); + } + }) + // Intentionally fail compilation due to -checkdiscard. This triggers the + // (re)running of the Enqueuer after the final round of tree shaking, for generating + // -whyareyoukeeping output. + .applyIf( + enableCheckDiscard, + testBuilder -> + testBuilder.addKeepRules("-checkdiscard class " + Main.class.getTypeName())) + .applyIf( + !enableVerticalClassMerging, + R8TestBuilder::enableNoVerticalClassMergingAnnotations) + .setMinApi(parameters.getApiLevel()) + .compileWithExpectedDiagnostics( + diagnostics -> { + if (enableCheckDiscard) { + diagnostics.assertErrorsMatch(diagnosticType(CheckDiscardDiagnostic.class)); + } else { + diagnostics.assertNoMessages(); + } + }) + // TODO(b/266049507): It is questionable not to keep C when vertical class merging + // is enabled. A simple fix is to disable vertical class merging of classes matched + // by the -if condition. + .inspect( + inspector -> + assertThat( + inspector.clazz(C.class), + notIf(isPresent(), enableVerticalClassMerging))) + .run(parameters.getRuntime(), Main.class) + .assertSuccessWithOutputLines("B")); + } + + static class Main { + + public static void main(String[] args) { + System.out.println(new B()); + } + } + + @NoVerticalClassMerging + static class A {} + + static class B extends A { + + @Override + public String toString() { + return "B"; + } + } + + static class C {} +}
diff --git a/third_party/kotlin/kotlin-compiler-1.8.0.tar.gz.sha1 b/third_party/kotlin/kotlin-compiler-1.8.0.tar.gz.sha1 new file mode 100644 index 0000000..71da776 --- /dev/null +++ b/third_party/kotlin/kotlin-compiler-1.8.0.tar.gz.sha1
@@ -0,0 +1 @@ +7863f9b7feccc1391176597e1417399b9edc5923 \ No newline at end of file
diff --git a/tools/archive_smali.py b/tools/archive_smali.py new file mode 100755 index 0000000..fdfb75c --- /dev/null +++ b/tools/archive_smali.py
@@ -0,0 +1,148 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023, 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. + +import argparse +import os +import re +try: + import resource +except ImportError: + # Not a Unix system. Do what Gandalf tells you not to. + pass +import shutil +import subprocess +import sys + +import utils + +ARCHIVE_BUCKET = 'r8-releases' +REPO = 'https://github.com/google/smali' +NO_DRYRUN_OUTPUT = object() + +def checkout(temp): + subprocess.check_call(['git', 'clone', REPO, temp]) + return temp + + +def parse_options(): + result = argparse.ArgumentParser(description='Release Smali') + result.add_argument('--archive-hash', + required=True, + metavar=('<main hash>'), + help='The hash to use for archiving a smali build') + result.add_argument('--version', + required=True, + metavar=('<version>'), + help='The version of smali to archive.') + result.add_argument('--dry-run', '--dry_run', + nargs='?', + help='Build only, no upload.', + metavar='<output directory>', + default=None, + const=NO_DRYRUN_OUTPUT) + result.add_argument('--checkout', + help='Use existing checkout.') + return result.parse_args() + + +def set_rlimit_to_max(): + (soft, hard) = resource.getrlimit(resource.RLIMIT_NOFILE) + resource.setrlimit(resource.RLIMIT_NOFILE, (hard, hard)) + + +def Main(): + options = parse_options() + if not utils.is_bot() and not options.dry_run: + raise Exception('You are not a bot, don\'t archive builds. ' + + 'Use --dry-run to test locally') + if options.checkout and not options.dry_run: + raise Exception('Using local checkout is only allowed with --dry-run') + if not options.checkout and (not options.archive_hash or not options.version): + raise Exception('Both --archive-hash and --version are required') + + if utils.is_bot() and not utils.IsWindows(): + set_rlimit_to_max() + + with utils.TempDir() as temp: + # Resolve dry run location to support relative directories. + dry_run_output = None + if options.dry_run and options.dry_run != NO_DRYRUN_OUTPUT: + if not os.path.isdir(options.dry_run): + os.mkdir(options.dry_run) + dry_run_output = os.path.abspath(options.dry_run) + + checkout_dir = options.checkout if options.checkout else checkout(temp) + with utils.ChangedWorkingDirectory(checkout_dir): + assert options.archive_hash + subprocess.check_call(['git', 'checkout', options.archive_hash]) + + # Find version from `build.gradle`. + for line in open(os.path.join('build.gradle'), 'r'): + result = re.match( + r'^version = \'(\d+)\.(\d+)\.(\d+)\'', line) + if result: + break + version = '%s.%s.%s' % (result.group(1), result.group(2), result.group(3)) + if version != options.version: + raise Exception( + 'Commit % has version %s, expected version %s' + % (options.archive_hash, version, options.version)) + print('Building version: %s' % version) + + # Build release to local Maven repository. + m2 = os.path.join(temp, 'm2') + os.mkdir(m2) + subprocess.check_call( + ['./gradlew', '-Dmaven.repo.local=%s' % m2 , 'release', 'publishToMavenLocal']) + base = os.path.join('com', 'android', 'tools', 'smali') + + # Check that the local maven repository only has the single version directory in + # each artifact directory. + for name in ['smali-util', 'smali-dexlib2', 'smali', 'smali-baksmali']: + dirnames = next(os.walk(os.path.join(m2, base, name)), (None, None, []))[1] + if not dirnames or len(dirnames) != 1 or dirnames[0] != version: + raise Exception('Found unexpected directory %s in %s' % (dirnames, name)) + + # Build an archive with the relevant content of the local maven repository. + m2_filtered = os.path.join(temp, 'm2_filtered') + shutil.copytree(m2, m2_filtered, ignore=shutil.ignore_patterns('maven-metadata-local.xml')) + maven_release_archive = shutil.make_archive( + 'smali-maven-release-%s' % version, 'zip', m2_filtered, base) + + # Collect names of the fat jars. + fat_jars = list(map( + lambda prefix: '%s-%s-fat.jar' % (prefix, version), + ['smali/build/libs/smali', 'baksmali/build/libs/baksmali'])) + + # Copy artifacts. + files = [maven_release_archive] + files.extend(fat_jars) + if options.dry_run: + if dry_run_output: + print('Dry run, not actually uploading. Copying to %s:' % dry_run_output) + for file in files: + destination = os.path.join(dry_run_output, os.path.basename(file)) + shutil.copyfile(file, destination) + print(" %s" % destination) + else: + print('Dry run, not actually uploading. Generated files:') + for file in files: + print(" %s" % os.path.basename(file)) + else: + destination_prefix = 'gs://%s/smali/%s' % (ARCHIVE_BUCKET, version) + if utils.cloud_storage_exists(destination_prefix): + raise Exception('Target archive directory %s already exists' % destination_prefix) + for file in files: + destination = '%s/%s' % (destination_prefix, os.path.basename(file)) + if utils.cloud_storage_exists(destination): + raise Exception('Target %s already exists' % destination) + utils.upload_file_to_cloud_storage(file, destination) + public_url = 'https://storage.googleapis.com/%s/smali/%s' % (ARCHIVE_BUCKET, version) + print('Artifacts available at: %s' % public_url) + + print("Done!") + +if __name__ == '__main__': + sys.exit(Main())
diff --git a/tools/gmaven.py b/tools/gmaven.py new file mode 100644 index 0000000..1ad96c0 --- /dev/null +++ b/tools/gmaven.py
@@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023, 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. + +import re +import subprocess + +GMAVEN_PUBLISHER = '/google/bin/releases/android-devtools/gmaven/publisher/gmaven-publisher' +GMAVEN_PUBLISH_STAGE_RELEASE_ID_PATTERN = re.compile('Release ID = ([0-9a-f\-]+)') + + +def publisher_stage(gfiles, dry_run = False): + if dry_run: + print('Dry-run, would have staged %s' % gfiles) + return 'dry-run-release-id' + + print("Staging: %s" % ', '.join(gfiles)) + print("") + + cmd = [GMAVEN_PUBLISHER, 'stage', '--gfile', ','.join(gfiles)] + output = subprocess.check_output(cmd) + + # Expect output to contain: + # [INFO] 06/19/2020 09:35:12 CEST: >>>>>>>>>> Staged + # [INFO] 06/19/2020 09:35:12 CEST: Release ID = 9171d015-18f6-4a90-9984-1c362589dc1b + # [INFO] 06/19/2020 09:35:12 CEST: Stage Path = /bigstore/studio_staging/maven2/sgjesse/9171d015-18f6-4a90-9984-1c362589dc1b + + matches = GMAVEN_PUBLISH_STAGE_RELEASE_ID_PATTERN.findall(output.decode("utf-8")) + if matches == None or len(matches) > 1: + print("Could not determine the release ID from the gmaven_publisher " + + "output. Expected a line with 'Release ID = <release id>'.") + print("Output was:") + print(output) + sys.exit(1) + + print(output) + + release_id = matches[0] + return release_id + + +def publisher_stage_redir_test_info(release_id, artifact, dst): + + redir_command = ("/google/data/ro/teams/android-devtools-infra/tools/redir " + + "--alsologtostderr " + + "--gcs_bucket_path=/bigstore/gmaven-staging/${USER}/%s " + + "--port=1480") % release_id + + get_command = ("mvn org.apache.maven.plugins:maven-dependency-plugin:2.4:get " + + "-Dmaven.repo.local=/tmp/maven_repo_local " + + "-DremoteRepositories=http://localhost:1480 " + + "-Dartifact=%s " + + "-Ddest=%s") % (artifact, dst) + + print("""To test the staged content with 'redir' run: + +%s + +Then add the following repository to settings.gradle to search the 'redir' +repository: + +dependencyResolutionManagement { + repositories { + maven { + url 'http://localhost:1480' + allowInsecureProtocol true + } + } +} + +and add the following repository to gradle.build for for the staged version: + +dependencies { + implementation('%s') { + changing = true + } +} + +Use this commands to get artifact from 'redir': + +rm -rf /tmp/maven_repo_local +%s +""" % (redir_command, artifact, get_command)) + + +def publisher_publish(release_id, dry_run = False): + if dry_run: + print('Dry-run, would have published %s' % release_id) + return + + cmd = [GMAVEN_PUBLISHER, 'publish', release_id] + output = subprocess.check_output(cmd)
diff --git a/tools/release_smali.py b/tools/release_smali.py new file mode 100755 index 0000000..12a9389 --- /dev/null +++ b/tools/release_smali.py
@@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023, 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. + +import argparse +import sys + +import gmaven + +ARCHIVE_BUCKET = 'r8-releases' +REPO = 'https://github.com/google/smali' + +def parse_options(): + result = argparse.ArgumentParser(description='Release Smali') + result.add_argument('--version', + required=True, + metavar=('<version>'), + help='The version of smali to release.') + result.add_argument('--dry-run', + default=False, + action='store_true', + help='Only perform non-commiting tasks and print others.') + return result.parse_args() + + +def Main(): + options = parse_options() + gfile = ('/bigstore/r8-releases/smali/%s/smali-maven-release-%s.zip' + % (options.version, options.version)) + release_id = gmaven.publisher_stage([gfile], options.dry_run) + + print('Staged Release ID %s.\n' % release_id) + gmaven.publisher_stage_redir_test_info( + release_id, 'com.android.tools.smali:smali:%s' % options.version, 'smali.jar') + + print() + answer = input('Continue with publishing [y/N]:') + + if answer != 'y': + print('Aborting release to Google maven') + sys.exit(1) + + gmaven.publisher_publish(release_id, options.dry_run) + + print() + print('Published. Use the email workflow for approval.') + +if __name__ == '__main__': + sys.exit(Main())