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